Git good — advance the knowledge
There are at least three very important things, almost every software developer should have a good knowledge of. That is a good familiarity of the code editor, an even better grasp of the version control system and some scripting proficiency. Nowadays our IDEs are becoming the swiss knives for everything, sometimes to the point of blatant Wenger 16999. I, however, prefer sticking to basic tools, which often prove to be more powerful at specific things than a "jack of all trades, master of none" solution.
So, by knowing well your version control system, you will be able to do things that are not possible from the IDE interface and you will retain this knowledge even after switching the editor. As for scripting, it comes handy in many cases, mostly during maintenance (searching through log files), bug fixing (creating data fixing scripts) and development (parsing and creating input/output data files).
Today I will refer to the second point and I will show you the most useful Git commands that I use in my daily work, which greatly improve my productivity. For a more accurate (but without a context) description, you can refer to the explainshell site, which explains commands bit by bit. Git documentation can be found here.
Command | Description | Warning |
---|---|---|
git log --pretty=format:"%h | A: %aN/%ad | C: %cN/%cd | %s" --date=format:"%y-%m-%d %H:%M:%S"
|
Shows formatted commit logs:
| |
git log --all --graph --decorate --oneline
| Shows a nicely formatted commit history in oneline graph-text format. | |
git log [a]..[b]
|
Shows commit logs between two tags/commits/branches:
| |
git reflog
|
Displays reference logs of the local repository and branch tip updates. Useful for:
| |
git diff [a]..[b] --name-only
|
Displays names o files which have been changed between a and b. Useful for:
| |
git pull --rebase origin master
| Pulls master from origin and rebases changes on top of that. |
|
git merge -X [theirs|ours] feature
| Merges feature branch into the current branch using default recursive strategy and in case of conflicts, takes ours/theirs (feature) changes instead of ours/theirs. | Conflicts are helpful to properly maintain and merge crossing features. |
git checkout feature && git merge -s ours master && git checkout master && git merge feature
|
Overwrites master with feature branch without rewriting history:
| |
git commit --date=relative.1.day.ago
| Commit with author date pushed back by one day. | |
git commit --date "$(date -d 24hours)"
|
Commit with author date in future:
| |
git commit --amend
|
Stage changes (git add ) before running this command to reuse the most recent commit (e.g. if you forgot to add/remove something):
| Rewrites history. |
git rebase --committer-date-is-author-date HEAD~1
| Runs non-interactive rebase to change committer date to the author date for the HEAD commit. | Rewrites history. |
git reset --hard [commit]
|
Resets index and working tree to a specific point. Use:
| Can rewrite history. |
git reset --soft HEAD~
| Discards last commit and retains staged files. | Rewrites history. |
git revert [commit]
|
Reverts specific commit introducing an additional one. Use:
| Can cause conflicts. |
git checkout different-branch -- path/to/a/file
| Copies file from different-branch from different-branch into the current working tree. | |
git stash [|apply|pop|list|drop]
| A convenient way to temporarily store unfinished (staged) work when switching branches. | |
git checkout .
| Undoes unstaged changes. | |
git clean -df
|
Removes untracked files and directories (
-x
also removes ignored files).
|
Can remove files not intended for removal. Consider using:
|
git rebase -i [commit]
|
Run an interactive rebase up to defined commit or branch. What's more:
| Rewrites history. |
git cherry-pick -x [commit]
| Cherry-pick a commit with a referenced commit message. Use:
| Can cause conflicts. |
git filter-branch --env-filter 'export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"'
| Rewrites whole branch resetting committer date of each commit to author date. | Rewrites history. |
git bisect start git bisect bad [|bad_commit] git bisect good [|good_commit] git bisect reset
| A bisect method which helps determine the source of regression bug using divide and conquer principle:
| |
gitk --follow [filename]
|
Displays commits for a given path/file visualizing commits graph and following renamed paths. Useful when:
|
The difference between ^
and ~
when combined with commits is slight but perceptible:
- ref~ is a reference to commit's first parent;
- ref~2 is a reference to commit's first parent's first parent;
- ref^ is a reference to commit's first parent;
- ref^2 is a reference to commit's second parent.
In case you get an error when using HEAD^1, your shell might be interpreting ^
as line continuation symbol, use "HEAD^" instead.
Here is an illustration, by Jon Loeliger. Both commit nodes B and C are parents of commit node A. Parent commits are ordered left-to-right.
G H I J
\ / \ /
D E F
\ | / \
\ | / |
\|/ |
B C
\ /
\ /
A
A = = A^0
B = A^ = A^1 = A~1
C = A^2 = A^2
D = A^^ = A^1^1 = A~2
E = B^2 = A^^2
F = B^3 = A^^3
G = A^^^ = A^1^1^1 = A~3
H = D^2 = B^^2 = A^^^2 = A~2^2
I = F^ = B^3^ = A^^3^
J = F^2 = B^3^2 = A^^3^2
There are also other ways to reference the revisions like master@{yesterday}
, @{push}
, /"fix nasty bug"
. You can read more about them in the git documentation about git rev-parse. One last thing which I would like to point out is that there is a difference between double-dot and triple-dot commit ranges. Check out the graphs on Chuck Lu's blog for a better insight on that.