Git for version control
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
- uncommitted
- 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
- A successful Git branching model: it talks about branching strategy for development and release