It’s been a while since I have reviewed Git release notes but that does not mean I haven’t been eagerly reading more recent ones and incorporating new gems in my routines. To celebrate my birthday (yay!) and the recent release of Bitbucket Server I have collected a round of my favorite features for the Git 2.x
series (up to 2.6
). Let me know if you end up using any of these.
Stashing your changes before rebase
In Git 2.6
the rebase
command received welcome attention. One of the more
interesting new flags is this one:
git rebase --autostash
You can now specify if uncommitted changes should be stashed temporarily when you start a rebase
or if the operation should fail in that case. You can make this behavior permanent by setting a new configuration option rebase.autostash
.
If you set it to true
Git will stash your uncommitted changes before the start of the rebase
and it will re-apply the changes at the end of the operation. If you turn on this feature be ready to handle possible conflicts when the stash content is popped back.
If you turned on the autostash
flag you will be able to temporarily disable it with the new --no-autostash
command line option, courtesy of upcoming release 2.7
.
Better handling of multiple clones: Git Worktree
A new worktree
command has been introduced in Git 2.5. It allows you to maintain multiple checked out work trees of the same root repository. It’s fantastic.
Before this command existed one had a few ways to switch context and work on different streams at the same time:
- Stash the current uncommitted changes and
checkout
a different branch (usinggit stash
). - Create work-in-progress (i.e.
WIP
) commits in the current branch to save ones work and switch branch. - Create a separate full clone of the repository to keep two ongoing development efforts separate and parallel.
- Set the
GIT_WORK_TREE
orGIT_DIR
environment variables, as explained here.
With worktree
one can create a sub-folder of the root project with a specific checked out branch
– or ref
for that matter – and keep working on it until done. The command saves you from having to create separate – out of band – clones.
So imagine you’re happily working on the develop
branch but you are tasked to work for a few days on the rewrite
branch that has massive changes. You can create a worktree
for this extended work and leave your other ongoing effort where it is. The syntax of the command is:
git worktree add [-f] [--detach] [-b <new-branch>] <path> [<branch>]
So in our example the command would become:
git worktree add rewrite-folder rewrite
The command creates a sub-folder in the root of your project named – surprise – rewrite-folder
which contains the checked out branch rewrite
.
We can push and pull from that sub-folder as if we are at the root of our Git project and when we are done with that work we can simply delete the folder rewrite-folder
. The administrative files stored in .git/worktrees
will be eventually pruned, but if you want to be thorough you can easily prune that data with:
git worktree prune [-n] [-v] [--expire <expire>]
Quicker fixes with git commit --fixup
This tip came to my attention because Git contributor Luke Diamand, interviewed in the most recent Git Rev News, mentioned that his favorite Git feature nowadays is git commit --fixup
.
Here’s the setting to understand how to use it. You are working on a feature or a bug fix; You haven’t shared that code with anyone else yet and you realise that one of the previous non-HEAD
commits should be changed – maybe to remove code which should not be there, maybe to fix a bug without creating an extra – unclean – commit. Here’s where commit --fixup
comes in:
Say I have a commit with id 026b6b5
that reads:
026b6b5 [2 days ago] Implement feature A [Author]
I make some changes to my work tree and I just mark this as a “fixup
” of that feature commit:
git commit -a --fixup 026b6b5
This command will create a commit for you that looks like this:
4b7076f [6 seconds ago] (HEAD -> feature-a) fixup! Implement feature A [Author]
The final step before I push this branch is to interactively rebase
it using --autosquash
. Git will pick up all the annotated commits, like the fixup!
one above and weave the fix into the right place:
git rebase --interactive --autosquash master
The command above will open an editor on the rebase interactive sheet with the correct action already pre-filled for you. You can omit the --autosquash
option if you have set the global configuration variable rebase.autosquash=true
in your .gitconfig
.
Track topic branches with show-branch --topics
The command show-branch
– in the words of the Git documentation – “shows the commit ancestry graph starting from the commits named with <rev>s
or <globs>s
semi-visually“.
Adding the --topics
flag will show only commits that are NOT on the branch given. This is useful to quickly hide commits that already appear in the main branch. A refinement has been added on 2.5
that makes the command:
git show-branch --topics HEAD
Compare the given commit against all the local branches. For example in the project containing this blog the result is:
git show-branch --topics HEAD
! [HEAD] Final Draft
* [blog/six-great-features-of-git-2.x] Final Draft
! [blog/git-power-routines] Added slideshare embed
! [blog/move-to-vertx-be-reactive] Initial markdown conversion, missing images
! [blog/reduce-build-time-with-java-8] Code cleanup
! [develop] Changing API to APIs category: we already have some of those.
! [master] minor tweaks, spelling, etc
! [pull-request-viewer-for-bitbucket-with-react-native] Merged in blog/osx-static-golang-binaries (pull request #159)
--------
+ [blog/move-to-vertx-be-reactive] Initial markdown conversion, missing images
+ [blog/reduce-build-time-with-java-8] Code cleanup
+ [blog/reduce-build-time-with-java-8^] Initial port from Confluence
+*++++++ [blog/git-power-routines] Added slideshare embed
Negative “grepping”
Sometimes you want to look for commits that do not have a specific string in their messages. This is where the new flag --invert-grep
comes in. For example find all commits that do not contain a certain issue id:
git log --invert-grep --grep=PRJ-25
It will return all commits that do not contain PRJ-25
in the commit messages. Nifty.
Atomic pushes
You can define the default behavior of a naked git push
by setting the push.default configuration parameter. In the cases where the push command is updating more than one ref
– like when pushing multiple branches or tags at the same time – you can now specify a new option --atomic
that guarantees the updates either all succeed or all fail.
Conclusions
There you have it. The drop is done. Did you find anything interesting? Are you using other esoteric flags in your daily development work? I’d like to hear about it, I am always eager to learn new tricks and flags so tweet at me at @durdn or @atlassiandev or leave a comment here.