With Git < 2.40.0 it was possible to create an initial empty commit (even though files were staged) using following steps:
$ git init test
$ cd test
$ touch readme.txt
$ git add .
$ git commit -m "initial commit" --allow-empty --only
[master (root-commit) 93f098e] initial commit
but with Git 2.40.0 this already commits the staged file:
$ git commit -m "initial commit" --allow-empty --only
[master (root-commit) c0b3214] initial commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 readme.txt
Is this an intentional change or a regression? If the first, how to create an empty commit though files have been staged?
[This is only a partial answer at the moment -- I believe it accurately describes the cause, but it does not offer a solution.]
I wrote a script to test this behavior:
#!/bin/bash
set -e
make CFLAGS="-g -O0 -Wall" -j 10 > /dev/null || exit 125
PATH="$PWD:$PATH"
tmpdir=$(mktemp -d repoXXXXXX)
trap "rm -rf $tmpdir" EXIT
git -C "$tmpdir" init
echo this is a test > "$tmpdir/file1"
git -C "$tmpdir" add file1
git -C "$tmpdir" commit -m test --allow-empty --only
tree=$(git -C "$tmpdir" cat-file -p HEAD^{tree})
if [[ -z "$tree" ]]; then
echo OKAY
retval=0
else
echo FAIL
retval=1
fi
exit "$retval"
We can use this script with git bisect
to find when this behavior changed:
git bisect start HEAD v2.39.2
git bisect run ./test-empty-commit.sh
The git bisect
process shows the the behavior changed in this commit:
commit 03267e8656c23cf1e2d1df8204d4cee236fb0077
Author: Ævar Arnfjörð Bjarmason <[email protected]>
Date: Tue Nov 8 19:17:39 2022 +0100
commit: discard partial cache before (re-)reading it
The read_cache() in prepare_to_commit() would end up clobbering the
pointer we had for a previously populated "the_index.cache_tree" in
the very common case of "git commit" stressed by e.g. the tests being
changed here.
We'd populate "the_index.cache_tree" by calling
"update_main_cache_tree" in prepare_index(), but would not end up with
a "fully prepared" index. What constitutes an existing index is
clearly overly fuzzy, here we'll check "active_nr" (aka
"the_index.cache_nr"), but our "the_index.cache_tree" might have been
malloc()'d already.
Thus the code added in 11c8a74a64a (commit: write cache-tree data when
writing index anyway, 2011-12-06) would end up allocating the
"cache_tree", and would interact here with code added in
7168624c353 (Do not generate full commit log message if it is not
going to be used, 2007-11-28). The result was a very common memory
leak.
Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]>
Signed-off-by: Taylor Blau <[email protected]>
Which introduced the following change in builtin/commit.c
:
diff --git a/builtin/commit.c b/builtin/commit.c
index e22bdf23f5..c291199b70 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -987,8 +987,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
struct object_id oid;
const char *parent = "HEAD";
- if (!active_nr && read_cache() < 0)
- die(_("Cannot read index"));
+ if (!active_nr) {
+ discard_cache();
+ if (read_cache() < 0)
+ die(_("Cannot read index"));
+ }
if (amend)
parent = "HEAD^1";
Update: I've reported this to the git mailing list along with a proposed solution: https://lore.kernel.org/git/bt4342bdip3nzlikjsv6wozszmcbsc2av6cyo3z2lra4jhx3ii@ut2sl5h4f5xn/T/#u
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With