Git Pro-tips

Updated 2017-09-15

Add hunks selectively

One of Git’s best practice is to limit every commit to an atomic change. Should your contribution require several changes to the code, it should result in just as many commits.

Sometimes we get carried away, or we simply don’t foresee the extent of our current work. When the time has come to commit, we realize that several, independent changes have occurend into the same file.

Git has a nice command that lets the user select individual hunks for staging:

git add --patch

This might prove daunting from the command-line. A UI can be very practical for this.

Converting repositories from another VCS

Want to revamp a project using another VCS? No problem, Git can import many VCS, such as Subversion. See git-svn(1) for the gory details.

Stashes

git stash

In the middle of an intense hacking session, stashes allow you to save some chunks, revert to a clean workspace, keep on hacking, re-apply the previous chunk, revert, etc. All without commiting anything.

It is also possible to stash the current hack and to keep working on it. A temporary save, in a way.

git stash && git stash apply

Custom logs

Logs decoration can be heavily customized. For instance:

git log --graph --decorate --pretty=format:'%C(yellow)%h %Cgreen%cd%C(bold red)%d%Creset %s' --abbrev-commit --date=short

Diffing

To highlight differences to the word:

git diff --color-words

Most importantly, use a UI for diff’ing between any commits, it helps a lot.

Merging with Ediff

Add this to .gitconfig:

[mergetool.ediff]
cmd = emacs --eval \" (progn (defun ediff-write-merge-buffer () (let ((file ediff-merge-store-file)) (set-buffer ediff-buffer-C) (write-region (point-min) (point-max) file) (message \\\"Merge buffer saved in: %s\\\" file) (set-buffer-modified-p nil) (sit-for 1))) (setq ediff-quit-hook 'kill-emacs ediff-quit-merge-hook 'ediff-write-merge-buffer) (ediff-merge-files-with-ancestor \\\"$LOCAL\\\" \\\"$REMOTE\\\" \\\"$BASE\\\" nil \\\"$MERGED\\\"))\"

[merge]
tool = ediff

Attributes

Some text files may not be “versionable” in that they are hardly human-readable, it not at all (e.g. generated content). A few good examples include .ps, .svg, and most XML-based files.

Git will treat all text files as such and store the diffs when necessary. This will increase disk-space consumption (and bandwidth) and slow down the repository.

You can tell Git to ignore the diff’s for specific extensions:

$ cat .gitattributes
*.pdf -diff
*.ps -diff
*.svg -diff
*.xml -diff

With such a setting, a Git repository can serve as a powerful cloud-based storage service.

Maintenance

Run

git gc

and be surprised by how much your repository just shrinked!

Rebase interactively

Rebasing can be a hassle. Thankfully Git comes with the very handy --interactive option to overview the whole operation from your favorite text editor:

git rebase -i

Delete file from history

Sometimes we need to carry a big binary blob with us. And more often than not we regret our decision!

It is never too late, and assuming the history is not public, you can rewrite it, alleviating it from its binary burden.

A few initial checks are in order:

Time to remove the file ${FILENAME} from the revision: Action!

git filter-branch --index-filter 'git rm --cached --ignore-unmatch ${FILENAME}'

Next, some clean-up might be necessary:

UI

While the git CLI is great and will get you far, I recommend using a dedicated UI such as the excellent Magit. It will ease many operations: