Git 2.2.0 is out!

December 1st 2014 Tim Pettersen in Git

After a few short months git 2.2.0 has been declared final. This is big news, as it comes with a host of new useful features for improving your git workflow. Here's the stuff we found useful at Atlassian:

git archive learned pathspecs

git archive is a command that lets you generate a zip or tarball of your repository contents at a particular revision. At Atlassian some teams use it to distribute the source code of our tools to our customers. As of 2.2.0 you can limit which files are included in the generated archive by using a pathspec (similar to an antglob). This can be useful for extracting files of a certain type from your repository - such as documentation or static web resources. For example, you could extract the HTML man pages for git 2.2.0 into an archive named docs.zip by running the following command in the git project's repository:

git archive -o docs.zip v2.2.0 'Documentation/*.html'

git config became a little friendlier

For first time git users, git config will now auto-generate a .gitconfig with a username and email address based on their username, hostname and environment variables (like $EMAIL, if it's set). This doesn't affect existing users, but it's nice to see the ongoing commitment the git team have to smoothing out git's on-boarding experience.

git stash list can now display patches

git stash is a handy little command that bundles up changes from your working copy and stashes them away so you can quickly switch context to work on something else. git stash list can later be used to display what you've previously stashed away. This is great! I'm perpetually distracted and contribute to several different projects, so recalling what's on my stash stack isn't always easy. However, the default output isn't always as useful as it could be:

$ git stash list
stash@{0}: WIP on master: 1347163 Merge branch 'release/1.1.4'
stash@{1}: On feature/ACDEV-1172-fileless-connect-addons: oh god why
stash@{2}: On feature/ACDEV-1208-move-shcemagen: docs refactor take 2
stash@{3}: On feature/ACDEV-1208-move-shcemagen: ugly munging of schema

Since I usually run git stash whilst under some pressure to fix something quickly, I don't always come up with the most descriptive messages (or, as in the case of stash@{0} above, I don't specify one at all and git substitutes in "WIP"). These messages are transitory in nature, so they don't matter in the long run, but it does make recalling exactly what's been done in each "stash" a little tricky.

According to the documentation, git stash list can be passed any option that you might pass to the git log command to format the output. Armed with this knowledge, you might reasonably think that you could pass the -p flag (or --patch) to git stash list to print out the diffs of each of your stashes.

However, prior to git 2.2.0, you'd be wrong.

$ git stash list -p
stash@{0}: WIP on master: 1347163 Merge branch 'release/1.1.4'
stash@{1}: On feature/ACDEV-1172-fileless-connect-addons: oh god why
stash@{2}: On feature/ACDEV-1208-move-shcemagen: docs refactor take 2
stash@{3}: On feature/ACDEV-1208-move-shcemagen: ugly munging of schema

The reason git stash list -p didn't display anything useful is due to the way a stash is stored by git. Just like almost everything else in git, it's stored as part of the DAG. A stash is actually stored as two commits:

  1. a commit containing any changes that were staged when you ran the git stash; and
  2. a commit containing any changes that hadn't been staged when you ran git stash. This commit has the "staged changes" commit and your previous HEAD as parents.

If you've stashed something recently, you can see this structure yourself by running:

git log --graph --oneline stash@{0}

* eebf8fa WIP on <branch_name>: <prev_commit_message>
|\  
| * 56206d3 index on <branch_name>: 2b2e5c3 <stash_message>
|/  
* 2b2e5c3 <prev_commit_message>
* ...

Because the stash is a merge commit with two parents, -p will refuse to generate a patch because it doesn't know which parent to diff against. As of git 2.2.0 git-stash.sh (that's right, git stash is implemented as a shell script) passes the -m and --first-parent flags on to the underlying git log command, so you can now use git stash list -p to show the actual patches that you've stashed away:

$ git stash list -p
stash@{0}: WIP on master: 1347163 Merge branch 'release/1.1.4'
diff --git a/pom.xml b/pom.xml
index 07131d7..dd9b1db 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <artifactId>atlassian-connect-api-parent</artifactId>
         <groupId>com.atlassian.plugins</groupId>
-        <version>1.1.4-RC-SNAPSHOT</version>
+        <version>1.1.4</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
stash@{1}: On feature/ACDEV-1172-fileless-connect-addons: oh god why
...

git fast-export is now anonymizable

Not so much a workflow feature as it is useful for those who develop git-related tools (like us!). git fast-export now accepts an --anonymize flag that replaces potentially sensitive repository content with innocuous strings. This means our support engineers can get customers to send us anonymized versions of their repositories when they run into problems with git or our software.

The new flag is also useful if you run into a hairy git problem and you want to post your repository structure on a forum without exposing your actual source code.

$ git fast-export v2.2.0~1..v2.2.0
blob
mark :1
data 105
* whitespace=!indent,trail,space
*.[ch] whitespace=indent,trail,space
*.sh whitespace=indent,trail,space
blob
mark :2
data 3667
/GIT-BUILD-OPTIONS
/GIT-CFLAGS
/GIT-LDFLAGS
...

$ git fast-export --anonymize v2.2.0~1..v2.2.0
blob
mark :1
data 16
anonymous blob 0
blob
mark :2
data 16
anonymous blob 1
...

Signed pushes

This item is a big win for security minded folks. Git has supported signing tags and commits for a while, which verify that a particular person created a certain ref or commit. Mike Gerwitz tells a great git horror story about why you might want to deploy one or both of these techniques.

As of git 2.2.0, you can sign the actual act of updating refs which occurs during a push. This is an important step in preventing man-in-the-middle attacks and any other unauthorized updates to your repository's refs. git push has learnt the --signed flag which applies your GPG signature to a "push certificate" sent over the wire during the push invocation. On the server-side, git receive-pack (the command that handles incoming git pushes) has learnt to verify GPG-signed push certificates. Failed verifications can be used to reject pushes and those that succeed can be logged in a file to provide an audit log of when and who pushed particular ref updates or objects to your git server.

GPG signing of pushes (or commits and tags for that matter) involves quite a bit of co-ordination overhead and the security benefits aren't worth the hassle for many teams, particularly if you're already hosting on a secured server with audit logging capabilities (such as Atlassian Stash). But if you're interested in learning more, check out the man pages for git receive-pack and git push for details on the new signing options.

git help everyday

Invoking git help everyday now displays the "Everyday Git in 20 commands or so" man page that's bundled with git. This is a decent reference, but can be a little brisk for developers who are relatively new to git. If you're looking to boost your git knowledge, I'd recommend checking out our git site at atlassian.com/git for usage patterns and workflow advice, and then diving into the Pro Git ebook for a deeper look at how git works under the covers.

Pretty formats now support %D for no frills decoration

If you're into git aliasing, you may have already pimped out your git log command with a pretty format. Filipe Kiss has put together a colorful log alias that incorporates many of the important elements of your git history.

A colorful git log

Previously, the only way you could incorporate ref names in your log output by using the %d symbol, which expands to " ($refnames)". This is awkward if you want to use something other than braces in your otherwise highly customizable log output format. As of 2.2.0, the %D symbol substitutes to a plain comma-separated list of ref names (tags, branches and HEAD) or the empty string if there are no refs pointing at a particular commit.

Performance, bug fixes and other improvements

As usual, the git team have managed to squeeze yet more performance from their already blazingly fast VCS, and have rectified some issues from earlier releases. For the full list of changes you can view the release notes or check out the repository yourself and see what's changed between tags with:

git log v2.1.0..v2.2.0 

If you've enjoyed this update, feel free to follow me on Twitter (I'm @kannonboy) for occasional updates about git and musings about developer workflows.