Re: [PATCH v2 07/11] git-gui: try harder to find worktree from gitdir
- From
Johannes Sixt <j6t@kdbg.org>
- Date
- May 23, 2026, 14:06 UTC
- Message-ID
- <a1e9da65-f8dd-4544-bbc9-d3b01328cebe@kdbg.org>
- 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.
Show 54 quoted lines
>
> 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
> <mainrepo>/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 <mlevedahl@gmail.com>
> ---
> 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?
Show 11 quoted lines
> + }
> + }]} {
> + 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.)
Show 28 quoted lines
> + 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