[PATCH v3 1/1] git-gui: handle missing worktree and separated gitdir
- From
- Shroom Moo <egg_mushroomcow@foxmail.com>
- Date
- Apr 30, 2026, 10:02 UTC
- Message-ID
- <tencent_8A236D9D4A8D8CCA7DAA083157AA8543700A@qq.com>
- In-Reply-To
- <tencent_AEE968E8E785907BA55A383977C8968ED406@qq.com>
When git-gui is started from a directory that Git recognizes as a valid repository but the working tree is not accessible (e.g., a separated gitdir created by `git clone --separate-git-dir`, a bare repository, or a case where the worktree directory was removed), it previously called `rev-parse --show-toplevel` without error handling, causing a fatal Tcl error ("this operation must be run in a work tree").
Wrap the call in a `catch` and handle the failure as follows:
- For bare repositories, keep `_gitworktree` empty so that the existing `is_bare` check shows "Cannot use bare repository" and exits. No behavioral change.
- For non‑bare repositories, try to locate the worktree from the parent directory using `git -C $parent rev-parse --show-toplevel`. If the parent is a valid worktree, change to it; this covers the legitimate case of starting git-gui from within the .git subdirectory of a normal working tree.
- If the parent directory is not a worktree, refuse to start with a clear error message. This prevents dangerous operations in a separated gitdir, where ordinary Git commands like `git status` would themselves refuse to run.
The approach intentionally avoids two pitfalls:
- Testing `--is-inside-git-dir` before calling `--show-toplevel`
would break the normal use case of starting git-gui from within
a .git subdirectory (where --show-toplevel would succeed). - A simple “non‑bare” check after a failed --show-toplevel would
reject a normal repository whose worktree was only temporarily
removed.The chosen method keeps the original behavior for bare repositories and for regular working trees, fixes the crash, and properly blocks separated gitdirs without a reachable worktree.
Signed-off-by: Shroom Moo <egg_mushroomcow@foxmail.com> --- git-gui/git-gui.sh | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 23fe76e498..2392282df3 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1169,7 +1169,28 @@ if {![file isdirectory $_gitdir]} { load_config 0 apply_config -set _gitworktree [git rev-parse --show-toplevel] +if {[catch {set _gitworktree [git rev-parse --show-toplevel]}]} { + # For bare repositories, use the existing error handling + if {![catch {set bare [git rev-parse --is-bare-repository]}] && $bare eq {true}} { + set _gitworktree {} + } else { + # Non-bare: try to find the worktree from the parent directory + set parent [file dirname [pwd]] + # Cannot go higher than the root directory; leave _gitworktree empty + if {[file normalize $parent] eq [file normalize [pwd]]} { + # Already at the filesystem root; let existing paths cope + set _gitworktree {} + } elseif {![catch { + set _gitworktree [git -C $parent rev-parse --show-toplevel] + }]} { + cd $parent + } else { + catch {wm withdraw .} + error_popup [mc "Cannot start git-gui from inside the Git directory."] + exit 1 + } + } +} if {$_prefix ne {}} { if {$_gitworktree eq {}} {
-- 2.52.0.windows.1