Git 2.4 — atomic pushes, push to deploy, and more
Git’s 10-year birthday celebrations notwithstanding, the Git community has been busy preparing another major new release of the Git command-line utility. Release 2.4.0 is weighted towards cleanups, bug fixes, and…
Git’s 10-year birthday celebrations notwithstanding, the Git community has been busy preparing another major new release of the Git command-line utility. Release 2.4.0 is weighted towards cleanups, bug fixes, and other small improvements, but here we would like to take a moment to highlight a few new features that you might find useful.
Atomic pushes
Until now, when you tried to push multiple branches to a remote Git server, some of the updates might have succeeded while others failed. For example, somebody else might have pushed to one of the branches, meaning that you have to reconcile your changes with theirs and try pushing that branch again.
But for some purposes you might want to push a set of reference changes atomically, meaning that either all of the reference updates are accepted, or none of them are. Now that is possible, using the new --atomic option to git push:
$ git push --atomic origin branch1 branch2 ...
This feature is probably most useful for automated tools. Suppose you have a tool that runs continuous integration on a branch, and if the test succeeds it merges the branch to master, creates a new tag, and adds a note to the commit. All three things can be pushed at the same time using
$ git push --atomic origin master refs/tags/release-17 refs/notes/test-results
The --atomic option guarantees that either all three references will be updated on the remote, or none of them will.
Please note that git push --atomic is still somewhat experimental, and it is possible to experience partial updates if you try to push something unusual. But if you use --atomic, the most common reason for a reference update to be rejected — the dreaded “non-fast-forward” update — will no longer leave your push half-accepted, half-rejected. [source]
Push-to-deploy improvements
The last major Git release, Git 2.3, introduced the ability to push directly to a branch that is checked out on a remote Git server, making it an easy way to deploy a new version of a website just by pushing. (But please read our last Git release blog post to learn about some caveats that apply to this approach.)
Git 2.4 improves push-to-deploy in two ways:
- There is now a
push-to-checkouthook, which can be installed on the server to customize exactly what happens when a user pushes to the checked-out branch. For example, by default such a push fails if there have been any changes to the working tree on the server. Thepush-to-checkouthook could instead try to merge any server-side edits with the new branch contents, or it could unconditionally overwrite any local changes with a pristine copy of the pushed branch contents. [source] - Push-to-deploy formerly didn’t work correctly when pushing to a server that is on an “unborn branch”. (An “unborn branch” is what Git calls a branch that doesn’t yet have any commits on it, as for example immediately after a Git repository is initialized.) Now this works as expected, which will hopefully reduce confusion for users who are trying to set up push-to-deploy for a new project. [source]
Inverted grep for logs
git log is a very powerful command, with a bewildering variety of options. One class of useful options includes --grep=<pattern>, --author=<pattern>, --committer=<pattern>, and --grep-reflog=<pattern>, which limit the output to commits whose commit message, author, committer, or reflog entry, respectively, matches the specified regular expression pattern.
There is a new option, --invert-grep, that inverts the sense of the other pattern-matching options. When this option is used, git log lists the commits that don’t match the specified pattern(s). For example, to search for merge commits that do not include a “Fixes” annotation in their commit messages, you could run
$ git log --all --merges --invert-grep --grep=Fixes
Advanced usage
It is not possible to combine pattern-matching options into arbitrary expressions like “match A and B but not C” in a single git log command. But now, thanks to --invert-grep, you can do so by stringing commands together in pipelines, though it is a bit subtle. For example, suppose you want to find the non-merge commits in Git’s master branch that were written by its maintainer, Junio Hamano, but are missing “Signed-off-by” lines:
$ git rev-list --no-merges --author="Junio C Hamano" master |
git log --stdin --no-walk --invert-grep --grep='^Signed-off-by:'
Note that the first command uses git rev-list, which just lists the SHA-1s of matching commits rather than showing their commit messages etc. git rev-list takes many of the same options as git log. Its output is used as the input to a second command, which uses --stdin --no-walk to read commit SHA-1s from its standard input and only process those commits. (Without --no-walk, the second command would also process the ancestors of the commits passed to it.) The second command thus skips any commits that contain “Signed-off-by” lines, and outputs the rest.
It turns out that many of the commits listed by the previous command are “revert” commits, which don’t really need Signed-off-by lines, so let’s exclude revert commits and count how many are left:
$ git rev-list --no-merges --author="Junio C Hamano" master |
git rev-list --stdin --no-walk --invert-grep --grep='^Signed-off-by:' |
git rev-list --stdin --no-walk --invert-grep --grep='^Revert ' |
wc -l
76
As you can see, it is possible to put together quite sophisticated queries using these building blocks.
Other minor improvements
-
git statusnow allows the--verboseoption to be specified twice, in which case it shows the changes that have been staged but not yet committed and also the changes in the working tree that have yet to be staged. [source] -
git log --decorate, which lists branch names alongside the usuallogoutput, now shows not only the currentHEAD, but also indicates which branch it currently points at, in the format(HEAD -> master). [source] - There is now a configuration setting
push.followTags, to turn ongit push‘s--follow-tagsoption by default. [source] - The HTTP-based transports now send
Accept-Languageheaders when making requests. This opens the way to internationalizing the informational messages emitted by the Git server, though that effort has not yet begun. [source]
The rest of the iceberg
Aside from the highlights listed here, there have been myriad small improvements to Git since version 2.3.0 — over 400 commits in all, by 76 different contributors. For full details, see the Git 2.4.0 release notes. Or, even better, view the commits using Git itself:
$ git clone https://github.com/git/git.git
$ cd git
$ git log --oneline --graph v2.3.0..v2.4.0
Looking to level up your Git game? Browse the docs on the main Git website, grab a copy of Pro Git, or read GitHub’s Guide to setting up Git.
Happy collaborating!
Tags:
Written by
Related posts
From karaoke terminals to AI résumés: The winners of GitHub’s For the Love of Code challenge
This summer, we invited devs to participate in our hackathon for joyful, ridiculous, and wildly creative projects. Here are the winners of For the Love of Code!
Inside the breach that broke the internet: The untold story of Log4Shell
Log4Shell proved that open source security isn’t guaranteed and isn’t just a code problem. It’s about supporting, enabling, and empowering the people behind the projects that build our digital infrastructure.
Accelerate developer productivity with these 9 open source AI and MCP projects
GitHub Copilot and VS Code teams, along with the Microsoft Open Source Program Office (OSPO), sponsored these nine open source MCP projects that provide new frameworks, tools, and assistants to unlock AI-native workflows, agentic tooling, and innovation.