Neat new features in Git 2.7

A quick two months after 2.6, Git 2.7 has been released with a plethora of
features, fixes and performance improvements. Here's some of the new stuff we
found interesting on the Bitbucket team.

Rounding out git worktree

The awesome git worktree command, introduced in Git 2.5, lets you check out
and work on multiple repository branches in separate directories, simultaneously.
For example, if you need to make a quick hotfix and don't want to mess with
your working copy you can check out a new branch in a new directory with:

The git bisect command's support for worktrees has also been improved. The
refs that bisect uses to track "good" and "bad" commits have been moved from
.git/refs/bisect to .git/refs/worktrees/$worktree_name/refs/bisect so you
can run bisects concurrently across multiple worktrees.

For completeness, as of Git 2.7, you can also now clone a worktree on disk.
This creates a new, independent Git repository (not another worktree).

Fun-fact: Git worktrees aren't just for branches! When researching the new
Git functionality for this post I compared the Git v2.6.0 and v2.7.0 tags in
parallel by checking them out in separate worktrees and building them:

A couple of git stash improvements

If you're a fan of git rebase, you might be familiar with the --autostash
option. It automatically stashes any local changes made to your working copy
before rebasing, and reapplies them after the rebase is completed.

$ git rebase master --autostash
Created autostash: 54f212a
HEAD is now at 8303dca It's a kludge, but put the tuple from the database in the cache.
First, rewinding head to replay your work on top of it...
Applied autostash.

This is handy as it allows you to rebase from a dirty worktree. There's also
a handy config flag named rebase.autostash to make this behaviour the default,
which you can enable globally with:

$ git config --global rebase.autostash true

rebase.autostash has actually been available since Git 1.8.4, but 2.7
introduces the ability to cancel this flag with the --no-autostash option. I
think this is mainly for completeness, as using it only seems to give you the
dirty worktree warning:

As an aside: --no-patchis a valid option, but doesn't negate stash.showPatch
as you'd expect.

git filter-branch gained speed (and a progress bar)

git filter-branch is a versatile tool for rewriting git history. Since
every commit object has a reference to its parents (and transitively to all of
its ancestors), rewriting a particular commit means rewriting all of its
successors as well. This means that even trivial history rewriting operations
can take some time if you pick an older commit.

Git 2.7 introduces a nifty new progress bar that estimates how much time a
filter-branch command will take to complete:

As a bonus, filter-branch commands that don't modify the index or tree, now
skip reading the index entirely, leading to dramatically better performance.
The commit-filter command in the GIF above simply rewrites the Git author
associated with each commit name from my real name ("Tim Pettersen"), to my
handle ("Kannonboy"), and doesn't touch the tree. It took only ~38s to rewrite
the first 1000 commits of Bitbucket Server under Git 2.7.0, versus ~64s under
Git 2.6.0: an impressive ~40% improvement. The tests introduced with the performance improvements show even more dramatic savings of ~60%.

Improved negation in .gitignore

.gitignore files let you exclude certain files that reside within your
worktree being staged in your repository. You can negate these patterns
by prepending a ! to "unignore" a particular file. For example:

# .gitignore
*.json
!cat.json

Will ignore all json files exceptcat.json.

However, in Git 2.6, you couldn't apply a negation to a file residing in a
directory that had been ignored.