Subject: Re: git reset --merge random behavior

From: Victoria Dye <[email-masked]>
Date: Thu, 24 Mar 2022 18:58:34 -0700

Maximilian Reichel wrote:
> Thank you for filling out a Git bug report!
> Please answer the following questions to help us understand your issue.
> 
> What did you do before the bug happened? (Steps to reproduce your issue)
> Running the following script (test.sh) multiple times:
> 
>  ```
>  #!/bin/bash
> GIT_TRACE=true
> export GIT_TRACE
> 
> mkdir gitDir0
> cd gitDir0
> env git -c init.defaultBranch=master init 
> echo bar > bar.txt
> env git add -v bar.txt 
> env git -c user.name="P" -c user.email="[email-masked]" commit -v -m first 
> 
> mkdir ../gitDir2
> cd ../gitDir2
> env git -c init.defaultBranch=master init 
> env git pull -v --set-upstream ../gitDir0 
> echo foo > foo.txt
> env git add -v foo.txt 
> env git mv -v -f -- foo.txt bar.txt 
> env git reset --merge HEAD
> ```
> 
> What did you expect to happen? (Expected behavior)
> I expect that the script shows the same behavior on every execution.
> 
> What happened instead? (Actual behavior)
> I encountered two different behaviors (random):
> 1. Most of the time the git reset command succeeds and the file gitDir2/bar.txt contains the string "bar" after running the script.
> 2. Sometimes the git reset command fails and the file gitDir2/bar.txt contains the string "foo" after running the script.
> In this case, the reset command produces the following output:
> ```
> error: Entry 'bar.txt' not uptodate. Cannot merge.
> fatal: Could not reset index file to revision 'HEAD'.
> ```
> The full console output of both cases is attached to this mail, but they only really differ in this error message.
> 

I was able to reliably reproduce both the success and failure scenarios with
a slightly simplified script:

# Setup
$ git init test-repo
$ cd test-repo
$ echo bar >bar.txt
$ git commit -am first

# Succeeds
$ echo foo >foo.txt
$ git add foo.txt
$ git mv -f foo.txt bar.txt
$ git update-index --refresh
$ git reset --merge HEAD

# Fails
$ echo foo >foo.txt
$ git mv -f foo.txt bar.txt
$ git reset --merge HEAD

It looks like the error happens because 'mv' doesn't refresh the
"up-to-date" flag on 'bar.txt', so the subsequent 'reset --merge' thinks
there's a conflict that doesn't actually exist. 

I've submitted a patch [1] to fix this permanently, but if you need a
workaround in the meantime, you can call 'git update-index --refresh' after
'git mv' to avoid the error.

[1] https://lore.kernel.org/git/[email-masked]/

> Anything else you want to add:
> I could observe this behavior on git 2.35.1 and 2.34.1.
> The behavior is not affected by whether GIT_TRACE is set.
> 
> I wrote a script that executes this test script repeatedly and keeps track of the possible outcomes of the gitDir2/bar.txt file.
> It will print a line each time the content differs from the previous execution.
> This script is attached to this mail (runner.sh).
> Sample output of this script:
> ```
> execution #0 	 hash: c157a79031e1c40f85931829bc5fc552 	 date: Thu Mar 24 13:22:17 UTC 2022
> execution #203 	 hash: d3b07384d113edec49eaa6238ad5ff00 	 date: Thu Mar 24 13:22:29 UTC 2022
> execution #204 	 hash: c157a79031e1c40f85931829bc5fc552 	 date: Thu Mar 24 13:22:29 UTC 2022
> execution #264 	 hash: d3b07384d113edec49eaa6238ad5ff00 	 date: Thu Mar 24 13:22:32 UTC 2022
> execution #265 	 hash: c157a79031e1c40f85931829bc5fc552 	 date: Thu Mar 24 13:22:32 UTC 2022
> execution #432 	 hash: d3b07384d113edec49eaa6238ad5ff00 	 date: Thu Mar 24 13:22:40 UTC 2022
> execution #433 	 hash: c157a79031e1c40f85931829bc5fc552 	 date: Thu Mar 24 13:22:40 UTC 2022
> execution #489 	 hash: d3b07384d113edec49eaa6238ad5ff00 	 date: Thu Mar 24 13:22:43 UTC 2022
> ```
> 
> 
> [System Info]
> git version:
> git version 2.35.1
> cpu: x86_64
> built from commit: 4c53a8c20f8984adb226293a3ffd7b88c3f4ac1a
> sizeof-long: 8
> sizeof-size_t: 8
> shell-path: /bin/sh
> uname: Linux 5.10.25-linuxkit #1 SMP Tue Mar 23 09:27:39 UTC 2021 x86_64
> compiler info: gnuc: 10.2
> libc info: glibc: 2.31
> $SHELL (typically, interactive shell): <unset>
> 
> 
> [Enabled Hooks]
> not run from a git repository - no hooks to show