Highlights from Git 2.19

Image of Taylor Blau

The open source Git project just released Git 2.19, with features and bug-fixes
from over 60 contributors.
Here’s a look at some of the most interesting features introduced in the latest
versions of Git.

Compare histories with git range-diff

You might have used git rebase, which is a powerful tool for rewriting history
by altering commits, commit order, or branch bases to name a few. Many people
do this to “polish” a series of commits before proposing to merge them into a
project. But how can we visualize the differences between two sets of commits,
before and after a rebase?

We can use git diff to show the difference between the two end states, but
that doesn’t provide information about the individual commits. And if the base
on which the commits were built has changed, the resulting state might be
quite different, even if the changes in the commits are largely the same.

Git 2.19 introduces git range-diff, a tool for comparing two sequences of
commits
, including changes to their order, commit messages, and the actual
content changes they introduce.

git range-diff example

In this example, we rewrote a series of three commits, and compared the tips of
each version using git range-diff. git range-diff shows that we moved the
commit introducing README.md to be first instead of second, amended both the
commit message and body of the typo fix, and introduced a new commit to add a
missing newline.

[source]

git grep‘s new tricks

When you search for a phrase using git grep, it’s often helpful to have
additional information pertaining to each match, such as its line number and
function context.

In Git 2.19 you can now locate the first matching column of your query with
git grep --column.

If you’re using Vim, you can also try out git-jump, a Git add-on that
converts useful locations in your code to jump locations in your text editor.
git-jump can take you to merge conflicts, diff hunks, and now, exact grep
locations with git grep --column.

git grep --column example

git grep also learned the new -o option (meaning --only-matching). This is
useful if you have a non-trivial regular expression and want to gather only the
matching parts of your search.

For example, if you want to count all of the various ways that the Git source
code spells “SHA-1” (e.g., “sha1”, “SHA1”, and so on):

git grep -o example

(The other options -hiI are to omit the filename, search case-insensitively,
and ignore matches in binary files, respectively.)

[source,
source]

Sorting branches

The git branch command, like git tag (and their scriptable counterpart, git for-each-ref), takes a --sort option to let you order the results by a number
of properties. For example, to show branches in the order of most recent update,
you could use git branch --sort=-authordate. But if you always prefer that
order, typing that sort option can get tiresome.

Now, you can use the branch.sort config to set the default ordering of git branch:

git branch --sort example

Note that by default, git branch sorts by refname, hence master is first and
newest is last. In the above example, we tell Git that we would instead prefer
the most recently updated branch first, and the rest in descending order. Hence,
newest is first and master is last.

You might also want to try these other sorting options:

  • --sort=numparent shows merges by how awesome they are
  • --sort=refname sorts branches alphabetically by their name (this is the
    default, but may be useful to override in your configuration)
  • --sort=upstream sorts branches by the remote from which they originate

[source]

Directory rename detection

Git has always detected renamed files as part of merges. For example, if one
branch moves a file from A to B and another modifies content in A, then
the resulting merge will apply that modification to the content’s new location
in B.

The same thing can happen with files in a directory. If one branch moves a
directory from A to B but another adds a new file A/file, we can infer
that the file should become B/file when the two are merged. In Git 2.18, git merge does this whenever rename detection is enabled (which is by default).

git merge directory rename example

[source]

Tidbits

  • In Git v2.18, a remote code execution vulnerability in .gitmodules was
    fixed, where an attacker could execute scripts when the victim cloned with
    --recurse-submodules. If you haven’t upgraded, please do! The fix was also
    backported to v2.17.1, v2.16.4, v2.15.2, v2.14.4, and v2.13.7, so you’re safe
    if you’re running one of those.
    [source]

  • Have you ever run into a Git command line option that should have
    tab-completed but didn’t? Keeping these up to date has long been an annoying
    source of manual work for the project, but now the completion of options for
    most commands is generated automatically (along with the list of commands
    itself, the names of config options, and more).
    [source,
    source,
    source,
    source]

  • gpg signing and verification of commits and tags has been extended to work
    with gpgsm, which uses X.509 certificates instead of OpenPGP keys. These
    certificates may be easier to manage for centralized groups (e.g., developers
    working for a large enterprise).
    [source]

  • To fetch a configuration variable with a “fallback” value, it’s common for
    scripts to say git config core.myFoo || echo <default>. But that doesn’t
    give Git the opportunity to interpret <default> for you. When it comes to
    colors, this is especially important for instances where you ultimately need
    the ANSI color code, for say, “bold red”, but don’t want to type