I learned the concept of version control in 2006 or 2007 from a tool called CVS. Since I didn’t worked on code with other people on regular basis, CVS meets my needs. When collaborating on paper drafts, we sent tex files or erratum-like messages back and forth, which was a pain. There were also times when we used Word for paper drafts. Word indeed tracks revisions quite nicely, but it hurts in many other ways: mysterious crashes, cross-platform format changes, image placement changes, etc. (Now I think about it, latex + Git may be a good choice.)

When preparing for industry jobs, I picked up Git. And I only started appreciate Git after my job began: it is a life safer to keep the sanity when multiple persons edit the same files at the same time, or one person works on multiple versions of the same files.

In this post, I will briefly describe its idea and list my most used commands. There are also two useful bash scripts: git-completion.bash (tab auto-completion) and git-prompt.sh (change status prompt). I learned about them from Udacity Git course, and you can download them here.

five types of changes

There are five types of changes one can make in a git repo, four of which are with respect to the local repo:

  • local
    • untracked
    • tracked
      • uncommitted
        • unstaged
        • staged
      • committed
  • remote
    • pushed

Three of them are quite intuitive and self-explanatory: untracked, committed, and pushed. In principle, they are enough for a version control system. The staging area provides finer control over the changes to become official.

basics

To interact with remote repo

git clone <remote location>
git fetch [branch]
git merge [branch]
git push
git pull [branch]

To see what’s going on

git log [--oneline]
git diff --stat [--staged]
git difftool
git branch
git remote -v
git blame <file name>
git status

To make changes

git add <file name>
git commit -am "<commit message>"
git commit -a --amend [--no-edit]
git rebase [-i] [branch]
git cherry-pick <commit>

clean up

git clean -dfx
git reset --hard <branch|commit>
git rm --cached [-r] <file/directory name>

collaboration

Instead of sending files to coworkers, it’s better to share a patch

git format-patch HEAD~
git am <patch-name>.patch
  • ~ indicates ancestor
  • ^ indicates parent (merge gives rise to multiple parents)
  • @<{n}> indicates more fine-gained history

Note that HEAD~3 is the same as HEAD~~~ or HEAD^^^, which indicates the grand-grand ancestor. However, it’s not the same as HEAD^3, which indicates the 3rd immediate parent.

ultimate life saver

Even if a commit no longer exists in git log (this is known as dangling commit), e.g., after a rebase or append, we can still go back:

git reflog
git reset --hard HEAD@{<n>}

Even better, there is a command to find uncommited changes (known as dangling blob):

git fsck

These dangling blobs do not have commit messages. You can see their content using

git show <hash>

Note that this reflog is only available on the local machine. If some other machine overwrites the remote Github repo, it may be savaged by checking the repo’s events.

curl -u <username> https://api.github.com/repos/<user>/<repo>/events

If you can find the overwritten commit’ ID, the you can access it at https://github.com/<user>/<repo>/commits/<ID>.

other configurations

git config --global diff.tool vimdiff
git config --global merge.tool vimdiff
git config --global difftool.prompt false

other good reads