On Wed, Nov 17, 2021 at 4:42 PM Waleed Khan <me@xxxxxxxxxxxxxxx> wrote: > > Hi all, > > I'm seeing unusual behavior on Git built from source at > cd3e606211bb1cf8bc57f7d76bab98cc17a150bc, but which appears to extend > back to Git v2.29. > > This is a repro script: > > ``` > #!/bin/sh > > temp_dir=$(mktemp -d) > echo "git dir is: $temp_dir" > mkdir -p "$temp_dir" > trap "rm -rf $temp_dir" EXIT > > cd "$temp_dir" || exit 1 > git init -q > date='Thu, 07 Apr 2005 22:13:13 +0200' > GIT_AUTHOR_DATE="$date" GIT_COMMITTER_DATE="$date" git commit -q > --allow-empty -m 'Initial commit' > > mkdir -p '.git/hooks' > cat >.git/hooks/reference-transaction <<'EOT' > #!/bin/sh > > [[ "$1" != 'committed' ]] && exit 0 > echo 'New reference-transaction invocation' > > while read old new ref; do > echo " old: $old, new: $new, ref: $ref" > done > EOT > chmod +x .git/hooks/reference-transaction > > git gc --prune=now -q > git show-ref refs/heads/master > ``` > > And this is the output it produces: > > ``` > git dir is: /var/folders/gn/gdp9z_g968b9nx7c9lvgy8y00000gp/T/tmp.b3Jc6qnb > New reference-transaction invocation > old: 0000000000000000000000000000000000000000, new: > e197d18c017d4038418be8b1cd38f4503e289165, ref: refs/heads/master > New reference-transaction invocation > old: e197d18c017d4038418be8b1cd38f4503e289165, new: > 0000000000000000000000000000000000000000, ref: refs/heads/master > e197d18c017d4038418be8b1cd38f4503e289165 refs/heads/master > ``` > > These hooks are invoked a few milliseconds one after another. There are two built-in "ref backends" that Git uses out of the box: A packed backend, which manages the "packed-refs" file, and a loose backend, which manages other files under "$GIT_DIR/refs". What you're seeing is a reference transaction for the packed backend which is adding the new value for "refs/heads/master" to "packed-refs" (packed backend reference-transactions rarely, if ever, include an actual old hash, as far as I can tell), and then a second reference transaction for the loose backend to delete the loose "refs/heads/master" file, now that it's packed. > > The expected behavior would be that the latest reference transaction > hook refers to the state of the references on disk. That is, either > `master` should point to 0 (be deleted), or it should have said that > `master` pointed to `e197d1`. > > But if we actually examine `master`, it's set to `e197d1`, just as you > would expect. The GC should have been a no-op overall. One of the subtasks of "git gc" is "git pack-refs". If you inspect in more detail, I suspect you'll find that "refs/heads/master" was loose before "git gc" ran (as in, there was a file "$GIT_DIR/refs/heads/master") and "packed-refs" either didn't have a "refs/heads/master" entry or had a different hash. (Loose refs always "win" over packed, since ref updates only write loose refs.) Hope this helps, Bryan Turner > > Best, > Waleed