What’s new since Git 1.7
Published on 28 August 2014
• 8 min
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.
(At the time of bringing this article back to our web properties, the latest version is 2.11.0, from Nov 29, 2016.)
The official website maintains official builds for Mac and Windows, 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)
- 16.04 LTS “Xenial Xerus” is on 2.7.4 (Mar. 2016)
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
andgit 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 withgit 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 agitdir: 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 ofgit reset --merge
, which later turned intogit merge --abort
) git cherry-pick
(and incidentallygit 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 ofgit 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 assumegit rebase @{u}
and rebase on upstream. Not very useful (I would want my remote sync’d first, so go through some form ofgit pull --rebase
instead), but any no-op-becoming-an-op is noteworthy in my book. In a later version it’ll happen togit merge
too, tsk tsk… - The
push.default
configuration variable gained a new name for its legacytracking
value:upstream
(in 1.7.5). I actually recommend this setting rather than the too-limitingsimple
. - The all-important
pull.rebase
config variable showed up in 1.7.9 (although just withtrue
andfalse
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 gave us the
--include-untracked
/-u
option forgit 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 forpush.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 preferupstream
, 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 usefulgit push --recurse-submodules=…
option learns theon-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 filesattributes
(the default path forcore.attributesfile
now) andignore
(default path forcore.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 whenman
doesn’t seem to be available (e.g. Windows). You can force this anywhere withgit 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
andcheckout
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
joinsmerge
,checkout
andcherry-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 newtag.sort
config variable for that. - The default value for
push.default
changes tosimple
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 likerebase
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!