From 87264b7dde2be9e555243f0dce649b785407827e Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Thu, 9 Oct 2025 21:56:18 +0000 Subject: [PATCH 01/19] docs: update pack index v3 format Our current pack index v3 format uses 4-byte integers to find the trailer of the file. This effectively means that the file cannot be much larger than 2^32. While this might at first seem to be okay, we expect that each object will have at least 64 bytes worth of data, which means that no more than about 67 million objects can be stored. Again, this might seem fine, but unfortunately, we know of many users who attempt to create repos with extremely large numbers of commits to get a "high score," and we've already seen repositories with at least 55 million commits. In the interests of gracefully handling repositories even for these well-intentioned but ultimately misguided users, let's change these lengths to 8 bytes. For the checksums at the end of the file, we're producing 32-byte SHA-256 checksums because that's what we already do with pack index v2 and SHA-256. Truncating SHA-256 doesn't pose any actual security problems other than those related to the reduced size, but our pack checksum must already be 32 bytes (since SHA-256 packs have 32-byte checksums) and it simplifies the code to use the existing hashfile logic for these cases for the index checksum as well. In addition, even though we may not need cryptographic security for the index checksum, we'd like to avoid arguments from auditors and such for organizations that may have compliance or security requirements. Using the simple, boring choice of the full SHA-256 hash avoids all possible discussion related to hash truncation and removes impediments for these organizations. Note that we do not yet have a pack index v3 implementation in Git, so it should be fine to change this format. However, such an implementation has been written for future inclusion following this format. Signed-off-by: brian m. carlson Signed-off-by: Junio C Hamano --- .../technical/hash-function-transition.adoc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Documentation/technical/hash-function-transition.adoc b/Documentation/technical/hash-function-transition.adoc index f047fd80cadd1e..274dc993d41513 100644 --- a/Documentation/technical/hash-function-transition.adoc +++ b/Documentation/technical/hash-function-transition.adoc @@ -227,9 +227,9 @@ network byte order): ** 4-byte length in bytes of shortened object names. This is the shortest possible length needed to make names in the shortened object name table unambiguous. - ** 4-byte integer, recording where tables relating to this format + ** 8-byte integer, recording where tables relating to this format are stored in this index file, as an offset from the beginning. - * 4-byte offset to the trailer from the beginning of this file. + * 8-byte offset to the trailer from the beginning of this file. * Zero or more additional key/value pairs (4-byte key, 4-byte value). Only one key is supported: 'PSRC'. See the "Loose objects and unreachable objects" section for supported values and how this @@ -276,10 +276,14 @@ network byte order): up to and not including the table of CRC32 values. - Zero or more NUL bytes. - The trailer consists of the following: - * A copy of the 20-byte SHA-256 checksum at the end of the + * A copy of the full main hash checksum at the end of the corresponding packfile. - * 20-byte SHA-256 checksum of all of the above. + * Full main hash checksum of all of the above. + +The "full main hash" is a full-length hash of the main (not compatibility) +algorithm in the repository. Thus, if the main algorithm is SHA-256, this is +a 32-byte SHA-256 hash and for SHA-1, it's a 20-byte SHA-1 hash. Loose object index ~~~~~~~~~~~~~~~~~~ From 6947ed321d271533237768354b64c145a8df1551 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Thu, 9 Oct 2025 21:56:19 +0000 Subject: [PATCH 02/19] docs: update offset order for pack index v3 The current design of pack index v3 has items in two different orders: sorted shortened object ID order and pack order. The shortened object IDs and the pack index offset values are in the former order and everything else is in the latter. This, however, poses some problems. We have many parts of the packfile code that expect to find out data about an object knowing only its index in pack order. With the current design, to find the pack offset after having looked up the index in pack order, we must then look up the full object ID and use that to look up the shortened object ID to find the pack offset, which is inconvenient, inefficient, and leads to poor cache usage. Instead, let's change the offset values to be looked up by pack order. This works better because once we know the pack order offset, we can find the full object name and its location in the pack with a simple index into their respective tables. This makes many operations much more efficient, especially with the functions we already have, and it avoids the need for the revindex with pack index v3. Signed-off-by: brian m. carlson Signed-off-by: Junio C Hamano --- Documentation/technical/hash-function-transition.adoc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Documentation/technical/hash-function-transition.adoc b/Documentation/technical/hash-function-transition.adoc index 274dc993d41513..adb0c61e5382d1 100644 --- a/Documentation/technical/hash-function-transition.adoc +++ b/Documentation/technical/hash-function-transition.adoc @@ -260,12 +260,10 @@ network byte order): compressed data to be copied directly from pack to pack during repacking without undetected data corruption. - * A table of 4-byte offset values. For an object in the table of - sorted shortened object names, the value at the corresponding - index in this table indicates where that object can be found in - the pack file. These are usually 31-bit pack file offsets, but - large offsets are encoded as an index into the next table with the - most significant bit set. + * A table of 4-byte offset values. The index of this table in pack order + indicates where that object can be found in the pack file. These are + usually 31-bit pack file offsets, but large offsets are encoded as + an index into the next table with the most significant bit set. * A table of 8-byte offset entries (empty for pack files less than 2 GiB). Pack files are organized with heavily used objects toward From d477892b30b25333badb829190eb349fb671458c Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Thu, 9 Oct 2025 21:56:20 +0000 Subject: [PATCH 03/19] docs: reflect actual double signature for tags The documentation for the hash function transition reflects the original design where the SHA-256 signature would always be placed in a header. However, due to a missed patch in Git 2.29, we shipped SHA-256 support such that the signature for the current algorithm is always an in-body signature and the opposite algorithm is always in a header. Since the documentation is inaccurate, update it to reflect the correct information. Signed-off-by: brian m. carlson Signed-off-by: Junio C Hamano --- .../technical/hash-function-transition.adoc | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Documentation/technical/hash-function-transition.adoc b/Documentation/technical/hash-function-transition.adoc index adb0c61e5382d1..2359d7d106f842 100644 --- a/Documentation/technical/hash-function-transition.adoc +++ b/Documentation/technical/hash-function-transition.adoc @@ -429,17 +429,19 @@ ordinary unsigned commit. Signed Tags ~~~~~~~~~~~ -We add a new field "gpgsig-sha256" to the tag object format to allow -signing tags without relying on SHA-1. Its signed payload is the -SHA-256 content of the tag with its gpgsig-sha256 field and "-----BEGIN PGP -SIGNATURE-----" delimited in-body signature removed. - -This means tags can be signed - -1. using SHA-1 only, as in existing signed tag objects -2. using both SHA-1 and SHA-256, by using gpgsig-sha256 and an in-body - signature. -3. using only SHA-256, by only using the gpgsig-sha256 field. +We add new fields "gpgsig" and "gpgsig-sha256" to the tag object format to +allow signing tags in both formats. The in-body signature is used for the +signature in the current hash algorithm and the header is used for the +signature in the other algorithm. Thus, a dual-signature tag will contain both +an in-body signature and a gpgsig-sha256 header for the SHA-1 format of an +object or both an in-body signature and a gpgsig header for the SHA-256 format +of and object. + +The signed payload of the tag is the content of the tag in the current +algorithm with both its gpgsig and gpgsig-sha256 fields and +"-----BEGIN PGP SIGNATURE-----" delimited in-body signature removed. + +This means tags can be signed using one or both algorithms. Mergetag embedding ~~~~~~~~~~~~~~~~~~ From 24d46f86337b79083ffcb0c9f8806a4f82f6b9c8 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Thu, 9 Oct 2025 21:56:21 +0000 Subject: [PATCH 04/19] docs: improve ambiguous areas of pack format documentation It is fair to say that our pack and indexing code is quite complex. Contributors who wish to work on this code or implementors of other implementations would benefit from clear, unambiguous documentation about how our data formats are structured and encoded and what data is used in the computation of certain values. Unfortunately, some of this data is missing, which leads to confusion and frustration. Let's document some of this data to help clarify things. Specify over what data CRC32 values are computed and also note which CRC32 algorithm is used, since Wikipedia mentions at least four 32-bit CRC algorithms and notes that it's possible to use different bit orderings. In addition, note how we encode objects in the pack. One might be led to believe that packed objects are always stored with the " \0" prefix of loose objects, but that is not the case, although for obvious reasons this data is included in the computation of the object ID. Explain why this is for the curious reader. Finally, indicate what the size field of the packed object represents. Otherwise, a reader might think that the size of a delta is the size of the full object or that it might contain the offset or object ID, neither of which are the case. Explain clearly, however, that the values represent uncompressed sizes to avoid confusion. Signed-off-by: brian m. carlson Signed-off-by: Junio C Hamano --- Documentation/gitformat-pack.adoc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Documentation/gitformat-pack.adoc b/Documentation/gitformat-pack.adoc index d6ae229be56859..1b4db4aa611e83 100644 --- a/Documentation/gitformat-pack.adoc +++ b/Documentation/gitformat-pack.adoc @@ -32,6 +32,10 @@ In a repository using the traditional SHA-1, pack checksums, index checksums, and object IDs (object names) mentioned below are all computed using SHA-1. Similarly, in SHA-256 repositories, these values are computed using SHA-256. +CRC32 checksums are always computed over the entire packed object, including +the header (n-byte type and length); the base object name or offset, if any; +and the entire compressed object. The CRC32 algorithm used is that of zlib. + == pack-*.pack files have the following format: - A header appears at the beginning and consists of the following: @@ -80,6 +84,16 @@ Valid object types are: Type 5 is reserved for future expansion. Type 0 is invalid. +=== Object encoding + +Unlike loose objects, packed objects do not have a prefix containing the type, +size, and a NUL byte. These are not necessary because they can be determined by +the n-byte type and length that prefixes the data and so they are omitted from +the compressed and deltified data. + +The computation of the object ID still uses this prefix by reconstructing it +from the type and length as needed. + === Size encoding This document uses the following "size encoding" of non-negative @@ -92,6 +106,11 @@ values are more significant. This size encoding should not be confused with the "offset encoding", which is also used in this document. +When encoding the size of an undeltified object in a pack, the size is that of +the uncompressed raw object. For deltified objects, it is the size of the +uncompressed delta. The base object name or offset is not included in the size +computation. + === Deltified representation Conceptually there are only four object types: commit, tree, tag and From d4f439548d46dd93087af8d9ff2e9f7e4d5e98bb Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Thu, 9 Oct 2025 21:56:22 +0000 Subject: [PATCH 05/19] docs: add documentation for loose objects We currently have no documentation for how loose objects are stored. Let's add some here so it's easy for people to understand how they work. Signed-off-by: brian m. carlson Signed-off-by: Junio C Hamano --- Documentation/Makefile | 1 + Documentation/gitformat-loose.adoc | 53 ++++++++++++++++++++++++++++++ Documentation/meson.build | 1 + 3 files changed, 55 insertions(+) create mode 100644 Documentation/gitformat-loose.adoc diff --git a/Documentation/Makefile b/Documentation/Makefile index df2ce187eb84cf..db8fb80608afb1 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -34,6 +34,7 @@ MAN5_TXT += gitformat-bundle.adoc MAN5_TXT += gitformat-chunk.adoc MAN5_TXT += gitformat-commit-graph.adoc MAN5_TXT += gitformat-index.adoc +MAN5_TXT += gitformat-loose.adoc MAN5_TXT += gitformat-pack.adoc MAN5_TXT += gitformat-signature.adoc MAN5_TXT += githooks.adoc diff --git a/Documentation/gitformat-loose.adoc b/Documentation/gitformat-loose.adoc new file mode 100644 index 00000000000000..947993663e167f --- /dev/null +++ b/Documentation/gitformat-loose.adoc @@ -0,0 +1,53 @@ +gitformat-loose(5) +================== + +NAME +---- +gitformat-loose - Git loose object format + + +SYNOPSIS +-------- +[verse] +$GIT_DIR/objects/[0-9a-f][0-9a-f]/* + +DESCRIPTION +----------- + +Loose objects are how Git stores individual objects, where every object is +written as a separate file. + +Over the lifetime of a repository, objects are usually written as loose objects +initially. Eventually, these loose objects will be compacted into packfiles +via repository maintenance to improve disk space usage and speed up the lookup +of these objects. + +== Loose objects + +Each loose object contains a prefix, followed immediately by the data of the +object. The prefix contains ` \0`. `` is one of `blob`, +`tree`, `commit`, or `tag` and `size` is the size of the data (without the +prefix) as a decimal integer expressed in ASCII. + +The entire contents, prefix and data concatenated, is then compressed with zlib +and the compressed data is stored in the file. The object ID of the object is +the SHA-1 or SHA-256 (as appropriate) hash of the uncompressed data. + +The file for the loose object is stored under the `objects` directory, with the +first two hex characters of the object ID being the directory and the remaining +characters being the file name. This is done to shard the data and avoid too +many files being in one directory, since some file systems perform poorly with +many items in a directory. + +As an example, the empty tree contains the data (when uncompressed) `tree 0\0` +and, in a SHA-256 repository, would have the object ID +`6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321` and would be +stored under +`$GIT_DIR/objects/6e/f19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321`. + +Similarly, a blob containing the contents `abc` would have the uncompressed +data of `blob 3\0abc`. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/meson.build b/Documentation/meson.build index 4404c623f006db..93fa3dee8b6d12 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -171,6 +171,7 @@ manpages = { 'gitformat-chunk.adoc' : 5, 'gitformat-commit-graph.adoc' : 5, 'gitformat-index.adoc' : 5, + 'gitformat-loose.adoc' : 5, 'gitformat-pack.adoc' : 5, 'gitformat-signature.adoc' : 5, 'githooks.adoc' : 5, From b95c59e21e6afeddc56400e162e818a9312f04d2 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Thu, 9 Oct 2025 21:56:23 +0000 Subject: [PATCH 06/19] rev-parse: allow printing compatibility hash Right now, we have a way to print the storage hash, the input hash, and the output hash, but we lack a way to print the compatibility hash. Add a new type to --show-object-format, compat, which prints this value. If no compatibility hash exists, simply print a newline. This is important to allow users to use multiple options at once while still getting unambiguous output. Signed-off-by: brian m. carlson Signed-off-by: Junio C Hamano --- Documentation/git-rev-parse.adoc | 11 ++++++----- builtin/rev-parse.c | 11 ++++++++++- t/t1500-rev-parse.sh | 34 ++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/Documentation/git-rev-parse.adoc b/Documentation/git-rev-parse.adoc index cc32b4b4f0f999..465ae3e29d0714 100644 --- a/Documentation/git-rev-parse.adoc +++ b/Documentation/git-rev-parse.adoc @@ -324,11 +324,12 @@ The following options are unaffected by `--path-format`: path of the current directory relative to the top-level directory. ---show-object-format[=(storage|input|output)]:: - Show the object format (hash algorithm) used for the repository - for storage inside the `.git` directory, input, or output. For - input, multiple algorithms may be printed, space-separated. - If not specified, the default is "storage". +--show-object-format[=(storage|input|output|compat)]:: + Show the object format (hash algorithm) used for the repository for storage + inside the `.git` directory, input, output, or compatibility. For input, + multiple algorithms may be printed, space-separated. If `compat` is + requested and no compatibility algorithm is enabled, prints an empty line. If + not specified, the default is "storage". --show-ref-format:: Show the reference storage format used for the repository. diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 44ff1b8342acae..187b7e8be93f3b 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -1108,11 +1108,20 @@ int cmd_rev_parse(int argc, const char *val = arg ? arg : "storage"; if (strcmp(val, "storage") && + strcmp(val, "compat") && strcmp(val, "input") && strcmp(val, "output")) die(_("unknown mode for --show-object-format: %s"), arg); - puts(the_hash_algo->name); + + if (!strcmp(val, "compat")) { + if (the_repository->compat_hash_algo) + puts(the_repository->compat_hash_algo->name); + else + putchar('\n'); + } else { + puts(the_hash_algo->name); + } continue; } if (!strcmp(arg, "--show-ref-format")) { diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh index 58a4583088b859..7739ab611bc1c0 100755 --- a/t/t1500-rev-parse.sh +++ b/t/t1500-rev-parse.sh @@ -207,6 +207,40 @@ test_expect_success 'rev-parse --show-object-format in repo' ' grep "unknown mode for --show-object-format: squeamish-ossifrage" err ' + +test_expect_success 'rev-parse --show-object-format in repo with compat mode' ' + mkdir repo && + ( + sane_unset GIT_DEFAULT_HASH && + cd repo && + git init --object-format=sha256 && + git config extensions.compatobjectformat sha1 && + echo sha256 >expect && + git rev-parse --show-object-format >actual && + test_cmp expect actual && + git rev-parse --show-object-format=storage >actual && + test_cmp expect actual && + git rev-parse --show-object-format=input >actual && + test_cmp expect actual && + git rev-parse --show-object-format=output >actual && + test_cmp expect actual && + echo sha1 >expect && + git rev-parse --show-object-format=compat >actual && + test_cmp expect actual && + test_must_fail git rev-parse --show-object-format=squeamish-ossifrage 2>err && + grep "unknown mode for --show-object-format: squeamish-ossifrage" err + ) && + mkdir repo2 && + ( + sane_unset GIT_DEFAULT_HASH && + cd repo2 && + git init --object-format=sha256 && + echo >expect && + git rev-parse --show-object-format=compat >actual && + test_cmp expect actual + ) +' + test_expect_success 'rev-parse --show-ref-format' ' test_detect_ref_format >expect && git rev-parse --show-ref-format >actual && From 51acda73d3ca96b763f0fca3d7b33b4beaef786d Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Thu, 9 Oct 2025 21:56:24 +0000 Subject: [PATCH 07/19] fsck: consider gpgsig headers expected in tags When we're creating a tag, we want to make sure that gpgsig and gpgsig-sha256 headers are allowed for the commit. The default fsck behavior is to ignore the fact that they're left over, but some of our tests enable strict checking which flags them nonetheless. Add improved checking for these headers as well as documentation and several tests. Signed-off-by: brian m. carlson Signed-off-by: Junio C Hamano --- Documentation/fsck-msgids.adoc | 6 ++++ fsck.c | 18 ++++++++++++ fsck.h | 2 ++ t/t1450-fsck.sh | 54 ++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/Documentation/fsck-msgids.adoc b/Documentation/fsck-msgids.adoc index 0ba4f9a27e4c73..52d9a8a811b118 100644 --- a/Documentation/fsck-msgids.adoc +++ b/Documentation/fsck-msgids.adoc @@ -10,6 +10,12 @@ `badFilemode`:: (INFO) A tree contains a bad filemode entry. +`badGpgsig`:: + (ERROR) A tag contains a bad (truncated) signature (e.g., `gpgsig`) header. + +`badHeaderContinuation`:: + (ERROR) A continuation header (such as for `gpgsig`) is unexpectedly truncated. + `badName`:: (ERROR) An author/committer name is empty. diff --git a/fsck.c b/fsck.c index 171b424dd57de1..341e100d24ece0 100644 --- a/fsck.c +++ b/fsck.c @@ -1067,6 +1067,24 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer, else ret = fsck_ident(&buffer, oid, OBJ_TAG, options); + if (buffer < buffer_end && (skip_prefix(buffer, "gpgsig ", &buffer) || skip_prefix(buffer, "gpgsig-sha256 ", &buffer))) { + eol = memchr(buffer, '\n', buffer_end - buffer); + if (!eol) { + ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_GPGSIG, "invalid format - unexpected end after 'gpgsig' or 'gpgsig-sha256' line"); + goto done; + } + buffer = eol + 1; + + while (buffer < buffer_end && starts_with(buffer, " ")) { + eol = memchr(buffer, '\n', buffer_end - buffer); + if (!eol) { + ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_HEADER_CONTINUATION, "invalid format - unexpected end in 'gpgsig' or 'gpgsig-sha256' continuation line"); + goto done; + } + buffer = eol + 1; + } + } + if (buffer < buffer_end && !starts_with(buffer, "\n")) { /* * The verify_headers() check will allow diff --git a/fsck.h b/fsck.h index dd7df3d5b3651b..c26616d7eb3ebc 100644 --- a/fsck.h +++ b/fsck.h @@ -25,9 +25,11 @@ enum fsck_msg_type { FUNC(NUL_IN_HEADER, FATAL) \ FUNC(UNTERMINATED_HEADER, FATAL) \ /* errors */ \ + FUNC(BAD_HEADER_CONTINUATION, ERROR) \ FUNC(BAD_DATE, ERROR) \ FUNC(BAD_DATE_OVERFLOW, ERROR) \ FUNC(BAD_EMAIL, ERROR) \ + FUNC(BAD_GPGSIG, ERROR) \ FUNC(BAD_NAME, ERROR) \ FUNC(BAD_OBJECT_SHA1, ERROR) \ FUNC(BAD_PACKED_REF_ENTRY, ERROR) \ diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 5ae86c42be55ac..c4b651c2dc7938 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -454,6 +454,60 @@ test_expect_success 'tag with NUL in header' ' test_grep "error in tag $tag.*unterminated header: NUL at offset" out ' +test_expect_success 'tag accepts gpgsig header even if not validly signed' ' + test_oid_cache <<-\EOF && + header sha1:gpgsig-sha256 + header sha256:gpgsig + EOF + header=$(test_oid header) && + sha=$(git rev-parse HEAD) && + cat >good-tag <<-EOF && + object $sha + type commit + tag good + tagger T A Gger 1234567890 -0000 + $header -----BEGIN PGP SIGNATURE----- + Not a valid signature + -----END PGP SIGNATURE----- + + This is a good tag. + EOF + + tag=$(git hash-object --literally -t tag -w --stdin bad-tag <<-EOF && + object $sha + type commit + tag good + tagger T A Gger 1234567890 -0000 + $header -----BEGIN PGP SIGNATURE----- + Not a valid signature + -----END PGP SIGNATURE----- + junk + + This is a bad tag with junk at the end of the headers. + EOF + + tag=$(git hash-object --literally -t tag -w --stdin out && + test_grep "error in tag $tag.*invalid format - extra header" out +' + test_expect_success 'cleaned up' ' git fsck >actual 2>&1 && test_must_be_empty actual From 5f23aa6f0f73bb2be7b64e56419e21b2c93cb9a7 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Thu, 9 Oct 2025 21:56:25 +0000 Subject: [PATCH 08/19] t: allow specifying compatibility hash We want to specify a compatibility hash for testing interactions for SHA-256 repositories where we have SHA-1 compatibility enabled. Allow the user to specify this scenario in the test suite by setting GIT_TEST_DEFAULT_HASH to "sha256:sha1". Note that this will get passed into GIT_DEFAULT_HASH, which Git itself does not presently support. However, we will support this in a future commit. Since we'll now want to know the value for a specific version, let's add the ability to specify either the storage hash (in this case, SHA-256) or the compatibility hash (SHA-1). We use a different value for the compatibility hash that will be enabled for all repositories (test_repo_compat_hash_algo) versus the one that is used individually in some tests (test_compat_hash_algo), since we want to still run those individual tests without requiring that the testsuite be run fully in a compatibility mode. In some cases, we'll need to adjust our test suite to work in a proper way with a compatibility hash. For example, in such a case, we'll only use pack index v3, since v1 and v2 lack support for multiple algorithms. Since we won't want to write those older formats, we'll need to skip tests that do so. Let's add a COMPAT_HASH prerequisite for this purpose. Finally, in this scenario, we can no longer rely on having broken objects work since we lack compatibility mappings to rewrite objects in the repository. Add a prerequisite, BROKEN_OBJECTS, that we define in terms of COMPAT_HASH and checks to see if creating deliberately broken objects is possible, so that we can disable these tests if not. Signed-off-by: brian m. carlson Signed-off-by: Junio C Hamano --- t/test-lib-functions.sh | 9 +++++++-- t/test-lib.sh | 13 +++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index a28de7b19bc001..52d7759bf5762d 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -1708,11 +1708,16 @@ test_set_hash () { # Detect the hash algorithm in use. test_detect_hash () { case "${GIT_TEST_DEFAULT_HASH:-$GIT_TEST_BUILTIN_HASH}" in - "sha256") + *:*) + test_hash_algo="${GIT_TEST_DEFAULT_HASH%%:*}" + test_compat_hash_algo="${GIT_TEST_DEFAULT_HASH##*:}" + test_repo_compat_hash_algo="$test_compat_hash_algo" + ;; + sha256) test_hash_algo=sha256 test_compat_hash_algo=sha1 ;; - *) + sha1) test_hash_algo=sha1 test_compat_hash_algo=sha256 ;; diff --git a/t/test-lib.sh b/t/test-lib.sh index 621cd31ae1dc51..9eb79324eee6f1 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1917,6 +1917,19 @@ test_lazy_prereq DEFAULT_HASH_ALGORITHM ' test_lazy_prereq DEFAULT_REPO_FORMAT ' test_have_prereq SHA1,REFFILES ' +# BROKEN_OBJECTS is a test whether we can write deliberately broken objects and +# expect them to work. When running using SHA-256 mode with SHA-1 +# compatibility, we cannot write such objects because there's no SHA-1 +# compatibility value for a nonexistent object. +test_lazy_prereq BROKEN_OBJECTS ' + ! test_have_prereq COMPAT_HASH +' + +# COMPAT_HASH is a test if we're operating in a repository with SHA-256 with +# SHA-1 compatibility. +test_lazy_prereq COMPAT_HASH ' + test -n "$test_repo_compat_hash_algo" +' # Ensure that no test accidentally triggers a Git command # that runs the actual maintenance scheduler, affecting a user's From db00605c13a9f5709da712671df5c7594c06cf31 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Thu, 9 Oct 2025 21:56:26 +0000 Subject: [PATCH 09/19] t1010: use BROKEN_OBJECTS prerequisite When hash compatibility mode is enabled, we cannot write broken objects because they cannot be mapped into the other hash algorithm. Use the BROKEN_OBJECTS prerequisite to disable these tests and the writing of broken objects in this mode. Signed-off-by: brian m. carlson Signed-off-by: Junio C Hamano --- t/t1010-mktree.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh index e9973f74949661..312fe6717a622f 100755 --- a/t/t1010-mktree.sh +++ b/t/t1010-mktree.sh @@ -11,10 +11,13 @@ test_expect_success setup ' git add "$d" || return 1 done && echo zero >one && - git update-index --add --info-only one && - git write-tree --missing-ok >tree.missing && - git ls-tree $(cat tree.missing) >top.missing && - git ls-tree -r $(cat tree.missing) >all.missing && + if test_have_prereq BROKEN_OBJECTS + then + git update-index --add --info-only one && + git write-tree --missing-ok >tree.missing && + git ls-tree $(cat tree.missing) >top.missing && + git ls-tree -r $(cat tree.missing) >all.missing + fi && echo one >one && git add one && git write-tree >tree && @@ -53,7 +56,7 @@ test_expect_success 'ls-tree output in wrong order given to mktree (2)' ' test_cmp tree.withsub actual ' -test_expect_success 'allow missing object with --missing' ' +test_expect_success BROKEN_OBJECTS 'allow missing object with --missing' ' git mktree --missing actual && test_cmp tree.missing actual ' From 85abbfc59b070816871ff64bba3eba94e749ce08 Mon Sep 17 00:00:00 2001 From: Julia Evans Date: Wed, 15 Oct 2025 13:13:28 +0000 Subject: [PATCH 10/19] doc: git-pull: move and params From user feedback: - it's confusing that we use both and to refer to the second argument - one user is not clear about what `refs/heads/*:refs/remotes/origin/*` is meant to be an example of ("is it like a path?") The DESCRIPTION section is also doing a lot right now: it's trying to describe both how the and arguments work (which is pretty complex, as seen in the DEFAULT BEHAVIOUR section) as well as how `git pull` calls `git fetch` and merge/rebase/etc depending on the arguments. Handle this by moving the description of the and arguments to the OPTIONS section, so that we can focus on the merge/rebase/etc behaviour in the DESCRIPTION section, and refer folks to the later sections for details. Use the term "upstream" instead of 'the "remote" and "merge" configuration for the current branch' since users are more likely to know what an "upstream" is. Signed-off-by: Julia Evans Signed-off-by: Junio C Hamano --- Documentation/git-pull.adoc | 32 +++++++++++++++++++---------- Documentation/pull-fetch-param.adoc | 1 + 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Documentation/git-pull.adoc b/Documentation/git-pull.adoc index 48e924a10a40c0..a3d248dd1d0c65 100644 --- a/Documentation/git-pull.adoc +++ b/Documentation/git-pull.adoc @@ -27,17 +27,6 @@ and then depending on configuration options or command line flags, will call either `git rebase` or `git merge` to reconcile diverging branches. - should be the name of a remote repository as -passed to linkgit:git-fetch[1]. can name an -arbitrary remote ref (for example, the name of a tag) or even -a collection of refs with corresponding remote-tracking branches -(e.g., refs/heads/{asterisk}:refs/remotes/origin/{asterisk}), -but usually it is the name of a branch in the remote repository. - -Default values for and are read from the -"remote" and "merge" configuration for the current branch -as set by linkgit:git-branch[1] `--track`. - Assume the following history exists and the current branch is "`master`": @@ -77,6 +66,26 @@ pulling or stash them away with linkgit:git-stash[1]. OPTIONS ------- +:: + The "remote" repository to pull from. This can be either + a URL (see the section <> below) or the name + of a remote (see the section <> below). ++ +Defaults to the configured upstream for the current branch, or `origin`. +See <> below for more on how to +configure upstreams. + +:: + Which branch or other reference(s) to fetch and integrate into the + current branch, for example `main` in `git pull origin main`. + Defaults to the configured upstream for the current branch. ++ +This can be a branch, tag, or other collection of reference(s). +See <>> below under "Options related to fetching" +for the full syntax, and <> below +for how `git pull` uses this argument to determine which remote branch +to integrate. + -q:: --quiet:: This is passed to both underlying git-fetch to squelch reporting of @@ -145,6 +154,7 @@ include::urls-remotes.adoc[] include::merge-strategies.adoc[] +[[DEFAULT-BEHAVIOUR]] DEFAULT BEHAVIOUR ----------------- diff --git a/Documentation/pull-fetch-param.adoc b/Documentation/pull-fetch-param.adoc index d79d2f6065bcd4..bb2cf6a4629e92 100644 --- a/Documentation/pull-fetch-param.adoc +++ b/Documentation/pull-fetch-param.adoc @@ -11,6 +11,7 @@ ifndef::git-pull[] (See linkgit:git-config[1]). endif::git-pull[] +[[fetch-refspec]] :: Specifies which refs to fetch and which local refs to update. When no s appear on the command line, the refs to fetch From 59b28f928b2b3b91033ee4e9cbe0cf51a781e55b Mon Sep 17 00:00:00 2001 From: Julia Evans Date: Wed, 15 Oct 2025 13:13:29 +0000 Subject: [PATCH 11/19] doc: git-pull: clarify options for integrating remote branch From user feedback: - One user is confused about the current default ("I was convinced that the git default was still to merge on pull") - One user is confused about why "git fetch" isn't mentioned earlier - One user says they always forget what the arguments to `git pull` are and that it's not immediately obvious that `--no-rebase` means "merge" - One user wants `--ff-only` to be mentioned Resolve this by listing the options for integrating the the remote branch. This should help users figure out at a glance which one they want to do, and make it clearer that --ff-only is the default. Signed-off-by: Julia Evans Signed-off-by: Junio C Hamano --- Documentation/git-pull.adoc | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/Documentation/git-pull.adoc b/Documentation/git-pull.adoc index a3d248dd1d0c65..0686a9d6661c97 100644 --- a/Documentation/git-pull.adoc +++ b/Documentation/git-pull.adoc @@ -15,17 +15,26 @@ SYNOPSIS DESCRIPTION ----------- -Incorporates changes from a remote repository into the current branch. -If the current branch is behind the remote, then by default it will -fast-forward the current branch to match the remote. If the current -branch and the remote have diverged, the user needs to specify how to -reconcile the divergent branches with `--rebase` or `--no-rebase` (or -the corresponding configuration option in `pull.rebase`). - -More precisely, `git pull` runs `git fetch` with the given parameters -and then depending on configuration options or command line flags, -will call either `git rebase` or `git merge` to reconcile diverging -branches. +Integrate changes from a remote repository into the current branch. + +First, `git pull` runs `git fetch` with the same arguments +(excluding merge options) to fetch remote branch(es). +Then it decides which remote branch to integrate: if you run `git pull` +with no arguments this defaults to the <> +for the current branch. +Then it integrates that branch into the current branch. + +There are 4 main options for integrating the remote branch: + +1. `git pull --ff-only` will only do "fast-forward" updates: it + fails if your local branch has diverged from the remote branch. + This is the default. +2. `git pull --rebase` runs `git rebase` +3. `git pull --no-rebase` runs `git merge`. +4. `git pull --squash` runs `git merge --squash` + +You can also set the configuration options `pull.rebase`, `pull.squash`, +or `pull.ff` with your preferred behaviour. Assume the following history exists and the current branch is "`master`": From d8942ac494fb08b5b99a3eb6fb6a2853a0232d21 Mon Sep 17 00:00:00 2001 From: Julia Evans Date: Wed, 15 Oct 2025 13:13:30 +0000 Subject: [PATCH 12/19] doc: git-pull: delete the example From user feedback: this example is confusing because it implies that `git pull` will run `git merge` by default, but the default is `--ff-only`. We could instead show an example of a fast-forward merge, but that may not add a lot since fast-forward merges are relatively simple. This lets us keep the description short. Signed-off-by: Julia Evans Signed-off-by: Junio C Hamano --- Documentation/git-pull.adoc | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/Documentation/git-pull.adoc b/Documentation/git-pull.adoc index 0686a9d6661c97..273172aa8036b5 100644 --- a/Documentation/git-pull.adoc +++ b/Documentation/git-pull.adoc @@ -36,32 +36,6 @@ There are 4 main options for integrating the remote branch: You can also set the configuration options `pull.rebase`, `pull.squash`, or `pull.ff` with your preferred behaviour. -Assume the following history exists and the current branch is -"`master`": - ------------- - A---B---C master on origin - / - D---E---F---G master - ^ - origin/master in your repository ------------- - -Then "`git pull`" will fetch and replay the changes from the remote -`master` branch since it diverged from the local `master` (i.e., `E`) -until its current commit (`C`) on top of `master` and record the -result in a new commit along with the names of the two parent commits -and a log message from the user describing the changes. - ------------- - A---B---C origin/master - / \ - D---E---F---G---H master ------------- - -See linkgit:git-merge[1] for details, including how conflicts -are presented and handled. - In Git 1.7.0 or later, to cancel a conflicting merge, use `git reset --merge`. *Warning*: In older versions of Git, running 'git pull' with uncommitted changes is discouraged: while possible, it leaves you From e9d221b0b70869fa770e95acf143149c0b8705f6 Mon Sep 17 00:00:00 2001 From: Julia Evans Date: Wed, 15 Oct 2025 13:13:31 +0000 Subject: [PATCH 13/19] doc: git-pull: clarify how to exit a conflicted merge From user feedback: - One user is confused about why `git reset --merge` (why not just `git reset`?). Handle this by mentioning `git merge --abort` and `git reset --abort` instead, which have a more obvious meaning. - 2 users want to know what "In older versions of Git" means exactly (in versions older than 1.7.0). Handle this by removing the warning since it was added 15 years ago (in 3f8fc184c0e2c) Signed-off-by: Julia Evans Signed-off-by: Junio C Hamano --- Documentation/git-pull.adoc | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Documentation/git-pull.adoc b/Documentation/git-pull.adoc index 273172aa8036b5..cd3bbc90e3008d 100644 --- a/Documentation/git-pull.adoc +++ b/Documentation/git-pull.adoc @@ -36,15 +36,9 @@ There are 4 main options for integrating the remote branch: You can also set the configuration options `pull.rebase`, `pull.squash`, or `pull.ff` with your preferred behaviour. -In Git 1.7.0 or later, to cancel a conflicting merge, use -`git reset --merge`. *Warning*: In older versions of Git, running 'git pull' -with uncommitted changes is discouraged: while possible, it leaves you -in a state that may be hard to back out of in the case of a conflict. - -If any of the remote changes overlap with local uncommitted changes, -the merge will be automatically canceled and the work tree untouched. -It is generally best to get any local changes in working order before -pulling or stash them away with linkgit:git-stash[1]. +If there's a merge conflict during the merge or rebase that you don't +want to handle, you can safely abort it with `git merge --abort` or `git +--rebase abort`. OPTIONS ------- From 0c4f1346ca57814a988be0846f9ec1560dea87dc Mon Sep 17 00:00:00 2001 From: Solly Date: Wed, 15 Oct 2025 15:03:29 +0100 Subject: [PATCH 14/19] t2401: update path checks using test_path helpers Update old-style shell path checks to use the modern test helpers 'test_path_is_file' and 'test_path_is_dir' for improved runtime diagnosis. Signed-off-by: Solly Signed-off-by: Junio C Hamano --- t/t2401-worktree-prune.sh | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh index fe671d41974281..f8f28c76ee56c7 100755 --- a/t/t2401-worktree-prune.sh +++ b/t/t2401-worktree-prune.sh @@ -24,8 +24,8 @@ test_expect_success 'prune files inside $GIT_DIR/worktrees' ' Removing worktrees/abc: not a valid directory EOF test_cmp expect actual && - ! test -f .git/worktrees/abc && - ! test -d .git/worktrees + test_path_is_missing .git/worktrees/abc && + test_path_is_missing .git/worktrees ' test_expect_success 'prune directories without gitdir' ' @@ -36,8 +36,8 @@ Removing worktrees/def: gitdir file does not exist EOF git worktree prune --verbose 2>actual && test_cmp expect actual && - ! test -d .git/worktrees/def && - ! test -d .git/worktrees + test_path_is_missing .git/worktrees/def && + test_path_is_missing .git/worktrees ' test_expect_success SANITY 'prune directories with unreadable gitdir' ' @@ -47,8 +47,8 @@ test_expect_success SANITY 'prune directories with unreadable gitdir' ' chmod u-r .git/worktrees/def/gitdir && git worktree prune --verbose 2>actual && test_grep "Removing worktrees/def: unable to read gitdir file" actual && - ! test -d .git/worktrees/def && - ! test -d .git/worktrees + test_path_is_missing .git/worktrees/def && + test_path_is_missing .git/worktrees ' test_expect_success 'prune directories with invalid gitdir' ' @@ -57,8 +57,8 @@ test_expect_success 'prune directories with invalid gitdir' ' : >.git/worktrees/def/gitdir && git worktree prune --verbose 2>actual && test_grep "Removing worktrees/def: invalid gitdir file" actual && - ! test -d .git/worktrees/def && - ! test -d .git/worktrees + test_path_is_missing .git/worktrees/def && + test_path_is_missing .git/worktrees ' test_expect_success 'prune directories with gitdir pointing to nowhere' ' @@ -67,8 +67,8 @@ test_expect_success 'prune directories with gitdir pointing to nowhere' ' echo "$(pwd)"/nowhere >.git/worktrees/def/gitdir && git worktree prune --verbose 2>actual && test_grep "Removing worktrees/def: gitdir file points to non-existent location" actual && - ! test -d .git/worktrees/def && - ! test -d .git/worktrees + test_path_is_missing .git/worktrees/def && + test_path_is_missing .git/worktrees ' test_expect_success 'not prune locked checkout' ' @@ -76,23 +76,23 @@ test_expect_success 'not prune locked checkout' ' mkdir -p .git/worktrees/ghi && : >.git/worktrees/ghi/locked && git worktree prune && - test -d .git/worktrees/ghi + test_path_is_dir .git/worktrees/ghi ' test_expect_success 'not prune recent checkouts' ' test_when_finished rm -r .git/worktrees && git worktree add jlm HEAD && - test -d .git/worktrees/jlm && + test_path_is_dir .git/worktrees/jlm && rm -rf jlm && git worktree prune --verbose --expire=2.days.ago && - test -d .git/worktrees/jlm + test_path_is_dir .git/worktrees/jlm ' test_expect_success 'not prune proper checkouts' ' test_when_finished rm -r .git/worktrees && git worktree add --detach "$PWD/nop" main && git worktree prune && - test -d .git/worktrees/nop + test_path_is_dir .git/worktrees/nop ' test_expect_success 'prune duplicate (linked/linked)' ' @@ -103,8 +103,8 @@ test_expect_success 'prune duplicate (linked/linked)' ' mv .git/worktrees/w2/gitdir.new .git/worktrees/w2/gitdir && git worktree prune --verbose 2>actual && test_grep "duplicate entry" actual && - test -d .git/worktrees/w1 && - ! test -d .git/worktrees/w2 + test_path_is_dir .git/worktrees/w1 && + test_path_is_missing .git/worktrees/w2 ' test_expect_success 'prune duplicate (main/linked)' ' @@ -116,7 +116,7 @@ test_expect_success 'prune duplicate (main/linked)' ' mv repo wt && git -C wt worktree prune --verbose 2>actual && test_grep "duplicate entry" actual && - ! test -d .git/worktrees/wt + test_path_is_missing .git/worktrees/wt ' test_expect_success 'not prune proper worktrees inside linked worktree with relative paths' ' From d014fb2914e3c318b72cd1f4efb777677aa15805 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 16 Oct 2025 15:48:09 +0000 Subject: [PATCH 15/19] build(deps): bump actions/download-artifact from 4 to 5 Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v4...v5) Signed-off-by: Junio C Hamano --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d122e79415a13e..ea192f6ff7a0a4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -140,7 +140,7 @@ jobs: cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - name: download tracked files and build artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: windows-artifacts path: ${{github.workspace}} @@ -226,7 +226,7 @@ jobs: steps: - uses: git-for-windows/setup-git-for-windows-sdk@v1 - name: download tracked files and build artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: vs-artifacts path: ${{github.workspace}} @@ -292,7 +292,7 @@ jobs: shell: pwsh run: pip install meson ninja - name: Download build artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: windows-meson-artifacts path: build From 63541ed9bc9213349f8957ecb362a0e8a97ad1f7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 16 Oct 2025 15:48:10 +0000 Subject: [PATCH 16/19] build(deps): bump actions/checkout from 4 to 5 Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) Signed-off-by: Junio C Hamano --- .github/workflows/check-style.yml | 2 +- .github/workflows/check-whitespace.yml | 2 +- .github/workflows/coverity.yml | 2 +- .github/workflows/main.yml | 22 +++++++++++----------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/check-style.yml b/.github/workflows/check-style.yml index c052a5df2381e9..19a145d4ad0c5a 100644 --- a/.github/workflows/check-style.yml +++ b/.github/workflows/check-style.yml @@ -20,7 +20,7 @@ jobs: jobname: ClangFormat runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 diff --git a/.github/workflows/check-whitespace.yml b/.github/workflows/check-whitespace.yml index d0a78fc426f9e4..928fd4cfe2456d 100644 --- a/.github/workflows/check-whitespace.yml +++ b/.github/workflows/check-whitespace.yml @@ -19,7 +19,7 @@ jobs: check-whitespace: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 01a0437b2f2634..cfa17d394a7dbc 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -38,7 +38,7 @@ jobs: COVERITY_LANGUAGE: cxx COVERITY_PLATFORM: overridden-below steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: install minimal Git for Windows SDK if: contains(matrix.os, 'windows') uses: git-for-windows/setup-git-for-windows-sdk@v1 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ea192f6ff7a0a4..ea1d9591cf6a39 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -112,7 +112,7 @@ jobs: group: windows-build-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: git-for-windows/setup-git-for-windows-sdk@v1 - name: build shell: bash @@ -173,10 +173,10 @@ jobs: group: vs-build-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: git-for-windows/setup-git-for-windows-sdk@v1 - name: initialize vcpkg - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: 'microsoft/vcpkg' path: 'compat/vcbuild/vcpkg' @@ -258,7 +258,7 @@ jobs: group: windows-meson-build-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: actions/setup-python@v5 - name: Set up dependencies shell: pwsh @@ -286,7 +286,7 @@ jobs: group: windows-meson-test-${{ matrix.nr }}-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: actions/setup-python@v5 - name: Set up dependencies shell: pwsh @@ -331,7 +331,7 @@ jobs: TEST_OUTPUT_DIRECTORY: ${{github.workspace}}/t runs-on: ${{matrix.vector.pool}} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - run: ci/install-dependencies.sh - run: ci/run-build-and-tests.sh - name: print test failures @@ -352,7 +352,7 @@ jobs: CI_JOB_IMAGE: ubuntu-latest runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - run: ci/install-dependencies.sh - run: ci/run-build-and-minimal-fuzzers.sh dockerized: @@ -429,7 +429,7 @@ jobs: else apt-get -q update && apt-get -q -y install git fi - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - run: ci/install-dependencies.sh - run: useradd builder --create-home - run: chown -R builder . @@ -454,7 +454,7 @@ jobs: group: static-analysis-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - run: ci/install-dependencies.sh - run: ci/run-static-analysis.sh - run: ci/check-directional-formatting.bash @@ -469,7 +469,7 @@ jobs: group: sparse-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install other dependencies run: ci/install-dependencies.sh - run: make sparse @@ -485,6 +485,6 @@ jobs: CI_JOB_IMAGE: ubuntu-latest runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - run: ci/install-dependencies.sh - run: ci/test-documentation.sh From b195b9526bc7fa642b9ff9dba56753acac165ea7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 16 Oct 2025 15:48:11 +0000 Subject: [PATCH 17/19] build(deps): bump actions/setup-python from 5 to 6 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v5...v6) Signed-off-by: Junio C Hamano --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ea1d9591cf6a39..fa7c60f95fdca0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -259,7 +259,7 @@ jobs: cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 - name: Set up dependencies shell: pwsh run: pip install meson ninja @@ -287,7 +287,7 @@ jobs: cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 - name: Set up dependencies shell: pwsh run: pip install meson ninja From 96978d7545a00dbffe99252a4749a7554ce124bb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 16 Oct 2025 15:48:12 +0000 Subject: [PATCH 18/19] build(deps): bump actions/github-script from 7 to 8 Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 8. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v7...v8) Signed-off-by: Junio C Hamano --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fa7c60f95fdca0..aa6bce673b4e99 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -63,7 +63,7 @@ jobs: echo "skip_concurrent=$skip_concurrent" >>$GITHUB_OUTPUT - name: skip if the commit or tree was already tested id: skip-if-redundant - uses: actions/github-script@v7 + uses: actions/github-script@v8 if: steps.check-ref.outputs.enabled == 'yes' with: github-token: ${{secrets.GITHUB_TOKEN}} From c54a18ef67e59cdbcd77d6294916d42c98c62d1d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 22 Oct 2025 11:38:46 -0700 Subject: [PATCH 19/19] The twenty-second batch Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.52.0.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/RelNotes/2.52.0.adoc b/Documentation/RelNotes/2.52.0.adoc index 1e41b7380aebe0..cfce098d1453a0 100644 --- a/Documentation/RelNotes/2.52.0.adoc +++ b/Documentation/RelNotes/2.52.0.adoc @@ -131,6 +131,8 @@ Performance, Internal Implementation, Development Support etc. and one for xdiff), roll everything into a single libgit.a archive. This would help later effort to FFI into Rust. + * The beginning of SHA1-SHA256 interoperability work. + Fixes since v2.51 ----------------- @@ -380,3 +382,5 @@ including security updates, are included in this release. (merge 3860985105 js/unreachable-workaround-for-no-symlink-head later to maint). (merge b3ac6e737d kh/doc-continued-paragraph-fix later to maint). (merge 2cebca0582 tb/cat-file-objectmode-update later to maint). + (merge 96978d7545 js/ci-github-actions-update later to maint). + (merge 0c4f1346ca so/t2401-use-test-path-helpers later to maint).