What’s new since Git 1.7

Christophe Porteneuve
10 min readAug 29, 2014

A lot of people use Git without quite tracking what’s coming up in later releases. Sometimes you just go with whatever’s available on your Linux distro, even if that is quite outdated.

So let’s review what happened since Git 1.7 that I consider noteworthy, just so you know what you’re missing :-)

So where am I right now, and how do I upgrade?

At the time of this writing, the current release is 2.1.0, from Aug 15, 2014.

The official website maintains official builds for Mac and Windows (although the latter generally lags a bit; right now it’s at 1.9.4), plus sources should you want/need to compile instead.

On my Mac, I tend to favor Homebrew for such installs and upgrades; it’s usually up-to-date within 48 hours.

You can check out your version like so:

$ git --version
git version 2.1.0

To upgrade on Windows, just use the latest provided download from the official website.

On a Mac, use either the official installer if you had gone that route already, or perhaps use an Homebrew upgrade:

$ brew update

$ brew upgrade git
==> Upgrading 1 outdated package, with result: git 2.1.0

$ git --version
git version 2.1.0

On Linux, if you’re going through official packages (or registered PPAs), use the proper install/upgrade command (usually apt-get on Debian/Ubuntu, yum on Fedora, etc.)

A word on Debian and Ubuntu

For Debian and Ubuntu, official releases usually lag a bit behind, especially LTS releases, that pretty much stick to whatever was available when they originally got out:

  • 10.04 LTS “Lucid Lynx” is on 1.7.0 (Sep. 2010)
  • 12.04 LTS “Precise Pangolin” is on 1.7.9 (Jan. 2012)
  • 14.04 LTS “Trusty Tahr” is on 1.9.1 (Mar. 2014)

I cannot recommend enough that you register the official PPA:

$ sudo add-apt-repository ppa:git-core/ppa

(If you do not have the add-apt-repository command, you need to install the necessary package first☺

$ sudo apt-get install python-software-properties
# And if you are on 14.04+…
$ sudo apt-get install software-properties-common

This way you’ll install git from a very recent source (the PPA is usually up-to-date within 3–4 days of original release).

A curated list of what’s been added to Git

I’m not interested in paraphrasing the release notes: I’d rather focus on new features than on bug/perf fixes, and even then only pick what’s relevant to me.

Specifically, I’ll leave aside everything related to foreign interfaces (bridges between Git and other source control systems) and graphical tools (gitk, git-gui, git-web…), and plumbing commands as well, to focus on porcelain stuff (commands your average user is likely to use on a reasonably frequent basis).

Rather than roll out a section per version, I’ll use three large intervals, intentionally set on the base versions for recent Ubuntu LTS releases.

Before we go in, note that something does get better in a consistent way as versions increase: shell completions and advanced prompts. Unless there’s a particularly cool upgrade, I won’t mention it everytime. And yes, at this point the provided prompts for Bash/Zsh run circles around Oh My Zsh’s fancy prompts.

From 1.7.0 to 1.7.9

There’s been a lot of 1.7.x releases (12!), but most useful updates got in at 1.7.2, which has long remained my “minimum required version.”

We start with numerous safeguards against classic submodule pitfalls:

  • git diff and git status are more detailed and explicit when it comes to local changes to submodules, which helps avoid forgotten commits/pushes on these. Various options and configuration variables let you tweak these news behaviors.
  • git fetch --recurse-submodules appears in 1.7.4, to save a few seconds.
  • Nice safeguard from 1.7.7 on with git push when local commits in submodules haven’t been pushed yet: git push --recurse-submodules=check.
  • Starting with 1.7.8, Git folders for submodules are not embedded in the submodule’s root directory anymore on checkout, but stored in the containing repo’s .git/modules, and referenced from the submodule’s gitfile (that is, the submodule’s .git is a text file with a gitdir: path-to-actual-git-dir line). The reason is that it lets you change the referenced commits in submodules from the containing repo, without having to actually check out submodules just for that.

Logs also got some nice love:

  • The :/pattern revision syntax, which up until 1.7.1 used a simple text and anchored at the beginning of commit messages, is now interpreted as a non-anchored regex, which is much more useful, really.
  • We get some nice colors in git log --decorate from 1.7.2 on.
  • Beyond git log -S: 1.7.4 brings us the regex variant, git log -G. I use this all the time!
  • git log also accepts globs (e.g. *.rb) for paths, starting with 1.7.5.
  • A sweet config option, log.abbrevCommit, shows up in 1.7.6, that dispenses with full-length SHAs in logs and, actually, other commands. Less noise.

A few important — some critical — things happened with merges, rebases, pushes and pulls, too:

  • Here comes the sweet --keep mode for git reset (a variation of git reset --merge, which later turned into git merge --abort)
  • git cherry-pick (and incidentally git revert) learned in 1.7.2 to use merge strategies (using --strategy), which is super handy when dealing with subtrees, for instance.
  • The important config variable merge.ff showed up in 1.7.6, driving the default behavior of git merge when it comes to fast forwards.
  • From 1.7.6 on, git rebase without parameter won’t just no-op when you’re on a tracking branch: it’ll assume git rebase @{u} and rebase on upstream. Not very useful (I would want my remote sync’d first, so go through some form of git pull --rebase instead), but any no-op-becoming-an-op is noteworthy in my book. In a later version it’ll happen to git merge too, tsk tsk…
  • The push.default configuration variable gained a new name for its legacy tracking value: upstream (in 1.7.5). I actually recommend this setting rather than the too-limiting simple.
  • The all-important pull.rebase config variable showed up in 1.7.9 (although just with true and false values yet, we’ll have to wait until 1.8.5 for actual awesomeness).
  • core.autocrlf became wiser and stopped breaking mixed-line-endings files (often fixtures for protocol tests): it only touches 100%-LF files now.

You should also be aware of a few comfort updates:

  • In the spirit of git checkout -, from 1.7.6 on you get git merge - for merging the branch you were on just before (this is actually super frequent). Other commands will follow suit later on that.
  • Version 1.7.7 finally have us the --include-untracked / -u option for git stash! Super cool.
  • Since 1.7.8 you can pass a glob to git branch, but you’ll need to prefix it with the explicit --list option, e.g. git branch --list pr-*.
  • 1.7.9 introduced a new way to do the traditional git commit --amend -C HEAD dance: git commit --amend --no-edit.
  • Lots of cool new features and tweaks on git notes, especially around persisting notes across history rewrites (rebases, amends, etc.).

From 1.7.9 to 1.9.1

An annoying behavior started with 1.7.10: when in a terminal (interactively), a successful merge would feel compelled to open the editor on the commit message, just FYI… This pisses me off like hell, so I disable that by exporting GIT_MERGE_AUTOEDIT=no in my environment.

Especially in the 1.8.x timeframe, tons of new and improved stuff happened. Here’s my selection…

Lots of sweet stuff with log and friends (e.g. diff):

  • git log -S / -G finally honor -i (case insensitive)
  • With 1.8.2, you can auto-disable color codes in your git log formats by prefixing them, e.g. using %C(auto,blue) instead of %C(blue). Not groundbreaking, but useful.
  • Starting at 1.8.3, the special %C(auto) color code can be used to surround %d in your log format. It will re-use the original color codes decorations have (e.g. green for local branches, red for remote branches, yellow for tags, blue for symbolic refs…). Nice little bonus.
  • 1.8.4 experimentally introduces git log -L for tracking the history of specific parts of a file (not just line ranges, either).
  • Since 1.9.0 you can state you’re interested in “all but one path,” e.g. with log you could say git log -- . ‘:!dir’ (do use single quotes around that to avoid shell expansion of the exclamation mark).
  • Also in 1.9.0, you can exclude specific branches from git log and friends using the --exclude=<glob> option, for instance you could deny slash-separated branches with git log --exclude=’*/*’ --branches.
  • You can now globally change the amount of context lines in diffs with the diff.context config variable, starting in 1.8.1.

A couple new tricks with push and pull, including an absolutely golden one:

  • The new simple mode for push.default shows up, which becomes the default in 2.0. I understand how that could prevent beginners from tripping up (even that is debatable, though), but I sure prefer upstream, as I reserve the right to push to non-eponymous remote branches.
  • Finally a zero-defect pull mode thanks to pull.rebase=preserve, thank you Git 1.8.5!

The trend to pile safeguards around submodule pitfalls continues:

  • After its introduction in 1.7.7 with the sole value check, the useful git push --recurse-submodules=… option learns the on-demand value, which actually performs the missing pushes.
  • All git submodule subcommands stopped in 1.8.4 demanding they run from the repo’s root folder. About damn time.

And because subtrees are a sweet alternative to submodules but can be tough to manipulate, 1.7.11 ships with the contrib script git subtree now. I’m not a fan, though: sure, it makes it a breeze to backport a partial log of local subtree changes upstream, but for everything else it completely screws up the history graph.

We also see a few cool things coming up about configuration, attributes and ignored files:

  • The global (i.e. per-user) configuration for Git isn’t necessarily in ~/.gitconfig anymore: it can also be in ~/.config/git/config, which falls in line with XDG base directory layout. It can now have companion files attributes (the default path for core.attributesfile now) and ignore (default path for core.excludesfile now), too.
  • We can finally use **/ in .gitignore (and .gitattributes) starting with 1.8.2, to describe any-depth matching. This of course assumes a prefix path, otherwise it’s superfluous.

As always, the completion and prompt are spruced up, but this time a few aspects of it are very noteworthy:

  • From 1.7.12 on, the completion and prompt scripts have been split apart and made independent.
  • Zsh- and Tcsh-specific completion scripts popped up in 1.8.1.
  • A great improvement to the prompt appeared in 1.8.3: during a rebase, it’ll tell us exactly where we stand (e.g. REBASE-i 3/8), a real joy. Along the same lines, git status will more clearly state this (during a bisect too, by the way).

A few other comfort upgrades worthy of note:

  • From 1.7.12 on, git help automatically uses HTML/browser display when man doesn’t seem to be available (e.g. Windows). You can force this anywhere with git help -w.
  • Rewriting the entire history of a branch used to be tricky as we had no base to specify. 1.7.12 introduces the --root option to express that easily.
  • From 1.8.5 you can now lazy up and type @ anywhere you’d type HEAD. Snappy on a Mac keyboard!
  • Just like merge and checkout before it, cherry-pick learned to interpret a single dash as “the previously active branch tip” in 1.8.5.

Finally, if you were scared of deleting too much with git clean, 1.8.4 introduces the usual -i flag that enters interactive mode. Nifty.

From 1.9.1 to 2.1.0

Starting with 1.9.0, Git went semver, so all 3rd-level versions (e.g. 1.9.1, 1.9.2) are only fixes. New and improved features are at 1st-level (e.g. 2.0.0) or 2nd-level (e.g. 2.1.0).

Anything in this section will currently require Debian/Ubuntu users to go with an alternative install instead of default packages, ideally the official PPA (see beginning of this article).

This is all fairly recent, so there’s less stuff to mention: 2–3 big items and a bunch of comfort/usage things.

  • With 2.0, git rebase joins merge, checkout and cherry-pick in dealing with a single dash as “the previously active branch tip” (as a reminder, a universal syntax for this on any command would be @{-1}).
  • From 2.0 still, git tag --list can sort tags as version numbers, so v2.10.3 would appear after v2.9.4, for instance. Just add --sort=version:refname. As a reminder, the --sort option can prefix its value with a single dash, which inverts the order. If you do mainly tag for versions and want this sorting mode by default, from 2.1 on you can set the new tag.sort config variable for that.
  • The default value for push.default changes to simple with 2.0. Again, I recommend upstream instead.
  • Another big change in 2.0: git add -A / -u without a path now deals with the entire repo, instead of just the local folder and its subfolders. Watch out for your existing scripts, aliases and habits!
  • Also be careful as with 2.1, git merge with no argument isn’t refusing anymore: if you’re tracking an upstream, it’ll merge it, just like rebase is now doing.

So upgrade!

It is with Git as with most of your critical pieces of software: running a recent version is probably a great idea. Remember to regularly upgrade (look at the beginning of this article for how-to’s).

I hope you liked reading this and found a few reasons to upgrade your Git setup if you haven’t already, perhaps even found out about cool features you didn’t know about.

Have a good Git!

Can’t believe this?

Have you just realized there was a ton of options, and perhaps commands, you didn’t know about and wish you had?

Although we don’t publicize it much for now, we do offer English-language Git training across Europe, based on our battle-tested, celebrated Total Git training course. If you fancy one, just let us know!

(We can absolutely come over to US/Canada or anywhere else in the world, but considering you’ll incur our travelling costs, despite us being super-reasonably priced, it’s likely you’ll find a more cost-effective deal using a closer provider, be it GitHub or someone else. Still, if you want us, follow the link above and let’s talk!)

--

--

Christophe Porteneuve

I make cool stuff and teach others to (Git, Rails, JS/CoffeeScript/Node/etc).