threads / discuss / 50198

Git rebase --exec cannot run git commands affecting other repos

Subject: Git rebase --exec cannot run git commands affecting other repos

## tl;dr

4 messages between Jan 10, 2019 and Jan 11, 2019.

replies: 3people: 3as markdown or json

Samir Benmendil· Jan 10, 2019, 16:19 UTC · lore

It is impossible to run git commands affecting a different repo from within a `git rebase --exec` because in that environment the `GIT_DIR` and `GIT_WORK_TREE` variables are set and inherited by any commands run as part of `git rebase --exec`.

A minimal reproduction is shown below:
    git init
    touch file
    git add file
    git commit -m"Commit"
    git rebase --root --exec="git clone . subrepo"

It is a bit convoluted for the sake of being self contained. But any git command in `--exec` acting on a different repo than the one being rebased will fail. See my ticket on CMake [0] for a more real usecase.

As mentioned in the other ticket, unsetting these variables will work around the issue.

    git rebase --root --exec="env -u GIT_DIR -u GIT_WORK_TREE git clone . subrepo"
[0] https://gitlab.kitware.com/cmake/cmake/issues/18778
Regards
Junio C Hamano· Jan 10, 2019, 18:26 UTC · re: Samir Benmendil · lore

Re: Git rebase --exec cannot run git commands affecting other repos

Samir Benmendil <me@rmz.io> writes:
> It is impossible to run git commands affecting a different repo from
> within a `git rebase --exec` because in that environment the `GIT_DIR`
> and `GIT_WORK_TREE` variables are set and inherited by any commands
> run as part of `git rebase --exec`.

If the user wants to work in a different repository, the environments that tells Git about the original repository can be unset to do so, which is a very much deliberately designed behaviour, primarily to help those who run "git rebase" from a subdirectory of the project.

Samir Benmendil· Jan 10, 2019, 21:48 UTC · re: Junio C Hamano · lore

Re: Git rebase --exec cannot run git commands affecting other repos

On Jan 10, 2019 at 10:26, Junio C Hamano wrote:
Show 12 quoted lines
> Samir Benmendil <me@rmz.io> writes:
> 
>> It is impossible to run git commands affecting a different repo from
>> within a `git rebase --exec` because in that environment the `GIT_DIR`
>> and `GIT_WORK_TREE` variables are set and inherited by any commands
>> run as part of `git rebase --exec`.
> 
> If the user wants to work in a different repository, the
> environments that tells Git about the original repository can be
> unset to do so, which is a very much deliberately designed
> behaviour, primarily to help those who run "git rebase" from a
> subdirectory of the project.

When run in a directory that does not have ".git" repository directory, Git tries to find such a directory in the parent directories to find the top of the working tree.

That should be the case as well for `git rebase`, is it not?

Rummaging through release notes to find out when this was added, I found the following in `RelNotes/2.19.0.txt`.

 * "git rebase" started exporting GIT_DIR environment variable and
   exposing it to hook scripts when part of it got rewritten in C.
   Instead of matching the old scripted Porcelains' behaviour,
   compensate by also exporting GIT_WORK_TREE environment as well to
   lessen the damage.  This can harm existing hooks that want to
   operate on different repository, but the current behaviour is
   already broken for them anyway.
   (merge ab5e67d751 bc/sequencer-export-work-tree-as-well later to maint).

To me it seems to be more of a regression introduced by porting rebase to C that was deemed to be acceptable at the time (only a few months ago).

I would argue that it is not.

The behaviour is also inconsistent with running these --exec commands from the command line while doing an interactive rebase, i.e. when changing one of the lines to "edit" and being dropped into the terminal for the edit, these env variables are not set.

Jeff King· Jan 11, 2019, 16:04 UTC · re: Samir Benmendil · lore

Re: Git rebase --exec cannot run git commands affecting other repos

On Thu, Jan 10, 2019 at 09:48:42PM +0000, Samir Benmendil wrote:
Show 11 quoted lines
> > If the user wants to work in a different repository, the
> > environments that tells Git about the original repository can be
> > unset to do so, which is a very much deliberately designed
> > behaviour, primarily to help those who run "git rebase" from a
> > subdirectory of the project.
> 
> When run in a directory that does not have ".git" repository directory, Git
> tries to find such a directory in the parent directories to find the top of
> the working tree.
> 
> That should be the case as well for `git rebase`, is it not?

Generally yes. But ".git" does not necessarily have to be connected. For example, try this:

  # a separate worktree and repo
  mkdir worktree
  git init --bare repo.git
  git -C repo.git config core.bare false
  git -C repo.git config core.worktree "$PWD/worktree"
  # an unrelated repo we'll try to access
  git init unrelated
  # operate in the separated repo using $GIT_DIR to point to the repo
  export GIT_DIR=$PWD/repo.git
  cd worktree
  # rebase that tries to operate in another repository
  echo content >file
  git add file
  git commit -m file
  git rebase --root -x 'cd ../unrelated && git rev-parse --git-dir'

And in fact, this case behaves the same now or with older versions of Git (because GIT_DIR would be set either way). Likewise the less exotic "git --git-dir=something rebase", which would set GIT_DIR in the environment. I think there are other cases, too, where we'd internally set GIT_DIR during repo discovery, but I don't remember all of them offhand.

So I think the reasoning at the time was along the lines of "scripts already should not be relying on the absence of $GIT_DIR". That said, I do think there's an argument to be made that it generally worked before in many common setups, even if it was not bulletproof.

And I am not sure I could construct a case where setting $GIT_DIR when it was not already set explicitly _helps_ the "exec" command (because if searching from the working tree does not work, then the caller of "git rebase" would had to have set $GIT_DIR itself).

-Peff

← back to recent threads