Since Git 2.29, repositories can use SHA-256 instead of SHA-1 as their
object format (git init --object-format=sha256). Diffs generated in
such repositories use SHA-256 hashes in their index lines.
* src/pch.c (sha_says_nonexistent): Add empty_sha256 constant for the
SHA256 empty blob hash. Replace byte-by-byte loop with strncmp prefix
matching against both SHA1 and SHA256 empty hashes.
* tests/empty-files-sha256: New test.
* tests/Makefile.am (TESTS): Add new test.
---
src/pch.c | 12 +++---
tests/Makefile.am | 1 +
tests/empty-files-sha256 | 86 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 94 insertions(+), 5 deletions(-)
create mode 100644 tests/empty-files-sha256
diff --git a/src/pch.c b/src/pch.c
index 6146ec4..1434de8 100644
--- a/src/pch.c
+++ b/src/pch.c
@@ -381,6 +381,8 @@ static char ATTRIBUTE_PURE
sha_says_nonexistent (char const *sha)
{
char const *empty_sha1 = "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391";
+ char const *empty_sha256 = "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7"
+ "749120a303721813";
char const *s;
/* Nonexistent files have an all-zero checksum. */
@@ -390,11 +392,11 @@ sha_says_nonexistent (char const *sha)
if (! *s)
return 2;
- /* Empty files have empty_sha1 as their checksum. */
- for (s = sha; *s; s++, empty_sha1++)
- if (*s != *empty_sha1)
- break;
- return ! *s;
+ /* Empty files have a well-known checksum
+ (prefix match for abbreviated hashes). */
+ idx_t len = strlen (sha);
+ return strncmp (sha, empty_sha1, len) == 0
+ || strncmp (sha, empty_sha256, len) == 0;
}
static char const * ATTRIBUTE_PURE
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8f1a248..1ef2e34 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -33,6 +33,7 @@ TESTS = \
deep-directories \
ed-style \
empty-files \
+ empty-files-sha256 \
false-match \
fifo \
file-create-modes \
diff --git a/tests/empty-files-sha256 b/tests/empty-files-sha256
new file mode 100644
index 0000000..ec5c83a
--- /dev/null
+++ b/tests/empty-files-sha256
@@ -0,0 +1,86 @@
+# Copyright 2010-2026 Free Software Foundation, Inc.
+#
+# Copying and distribution of this file, with or without modification,
+# in any medium, are permitted without royalty provided the copyright
+# notice and this notice are preserved.
+
+# Symlink related tests
+
+. $srcdir/test-lib.sh
+
+require cat
+use_local_patch
+use_tmpdir
+umask 022
+
+# ==============================================================
+# Create an empty file
+
+cat > create-empty.diff <<EOF
+diff --git a/f b/f
+new file mode 100644
+index 0000000..473a0f4
+EOF
+
+check 'patch < create-empty.diff || echo "Status: $?"' <<EOF
+patching file f
+EOF
+
+ncheck 'test -e f && test ! -s f'
+
+# --------------------------------------------------------------
+# Empty out a file
+
+echo f > f
+
+cat > empty-out.diff <<EOF
+diff --git a/f b/f
+index e8e91e4..473a0f4 100644
+--- a/f
++++ b/f
+@@ -1 +0,0 @@
+-f
+EOF
+
+check 'patch < empty-out.diff || echo "Status: $?"' <<EOF
+patching file f
+EOF
+
+ncheck 'test -e f && test ! -s f'
+
+# --------------------------------------------------------------
+# Empty out a file and delete it with -E
+
+echo f > f
+
+cat > empty-out.diff <<EOF
+diff --git a/f b/f
+index e8e91e4..473a0f4 100644
+--- a/f
++++ b/f
+@@ -1 +0,0 @@
+-f
+EOF
+
+check 'patch -E < empty-out.diff || echo "Status: $?"' <<EOF
+patching file f
+EOF
+
+ncheck 'test ! -e f'
+
+# --------------------------------------------------------------
+# Delete an empty file
+
+: > f
+
+cat > delete-empty.diff <<EOF
+diff --git a/f b/f
+deleted file mode 100644
+index 473a0f4..0000000
+EOF
+
+check 'patch < delete-empty.diff || echo "Status: $?"' <<EOF
+patching file f
+EOF
+
+ncheck 'test ! -e f'
--
gabi