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
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
rebaseor if the operation should fail in that case. You can make this behavior permanent by setting a new configuration option
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
Better handling of multiple clones: Git Worktree
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
checkouta different branch (using
- 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_DIRenvironment variables, as explained here.
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-folderwhich contains the checked out branch
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
Track topic branches with
show-branch – in the words of the Git documentation – “shows the commit ancestry graph starting from the commits named with
--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
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.
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.
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.