{"id":54839,"date":"2020-10-19T09:44:04","date_gmt":"2020-10-19T16:44:04","guid":{"rendered":"https:\/\/github.blog\/?p=54839"},"modified":"2021-01-12T14:25:08","modified_gmt":"2021-01-12T22:25:08","slug":"git-2-29-released","status":"publish","type":"post","link":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/","title":{"rendered":"Highlights from Git 2.29"},"content":{"rendered":"<p>The open source Git project\u00a0<a href=\"https:\/\/lore.kernel.org\/git\/xmqqy2k2t77l.fsf@gitster.c.googlers.com\/\">just released Git 2.29<\/a>\u00a0with features and bug fixes from over 89 contributors, 24 of them new. Last time\u00a0<a href=\"https:\/\/github.blog\/2020-07-27-highlights-from-git-2-28\/\" rel=\"nofollow\">we caught up<\/a>\u00a0with you, Git 2.28 had just been released. One version later, let&#8217;s take a look at the most interesting features and changes that have happened since then.<\/p>\n<h2 ><a class=\"heading-link\" href=\"#\"><a id=\"user-content-experimental-sha-256-support\" class=\"anchor\" href=\"https:\/\/gist.github.com\/leereilly\/c08ba724a13d9c27a210458ce540f11d#experimental-sha-256-support\" aria-hidden=\"true\"><\/a>Experimental SHA-256 support<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>Git 2.29 includes experimental support for writing your repository&#8217;s objects using a SHA-256 hash of their contents, instead of using SHA-1.<\/p>\n<p>What does all of that mean? To explain, let&#8217;s start from the beginning.<\/p>\n<p>When you add files to a repository, Git copies their contents into\u00a0<code>blob<\/code>\u00a0objects in its local database, and creates\u00a0<code>tree<\/code>\u00a0objects that refer to the blobs. Likewise, when you run\u00a0<code>git commit<\/code>, this creates a\u00a0<code>commit<\/code>\u00a0object that refers to the tree representing the committed state. How do these objects &#8220;refer&#8221; to each other, and how can you identify them when interacting with Git? The answer is that each object is given a unique name, called its\u00a0<em>object id<\/em>, based on a hash of its contents. Git uses SHA-1 as its hash algorithm of choice, and depends on the object ids of different objects to be unique.<\/p>\n<p>Back in\u00a0<a href=\"https:\/\/github.blog\/2017-03-20-sha-1-collision-detection-on-github-com\/\" rel=\"nofollow\">this blog post<\/a>, we estimated that even if you had five million programmers writing one commit every second, you would only have a 50% chance of accidentally generating a collision before the Sun engulfs the Earth.\u00a0<a href=\"https:\/\/shattered.io\/static\/shattered.pdf\" rel=\"nofollow\">Some<\/a>\u00a0<a href=\"https:\/\/eprint.iacr.org\/2019\/459.pdf\" rel=\"nofollow\">published<\/a>\u00a0<a href=\"https:\/\/eprint.iacr.org\/2020\/014.pdf\" rel=\"nofollow\">attacks<\/a>\u00a0exist which use tricks that exploit weaknesses in SHA-1 that can reduce the effort required to generate a collision, but these attacks still cost tens of thousands of dollars to execute, and no known examples have been published which target Git.<\/p>\n<p>Like we stated back in that earlier blog post, Git (and providers that use it, like GitHub) checks each object it hashes to see if there is evidence that that object is part of a colliding pair. This prevents GitHub from accepting both the benign and malicious halves of the pair, since the mathematical tricks required to generate a collision in any reasonable amount of time can be detected and rejected by Git.<\/p>\n<p>Even so, any weaknesses in a cryptographic hash are a bad sign. Even though Git has implemented detections that prevent the known attacks from being carried out, there&#8217;s no guarantee that new attacks won&#8217;t be found and used in the future. So the Git project has been preparing a transition plan to begin using a new object format with no known attacks: SHA-256.<\/p>\n<p>In Git 2.29, you can try out a SHA-256 enabled repository for yourself:<\/p>\n<div class=\"highlight highlight-text-shell-session\">\n<pre>$ <span class=\"pl-s1\">git --version<\/span>\n<span class=\"pl-c1\">git version 2.29.0<\/span>\n$ <span class=\"pl-s1\">git init --object-format=sha256 repo<\/span>\n<span class=\"pl-c1\">Initialized empty Git repository in \/home\/ttaylorr\/repo\/.git\/<\/span>\n$ <span class=\"pl-s1\"><span class=\"pl-c1\">cd<\/span> repo<\/span>\n\n$ <span class=\"pl-s1\"><span class=\"pl-c1\">echo<\/span> <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>Hello, SHA-256!<span class=\"pl-pds\">'<\/span><\/span> <span class=\"pl-k\">&gt;<\/span>README.md<\/span>\n$ <span class=\"pl-s1\">git add README.md<\/span>\n$ <span class=\"pl-s1\">git commit -m <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>README.md: initial commit<span class=\"pl-pds\">\"<\/span><\/span><\/span>\n<span class=\"pl-c1\">[master (root-commit) 6e92961] README.md: initial commit<\/span>\n<span class=\"pl-c1\"> 1 file changed, 1 insertion(+)<\/span>\n<span class=\"pl-c1\"> create mode 100644 README.md<\/span>\n\n$ <span class=\"pl-s1\">git rev-parse HEAD<\/span>\n<span class=\"pl-c1\">6e929619da9d82c78dd854dfe237c61cbad9e95148c1849b1f96ada5ee800810<\/span><\/pre>\n<\/div>\n<p>As of version 2.29, Git can operate in either a full SHA-1 or full SHA-256 mode. It is currently not possible for repositories using different object formats to interoperate with one another, but eventual support is planned. It is also important to note that there are no major providers (including GitHub) which support hosting SHA-256-enabled repositories at the time of writing.<\/p>\n<p>In future releases, Git will support interoperating between repositories with different object formats by computing both a SHA-1 and SHA-256 hash of each object it writes, and storing a translation table between them. This will eventually allow repositories that store their objects using SHA-256 to interact with (sufficiently up-to-date) SHA-1 clients, and vice-versa. It will also allow converted SHA-256 repositories to have their references to older SHA-1 commits still function as normal (e.g., if I write a commit whose message references an earlier commit by its SHA-1 name, then Git will still be able to follow that reference even after the repository is converted to use SHA-256 by consulting the translation table).<\/p>\n<p>For more about SHA-256 in Git, and what some of the future releases might look like, you can read\u00a0<a href=\"https:\/\/git-scm.com\/docs\/hash-function-transition\/\" rel=\"nofollow\">Git&#8217;s transition plan<\/a>.<\/p>\n<p>[<a href=\"https:\/\/github.com\/git\/git\/compare\/5d3635db19c6dff4fb063fabfa4161fd3b8285f0...4b4e2918099600c1eefe7b5a71bf647803905b7e\">source<\/a>,\u00a0<a href=\"https:\/\/github.com\/git\/git\/compare\/fe870600fe2735782e9e8a8c5441f91b1a58e273...1bdca816412910e1206c15ef47f2a8a6b369b831\">source<\/a>,\u00a0<a href=\"https:\/\/github.com\/git\/git\/compare\/a08a83db2bf27f015bec9a435f6d73e223c21c5e...3716d50dd5c8ee7e5ccaa89fcbfff2cd1b82ad1d\">source<\/a>,\u00a0<a href=\"https:\/\/github.com\/git\/git\/compare\/4f0a8be78499454eac3985b6e7e144b8376ab0a5...e023ff0691ca207d421a0e75ea23c132ada9142a\">source<\/a>, and\u00a0<a href=\"https:\/\/github.com\/git\/git\/compare\/2f0e14e649d69f9535ad6a086c1b1b2d04436ef5...752414ae4310cd304f5e31649aaab2dcf307057c\">so<\/a>,\u00a0<a href=\"https:\/\/github.com\/git\/git\/compare\/95ec6b1b3393eb6e26da40c565520a8db9796e9f...c250e02e2c6de8c116f4320a48ce44bbdb43015c\">much<\/a>,\u00a0<a href=\"https:\/\/github.com\/git\/git\/compare\/752414ae4310cd304f5e31649aaab2dcf307057c...31bdb1f28ecdce738aa3f2f23b7b1c531a06e76e\">more<\/a>]<\/p>\n<h2 ><a class=\"heading-link\" href=\"#\"><a id=\"user-content-negative-refspecs\" class=\"anchor\" href=\"https:\/\/gist.github.com\/leereilly\/c08ba724a13d9c27a210458ce540f11d#negative-refspecs\" aria-hidden=\"true\"><\/a>Negative refspecs<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>When you run\u00a0<code>git fetch origin<\/code>, all of the branches from the remote\u00a0<code>origin<\/code>\u00a0repository are fetched into your local\u00a0<code>refs\/remotes\/origin\/<\/code>\u00a0hierarchy. How does Git know which branches to fetch, and where to put them?<\/p>\n<p>The answer is that your configuration file contains one or more &#8220;refspecs&#8221; for each remote (remember that a &#8220;ref&#8221; is Git&#8217;s word for any named point in history: branches, tags, etc). When you run\u00a0<code>git clone<\/code>, it sets up a default refspec to be used when you fetch from your origin repository:<\/p>\n<div class=\"highlight highlight-text-shell-session\">\n<pre>$ <span class=\"pl-s1\">git config remote.origin.fetch<\/span>\n<span class=\"pl-c1\">+refs\/heads\/*:refs\/remotes\/origin\/*<\/span><\/pre>\n<\/div>\n<p>This refspec tells Git to fetch what&#8217;s on the left side of the colon (everything in\u00a0<code>refs\/heads\/<\/code>; i.e., all branches) and to write them into the hierarchy on the right-hand side. The\u00a0<code>*<\/code>\u00a0means &#8220;match everything&#8221; on the left-hand side and &#8220;replace with the matched part&#8221; on the right-hand side.<\/p>\n<p>You can have multiple refspecs, and they can refer to individual refs. For example, this command instructs Git to additionally fetch any\u00a0<a href=\"https:\/\/git-scm.com\/docs\/git-notes\" rel=\"nofollow\">git notes<\/a>\u00a0from the remote (the\u00a0<code>--add<\/code>\u00a0is important so that we don&#8217;t overwrite the default refspec that fetches branches):<\/p>\n<div class=\"highlight highlight-text-shell-session\">\n<pre>$ <span class=\"pl-s1\">git config --add remote.origin.fetch refs\/notes\/commits:refs\/notes\/origin-notes<\/span><\/pre>\n<\/div>\n<p>Refspecs are used by\u00a0<code>git push<\/code>, as well. Even if you type only\u00a0<code>git push origin mybranch<\/code>, that last\u00a0<code>mybranch<\/code>\u00a0is really a shorthand for\u00a0<code>refs\/heads\/mybranch:refs\/heads\/mybranch<\/code>. This allows you to express more complicated scenarios. Say you&#8217;re tagging and want to push all of the tags you have, but you&#8217;re not quite ready to share the tips of all of your branches. Here, you could write something like:<\/p>\n<div class=\"highlight highlight-text-shell-session\">\n<pre>$ <span class=\"pl-s1\">git push origin <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>refs\/tags\/*:refs\/tags\/*<span class=\"pl-pds\">'<\/span><\/span><\/span><\/pre>\n<\/div>\n<p>Prior to Git 2.29, refspecs could only be used to say which selection of reference(s) you want. So, if you wanted to fetch all branches except one, you&#8217;d have to list them out as arguments one by one. Of course, that assumes that you know the names of all the other references beforehand, so in practice this would look something like:<\/p>\n<div class=\"highlight highlight-text-shell-session\">\n<pre>$ <span class=\"pl-s1\">git ls-remote origin <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>refs\/heads\/*<span class=\"pl-pds\">'<\/span><\/span> <span class=\"pl-k\">|<\/span><\/span>\n<span class=\"pl-c1\">  grep -v ref-to-exclude |<\/span>\n<span class=\"pl-c1\">  awk '{ print $2:$2 }' |<\/span>\n<span class=\"pl-c1\">  xargs git fetch origin<\/span><\/pre>\n<\/div>\n<p>to get all refs in\u00a0<code>refs\/heads\/*<\/code>\u00a0except for\u00a0<code>refs\/heads\/ref-to-exclude<\/code>. Yeesh; there must be a better way.<\/p>\n<p>In Git 2.29, there is: negative refspecs. Now, if a refspec begins with\u00a0<code>^<\/code>\u00a0it indicates which references are to be excluded. So, instead of the above, you could write instead something like:<\/p>\n<div class=\"highlight highlight-text-shell-session\">\n<pre>$ <span class=\"pl-s1\">git fetch origin <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>refs\/heads\/*:refs\/heads\/*<span class=\"pl-pds\">'<\/span><\/span> ^refs\/heads\/ref-to-exclude<\/span><\/pre>\n<\/div>\n<p>and achieve the same result. When a negative refspec is present, the server considers a reference worth sending if it matches at least one positive refspec and does not match any negative refspecs. Negative refspecs behave exactly as you expect, with a couple of caveats:<\/p>\n<ul>\n<li>Negative refspecs can contain wildcard patterns, but cannot specify the destination. These wouldn&#8217;t mean anything, anyway (you wouldn&#8217;t want to say\u00a0<code>^refs\/heads\/foo\/*:refs\/heads\/bar\/*<\/code>\u00a0which means, literally, &#8220;map heads from\u00a0<code>foo<\/code>\u00a0to\u00a0<code>bar<\/code>, but don&#8217;t send me any\u00a0<code>foo<\/code>\u00a0refs to begin with&#8221;). To exclude a wildcard refspec, you&#8217;d just write\u00a0<code>^refs\/heads\/foo\/*<\/code>.<\/li>\n<li>While positive refspecs can refer to a single object by its object id, negative refspecs cannot.<\/li>\n<\/ul>\n<p>And of course those negative refspecs work equally well in configuration values. If you always want to fetch every branch except\u00a0<code>foo<\/code>, you can just add it to your config:<\/p>\n<div class=\"highlight highlight-text-shell-session\">\n<pre>$ <span class=\"pl-s1\">git config --add remote.origin.fetch ^refs\/heads\/foo<\/span><\/pre>\n<\/div>\n<p>[<a href=\"https:\/\/github.com\/git\/git\/compare\/f6b06b459092520bd90e5a191589e2d4371ef7d1...c0192df6306d4d9ad77f6015a053925b13155834\">source<\/a>]<\/p>\n<h2 ><a class=\"heading-link\" href=\"#\"><a id=\"user-content-new-git-shortlog-tricks\" class=\"anchor\" href=\"https:\/\/gist.github.com\/leereilly\/c08ba724a13d9c27a210458ce540f11d#new-git-shortlog-tricks\" aria-hidden=\"true\"><\/a>New\u00a0<code>git shortlog<\/code>\u00a0tricks<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>While you have almost certainly used (or heard of)\u00a0<code>git log<\/code>, the same might not be necessarily true of\u00a0<code>git shortlog<\/code>. For those who haven&#8217;t,\u00a0<code>git shortlog<\/code>\u00a0acts a lot like\u00a0<code>git log<\/code>, except instead of displaying commits in a sequence, it groups them by the author.<\/p>\n<p>In fact, the Git release notes end with a shortlog of all of the patches in the release, broken out by their author, generated by\u00a0<code>git shortlog<\/code>\u00a0[<a href=\"https:\/\/github.com\/git\/git\/blob\/todo\/Announce#L165-L166\">source<\/a>]. At the time of writing, they look something like this:<\/p>\n<pre><code class=\"language-ShellSession\">Aaron Lipman (12):\n      t6030: modernize \"git bisect run\" tests\n      rev-list: allow bisect and first-parent flags\n      cmd_bisect__helper: defer parsing no-checkout flag\n      [...]\n\nAdrian Moennich (1):\n      ci: fix inconsistent indentation\n\nAlban Gruin (1):\n      t6300: fix issues related to %(contents:size)\n\n[...]\n<\/code><\/pre>\n<p>In older versions of Git,\u00a0<code>git shortlog<\/code>\u00a0could only group by commit author (the default behavior), and optionally by the committer identity (with\u00a0<code>git shortlog -c<\/code>). This restricts who gets the credit for a commit by who that commit&#8217;s author\/committer is. So, if your project uses\u00a0<a href=\"https:\/\/git-scm.com\/docs\/git-interpret-trailers\" rel=\"nofollow\">the &#8216;Co-authored-by&#8217; trailer<\/a>\u00a0(like\u00a0<a href=\"https:\/\/github.com\/git\/git\/commit\/87b68db3ac5465bbd10ff0fc22fa5209b6452a31\">this<\/a>\u00a0commit in\u00a0<code>git\/git<\/code>\u00a0does), then your co-authors are out of luck: there is no way to tell\u00a0<code>git shortlog<\/code>\u00a0to group commits by co-authors.<\/p>\n<p>&#8230;That is, until Git 2.29! In this release,\u00a0<code>git shortlog<\/code>\u00a0learned a new\u00a0<code>--group<\/code>\u00a0argument, to specify how commits are grouped and assigned credit. It takes\u00a0<code>--group=author<\/code>\u00a0(the default behavior from before) and\u00a0<code>--group=committer<\/code>\u00a0(equivalent to\u00a0<code>git shortlog -c<\/code>), but it also accepts a\u00a0<code>--group=trailer:&lt;field&gt;<\/code>\u00a0argument.<\/p>\n<p>Passing the latter allows us to group commits by their co-authors, and it also allows for more creative uses. If your project is using the\u00a0<code>Reviewed-by<\/code>\u00a0trailer, you can use\u00a0<code>git shortlog<\/code>\u00a0to see who is reviewing the most patches:<\/p>\n<div class=\"highlight highlight-text-shell-session\">\n<pre>$ <span class=\"pl-s1\">git shortlog -ns --group=trailer:reviewed-by v2.28.0.. <span class=\"pl-k\">|<\/span> head -n5<\/span>\n<span class=\"pl-c1\">    40  Eric Sunshine<\/span>\n<span class=\"pl-c1\">    10  Taylor Blau<\/span>\n<span class=\"pl-c1\">     4  brian m. carlson<\/span>\n<span class=\"pl-c1\">     2  Elijah Newren<\/span>\n<span class=\"pl-c1\">     1  Jeff King<\/span><\/pre>\n<\/div>\n<p><code>git shortlog<\/code>\u00a0also allows multiple\u00a0<code>--group=&lt;type&gt;<\/code>\u00a0arguments, in which case commits are counted once per each grouping. So, if you want to see who is\u00a0<em>contributing<\/em>\u00a0the most whether that individual is the primary author, or is listed as a co-author, then you can write:<\/p>\n<div class=\"highlight highlight-text-shell-session\">\n<pre>$ <span class=\"pl-s1\">git shortlog -ns --group=author --group=trailer:co-authored-by<\/span><\/pre>\n<\/div>\n<p>&#8230;putting authors and co-authors on equal footing. Instead of counting, you can also use the\u00a0<code>--format<\/code>\u00a0option to find other fun ways to show the data. For example:<\/p>\n<div class=\"highlight highlight-text-shell-session\">\n<pre>$ <span class=\"pl-s1\">git shortlog --format=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>...helped %an on %as<span class=\"pl-pds\">\"<\/span><\/span> --group=trailer:helped-by v2.28.0..v2.29.0<\/span>\n<span class=\"pl-c1\">Chris Torek (3):<\/span>\n<span class=\"pl-c1\">      ...helped Ren\u00e9 Scharfe on 2020-08-12<\/span>\n<span class=\"pl-c1\">      ...helped Ren\u00e9 Scharfe on 2020-08-12<\/span>\n<span class=\"pl-c1\">      ...helped Ren\u00e9 Scharfe on 2020-08-12<\/span>\n\n<span class=\"pl-c1\">David Aguilar (1):<\/span>\n<span class=\"pl-c1\">      ...helped Lin Sun on 2020-05-07<\/span>\n\n<span class=\"pl-c1\">Denton Liu (1):<\/span>\n<span class=\"pl-c1\">      ...helped Shourya Shukla on 2020-08-21<\/span>\n\n<span class=\"pl-c1\">Derrick Stolee (2):<\/span>\n<span class=\"pl-c1\">      ...helped Taylor Blau on 2020-08-25<\/span>\n<span class=\"pl-c1\">      ...helped Taylor Blau on 2020-09-17<\/span>\n\n<span class=\"pl-c1\">[...]<\/span><\/pre>\n<\/div>\n<p>[<a href=\"https:\/\/github.com\/git\/git\/compare\/ea1f6118b772d8d03302937afc16e71719d33587...63d24fa0b055d3f0386ee3686c07428450add708\">source<\/a>]<\/p>\n<h2 ><a class=\"heading-link\" href=\"#\"><a id=\"user-content-tidbits\" class=\"anchor\" href=\"https:\/\/gist.github.com\/leereilly\/c08ba724a13d9c27a210458ce540f11d#tidbits\" aria-hidden=\"true\"><\/a>Tidbits<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p><code>git for-each-ref<\/code>\u00a0learned a few new tricks in Git 2.29. Since there are a good handful of them, let&#8217;s start there:<\/p>\n<ul>\n<li><code>git for-each-ref<\/code>\u00a0usually outputs the name, type, and object id of each ref, but you can find out a lot more with its\u00a0<a href=\"https:\/\/git-scm.com\/docs\/git-for-each-ref#_field_names\" rel=\"nofollow\"><code>--format<\/code>\u00a0option<\/a>. Git 2.29 learned some new fields, including\u00a0<code>contents:size<\/code>,\u00a0<code>subject:sanitize<\/code>, and more consistent\u00a0<code>:short<\/code>\u00a0modifiers to get abbreviated object ids. These last few were contributed by\u00a0<a href=\"https:\/\/github.com\/harry-hov\">Hariom Verma<\/a>, a Google Summer of Code student working on the Git project.[<a href=\"https:\/\/github.com\/git\/git\/compare\/a20e20e4c8fe6c13e03af8109644a84d8f4e7f7f...b6839fda6809b1de8d528837dfc99d0837f77c9d\">source<\/a>,\u00a0<a href=\"https:\/\/github.com\/git\/git\/compare\/9f7833fd55c0039ef304beea7c1263d428410b95...905f0a4e64bef35482a999dd01c64945b260c010\">source<\/a>]<\/li>\n<li><code>git for-each-ref<\/code>\u00a0can now take multiple\u00a0<code>--merged<\/code>\u00a0and\u00a0<code>--no-merged<\/code>\u00a0arguments, printing references if they are reachable from at least one\u00a0<code>--merged<\/code>\u00a0argument, and aren&#8217;t reachable from any\u00a0<code>--no-merged<\/code>\u00a0ones.[<a href=\"https:\/\/github.com\/git\/git\/compare\/4d515253afcef985e94400adbfed7044959f9121...b59cdffd7e3d791ee289ebb46d7109ad3d51d7ea\">source<\/a>]<\/li>\n<\/ul>\n<p>Now with all of the\u00a0<code>git for-each-ref<\/code>\u00a0updates out of the way, let&#8217;s move on to all of the rest of the tidbits:<\/p>\n<ul>\n<li>When your\u00a0<code>git merge<\/code>\u00a0results in a merge conflict, you&#8217;re greeted by a message that looks something like the following (this example is\u00a0<a href=\"https:\/\/lore.kernel.org\/git\/pull.828.git.git.1596654345718.gitgitgadget@gmail.com\/\" rel=\"nofollow\">courtesy of Elijah Newren<\/a>):<br \/>\n<blockquote>\n<pre><code class=\"language-ShellSession\">CONFLICT (rename\/delete): foo.c deleted in b01dface... Removed\nunnecessary stuff and renamed in HEAD.  Version HEAD of foo.c left\nin tree.\n<\/code><\/pre>\n<\/blockquote>\n<p>Can you tell what this message means? In versions of Git prior to 2.29, it was ambiguous: did Git remove stuff and rename files in\u00a0<code>HEAD<\/code>, or is &#8220;Removed unnecessary stuff&#8221; the name of a commit message? It turns out that it&#8217;s the latter, but you had no way of knowing that!<\/p>\n<p>In 2.29, Git will now enclose the subject of a commit message in parenthesis, making much clearer what part of the conflict message came from a commit, and what part was generated by Git.<\/p>\n<p>[<a href=\"https:\/\/github.com\/git\/git\/compare\/9cdf86b2ee998d66008eeb9690571939db9074e2...7d056deacea488833192d517059e04916285e90f\">source<\/a>]<\/li>\n<li>Here&#8217;s an easy one! Git supports a configuration option called\u00a0<code>merge.renormalize<\/code>. In case you&#8217;re not familiar with the entirety of Git&#8217;s\u00a0<a href=\"https:\/\/git-scm.com\/docs\/git-config\" rel=\"nofollow\">nearly 5,000 line\u00a0<code>man git-config<\/code><\/a>, here&#8217;s a refresher:\u00a0<code>merge.renormalize<\/code>\u00a0causes Git to check-out and check-in each stage of a three-way merge. This can be useful if the line-endings change between two branches you&#8217;re working on.This configuration used to not get picked up by\u00a0<code>git checkout -m<\/code>\u00a0(and a few related invocations), but now it is![<a href=\"https:\/\/github.com\/git\/git\/compare\/1aa3dff4ba492483a4cce0a3aa315cfc05b0bdd3...00906d6f227b259ac7c8cebd07bbea0ba4792185\">source<\/a>]<\/li>\n<li>In our highlights from Git 2.26, we talked about\u00a0<a href=\"https:\/\/github.blog\/2020-03-22-highlights-from-git-2-26\/#protocol-version-2-is-now-the-default\" rel=\"nofollow\">protocol v2<\/a>, which became the default in that release. Between 2.26 and 2.27, a bug in this new protocol was found and fixed (see\u00a0<a href=\"https:\/\/github.com\/git\/git\/commit\/4fa3f00abb55c3334cce71e201a5ff2c70f8561f\"><code>4fa3f00abb<\/code><\/a>\u00a0for the juicy details). For safety,\u00a0<a href=\"https:\/\/github.com\/git\/git\/commit\/11c7f2a30b9dadcccc7bde66a34e0cb0cb5cf52c\">Git 2.27 went back to protocol &#8220;v0&#8221;<\/a>\u00a0to ease back the transition, and\u00a0<a href=\"https:\/\/github.com\/git\/git\/commit\/3697caf4b962f65430fdcd6f0d41b7fe1f579e18\">marked the feature experimental<\/a>\u00a0in Git 2.28.Now that we&#8217;ve had a few chances to iron out any linger bugs after Git 2.28, protocol v2 is re-enabled as the default protocol in Git 2.29.[<a href=\"https:\/\/github.com\/git\/git\/compare\/b28919c7bcfabad81896070e6b7b66be8310e6a8...eb049759fb6b739310af52ee0e13ce6cd0c86be7\">source<\/a>]<\/li>\n<li><code>git bisect<\/code>\u00a0is an incredibly handy tool to use when trying to determine the source of a bug. You mark a &#8220;good&#8221; and &#8220;bad&#8221; endpoint, and then Git leads you through a binary search between the endpoints to find the commit that introduced the problem.In Git 2.29,\u00a0<code>git bisect<\/code>\u00a0learned a new\u00a0<code>--first-parent<\/code>\u00a0option to modify which commits are traversed between those endpoints. One way to understand this option is to imagine what happens when bisecting through a merge. Before, your bisection would include commits on the branch being merged in, in addition to the merge commit itself.Passing\u00a0<code>--first-parent<\/code>\u00a0tells Git to avoid considering commits that are only on the branch being merged in as a potential source of the bug. If your workflow is such that only the merges on the main branch are interesting stopping points (because you primarily work by merging pull requests, and each individual pull request may have work-in-progress commits that might not even build), then\u00a0<code>--first-parent<\/code>\u00a0lets you skip all that.[<a href=\"https:\/\/github.com\/git\/git\/compare\/789279e7f8439ea0e0727f6de36b2edafcbc5f3c...ad464a4e84b502fdfd4671f1c443060c7e87113f\">source<\/a>]<\/li>\n<li>Git optionally includes a remote backend for pushing and pulling from a\u00a0<a href=\"https:\/\/www.mediawiki.org\/wiki\/MediaWiki\" rel=\"nofollow\">MediaWiki<\/a>\u00a0instance. It is generally unsupported and not compiled by default, but a recently discovered vulnerability can lead to arbitrary command execution, which has been patched in this release.Note that you are only affected by this vulnerability if you use the mediawiki backend against an untrusted MediaWiki instance (chances are if you have to ask yourself whether or not you are affected, you probably aren&#8217;t).[<a href=\"https:\/\/github.com\/git\/git\/compare\/306ee63a703ad67c54ba1209dc11dd9ea500dc1f...9a8606465e81a04d58c20324c402ba3464bc706a\">source<\/a>]<\/li>\n<li>Git uses the low-level\u00a0<code>git index-pack<\/code>\u00a0command to receive a\u00a0<code>git push<\/code>\u00a0or process a\u00a0<code>git fetch<\/code>. In Git 2.29,\u00a0<code>git index-pack<\/code>\u00a0learned to work more efficiently on multi-core machines, which means all of your pushes and fetches should get faster just by upgrading.[<a href=\"https:\/\/github.com\/git\/git\/compare\/634e0084fac75cf85449a813da14968c9663a094...f08cbf60fe11507b5ff722ceae95dfb86ce654ee\">source<\/a>,\u00a0<a href=\"https:\/\/github.com\/git\/git\/compare\/e17723842b4fd42215ebf9c7ee5ab0bdfbe5a402...fbff95b67f7e7bfc8799c2d6d16263cfeb61bc6f\">source<\/a>]<\/li>\n<li>When you create a merge commit, the default message reads something like &#8220;Merge\u00a0<code>$upstream<\/code>\u00a0into\u00a0<code>$dest<\/code>&#8220;. Historically, merges into the main branch would omit the &#8220;into\u00a0<code>$dest<\/code>&#8221; part.Git 2.29 learned\u00a0<a href=\"https:\/\/git-scm.com\/docs\/git-config#Documentation\/git-config.txt-mergesuppressDest\" rel=\"nofollow\">the\u00a0<code>merge.suppressDest<\/code>\u00a0configuration<\/a>. Any branch in this multi-valued config variable will cause\u00a0<code>git merge<\/code>\u00a0to omit &#8220;into\u00a0<code>$dest<\/code>&#8221; part.[<a href=\"https:\/\/github.com\/git\/git\/compare\/e8ab941b671da6890181aea5b5755d1d9eea24ec...6e6029a82acdb3d785eef15dc798f4d86c4ea445\">source<\/a>]<\/li>\n<\/ul>\n<h2 ><a class=\"heading-link\" href=\"#\"><a id=\"user-content-the-kaboodle\" class=\"anchor\" href=\"https:\/\/gist.github.com\/leereilly\/c08ba724a13d9c27a210458ce540f11d#the-kaboodle\" aria-hidden=\"true\"><\/a>The kaboodle<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>That&#8217;s just a sample of changes from the latest release. For more, check out\u00a0<a href=\"https:\/\/github.com\/git\/git\/blob\/v2.29.0\/Documentation\/RelNotes\/2.29.0.txt\">the release notes for 2.29<\/a>, or\u00a0<a href=\"https:\/\/github.com\/git\/git\/tree\/v2.29.0\/Documentation\/RelNotes\">any previous version<\/a>\u00a0in\u00a0<a href=\"https:\/\/github.com\/git\/git\">the Git repository<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The open source Git project\u00a0just released Git 2.29\u00a0with features and bug fixes from over 89 contributors, 24 of them new. Last time\u00a0we caught up\u00a0with you, Git 2.28 had just been&hellip;<\/p>\n","protected":false},"author":1282,"featured_media":54847,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_gh_post_show_toc":"","_gh_post_is_no_robots":"","_gh_post_is_featured":"","_gh_post_is_excluded":"","_gh_post_is_unlisted":"","_gh_post_related_link_1":"","_gh_post_related_link_2":"","_gh_post_related_link_3":"","_gh_post_sq_img":"","_gh_post_sq_img_id":"","_gh_post_cta_title":"","_gh_post_cta_text":"","_gh_post_cta_link":"","_gh_post_cta_button":"","_gh_post_recirc_hide":"","_gh_post_recirc_col_1":"","_gh_post_recirc_col_2":"","_gh_post_recirc_col_3":"","_gh_post_recirc_col_4":"","_featured_video":"","_gh_post_additional_query_params":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"{title}\n\n{excerpt}\n\n{url}","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false,"jetpack_post_was_ever_published":false,"_links_to":"","_links_to_target":""},"categories":[3330,67],"tags":[132],"coauthors":[],"class_list":["post-54839","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-git","category-open-source","tag-git"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v28.6 (Yoast SEO v28.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Highlights from Git 2.29 - The GitHub Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Highlights from Git 2.29\" \/>\n<meta property=\"og:description\" content=\"The open source Git project\u00a0just released Git 2.29\u00a0with features and bug fixes from over 89 contributors, 24 of them new. Last time\u00a0we caught up\u00a0with you, Git 2.28 had just been&hellip;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/\" \/>\n<meta property=\"og:site_name\" content=\"The GitHub Blog\" \/>\n<meta property=\"article:published_time\" content=\"2020-10-19T16:44:04+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-01-12T22:25:08+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/github.blog\/wp-content\/uploads\/2020\/10\/gitrelease-blog-dd_2-29.png?fit=1200%2C630\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Taylor Blau\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/github.blog\/wp-content\/uploads\/2020\/10\/gitrelease-blog-dd_2-29.png?fit=1200%2C630\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Taylor Blau\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/git-2-29-released\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/git-2-29-released\\\/\"},\"author\":{\"name\":\"Taylor Blau\",\"@id\":\"https:\\\/\\\/github.blog\\\/#\\\/schema\\\/person\\\/f2a5dc09d09f41c8c731679cc07da524\"},\"headline\":\"Highlights from Git 2.29\",\"datePublished\":\"2020-10-19T16:44:04+00:00\",\"dateModified\":\"2021-01-12T22:25:08+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/git-2-29-released\\\/\"},\"wordCount\":2147,\"image\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/git-2-29-released\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2020\\\/10\\\/gitrelease-blog-dd_2-29.png?fit=1200%2C630\",\"keywords\":[\"Git\"],\"articleSection\":[\"Git\",\"Open Source\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/git-2-29-released\\\/\",\"url\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/git-2-29-released\\\/\",\"name\":\"Highlights from Git 2.29 - The GitHub Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/github.blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/git-2-29-released\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/git-2-29-released\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2020\\\/10\\\/gitrelease-blog-dd_2-29.png?fit=1200%2C630\",\"datePublished\":\"2020-10-19T16:44:04+00:00\",\"dateModified\":\"2021-01-12T22:25:08+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/github.blog\\\/#\\\/schema\\\/person\\\/f2a5dc09d09f41c8c731679cc07da524\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/git-2-29-released\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/git-2-29-released\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/git-2-29-released\\\/#primaryimage\",\"url\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2020\\\/10\\\/gitrelease-blog-dd_2-29.png?fit=1200%2C630\",\"contentUrl\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2020\\\/10\\\/gitrelease-blog-dd_2-29.png?fit=1200%2C630\",\"width\":1200,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/git-2-29-released\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/github.blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Open Source\",\"item\":\"https:\\\/\\\/github.blog\\\/open-source\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Git\",\"item\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Highlights from Git 2.29\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/github.blog\\\/#website\",\"url\":\"https:\\\/\\\/github.blog\\\/\",\"name\":\"The GitHub Blog\",\"description\":\"Updates, ideas, and inspiration from GitHub to help developers build and design software.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/github.blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/github.blog\\\/#\\\/schema\\\/person\\\/f2a5dc09d09f41c8c731679cc07da524\",\"name\":\"Taylor Blau\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/d5f3476f26b6f99cbb6b467e7ed7482f5762c8157bc73f569196e428bdcbea25?s=96&d=mm&r=g2ce44289191883c54a58a554d8fc874a\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/d5f3476f26b6f99cbb6b467e7ed7482f5762c8157bc73f569196e428bdcbea25?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/d5f3476f26b6f99cbb6b467e7ed7482f5762c8157bc73f569196e428bdcbea25?s=96&d=mm&r=g\",\"caption\":\"Taylor Blau\"},\"description\":\"Taylor Blau is a Principal Software Engineer at GitHub where he works on Git.\",\"sameAs\":[\"https:\\\/\\\/ttaylorr.com\"],\"url\":\"https:\\\/\\\/github.blog\\\/author\\\/ttaylorr\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Highlights from Git 2.29 - The GitHub Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/","og_locale":"en_US","og_type":"article","og_title":"Highlights from Git 2.29","og_description":"The open source Git project\u00a0just released Git 2.29\u00a0with features and bug fixes from over 89 contributors, 24 of them new. Last time\u00a0we caught up\u00a0with you, Git 2.28 had just been&hellip;","og_url":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/","og_site_name":"The GitHub Blog","article_published_time":"2020-10-19T16:44:04+00:00","article_modified_time":"2021-01-12T22:25:08+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/github.blog\/wp-content\/uploads\/2020\/10\/gitrelease-blog-dd_2-29.png?fit=1200%2C630","type":"image\/png"}],"author":"Taylor Blau","twitter_card":"summary_large_image","twitter_image":"https:\/\/github.blog\/wp-content\/uploads\/2020\/10\/gitrelease-blog-dd_2-29.png?fit=1200%2C630","twitter_misc":{"Written by":"Taylor Blau","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/#article","isPartOf":{"@id":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/"},"author":{"name":"Taylor Blau","@id":"https:\/\/github.blog\/#\/schema\/person\/f2a5dc09d09f41c8c731679cc07da524"},"headline":"Highlights from Git 2.29","datePublished":"2020-10-19T16:44:04+00:00","dateModified":"2021-01-12T22:25:08+00:00","mainEntityOfPage":{"@id":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/"},"wordCount":2147,"image":{"@id":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/#primaryimage"},"thumbnailUrl":"https:\/\/github.blog\/wp-content\/uploads\/2020\/10\/gitrelease-blog-dd_2-29.png?fit=1200%2C630","keywords":["Git"],"articleSection":["Git","Open Source"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/","url":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/","name":"Highlights from Git 2.29 - The GitHub Blog","isPartOf":{"@id":"https:\/\/github.blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/#primaryimage"},"image":{"@id":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/#primaryimage"},"thumbnailUrl":"https:\/\/github.blog\/wp-content\/uploads\/2020\/10\/gitrelease-blog-dd_2-29.png?fit=1200%2C630","datePublished":"2020-10-19T16:44:04+00:00","dateModified":"2021-01-12T22:25:08+00:00","author":{"@id":"https:\/\/github.blog\/#\/schema\/person\/f2a5dc09d09f41c8c731679cc07da524"},"breadcrumb":{"@id":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/github.blog\/open-source\/git\/git-2-29-released\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/#primaryimage","url":"https:\/\/github.blog\/wp-content\/uploads\/2020\/10\/gitrelease-blog-dd_2-29.png?fit=1200%2C630","contentUrl":"https:\/\/github.blog\/wp-content\/uploads\/2020\/10\/gitrelease-blog-dd_2-29.png?fit=1200%2C630","width":1200,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/github.blog\/open-source\/git\/git-2-29-released\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/github.blog\/"},{"@type":"ListItem","position":2,"name":"Open Source","item":"https:\/\/github.blog\/open-source\/"},{"@type":"ListItem","position":3,"name":"Git","item":"https:\/\/github.blog\/open-source\/git\/"},{"@type":"ListItem","position":4,"name":"Highlights from Git 2.29"}]},{"@type":"WebSite","@id":"https:\/\/github.blog\/#website","url":"https:\/\/github.blog\/","name":"The GitHub Blog","description":"Updates, ideas, and inspiration from GitHub to help developers build and design software.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/github.blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/github.blog\/#\/schema\/person\/f2a5dc09d09f41c8c731679cc07da524","name":"Taylor Blau","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/d5f3476f26b6f99cbb6b467e7ed7482f5762c8157bc73f569196e428bdcbea25?s=96&d=mm&r=g2ce44289191883c54a58a554d8fc874a","url":"https:\/\/secure.gravatar.com\/avatar\/d5f3476f26b6f99cbb6b467e7ed7482f5762c8157bc73f569196e428bdcbea25?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d5f3476f26b6f99cbb6b467e7ed7482f5762c8157bc73f569196e428bdcbea25?s=96&d=mm&r=g","caption":"Taylor Blau"},"description":"Taylor Blau is a Principal Software Engineer at GitHub where he works on Git.","sameAs":["https:\/\/ttaylorr.com"],"url":"https:\/\/github.blog\/author\/ttaylorr\/"}]}},"jetpack_publicize_connections":[],"jetpack_shortlink":"https:\/\/wp.me\/pamS32-egv","jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/github.blog\/wp-content\/uploads\/2020\/10\/gitrelease-blog-dd_2-29.png?fit=1200%2C630","_links":{"self":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts\/54839","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/users\/1282"}],"replies":[{"embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/comments?post=54839"}],"version-history":[{"count":11,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts\/54839\/revisions"}],"predecessor-version":[{"id":55819,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts\/54839\/revisions\/55819"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/media\/54847"}],"wp:attachment":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/media?parent=54839"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/categories?post=54839"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/tags?post=54839"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/coauthors?post=54839"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}