Re: [PATCH] bisect: allow to run from subdirectories

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

 



On Mon, Jun 21, 2021 at 12:43:32PM +0900, Junio C Hamano wrote:

> Roland Hieber <rhi@xxxxxxxxxxxxxx> writes:
> 
> > Currently, calling 'git bisect' from a directory other than the top
> > level of a repository only comes up with an error message:
> >
> >     You need to run this command from the toplevel of the working tree.
> >
> > After a glance through the bisect code, there seems to be nothing that
> > relies on the current working directory, and a few hours of bisect usage
> > also didn't turn up any problems. Set the appropriate flag for
> > git-sh-setup to remove the error message.
> 
> Try to find a history in which to run a bisect that
> 
>  (1) has a directory T in the recent part of the history, and
> 
>  (2) does not have that directory in the older part of the history.
>      Better yet, if the older part of the history has T as a regular
>      file, that would be ideal.  Even better, if that old regular
>      file T was added, then removed, and then recreated, before it
>      got turned into a directory.
> 
> Now, using the two commits you used to satisfy conditions (1) and
> (2) as "bad" and "good", and using "bad - has T as a directory" and
> "good - does not have T as a directory", as the bisection criterion,
> try to find where "good" turns "bad"---in other words, find the
> commit that either creates T as a directory or turns the regular
> file T into a directory.
> 
> Perform that bisect from the subdirectory T.  Would that work?  I
> suspect it wouldn't; when trying to check out an old version that
> does not have T in the directory, either the checkout would fail
> because it cannot remove T which has an active process (i.e. your
> terminal session) in it, or your process sitting in an orphaned
> directory (i.e. your ".." may still be the original top-level
> directory that used to have T subdirectory, but "cd T" from the
> top-level will not reach where you are).  All sorts of things can
> go wrong and that is why we forbid it.  Just a single "cd" upfront
> would save the user a lot of headache.
> 
> This does not depend on "do we have T as a directory?" being the
> bisection criteria.  The important thing is that the current
> directory would appear and disappear as the bisection process makes
> you jump around in the history.

I think that is a good explanation. But I remain somewhat unconvinced
that it is that big a problem in practice.

There are already other cases where checkout may fail (e.g., an
untracked build artifact in one commit conflicting with a tracked file
in another). E.g., this sequence in git.git:

  # here we build git-remote-testgit from its .sh counterpart
  git checkout 5afb2ce4cd^
  make

  # now imagine our bisect jumps forward; this one drops it from
  # the .gitignore, so its now a precious untracked file
  git checkout 5afb2ce4cd
  make

  # now jump backwards. I'm not sure if this can actually happen in
  # a bisection of git.git, since we went forward then back. But
  # possibly you could hit it in parallel lines of history[1], and
  # certainly a similar history which didn't update ".gitignore" at the
  # same time could run into it.
  git checkout 709a957d9493^

That last command yields:

  error: The following untracked working tree files would be overwritten by checkout:
	git-remote-testgit
  Please move or remove them before you switch branches.
  Aborting

Which is annoying, but it's pretty clear that you need to remove the
file and then re-run your "bisect good" or "bisect bad" (and if we want
to make it more clear, then git-bisect could notice that git-checkout
failed and add extra advice).

And I think any directory typechange shenanigans would end up with a
similar message. It's nice to avoid that ahead of time, but it comes at
the cost of bugging the user to preemptively "cd" to the toplevel _every
time_, even if they are not going to bisect through history where the
directory goes away.

So while I don't disagree with avoiding the confusing case, it seems
like the safety check is overly cautious. (Of course an alternative is
that it could actually examine the history to make sure $PWD never goes
away; I wonder if that would be annoyingly costly or not).

The more interesting case, I think, is when T is simply removed.  If
there are untracked files (even ignored build artifacts) in T, then the
directory sticks around anyway. But if not, Git is able to checkout the
original commit and deletes the directory. And then you get:

  $ cd builtin
  $ git checkout 81b50f3ce40bfdd66e5d967bf82be001039a9a98^
  $ git status
  fatal: Unable to read current working directory: No such file or directory

That's potentially more confusing, as things subtly don't work. But as
shown by the command above, it's not the exclusive domain of bisect.
Perhaps a poorly written bisect-run script could get confused. But it
still doesn't seem to me like it justifies the tradeoff of "we must
never allow bisect from a subdirectory, on the off chance that we might
run into this case".

If we did want try helping the user in this case, we could also diagnose
it pretty easily by confirming that $PWD will be in the destination
commit before checking it out, and complaining otherwise (which turns it
into the earlier case). In fact, regular "checkout" could perhaps do
that, too, as a courtesy (with "-f" overriding).

There may be other corner cases of interest (I didn't think too hard
about weird symlink cases, for example). But overall I think people are
more likely to be annoyed by the "must be at the toplevel" safety valve
than they are by "checkout failed midway through my bisect", if only
because the former happens a lot more frequently.

-Peff

[1] I'm sorry not to have produced a real git-bisect example that causes
    "checkout" to bail. My subjective recollection is that I have run
    into this problem with git-remote-testgit before during real-world
    use, but I'm not 100% sure it was while bisecting, and not simply
    sight-seeing around history.



[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