Change:
To reproduce, I am in a worktree without (i.e., not the "main" worktree). I have a pre-commit hook set up as follows Now I change something trivial (e.g. remove a trailing in some comments) and commit. That does the following After a second or two I get suspicious and hit Ctrl-C. Now it looks like bootstrap has done something with the (previously clean) cargo submodule So let's and see what's up Eh... so the files are rustc files? Why are those being in ? Something is going seriously wrong here.
I think this only happens with . I attempted to reproduce it about 25 times without success.
Yes indeed, this does not happen in my folder (the main checkout, where lives), but it happens in worktree folders.
Adding some debug logging, it seems like some truly strange things are happening... This is the HEAD commit of the outer repository! I think what's happening is that some environment variables are set inside the git hook which overwrite the . x.py relies on just setting the working directory to determine which git dir to use, but e.g. GITDIR takes precedence over that. I tried setting instead of using and that does seem to help.

Discussion:
return; } <del> // check_submodule let checked_out_hash = output(helpers::git(Some(&absolute_path)).args(["rev-parse", "HEAD"])); // update_submodules </del> <ins> let submodule_git = || helpers::git(Some(&absolute_path)); // Determine commit checked out in submodule. let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"])); let checked_out_hash = checked_out_hash.trim_end(); // Determine commit that the submodule *should* have. </ins> let recorded = output(helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path)); let actual_hash = recorded

.nth(2) .unwrap_or_else(|| panic!("unexpected output `{}`", recorded)); <del> // update_submodule if actual_hash == checked_out_hash.trim_end() { </del> <ins> if actual_hash == checked_out_hash { </ins> // already checked out return; }

// Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). // diff-index reports the modifications through the exit status let has_local_modifications = !self.run_cmd( <del> BootstrapCommand::from(helpers::git(Some(&absolute_path)).args([ "diff-index", "--quiet", "HEAD", ])) .allow_failure() .output_mode(match self.is_verbose() { true => OutputMode::PrintAll, false => OutputMode::PrintOutput, }), </del> <ins> BootstrapCommand::from(submodule_git().args(["diff-index", "--quiet", "HEAD"])) .allow_failure() .output_mode(match self.is_verbose() { true => OutputMode::PrintAll, false => OutputMode::PrintOutput, }), </ins> ); if has_local_modifications { <del> self.run(helpers::git(Some(&absolute_path)).args(["stash", "push"])); </del> <ins> self.run(submodule_git().args(["stash", "push"])); </ins> } <del> self.run(helpers::git(Some(&absolute_path)).args(["reset", "-q", "--hard"])); self.run(helpers::git(Some(&absolute_path)).args(["clean", "-qdfx"])); </del> <ins> self.run(submodule_git().args(["reset", "-q", "--hard"])); self.run(submodule_git().args(["clean", "-qdfx"])); </ins> if has_local_modifications { <del> self.run(helpers::git(Some(&absolute_path)).args(["stash", "pop"])); </del> <ins> self.run(submodule_git().args(["stash", "pop"])); </ins> } }

if let Some(source_dir) = source_dir { git.current_dir(source_dir); <ins> // If we are running inside git (e.g. via a hook), `GIT_DIR` is set and takes precedence // over the current dir. Un-set it to make the current dir matter. git.env_remove("GIT_DIR"); // Also un-set some other variables, to be on the safe side (based on cargo's // `fetch_with_cli`). In particular un-setting `GIT_INDEX_FILE` is required to fix some odd // misbehavior. git.env_remove("GIT_WORK_TREE") .env_remove("GIT_INDEX_FILE") .env_remove("GIT_OBJECT_DIRECTORY") .env_remove("GIT_ALTERNATE_OBJECT_DIRECTORIES"); </ins> } git