From: Johannes Sixt Date: Sat, 23 May 2026 14:06:00 GMT Subject: Re: [PATCH v2 07/11] git-gui: try harder to find worktree from gitdir Message-ID: In-Reply-To: <20260520202411.108764-8-mlevedahl@gmail.com> Am 20.05.26 um 22:24 schrieb Mark Levedahl: > git-gui, since 87cd09f43e ("git-gui: work from the .git dir", > 2010-01-23), has had the intent to allow starting from inside a > repository, then switching to the parent directory if that is a valid > worktree. I can imagine that this kind of use occurs in "Git GUI here" menu item of the file explorer on Windows. So, we should resurrect the feature. > > This certainly hasn't worked since 2d92ab32fd ("rev-parse: make > --show-toplevel without a worktree an error", 2019-11-19) in git, but > breaking this git-gui feature was unintentional. > > There are (at least) 3 cases where the gitdir can tell us where the > worktree is, and we would like all to work: > > - core.worktree is set, and points to a valid worktree. This is already > handled by git rev-parse --show-toplevel, even when not in the worktree. > There is nothing more to do in this case. > > - the gitdir is embedded in a worktree as subdirectory .git. The parent > is (or at least should be) a valid worktree. This worked long ago. > > - the gitdir is a worktree specific directory (under > /worktrees/worktree_name), within which there is a file > "gitdir" pointing to .git in the worktree. git gui never learned to > handle this case. > > Let's handle the latter two cases. Always check that the discovered > worktree is valid and points to the already discovered gitdir according > to git rev-parse. This avoids issues that may arise because we are > discovering from the gitdir up, rather than the worktree down, and file > system non-posix behavior or misconfiguration of git might cause > confusion. For instance, a manually moved worktree might not be where > the gitdir points. > > Signed-off-by: Mark Levedahl > --- > git-gui.sh | 42 ++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 42 insertions(+) > > diff --git a/git-gui.sh b/git-gui.sh > index 8fe25fe188..aeb7ed3548 100755 > --- a/git-gui.sh > +++ b/git-gui.sh > @@ -1100,6 +1100,41 @@ unset argv0dir > ## > ## repository setup > > +proc find_worktree_from_gitdir {} { > + # Directory 'parent' of a repository named 'parent/.git' might be the worktree. > + # Assure parent is a worktree and using the git repository already discovered. > + # Also, handle case of being in a worktree's gitdir, where file "gitdir" points to > + # gitlink file .git in the real worktree. > + set worktree {} > + if {[file tail $::_gitdir] eq {.git}} { > + if {[catch { > + set gitdir_parent [file dirname $::_gitdir] > + set worktree [git -C $gitdir_parent rev-parse --show-toplevel] > + set parent_gitdir [git -C $worktree rev-parse --absolute-git-dir] > + if {$::_gitdir ne $parent_gitdir} { > + set worktree {} I tried to come up with a situation where we end up here, but couldn't. When would this happen? If it actually can't happen, I would prefer to spawn fewer git processes and just take the result of 'file dirname'. If the code must remain, can we please rename one of gitdir_parent or parent_gitdir? > + } > + }]} { > + set worktree {} > + } > + } elseif [file exists {gitdir}] { > + if {[catch { > + set fd_gitdir [open {gitdir} {r}] > + set gitlink_parent [file dirname [read $fd_gitdir]] > + catch {close $fd_gitdir} > + set worktree [git -C $gitlink_parent rev-parse --show-toplevel] > + set parent_gitdir [git -C $worktree rev-parse --absolute-git-dir] Since worktrees can be messed up quite easily, it looks reasonable to check whether the worktree points back to the gitdir. (But I haven't tried to construct a case that passes the check in the next line.) > + if {$::_gitdir ne $parent_gitdir} { > + set worktree {} > + } > + }]} { > + catch {close $fd_gitdir} > + set worktree {} > + } > + } > + return $worktree > +} > + > proc is_gitvars_error {err} { > set havevars 0 > set GIT_DIR {} > @@ -1176,6 +1211,13 @@ if {[catch { > set _prefix {} > } > > +if {[is_bare]} { > + # Maybe we are in an embedded or worktree specific gitdir > + if {[set _gitworktree [find_worktree_from_gitdir]] ne {}} { > + set _prefix {} > + } > +} > + > if {![is_bare]} { > if {[catch { > cd $_gitworktree -- Hannes