Hello, I may have found a bug in Git. It seems that if (1) multiple git(1) are installed on the system, (2) one is in the shell’s default path (i.e., used if $PATH is unset, not the default value of $PATH), and (3) the desired git(1) is at a different path, then subprocesses of the desired git(1) invoke the undesired git(1) instead. $PATH unset is indeed a pathological situation; one of our own bugs in our software that calls git(1) inappropriately cleared it. However, in my view it’s surprising enough to be a usability bug. I would expect git(1) to call itself for subprocesses regardless of the environment. > 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) 1. If /usr/bin/git exists, move it out of the way. 2. Write a shell script at /usr/bin/git that prints an error message and then fails. 3. Install a different Git at prefix other than /usr and put it in your path before /usr/bin. 4. Run the following Python script. (It’s Python because I know how to manipulate the environment how I wanted, and I don’t in shell.) ~~~~ #!/usr/bin/env python3 import os import subprocess import sys def chdir(p): print("", file=sys.stderr) print("$ cd %s" % p, file=sys.stderr) os.chdir(p) def c(msg, argv, **kwargs): print("", file=sys.stderr) print("# " + msg, file=sys.stderr) print("$ " + " ".join(argv), file=sys.stderr) try: subprocess.run(argv, check=True, **kwargs) except subprocess.CalledProcessError as x: print("# command failed with exit code %d" % x.returncode) else: print("# success") c("fake system Git contents", ["cat", "/usr/bin/git"]) c("path to desired Git", ["which", "git"]) c("Git version", ["git", "--version"]) chdir("/tmp") c("remove existing test repo", ["rm", "-Rf", "test"]) c("create test repo", ["git", "init", "-q", "test"]) chdir("test") c("test commit A", ["git", "commit", "-m", "a", "--allow-empty"]) c("branch", ["git", "checkout", "-b", "foo"]) c("test commit B", ["git", "commit", "-m", "b", "--allow-empty"]) # This uses the existing $PATH to find git(1), but then runs it with an empty # environment. c("checkout w/ empty env", ["git", "checkout", "master"], env=dict()) ~~~~ > What happened instead? (Actual behavior) > (Note re-ordering for clarity.) Script output: # fake system Git contents $ cat /usr/bin/git #!/bin/sh echo 'you should not see this' 1>&2 exit 1 # success # path to desired Git $ which git /usr/local/bin/git # success # Git version $ git --version git version 2.41.0 # success $ cd /tmp # remove existing test repo $ rm -Rf test # success # create test repo $ git init -q test # success $ cd test # test commit A $ git commit -m a --allow-empty [master (root-commit) 03e2eb0] a # success # branch $ git checkout -b foo Switched to a new branch 'foo' # success # test commit B $ git commit -m b --allow-empty [foo c417cee] b # success # checkout w/ empty env $ git checkout master you should not see this # command failed with exit code 1 > What did you expect to happen? (Expected behavior) Every command in the script should be successful. In particular, I expected the final output to be: # checkout w/ empty env $ git checkout master [... normal checkout chatter ...] # success > What's different between what you expected and what actually happened? /usr/local/bin/git called /usr/bin/git for some subprocess. I expected it to call itself. > Anything else you want to add Usually for us, the version skew is close enough that everything seemed to work. I believe we installed Git 2.40.0 and subprocesses were presumably using the system’s 2.31 and everything appeared to work fine. Only when we tried our software on a different box where the system Git was 1.8 did it crash. Therefore, I worry about silent problems due to version skew in the internal command-line API. > Please review the rest of the bug report below. > You can delete any lines you don't wish to share. > > [System Info] > git version: > git version 2.41.0 > cpu: x86_64 > no commit associated with this build [I built the source tarball] > sizeof-long: 8 > sizeof-size_t: 8 > shell-path: /bin/sh > uname: Linux 5.10.0-23-amd64 #1 SMP Debian 5.10.179-1 (2023-05-12) x86_64 > compiler info: gnuc: 10.2 > libc info: glibc: 2.31 > $SHELL (typically, interactive shell): /bin/bash > > [Enabled Hooks] Thanks, Reid — he/his