Re: Bug report: Strange behavior with `git gc` and `reference-transaction` hook

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux