Skip to content

Using Git For Lirch

Tor E Hagemann edited this page Jun 24, 2013 · 9 revisions

You rang? - Lurch (The Addams Family)

The basics of using git are covered by an inordinate amount of tutorials. (Some are good; some can be very bad, depending on your prior experience with version control.) I've found the best policy is to shop around until you find one that just makes sense to you. There are also lots of reference guides. (If you're coming from a system like Mercurial, this might be all you need.) GitHub has some pretty good ones itself, along with a beginner's tutorial. If this is your first git project, make sure to run (at least) the two initial git config --global commands that configure your name and email address. This info will be (automatically) included in each commit you make, in order to link your authorship with the associated change-set. (Other more-advanced facilities, like signing-off on tags et cetera, also require such information.) All commands listed herein should be issued from a prompt in a directory that is a git repository (one containing a .git folder).

Scheme

Lirch uses a "branch-y" development scheme, which means every "topic" goes in its own branch. A topic can be a new feature, overhaul of an old one, etc. Just a cohesive logical unit, basically (one or more commits that modify the code base with a common aim [fixing communication between two subsystems] or for a specific purpose [adding new functionality]).

Topic Branches

When you want to make a new topic, branch off master. From there, you can branch into sub-features or what have you. The general idea is that new working slates are borne of the stable code base, and the result will return once it has properly matured to fulfill its purpose. (Then, the branch can safely be removed.) This allows everything to merge cleanly back into master, when the time comes for making a release. (So the master branch should basically consist of "merge" commits entirely.) Caveat: you can avoid branching for very small things, or tweaks that are largely independent of the remaining code base, like spelling errors. (However, if you're overhauling a bulk of the documentation, you might consider using a separate branch.) You can always check your branches using git branch -a, examine the current HEAD with git show, and get information about the current situation (state of your working directory) with git status.

Example (adding a plug-in)

  • Clone the repository and checkout master. git clone -b master <origin_git_url> <working_dir>
  • Enter the new directory; you're on master automatically, so make a branch. git branch <branch_name>
  • Now you've got a local branch and that came from the master. Switch to it. git checkout <branch_name> (You can also create and checkout a new branch in one command. git checkout -b <branch_name>) Please make your branch as descriptive as possible to help others identify its purpose. On many systems, tab completion is available, so don't worry about using long branch names like fix-crash-on-config-window-minimize.
  • Now you'll do your work. When you encounter logical divisions in your development, commit: 1) Select the files you'd like to include in this commit: git add _file1_ _file2_ This is called "staging." 2) Type git commit. Your system's default editor will open. In the first 80 lines, provide a short description of your changes. If you'd like to include more detailed notes, add a blank line after the first and type to your heart's content. These long-forms are ignored in situations where only short digests are needed, for brevity.
  • As often as you please (push early, push often!) check in your commits. git push origin HEAD (You should be able to see your contribution on GitHub immediately!)

Example (safe update procedure)

  • Let's say you've made commits that improve some files, but you want to make sure not to trample anyone else's work on those files, which may have happened in the meantime (git calls this a "fast-forward"). (The nice thing about git is that if you manage to do this accidentally [unless you're really quite thorough about stampeding] the damage is completely reversible! But, it may require some finesse.)
  • For the sake of simplicity, you're working on branch "branch_name", which is present on "origin".
  • You can check git status to make sure there are no changes pending on the current branch. (This is always safe, and in general, a good move before any potentially-destructive operation.)
  • Make sure your repository knows about everything that's present on the remote-end: git fetch origin --prune (This does not apply any changes. You're telling git to check for any activity that's happened on "origin" since your last fetch. When you "clone" you're fetching into a new directory and checking out a certain branch [usually master]. The --prune flag cleans up your local copy by removing old branches that are no longer present on the other end and that you do not have a newer version of yourself.)
  • Use git merge origin/branch_name to merge "origin/branch_name" into your updated copy of "branch_name". (!!! You might have conflicts to clean up at this point, if someone modified the same line as you did and checked it their changes before you. These will be obviously marked in the files git lists as conflicting. Your client should issue easy-to-follow instructions for how to resolve the conflicts, which will conclude with a commit, to seal the merge. !!!)
  • Now, you can safely run git push origin branch_name, or git push origin HEAD to complete your check-in.

Example (moving files around)

It might happen that you'd like to rename x.cpp to y.cpp. (Or move x.cpp to z/x.cpp.) Don't just mv files and make a commit! Git allows you to let it know when the file structure changes. So, use git mv x.cpp y.cpp unless you want enormous diffs. (Under normal conditions, every line in "x.cpp" would be marked removed, and a new file with as many "new" lines will appear in the repository. git mv prevents this mess.) You might want to consider making any git mv in its own commit so as not to confuse modifications to files before and after, but this may be done at your own discretion. The same applies for git rm <old_file>, which also avoids wasting space if the file ever needs to come back.

Useful Tips

  • If you have ephemeral files in your local repository that you would like git to disregard, you can tell git to ignore them by entering their paths, line by line, in the file .gitignore. For example, if you are building the project in the directory build, you might consider adding "build/*". It can also be effective to include the line ".gitignore" in .gitignore, if you'd rather not publish it.
  • Remember that remote branches have "origin/" prefixes, while local ones do not. If you haven't just pushed, they might be very different.
  • You can use the command gitk to view a graphical model of the commit tree.
  • Use git diff <file_name> to show any unstaged changes to a file, in the expected format. (There are many advanced uses for this command [and many others]. No one [except Linus?] knows all of them.)
  • git log provides a mechanism to see a brief history of recent commits on this branch. git blame <file_name> provides the inverse functionality. Use it to view who is responsible for the more recent change on each line of a file.
  • If you're sure you'd like to ditch everything and start fresh: git reset --hard origin/master
  • The stash is an advanced tool for saving works in progress when you've gotta-have-to switch branches and don't want to commit. It works like a stack. git stash or git stash save <label> pushes your unstaged change set to a temporarily location and reverts to a place where you can safely git checkout without loosing unsaved work. When you're done averting whatever catastrophe made you leap into action, you can return to the branch where you "stashed" and get right back to where you were using git stash apply. View your stash stack with git stash list.