Git: Twelve Curated Tips And Workflows From The Trenches
My Evernote tech-tips folder and my Notational Velocity stash have been collecting a huge list of git tips, many of which I have to look up again and again. Until I finally give up and create aliases for them (by the way you can find some of my more advanced git aliases explained in my previous post).
I expect many git practitioners will find them useful as much as I do. Here we go, let’s start from tiny and simple things first.
Making ‘git diff’ wrap long lines
This has been driving me mad for a while. My
git diff would not wrap lines and leave a lot of information hidden from view in my terminal. Luckily the solution for this is easy.
If you use
less as default pager just type
-S while viewing the diff to reenable wrapping in
You can also use git config to setup pager to wrap:
$ git config core.pager 'less -r'
Sets the pager setting for the current project.
$ git config --global core.pager 'less -r'
Sets the pager globally for all projects. (Stack Overflow reference)
Set a global proxy
In some network configurations you might need to use a proxy with your
git. It is a straight forward oneliner to do so:
git config --global https.proxy https://user:password@address:port
Clone only a specific branch
For big projects or for ease of access sometimes you want to clone just one branch. To clone a branch without fetching other branches here’s what you can do:
mkdir $BRANCH cd $BRANCH git init git remote add -t $BRANCH -f origin $REMOTE_REPO git checkout $BRANCH
Diff file against remote branch
This is basic git knowledge but it does not hurt to show you. Here is the outline:
git diff localbranch remotebranch filepath
As an example, supposing you have a few local and remote branches fetched and up-to-date:
[developer][ubuntu:~/delixl] $ git branch -ra * 631 fsh-502 master remotes/6.29 remotes/6.30 remotes/6.31 remotes/ECM-1670.3 remotes/trunk
You can perform a diff with one of the remote branches with:
git diff master ECM-1670.3 pom.xml diff --git a/pom.xml b/pom.xml index f3fc810..27154e3 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ <groupId>nl.delixl</groupId> <artifactId>delixl</artifactId> <packaging>pom</packaging> - <version>6.32-SNAPSHOT</version> + <version>7.30-SNAPSHOT</version> [...]
List all deleted files in the repository
You might want to restore them, you might want to double check some merge behavior, in any case it’s quite useful to be able to list all the files that have been deleted in your repository. Here’s how to go about it:
git log --diff-filter=D --summary
If you want to restore some of them see this.
If you don’t want all the information about which commit they were removed in, you can just add a grep delete in there.
git log --diff-filter=D --summary | grep delete
Search for a string in all revisions of entire git history
I had to do this many times. I remember a piece of code, a function name, a constant, a file, that was there. And now it’s gone. What happened? In which commit was it removed? This trick rocks as you can search through the entire git diff history for a string.
Update: Jaime in the comments thread pointed me to the right way to do this:
git log -Stext
I was doing it in an inefficient way found on SO:
git rev-list --all | ( while read revision; do git grep -F 'Your search string' $revision done )
Apply a patch from another (unrelated) local repository
The proper way to cherry-pick a commit from another repository is to first add the other repository as a remote, fetch its changes and then cherry-pick the commit.
But if you want a raw and quick procedure, that works even between unrelated repositories you can do:
git --git-dir=../some_other_repo/.git format-patch -k -1 --stdout <commit SHA>| git am -3 -k
Making a more recent branch the new master
Sometimes you work on a separate
better_branch for quite some time, and you’re so satisfied with it that it makes sense to just make it the new
master. So how do you do it? As usual stack overflow to the rescue:
Switch to the
git checkout better_branch
Keep the full content of
better_branchbut record a merge:
git merge --strategy=ours master
git checkout master
Fast-forward master up to the merge:
git merge better_branch
If you want your history to be a little clearer, you can customize the commit message to clarify what you are doing. You can change the second step to:
git merge --strategy=ours --no-commit master git commit # Here add your custom message to the commit template
Adding an initial empty commit to a branch to allow full rebase
This tip rewrites history so as usual you should only do it on branches that you haven’t shared with anyone, otherwise you risk breaking things for all your peers.
Create a new empty branch i.e.
git checkout --orphan newroot git rm --cached -r . git clean -f -d
Create the empty commit
git commit --allow-empty -m '[empty] initial commit'
Replay the whole content of the branch
git rebase --onto newroot --root master
Delete the temporary branch
git branch -d newroot
Done. Your master had its history rewritten to include an empty root commit. (Stack overflow reference)
Zero a branch to do something radically different
Sometimes you want a branch where you can start everything from scratch, or keep some code that logically is related to your master but tracks another cross-functional aspect of it. Like
gh-pages in a github project.
So how do you zero a branch, erasing all its history so that you can start something new?
Update: helpful user in the comments and in the reddit thread pointed me to a much easier way to accomplish this:
git checkout --orphan new_empty_branch
My original process was way more convoluted:
Checkout a branch:
git checkout -b branch_to_zero
Follow the tip above about adding an initial empty commit and after that you can very easily zero a branch by doing a simple reset.
Reset hard the branch to the initial commit you just created
git reset --hard initial_commit
How to modify a specified commit?
The amend command (
git commit --amend) is very useful to rework your last commit before pushing it. But what if the commit you want to change is not the last?
You can use git rebase, for example, if you want to modify commit
$ git rebase bbc643cd^ --interactive
In the default editor, modify
edit in the line whose commit you want to modify. Make your changes and then stage them with:
$ git add <filepattern>
Now you can use:
$ git commit --amend
To modify the commit, and after that
$ git rebase --continue
To return back to the previous head commit. (Stack Overflow reference)
How to stash only one file out of multiple files that have changed
git stash --keep-index Will stash everything that you haven’t previously added. Just git add the things you want to keep, then run it.
By using this you can split an old commit into more than one changeset:
Rebase interactively from your last good commit:
git rebase -i last_good_commit
Mark some changes as
git reset HEAD^
Add the files you want to keep in this change:
git add file1 file2 file3
Stash everything that you haven’t previously added:
git stash --keep-index
Fix things up as necessary. Don’t forget to
git addany changes.
git commit git stash pop
Repeat, from step 2, as necessary.
git rebase --continue
I hope you enjoyed these tips and workflows roundup. More is in store if there is interest.
Notifications for new articles and virtual interactions with the author of this (me!) are available on twitter @durdn.
5 December 2012