Baking Clouds Ltd

Baking Clouds provide tailored IT consultancy services to small and medium-sized companies; we cover all aspects of IT without any hidden costs.

Git 2.17 is now available

The open source Git project just released Git 2.17.0, with features and
bugfixes from over 60 contributors.
Here’s our look at some of the most interesting new features from the
last few versions of Git.

Coloring moved code

When you’re reviewing a commit that moves some code, its diff will show
a big chunk of lines being deleted in one place and a big chunk of
lines appearing elsewhere. The commit message may claim that this was
pure code movement, but how can you verify that? And if some lines needed
to be changed, how can you easily see which lines?

Git v2.15 offers a new
--color-moved option
which colors groups of moved lines differently. Use this option
for any command that generates a diff: git diff, git log -p, git
show
, and so on.

Diff shown with --color-moved

The blue lines show the blocks that were moved verbatim, while the red
and green lines show the corrected typo. Note that these aren’t the
default colors; we’ve just used them to highlight this simple example. By
default, old and new blocks get their own colors, and non-adjacent
groups of lines are colored independently. This helps when there are
several moved blocks in a single diff. You can configure the
colors

to match your preferences.

[source]

Speeding up status with watchman

One reason that Git is fast is avoiding unnecessary disk reads.
For example, when you run git status, Git
uses the stat() system call to check whether each file’s size or
timestamp has changed since the last time Git checked. If not, it
assumes that its contents haven’t changed and avoids reading the file
contents at all.

This helps a lot, but it still requires Git to call stat() once for
every file in your working copy. If you have a lot of files, that work
adds up. This can be further exacerbated if you’re on an operating
systems where stat() is more expensive.

Git v2.16 adds a new fsmonitor hook
that relies on the operating system to tell us what has changed. Doing
so allows us to avoid the repeated stat() calls, making the work
proportional to the number of changed files, not the total size of the
repository.

The hook provides a generic interface into which you can plug any
tool, but most people will want to use the
watchman tool, which runs on
Linux, macOS, and Windows. Git ships with a
sample hook
for using watchman.

[source]

Finding objects in history

Have you ever gotten hold of an object hash for a blob or tree like
c1626490c2 and had no idea what path it corresponds to, or in which
commits it could be found? Perhaps somebody else mentioned the object,
or a Git command lke fsck complained about it.

There’s no single defined answer for these questions. Because Git
commits are snapshots of the tree, an object may appear in many commits:
it may get introduced in commit A, then persist in commit B that
only touches another file, and then finally go away in commit C.
Likewise, an object may appear at multiple paths if it’s renamed or
copied.

Getting this information used to require a pipeline of arcane commands.
But now you can use --find-object to select the commits you want and
display them however you like.

Using --find-object to locate a commit

Here we’ve used --raw to easily show that these commits are the ones
where the object comes and goes (and that Git omitted any in the middle
which didn’t affect it). You might be more likely to use -p to show
the full diff.

[source]

Grepping with function context

When you search for a string with git grep, it’s often helpful to see
the surrounding context. You can use -C 2 to tell Git to show you two
lines of context on either side, but it’s hard to know the right number
in advance without ending up with too much or too little context.

For many years, git grep has had a --function-context option (and
its shorter alias -W) to show you the whole function surrounding each
match. This uses language-specific patterns if you have the appropriate
gitattributes
defined, or it can fall back to some generic heuristics.

Since Git v2.16, it can now also find and show comments before the start
of a function, which provides even more context for your matches.

grep -W shows comments above function context

Without -W, we’re left with very little information about how the
function is used. With it, we can see the whole function, including its
accompanying comment.

[source]

Tidbits

  • The diff --indent-heuristic option we mentioned in
    our v2.11 post
    has now become the default. If you’ve never tried it, you may now see your
    diffs subtly improved. Automatically!
    [source]
  • Our v2.11
    post

    also talked about a new protocol that lets Git more efficiently
    invoke filters like Git LFS. That protocol has been extended to allow
    filters to return results asynchronously. That lets Git proceed with
    the work of checking out files while a filter like Git LFS is waiting
    on the network.
    [source]
  • If you build Git with support for Perl Compatible Regular
    Expressions, it now supports libpcre2, as well as JIT support for
    both libpcre1 and libpcre2. This can improve the performance of git
    grep -P
    by
    up to 70%.
    [source]
  • Our v2.13 post
    described Git’s pathspecs and how globs like *.c no longer require
    you to enter -- on the command line. That convenience has been
    extended to “magic” pathspecs, letting you more easily write exotic
    matches like git ls-files ':attr(filter=lfs)'.
    [source]
  • Have you ever found yourself in the middle of a conflicted rebase and
    needed to see the original patch? And you couldn’t remember that the
    magic invocation is cat .git/rebase-apply/patch? Or sometimes
    /rebase-merge/, depending on how rebase was invoked? Now you can use
    git rebase --show-current-patch, and even tab-complete it.
    [source]
  • Some projects put trailers like “Signed-off-by:” or “Reported-by:” in
    their commit messages to give additional information. These are meant
    to be machine-readable, but parsing them can be non-trivial. Now you
    can use git log --format='%h%n%(trailers:only,unfold)' to get just
    the key: value trailers, with any whitespace normalized.
    [source,
    source]
  • The epic quest
    to transition Git off of the SHA-1 algorithm has continued. There’s a
    public transition plan,
    and the internal code cleanups to prepare for an alternate hash
    function are nearly complete.
    [source
    of
    so
    many
    sha1
    related
    code
    cleanups]
  • Have you ever enabled automatic line conversion or another
    file attribute
    after you’ve already run git add on the files? Fixing that used to be
    a pain,
    but since Git v2.16 you can just use
    git add --renormalize.
    [source]
  • You can enable or disable the pager for an individual command like
    git log by setting the pager.log config option. But this was
    useless for commands like git tag, which sometimes generate a lot
    of output (when listing tags) but other times generate none (when
    creating a tag, in which case having to quit the pager is an
    irritation). The tag, branch, and config commands have all
    learned only to invoke the pager in their “list” modes, and now
    default to paging in those modes.
    [source,
    source,
    source]

And the rest

That’s just a sampling of changes from the last few versions. Read the full
release notes for 2.17
,
or find the release notes for previous versions in the Git repository.

Git 2.17 is now available
Scroll to top