git-gui: use git rev-parse for worktree discovery

git gui uses a combination of tcl code and git invocations to determine the worktree and the location with respect to the worktree root (_prefix). But, git rev-parse provides all of this information directly, and assures full error and configuration checking are done by git itself. The entirety of discovery in normal configurations involves git rev-parse --show-toplevel (gets worktree root) git rev-parse --show-prefix (shows location wrt the root) An error thrown on either of these lines means the worktree discovered by git is unusable, or git did not discover a worktree because the current directory is inside the repository. If the user has defined GIT_DIR or GIT_WORK_TREE, this is a user configuration error and git-gui should stop. Otherwise, the blame or browser subcommands can be used without a worktree. A separate error might occur when changing to the root of the discovered worktree. The cause would be file system related and completely outside of git's control, so trap that independently. Discovery of the repository and the worktree must be guarded to trap errors: the intent is that any configuration problems are caught during discovery, and later processing need not include error trapping and recovery. So, move all worktree discovery code to be immediately after repository discovery. This does move configuration loading to occur after worktree discovery rather than before. None of the code executed in worktree discovery has any option controlled by a git-gui configuration variable, so no impact is expected. git itself will always read the repository configuration, including worktree specific configuration data if that exists, so this is unaffected by when git-gui loads its own config data. Also, we cannot be sure the worktree dependent configuration can be loaded before full discovery is complete. Signed-off-by: Mark Levedahl <mlevedahl@gmail.com> Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Mark Levedahl committed May 31, 2026 at 19:02 UTC 80b7207e68ffaf56077d9b7d00eb31490fb48cc5
1 file changed +27 -34
git-gui.sh
+27 -34
@@ -1187,6 +1187,33 @@ if {$_gitdir eq {}} {
1187 set picked 1
1188 }
1189
1190 +# find worktree, continue without if not required
1191 +if {[catch {
1192 + set _gitworktree [git rev-parse --show-toplevel]
1193 + set _prefix [git rev-parse --show-prefix]
1194 + } err]} {
1195 + if {[is_gitvars_error $err]} {
1196 + exit 1
1197 + }
1198 + set _gitworktree {}
1199 + set _prefix {}
1200 +}
1201 +
1202 +if {![is_bare]} {
1203 + if {[catch {cd $_gitworktree} err]} {
1204 + catch {wm withdraw .}
1205 + error_popup [strcat [mc "No working directory"] " $_gitworktree:\n\n$err"]
1206 + exit 1
1207 + }
1208 +} elseif {![is_enabled bare]} {
1209 + catch {wm withdraw .}
1210 + error_popup [strcat [mc "Cannot use bare repository:"] "\n\n$_gitdir"]
1211 + exit 1
1212 +}
1213 +
1214 +# repository and worktree config are complete, export them
1215 +set_gitdir_vars
1216 +
1217 # Use object format as hash algorithm (either "sha1" or "sha256")
1218 set hashalgorithm [git rev-parse --show-object-format]
1219 if {$hashalgorithm eq "sha1"} {
@@ -1202,37 +1229,6 @@ if {$hashalgorithm eq "sha1"} {
1229 load_config 0
1230 apply_config
1231
1205 -set _gitworktree [git rev-parse --show-toplevel]
1206 -
1207 -if {$_prefix ne {}} {
1208 - if {$_gitworktree eq {}} {
1209 - regsub -all {[^/]+/} $_prefix ../ cdup
1210 - } else {
1211 - set cdup $_gitworktree
1212 - }
1213 - if {[catch {cd $cdup} err]} {
1214 - catch {wm withdraw .}
1215 - error_popup [strcat [mc "Cannot move to top of working directory:"] "\n\n$err"]
1216 - exit 1
1217 - }
1218 - set _gitworktree [pwd]
1219 - unset cdup
1220 -} elseif {![is_enabled bare]} {
1221 - if {[is_bare]} {
1222 - catch {wm withdraw .}
1223 - error_popup [strcat [mc "Cannot use bare repository:"] "\n\n$_gitdir"]
1224 - exit 1
1225 - }
1226 - if {$_gitworktree eq {}} {
1227 - set _gitworktree [file dirname $_gitdir]
1228 - }
1229 - if {[catch {cd $_gitworktree} err]} {
1230 - catch {wm withdraw .}
1231 - error_popup [strcat [mc "No working directory"] " $_gitworktree:\n\n$err"]
1232 - exit 1
1233 - }
1234 - set _gitworktree [pwd]
1235 -}
1232 set _reponame [file split [file normalize $_gitdir]]
1233 if {[lindex $_reponame end] eq {.git}} {
1234 set _reponame [lindex $_reponame end-1]
@@ -1240,9 +1236,6 @@ if {[lindex $_reponame end] eq {.git}} {
1236 set _reponame [lindex $_reponame end]
1237 }
1238
1243 -# Export the final paths
1244 -set_gitdir_vars
1245 -
1239 ######################################################################
1240 ##
1241 ## global init