Git 2.37, the most recent version of the open source project, was just launched with features and bug fixes from over 75 contributors, 20 of them were new. Here, we will discuss the most intriguing features and modifications added since the last release.
We want to let you know that before we go into the specifics of Git 2.37.0 that the Git Merge will be back in September.
A new method for pruning inaccessible objects
Git frequently discusses categorising objects as "reachable" or "unreachable." When you can start an object walk (travelling from commits to their parents, from trees into their sub-trees, and so on) from at least one reference (a branch or a tag) and wind up at your goal, that object is said to be "reachable." Similar to this, when there isn't a reference to an object, it is "unreachable."
To guarantee that a Git repository is complete, all of its accessible items must be present. However, it is always free to get rid of out of the way items. And doing just that is frequently beneficial, especially when a large number of unreachable objects have accumulated, you're running out of storage space, or anything similar. In reality, while executing garbage collection, Git accomplishes this automatically.
But keen readers will notice the setting for gc.pruneExpire. The "grace period" defined by this setting refers to the length of time during which inaccessible items that are not yet old enough to be totally deleted from the repository are left alone. This is done to prevent a race issue when a deleted item that was previously unreachable becomes accessible to another process (such as an inbound reference update or a push) before being removed, corrupting the repository.
It is far less likely to come across this race in practise if you set a small, non-zero grace period. However, it brings up a different issue: how can we keep track of the age of the immovable objects that remained in the repository? They cannot be combined into a single packfile because changing one object in a pack moves all the other objects forward because they all share the same modification time. Prior to Git 2.37, each surviving unreachable object was written down as a loose object and its mtime was used to store its age. When there are numerous unreachable items that are too fresh and cannot be trimmed, this can cause major issues.
Cruft packs, introduced in Git 2.37, enable the storage of inaccessible objects in a single packfile by recording the ages of each object in an auxiliary table that is kept in a *.mtimes file alongside the pack.
Cruft packs can help reduce the likelihood of the data race we previously discussed, even though they do not completely prevent it. This is because they provide repositories more time to prune without having to worry about the possibility of producing a lot of loose items. You can try it out for yourself by running:
git gc --cruft --prune=1.day.ago
and take note of the additional .mtimes
file in your $GIT_DIR/objects/pack
directory, which stores the ages of any inaccessible objects written within the previous 24 hours.
ls -1 .git/objects/pack
pack-243103d0f640e0096edb3ef0c842bc5534a9f9a4.idx
pack-243103d0f640e0096edb3ef0c842bc5534a9f9a4.mtimes
pack-243103d0f640e0096edb3ef0c842bc5534a9f9a4.pack
pack-5a827af6f1a793a45c816b05d40dfd4d5f5edf28.idx
pack-5a827af6f1a793a45c816b05d40dfd4d5f5edf28.pack
Builtin filesystem monitor for Windows and macOS
The size of your working directory is one of the elements that significantly affects Git's performance. For instance, to determine which files have been updated when you run git status
, Git (in the worst scenario) has to crawl your whole working directory.
Git uses its own stored knowledge of the filesystem to frequently avoid having to traverse entire directories. However, updating Git's cached knowledge of the filesystem with the disk's real condition while you work can be expensive.
Previously, Git allowed for integration with programmes like Watchman via a hook, which allowed for the direct replacement of Git's pricey refreshing process with a long-running daemon that watches the filesystem state more closely.
It can be difficult to set up this hook and install a third-party utility, though. Git 2.37 eliminates the need to install an additional tool and set up the hook by integrating this feature directly into Git on Windows and macOS.
Enabling the core.fsmonitor
config parameter will enable this for your repository.
git config core.fsmonitor true
An initial git status will take the usual length of time after configuring the configuration, but subsequent commands will benefit from the monitored data and execute noticeably faster.
It is impossible to fully discuss the implementation in this post. For further information, interested readers can read Jeff Hostetler's blog article later this week. When that article is published, we'll make sure to provide a link here.
The sparse index is prepared for widespread use
You frequently don't need to have the whole contents of your repository on your local computer in order to contribute while working in a really large repository. If your organisation just utilises one monorepo, for instance, you might only be interested in the portions of that repository that relate to the few items you work on.
Git can download only the objects you care about thanks to partial clones. The sparse index is a crucial part of the equation as well. The sparse index enables the index, a crucial data structure that keeps track of the contents of your upcoming commit, which files have been modified, and other information, to just maintain track of the portions of your repository that you are interested in.
The last integrations were for git display, git sparse-checkout, and git stash in this release. Because the command reads and writes indexes numerous times in a single process, git stash has the highest performance improvement of all the integrations so far, sometimes speeding up to around 80%.
Tidbits
Let's move on to some of the release's smaller topics now that we have examined some of the more significant features in depth.
- The non-
--cone
-mode approach of sparse checkout declarations is deprecated in this release.
For those who are unfamiliar, thegit sparse-checkout
tool provides two types of patterns called "cone" mode and "non-cone" mode that specify which components of your repository should be checked out. The latter, which enables specifying specific files using a syntax akin to.gitignore
, can be challenging to utilise appropriately and has performance issues (namely that in the worst case all patterns must try to be matched with all files, leading to slow-downs). The most significant issue is that it is incompatible with the sparse-index, which adds the efficiency benefits of utilising a sparse checkout to all of the Git commands you are already familiar with.
The non---cone
mode style of patterns is discouraged for these and other reasons, and users are urged to utilise--cone
mode instead.
- This update adds a fresh strategy to the list of core-supported ones. When writing numerous separate files, using the
fsyncMethod
: "batch" on supported filesystems can significantly speed up the process. This new mode operates by staging numerous changes to the writeback cache on the disc before performing a singlefsync()
, which causes the disc to flush its writeback cache. Following that, files are atomically relocated into position, ensuring that they arefsync()
-durable when they reach the object directory.
For instance, adding 500 files on Linux takes .06 seconds without any calls tofsync()
, 1.88 seconds with afsync()
every each write to a loose object, and only.15 seconds with the new batchedfsync()
. Similar speedups can be seen on other systems, with Windows serving as a notable example with statistics like .35 seconds, 11.18 seconds, and just.41 seconds, respectively.
- All commonly used revision-walking commands, including
log
andrev-list
, include the--since
option, which allows you to find out what has changed in your repository since yesterday.
Starting with the supplied commits, this option iteratively traverses each commit's parents, halting when it reaches a commit that is older than the--since
date. However, occasionally (especially when there is) clock skew, this can result in unclear results.
Consider the following scenario: You have three commits,C1
,C2
, andC3
, withC2
being the parent ofC3
andC1
being the parent ofC2
. A traversal with--since=1.hour.ago
will only displayC3
ifC1
andC3
were both written within the previous hour, but C2 is a day old (perhaps because the committer's clock is running slowly). This is because seeingC2
triggers Git to stop its traversal.
Use--since-as-filter
instead of--since
if you anticipate that your repository's history has some clock skew. This filter only prints commits that are newer than the provided date and does not stop when it encounters an older commit.
It can be challenging to remember which partial clone filter is associated to which remote if you work with partial clones and have a range of different Git remotes.
- When it comes to remote configuration, Git 2.37 comes pre-configured with the ability to alert or quit if it finds plain-text credentials kept in your configuration with the new transfer.credentialsInUrl setting.
It is not recommended to store credentials in plain text in your repository's settings, as doing so necessitates you to make sure the configuration file has adequately restricted rights. Git frequently transmits the entire URL (including credentials) to other programmes in addition to storing the data unencrypted at rest. This exposes the data on systems where other processes have access to the arguments list of sensitive processes. Generally speaking, using GCM or Git's credential system is advised.
By setting the transfer.credentialsInUrl to "warn" or "die," respectively, this new setting enables Git to either disregard or halt execution when it encounters one of these credentials. "Allow" is the default and has no effect.
- You may be familiar with git add's "interactive mode," or
git add -i
, of whichgit add -p
is a sub-mode, if you've ever usedgit add -p
to incrementally stage the contents of your working tree.git add -i
offers "status," "update," "revert," "add untracked," "patch," and "diff" modes in addition to "patch" mode. This method ofgit add -i
was really created in Perl till recently. Git commands built in Perl have long been ported to C, with this command serving as the most current example. By eliminating the need to start sub-processes, which might be prohibitively expensive on some platforms, it is now viable to use Git's libraries.
As early as Git v2.25.0, the C reimplementation ofgit add -i
was available in releases. This reimplementation has been in "testing" mode behind an opt-in configuration in more recent versions. Git 2.37 encourages the C reimplementation by default, therefore Windows users usinggit add -p
should experience an increase in speed.