{"id":77738,"date":"2024-04-29T10:14:27","date_gmt":"2024-04-29T17:14:27","guid":{"rendered":"https:\/\/github.blog\/?p=77738"},"modified":"2024-04-30T06:42:43","modified_gmt":"2024-04-30T13:42:43","slug":"highlights-from-git-2-45","status":"publish","type":"post","link":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/","title":{"rendered":"Highlights from Git 2.45"},"content":{"rendered":"<!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD HTML 4.0 Transitional\/\/EN\" \"http:\/\/www.w3.org\/TR\/REC-html40\/loose.dtd\">\n<html><body><p>The open source Git project just <a href=\"https:\/\/lore.kernel.org\/git\/xmqq8r0ww0sj.fsf@gitster.g\/T\/#u\">released Git 2.45<\/a> with features and bug fixes from over 96 contributors, 38 of them new. We last caught up with you on the latest in Git back when <a href=\"https:\/\/github.blog\/2024-02-23-highlights-from-git-2-44\/\">2.44 was released<\/a>.<\/p>\n<p>To celebrate this most recent release, here is GitHub&rsquo;s look at some of the most interesting features and changes introduced since last time.<\/p>\n<h2 id=\"preliminary-reftable-support\" id=\"preliminary-reftable-support\" ><a class=\"heading-link\" href=\"#preliminary-reftable-support\">Preliminary reftable support<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>Git 2.45 introduces preliminary support for a new reference storage backend called &ldquo;reftable,&rdquo; promising faster lookups, reads, and writes for repositories with any number of references.<\/p>\n<p>If you&rsquo;re unfamiliar with our previous coverage of the new reftable format, don&rsquo;t worry, this post will catch you up to speed (and then some!). But if you just want to play around with the new reference backend, you can initialize a new repository with <code>--ref-format=reftable<\/code> like so:<\/p>\n<pre><code>$ git init --ref-format=reftable \/path\/to\/repo\nInitialized empty Git repository in \/path\/to\/repo\/.git\n$ cd \/path\/to\/repo\n$ git commit --allow-empty -m 'hello reftable!'\n[main (root-commit) 2eb0810] hello reftable!\n$ ls -1 .git\/reftable\/\n0x000000000001-0x000000000002-565c6bf0.ref\ntables.list\n$ cat .git\/reftable\/tables.list\n0x000000000001-0x000000000002-565c6bf0.ref\n<\/code><\/pre>\n<p>With that out of the way, let&rsquo;s jump into the details. If you&rsquo;re new to this series, or didn&rsquo;t catch our initial coverage of the reftable feature, don&rsquo;t worry, here&rsquo;s a refresher. When we talk about <a href=\"https:\/\/git-scm.com\/book\/en\/v2\/Git-Internals-Git-References\">references<\/a> in Git, we&rsquo;re referring to the branches and tags that make up your repository. In essence, a reference is nothing more than a name (like <code>refs\/heads\/my-feature<\/code>, or <code>refs\/tags\/v1.0.0<\/code>) and the object ID of the thing that reference points at.<\/p>\n<p>Git has historically stored references in your repository in one of two ways: either &ldquo;loose&rdquo; as a file inside of <code>$GIT_DIR\/refs<\/code> (like <code>$GIT_DIR\/refs\/heads\/my-feature<\/code>) or &ldquo;packed&rdquo; as an entry inside of the file at <code>$GIT_DIR\/packed_refs<\/code>.<\/p>\n<p>For most repositories today, the existing reference backend works fine. For repositories with a truly gigantic number of references, however, the existing backend has some growing pains. For instance, storing a large number of references as &ldquo;loose&rdquo; can lead to directories with a large number of entries (slowing down lookups within that directory) and\/or <a href=\"https:\/\/en.wikipedia.org\/wiki\/Inode#Potential_for_inode_exhaustion_and_solutions\">inode exhaustion<\/a>. Likewise, storing all references in a single <code>packed_refs<\/code> file can become expensive to maintain, as even small reference updates require a significant I\/O-cost to rewrite the entire <code>packed_refs<\/code> file on each update.<\/p>\n<p>That&rsquo;s where the reftable format comes in. Reftable is an entirely new format for storing Git references. Instead of storing loose references, or constantly updating a large <code>packed_refs<\/code> file, reftable implements a binary format for storing references that promises to achieve:<\/p>\n<ul>\n<li>Near constant-time lookup for individual references, and near constant-time verification that a given object ID is referred to by at least one reference.<\/li>\n<li>Efficient lookup of entire reference namespaces through prefix compression.<\/li>\n<li>Atomic reference updates that scale with the size of the reference update, not the number of overall references.<\/li>\n<\/ul>\n<p>The reftable format is incredibly detailed (curious readers can learn more about it in more detail by reading <a href=\"https:\/\/github.com\/git\/git\/blob\/v2.45.0\/Documentation\/technical\/reftable.txt\">the original specification<\/a>), but here&rsquo;s a high-level overview. A repository can have any number of reftables (stored as <code>*.ref<\/code> files), each of which is organized into variable-sized blocks. Blocks can store information about a collection of references, refer to the contents of other blocks when storing references across a collection of blocks, and more.<\/p>\n<p>The format is designed to both (a) take up a minimal amount of space (by storing reference names with prefix compression) and (b) support fast lookups, even when reading the <code>.ref<\/code> file(s) from a cold cache.<\/p>\n<p>Most importantly, the reftable format supports multiple <code>*.ref<\/code> files, meaning that each reference update transaction can be processed individually without having to modify existing <code>*.ref<\/code> files. A separate compaction process describes how to &ldquo;merge&rdquo; a range of adjacent <code>*.ref<\/code> files together into a single <code>*.ref<\/code> file to maintain read performance.<\/p>\n<p>The reftable format was originally designed by <a href=\"https:\/\/git.github.io\/rev_news\/2017\/08\/16\/edition-30\/#developer-spotlight-shawn-pearce\">Shawn Pearce<\/a> for use in <a href=\"https:\/\/www.eclipse.org\/jgit\/\">JGit<\/a> to better support the large number of references stored by <a href=\"https:\/\/www.gerritcodereview.com\/\">Gerrit<\/a>. Back in our <em><a href=\"https:\/\/github.blog\/2022-01-24-highlights-from-git-2-35\/\">Highlights from Git 2.35<\/a><\/em> post, we covered that an implementation of the reftable format had landed in Git. In that version, Git did not yet know how to use the new reftable code in conjunction with its existing reference backend system, meaning that you couldn&rsquo;t yet create repositories that store references using reftable.<\/p>\n<p>In Git 2.45, support for a reftable-powered storage backend has been integrated into Git&rsquo;s generic reference backend system, meaning that you can play with reftable on your own repository by running:<\/p>\n<pre><code>$ git init --ref-format=reftable \/path\/to\/repo\n<\/code><\/pre>\n<p>[<a href=\"https:\/\/github.com\/git\/git\/compare\/3c2a3fdc388747b9eaf4a4a4f2035c1c9ddb26d0...8a0bebdeaec60623c8a791b197d574bdd031a452\">source<\/a>, <a href=\"https:\/\/github.com\/git\/git\/compare\/274400998b0a2da64d20e9fa95b288bf1403459c...c68ca7abd30b22404ce59d5133566729c07ffe8f\">source<\/a>, <a href=\"https:\/\/github.com\/git\/git\/compare\/ce65a188b15bef0ef68e81d5b083e7dda34ab2c9...e0795e2c7912bc407e311b8cd3ae908bc354d8c9\">source<\/a>, <a href=\"https:\/\/github.com\/git\/git\/compare\/066124da88a6d43d125b30a1bc8a66c2d8ef6423...43f70eaea0e3fa9d98c895e9341674a67262b657\">source<\/a>, <a href=\"https:\/\/github.com\/git\/git\/compare\/7a01b444638a2704befcd4c24e1d441b818ae67b...60c4c425155c61a081cc035240ee649aa2cb2e37\">source<\/a>, <a href=\"https:\/\/github.com\/git\/git\/compare\/330ed38a2df0d67e247edc7ea69175520ead469d...fffd981ec2d7965733a4a15f9071e3734f7654a6\">source<\/a>, <a href=\"https:\/\/github.com\/git\/git\/compare\/dc97afdcb93ca683bf73b4ae2ff028c161206617...fcacc2b161b095c99dfd4e0b05dcc1ed8ca80a62\">source<\/a>, <a href=\"https:\/\/github.com\/git\/git\/compare\/50b52cafae4250319944d49d65f1fa8d83aedd58...0068aa794696188d3c9bea62804780d44bee824f\">source<\/a>, <a href=\"https:\/\/github.com\/git\/git\/compare\/847af43a3afb39394d5fe58192f94b993ca18f9f...d51d8cc36831bdabbbcec8553a7e83d9f5a3be4d\">source<\/a>, <a href=\"https:\/\/github.com\/git\/git\/compare\/2b49e41155d826d40ede07dfd4d34a7a36f9f64b...a949ebd342440049a1ac77ca675f66884eae4187\">source<\/a>]<\/p>\n<h2 id=\"preliminary-support-for-sha-1-and-sha-256-interoperability\" id=\"preliminary-support-for-sha-1-and-sha-256-interoperability\" ><a class=\"heading-link\" href=\"#preliminary-support-for-sha-1-and-sha-256-interoperability\">Preliminary support for SHA-1 and SHA-256 interoperability<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>Returning readers of this series will be familiar with our ongoing coverage of the Git project&rsquo;s <a href=\"https:\/\/git-scm.com\/docs\/hash-function-transition\">hash function transition<\/a>. If you&rsquo;re new around here, or need a refresher, don&rsquo;t worry!<\/p>\n<p>Git identifies objects (the blobs, trees, commits, and tags that make up your repository) by a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hash_function\">hash<\/a> of their contents. Since its inception, Git has used the <a href=\"https:\/\/en.wikipedia.org\/wiki\/SHA-1\">SHA-1 hash function<\/a> to hash and identify objects in a repository.<\/p>\n<p>However, the SHA-1 function has known collision attacks (e.g., <a href=\"https:\/\/shattered.io\/\">Shattered<\/a>, and <a href=\"https:\/\/sha-mbles.github.io\/\">Shambles<\/a>), meaning that a sufficiently motivated attacker can generate a colliding pair of SHA-1 inputs, which have the same SHA-1 hash despite containing different contents. (Many providers, like GitHub, use a SHA-1 implementation that detects and rejects inputs that contain the telltale signs of being part of a colliding pair attack. For more details, see our post, <em><a href=\"https:\/\/github.blog\/2017-03-20-sha-1-collision-detection-on-github-com\/\">SHA-1 collision detection on GitHub.com<\/a><\/em>).<\/p>\n<p>Around this time, the Git project <a href=\"https:\/\/lore.kernel.org\/git\/20170304011251.GA26789@aiede.mtv.corp.google.com\/\">began discussing<\/a> a plan to transition from SHA-1 to a more secure hash function that was not susceptible to the same chosen-prefix attacks. The project decided on SHA-256 as the successor to Git&rsquo;s use of SHA-1 and work on supporting the new hash function began in earnest. In Git 2.29 (released in October 2020), Git gained experimental support for using SHA-256 instead of SHA-1 in specially-configured repositories. That feature was declared no longer experimental in Git 2.42 (released in August 2023).<\/p>\n<p>One of the goals of the hash function transition was to introduce support for repositories to interoperate between SHA-1 and SHA-256, meaning that repositories could in theory use one hash function locally, while pushing to another repository that uses a different hash function.<\/p>\n<p>Git 2.45 introduces experimental preliminary support for limited interoperability between SHA-1 and SHA-256. To do this, Git 2.45 introduces a new concept called the &ldquo;compatibility&rdquo; object format, and allows you to refer to objects by either their given hash, or their &ldquo;compatibility&rdquo; hash. An object&rsquo;s compatibility hash is the hash of an object as it would have been written under the compatibility hash function.<\/p>\n<p>To give you a better sense of how this new feature works, here&rsquo;s a short demo. To start, we&rsquo;ll initialize a repository in SHA-256 mode, and declare that SHA-1 is our compatibility hash function:<\/p>\n<pre><code>$ git init --object-format=sha256 \/path\/to\/repo\nInitialized empty Git repository in \/path\/to\/repo\/.git\n$ cd \/path\/to\/repo\n$ git config extensions.compatObjectFormat sha1\n<\/code><\/pre>\n<p>Then, we can create a simple commit with a single file (<code>README<\/code>) whose contents are &ldquo;Hello, world!&rdquo;:<\/p>\n<pre><code>$ echo 'Hello, world!' &gt;README\n$ git add README\n$ git commit -m \"initial commit\"\n[main (root-commit) 74dcba4] initial commit\n Author: A U Thor &lt;author@example.com&gt;\n 1 file changed, 1 insertion(+)\n create mode 100644 README\n<\/code><\/pre>\n<p>Now, we can ask Git to show us the contents of the commit object we just created with <code>cat-file<\/code>. As we&rsquo;d expect, the hash of the commit object, as well as its root tree are computed using SHA-256:<\/p>\n<pre><code>$ git rev-parse HEAD | git cat-file --batch\n74dcba4f8f941a65a44fdd92f0bd6a093ad78960710ac32dbd4c032df66fe5c6 commit 202\ntree ace45d916e870ce0fadbb8fc579218d01361da4159d1e2b5949f176b1f743280\nauthor A U Thor &lt;author@example.com&gt; 1713990043 -0400\ncommitter C O Mitter &lt;committer@example.com&gt; 1713990043 -0400\n\ninitial commit\n<\/code><\/pre>\n<p>But we can also tell <code>git rev-parse<\/code> to output any object IDs using the compatibility hash function, allowing us to ask for the SHA-1 object ID of that same commit object. When we print its contents out using <code>cat-file<\/code>, its root tree OID is a different value (starting with <code>7dd4941980<\/code> instead of <code>ace45d916e<\/code>), this time computed using SHA-1 instead of SHA-256:<\/p>\n<pre><code>$ git rev-parse --output-object-format=sha1 HEAD\n2a4f4a2182686157a2dc887c46693c988c912533\n\n$ git rev-parse --output-object-format=sha1 HEAD | git cat-file --batch\n2a4f4a2182686157a2dc887c46693c988c912533 commit 178\ntree 7dd49419807b37a3afd2f040891a64d69abb8df1\nauthor A U Thor &lt;author@example.com&gt; 1713990043 -0400\ncommitter C O Mitter &lt;committer@example.com&gt; 1713990043 -0400\n\ninitial commit\n<\/code><\/pre>\n<p>Support for this new feature is still considered experimental, and many features may not work quite as you expect them to. There is still much work ahead for full interoperability between SHA-1 and SHA-256 repositories, but this release delivers an important first step towards full interoperability support.<\/p>\n<p>[<a href=\"https:\/\/github.com\/git\/git\/compare\/c75fd8d8150afdf836b63a8e0534d9b9e3e111ba...7673ecd2dcdcf0aae01cccdb5c25f9b96160a8c0\">source<\/a>]<\/p>\n<hr>\n<ul>\n<li>If you&rsquo;ve ever scripted around your repository, then you have no doubt used <code>git rev-list<\/code> to list commits or objects reachable from some set of inputs. <code>rev-list<\/code> can also come in handy when trying to diagnose repository corruption, including investigating missing objects.\n<p>In the past, you might have used something like <code>git rev-list --missing=print<\/code> to gather a list of objects which are reachable from your inputs, but are missing from the local repository. But what if there are missing objects at the tips of your reachability query itself? For instance, if the tip of some branch or tag is corrupt, then you&rsquo;re stuck:<\/p>\n<pre><code>$ git rev-parse HEAD | tr 'a-f1-9' '1-9a-f' &gt;.git\/refs\/heads\/missing\n$ git rev-list --missing=print --all | grep '^?'\nfatal: bad object refs\/heads\/missing\n<\/code><\/pre>\n<p>Here, Git won&rsquo;t let you continue, since one of the inputs to the reachability query itself (<code>refs\/heads\/missing<\/code>, via <code>--all<\/code>) is missing. This can make debugging missing objects in the reachable parts of your history more difficult than necessary.<\/p>\n<p>But with Git 2.45, you can debug missing objects even when the tips of your reachability query are themselves missing, like so:<\/p>\n<pre><code>$ git rev-list --missing=print --all | grep '^?'\n?70678e7afeacdcba1242793c3d3d28916a2fd152\n<\/code><\/pre>\n<p>[<a href=\"https:\/\/github.com\/git\/git\/compare\/2c206fc82abb3ae3d8a5fb5b3c07c1a933007f31...a4324babe679352a801310f8e30f3cbcd9c1f16b\">source<\/a>]<\/p>\n<\/li>\n<li>\n<p>One of Git&rsquo;s lesser-known features are &ldquo;reference logs,&rdquo; or &ldquo;<a href=\"https:\/\/git-scm.com\/docs\/git-reflog\">reflogs<\/a>&rdquo; for short. These reference logs are extremely useful when asking questions about the history of some reference, such as: &ldquo;what was main pointing at two weeks ago?&rdquo; or &ldquo;where was I before I started this rebase?&rdquo;.<\/p>\n<p>Each reference has its own corresponding reflog, and you can use the <code>git reflog<\/code> command to see the reflog for the currently checked-out reference, or for an arbitrary reference by running <code>git reflog refs\/heads\/some\/branch<\/code>.<\/p>\n<p>If you want to see what branches have corresponding reflogs, you could look at the contents of .git\/logs like so:<\/p>\n<pre><code>$ find .git\/logs\/refs\/heads -type f | cut -d '\/' -f 3-\n<\/code><\/pre>\n<p>But what if you&rsquo;re using reftable? In that case, the reflogs are stored in a binary format, leaving tools like <code>find<\/code> out of your reach.<\/p>\n<p>Git 2.45 introduced a new sub-command <code>git reflog list<\/code> to show which references have corresponding reflogs available to them, regardless of whether or not you are using reftable.<\/p>\n<p>[<a href=\"https:\/\/github.com\/git\/git\/compare\/221c3daef41bdd7eebd5f45d711e847d0a85aa86...d699d15c328b03fd822d3950f7ed76debef02c26\">source<\/a>]<\/p>\n<\/li>\n<li>\n<p>If you&rsquo;ve ever looked closely at Git&rsquo;s diff output, you might have noticed the prefixes <code>a\/<\/code> and <code>b\/<\/code> used before file paths to indicate the before and after versions of each file, like so:<\/p>\n<pre><code>$ git diff HEAD^ -- GIT-VERSION-GEN\ndiff --git a\/GIT-VERSION-GEN b\/GIT-VERSION-GEN\nindex dabd2b5b89..c92f98b3db 100755\n--- a\/GIT-VERSION-GEN\n+++ b\/GIT-VERSION-GEN\n@@ -1,7 +1,7 @@\n#!\/bin\/sh\n\nGVF=GIT-VERSION-FILE\n-DEF_VER=v2.45.0-rc0\n+DEF_VER=v2.45.0-rc1\n\nLF='\n'\n<\/code><\/pre>\n<p>In Git 2.45, you can now configure alternative prefixes by setting the <code>diff.srcPrefix<\/code> and <code>diff.dstPrefix<\/code> configuration options. This can come in handy if you want to make clear which side is which (by setting them to something like &ldquo;before&rdquo; and &ldquo;after,&rdquo; respectively). Or if you&rsquo;re viewing the output in your terminal, and your terminal supports hyperlinking to paths, you could change the prefix to <code>.\/<\/code> to allow you to click on filepaths within a diff output.<\/p>\n<p>[<a href=\"https:\/\/github.com\/git\/git\/compare\/1002f28a527d33893f7dab068dbac7011f84af65...178401dc25cf8c3f1a716b852b14dafa79367646\">source<\/a>]<\/p>\n<\/li>\n<li>\n<p>When writing a commit message, Git will open your editor with a mostly blank file containing some instructions, like so:<\/p>\n<pre><code># Please enter the commit message for your changes. Lines starting\n# with '#' will be ignored, and an empty message aborts the commit.\n#\n# On branch main\n# Your branch is up to date with 'origin\/main.\n<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/git\/git\/compare\/bcd45b4085f9269a536c8fb1963ac8380bfac0e8...eff80a9fd990de3605063050dae32f969ef18ba8\">Since 2013<\/a>, Git has supported customizing the comment character to be something other than the default #. This can come in handy, for instance, if you&rsquo;re trying to refer to a GitHub issue by its numeric shorthand (e.g. <code>#12345<\/code>). If you write <code>#12345<\/code> at the beginning of a line in your commit message, Git will treat the entire line as a comment and ignore it.<\/p>\n<p>In Git 2.45, Git allows not just any single ASCII character, but any arbitrary multi-byte character or even an arbitrary string. Now, you can customize your commit message template by setting <code>core.commentString<\/code> (or <code>core.commentChar<\/code>, the two are synonyms for one another) to your heart&rsquo;s content.<\/p>\n<p>[<a href=\"https:\/\/github.com\/git\/git\/compare\/3256584c36f649abb2af58e7b190d3cf674ba56e...9ccf3e9b22b6843892319b189fd7aed37c451420\">source<\/a>]<\/p>\n<\/li>\n<li>\n<p>Speaking of comments, <code>git config<\/code> learned a new option to help document your <code>.gitconfig<\/code> file. The <code>.gitconfig<\/code> file format allows for comments beginning with a <code>#<\/code> character, meaning that everything following that <code>#<\/code> until the next newline will be ignored.<\/p>\n<p>The <code>git config<\/code> command gained a new <code>--comment<\/code> option, which allows specifying an optional comment to leave at the end of the newly configured line, like so:<\/p>\n<pre><code>$ git config --comment 'to show the merge base' merge.conflictStyle diff3\n$ tail -n 2 .git\/config\n[merge]\nconflictStyle = diff3 # to show the merge base\n<\/code><\/pre>\n<p>This can be helpful when tweaking some of Git&rsquo;s more esoteric settings to try and remember why you picked a particular value.<\/p>\n<p>[<a href=\"https:\/\/github.com\/git\/git\/compare\/7774cfed6261ce2900c84e55906da708c711d601...31399a6b6166cf76cc533bc9915878211607ed80\">source<\/a>]<\/p>\n<\/li>\n<li>\n<p>Sometimes when you are rebasing or cherry-picking a series of commits, one or more of those commits become &ldquo;empty&rdquo; (i.e., because they contain a subset of changes that have already landed on your branch).<\/p>\n<p>When rebasing, you can use the <code>--empty<\/code> option to specify how to handle these commits. <code>--empty<\/code> supports a few options: &ldquo;drop&rdquo; (to ignore those commits), &ldquo;keep&rdquo; (to keep empty commits), or &ldquo;stop&rdquo; which will halt the rebase and ask for your input on how to proceed.<\/p>\n<p>Despite its similarity to <code>git rebase<\/code>, <code>git cherry-pick<\/code> never had an equivalent option to <code>--empty<\/code>. That meant that if you were cherry-picking a long sequence of commits, some of which became empty, you&rsquo;d have to type either <code>git cherry-pick --skip<\/code> (to drop the empty commit), or <code>git commit --allow-empty<\/code> (to keep the empty commit).<\/p>\n<p>In Git 2.45, <code>git cherry-pick<\/code> learned the same <code>--empty<\/code> option from <code>git rebase<\/code>, meaning that you can specify the behavior once at the beginning of your <code>cherry-pick<\/code> operation, instead of having to specify the same thing each time you encounter an empty commit.<\/p>\n<p>[<a href=\"https:\/\/github.com\/git\/git\/compare\/d988e80bd3a24387c74810b187a47813f8460699...ec79d763de617905bd9275de0b5941a160d6159b\">source<\/a>]<\/p>\n<\/li>\n<\/ul>\n<h2 id=\"the-rest-of-the-iceberg\" id=\"the-rest-of-the-iceberg\" ><a class=\"heading-link\" href=\"#the-rest-of-the-iceberg\">The rest of the iceberg<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>That&rsquo;s just a sample of changes from the latest release. For more, check out the release notes for <a href=\"https:\/\/github.com\/git\/git\/blob\/v2.45.0\/Documentation\/RelNotes\/2.45.0.txt\">2.45<\/a>, or <a href=\"https:\/\/github.com\/git\/git\/tree\/v2.45.0\/Documentation\/RelNotes\">any previous version<\/a> in <a href=\"https:\/\/github.com\/git\/git\">the Git repository<\/a>.<\/p>\n<\/body><\/html>\n","protected":false},"excerpt":{"rendered":"<p>Git 2.45 is here with experimental support for reftables, and SHA-256 interoperability. Get our take on the latest here.<\/p>\n","protected":false},"author":1282,"featured_media":77739,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_gh_post_show_toc":"yes","_gh_post_is_no_robots":"no","_gh_post_is_featured":"no","_gh_post_is_excluded":"no","_gh_post_is_unlisted":"no","_gh_post_related_link_1":"","_gh_post_related_link_2":"","_gh_post_related_link_3":"","_gh_post_sq_img":"https:\/\/github.blog\/wp-content\/uploads\/2023\/03\/git-240-1.png","_gh_post_sq_img_id":"70712","_gh_post_cta_title":"","_gh_post_cta_text":"","_gh_post_cta_link":"","_gh_post_cta_button":"Click Here to Learn More","_gh_post_recirc_hide":"no","_gh_post_recirc_col_1":"gh-auto-select","_gh_post_recirc_col_2":"77524","_gh_post_recirc_col_3":"65303","_gh_post_recirc_col_4":"65316","_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":[2189],"class_list":["post-77738","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.4 (Yoast SEO v28.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Highlights from Git 2.45 - The GitHub Blog<\/title>\n<meta name=\"description\" content=\"Git 2.45 is here with experimental support for reftables, and SHA-256 interoperability. Get our take on the latest here.\" \/>\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\/highlights-from-git-2-45\/\" \/>\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.45\" \/>\n<meta property=\"og:description\" content=\"Git 2.45 is here with experimental support for reftables, and SHA-256 interoperability. Get our take on the latest here.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/\" \/>\n<meta property=\"og:site_name\" content=\"The GitHub Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-04-29T17:14:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-04-30T13:42:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/git-245.png?fit=4800%2C2520\" \/>\n\t<meta property=\"og:image:width\" content=\"4800\" \/>\n\t<meta property=\"og:image:height\" content=\"2520\" \/>\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: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=\"10 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\\\/highlights-from-git-2-45\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/highlights-from-git-2-45\\\/\"},\"author\":{\"name\":\"Taylor Blau\",\"@id\":\"https:\\\/\\\/github.blog\\\/#\\\/schema\\\/person\\\/f2a5dc09d09f41c8c731679cc07da524\"},\"headline\":\"Highlights from Git 2.45\",\"datePublished\":\"2024-04-29T17:14:27+00:00\",\"dateModified\":\"2024-04-30T13:42:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/highlights-from-git-2-45\\\/\"},\"wordCount\":2054,\"image\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/highlights-from-git-2-45\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/git-245.png?fit=4800%2C2520\",\"keywords\":[\"Git\"],\"articleSection\":[\"Git\",\"Open Source\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/highlights-from-git-2-45\\\/\",\"url\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/highlights-from-git-2-45\\\/\",\"name\":\"Highlights from Git 2.45 - The GitHub Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/github.blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/highlights-from-git-2-45\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/highlights-from-git-2-45\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/git-245.png?fit=4800%2C2520\",\"datePublished\":\"2024-04-29T17:14:27+00:00\",\"dateModified\":\"2024-04-30T13:42:43+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/github.blog\\\/#\\\/schema\\\/person\\\/f2a5dc09d09f41c8c731679cc07da524\"},\"description\":\"Git 2.45 is here with experimental support for reftables, and SHA-256 interoperability. Get our take on the latest here.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/highlights-from-git-2-45\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/highlights-from-git-2-45\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/highlights-from-git-2-45\\\/#primaryimage\",\"url\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/git-245.png?fit=4800%2C2520\",\"contentUrl\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/git-245.png?fit=4800%2C2520\",\"width\":4800,\"height\":2520},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/highlights-from-git-2-45\\\/#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.45\"}]},{\"@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.45 - The GitHub Blog","description":"Git 2.45 is here with experimental support for reftables, and SHA-256 interoperability. Get our take on the latest here.","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\/highlights-from-git-2-45\/","og_locale":"en_US","og_type":"article","og_title":"Highlights from Git 2.45","og_description":"Git 2.45 is here with experimental support for reftables, and SHA-256 interoperability. Get our take on the latest here.","og_url":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/","og_site_name":"The GitHub Blog","article_published_time":"2024-04-29T17:14:27+00:00","article_modified_time":"2024-04-30T13:42:43+00:00","og_image":[{"width":4800,"height":2520,"url":"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/git-245.png?fit=4800%2C2520","type":"image\/png"}],"author":"Taylor Blau","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Taylor Blau","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/#article","isPartOf":{"@id":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/"},"author":{"name":"Taylor Blau","@id":"https:\/\/github.blog\/#\/schema\/person\/f2a5dc09d09f41c8c731679cc07da524"},"headline":"Highlights from Git 2.45","datePublished":"2024-04-29T17:14:27+00:00","dateModified":"2024-04-30T13:42:43+00:00","mainEntityOfPage":{"@id":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/"},"wordCount":2054,"image":{"@id":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/#primaryimage"},"thumbnailUrl":"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/git-245.png?fit=4800%2C2520","keywords":["Git"],"articleSection":["Git","Open Source"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/","url":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/","name":"Highlights from Git 2.45 - The GitHub Blog","isPartOf":{"@id":"https:\/\/github.blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/#primaryimage"},"image":{"@id":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/#primaryimage"},"thumbnailUrl":"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/git-245.png?fit=4800%2C2520","datePublished":"2024-04-29T17:14:27+00:00","dateModified":"2024-04-30T13:42:43+00:00","author":{"@id":"https:\/\/github.blog\/#\/schema\/person\/f2a5dc09d09f41c8c731679cc07da524"},"description":"Git 2.45 is here with experimental support for reftables, and SHA-256 interoperability. Get our take on the latest here.","breadcrumb":{"@id":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/#primaryimage","url":"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/git-245.png?fit=4800%2C2520","contentUrl":"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/git-245.png?fit=4800%2C2520","width":4800,"height":2520},{"@type":"BreadcrumbList","@id":"https:\/\/github.blog\/open-source\/git\/highlights-from-git-2-45\/#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.45"}]},{"@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-kdQ","jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/git-245.png?fit=4800%2C2520","_links":{"self":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts\/77738","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=77738"}],"version-history":[{"count":7,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts\/77738\/revisions"}],"predecessor-version":[{"id":77770,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts\/77738\/revisions\/77770"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/media\/77739"}],"wp:attachment":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/media?parent=77738"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/categories?post=77738"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/tags?post=77738"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/coauthors?post=77738"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}