git-gui: guard set/unset of GIT_DIR and GIT_WORK_TREE

git-gui unconditionally exports _gitdir as GIT_DIR, and _gitworktree as GIT_WORK_TREE, to the environment, and unconditionally unsets these environment variables before invoking gitk or git-gui when a submodule is involved. This export happens even if _gitworktree is empty, which happens when running from a bare repository. However, exporting GIT_WORK_TREE as empty is never valid, and causes errors in git. GIT_DIR must be exported if the repository is not discoverable from the worktree (or current directory if there is no worktree). The user might have configured this. If there is a worktree, git-gui makes this the current directory. However, if the repository sets core.worktree, this value can only be overridden by GIT_WORK_TREE so the latter must be exported. As we cannot eliminate conditions where either variable is needed, let's implement a pair of functions to set / unset these variables without error, and without ever exporting an empty GIT_WORK_TREE. 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 d4800b7a6e8eef7de8c419ffc55c631c62a902de
1 file changed +20 -16
git-gui.sh
+20 -16
@@ -1125,6 +1125,20 @@ unset argv0dir
1125 ##
1126 ## repository setup
1127
1128 +proc set_gitdir_vars {} {
1129 + global _gitdir _gitworktree env
1130 + set env(GIT_DIR) $_gitdir
1131 + if {$_gitworktree ne {}} {
1132 + set env(GIT_WORK_TREE) $_gitworktree
1133 + }
1134 +}
1135 +
1136 +proc unset_gitdir_vars {} {
1137 + global env
1138 + catch {unset env(GIT_DIR)}
1139 + catch {unset env(GIT_WORK_TREE)}
1140 +}
1141 +
1142 set picked 0
1143 if {[catch {
1144 set _gitdir $env(GIT_DIR)
@@ -1210,8 +1224,8 @@ if {[lindex $_reponame end] eq {.git}} {
1224 set _reponame [lindex $_reponame end]
1225 }
1226
1213 -set env(GIT_DIR) $_gitdir
1214 -set env(GIT_WORK_TREE) $_gitworktree
1227 +# Export the final paths
1228 +set_gitdir_vars
1229
1230 ######################################################################
1231 ##
@@ -2010,7 +2024,6 @@ proc incr_font_size {font {amt 1}} {
2024
2025 proc do_gitk {revs {is_submodule false}} {
2026 global current_diff_path file_states current_diff_side ui_index
2013 - global _gitdir _gitworktree
2027
2028 # -- Always start gitk through whatever we were loaded with. This
2029 # lets us bypass using shell process on Windows systems.
@@ -2020,8 +2033,6 @@ proc do_gitk {revs {is_submodule false}} {
2033 if {$exe eq {}} {
2034 error_popup [mc "Couldn't find gitk in PATH"]
2035 } else {
2023 - global env
2024 -
2036 set pwd [pwd]
2037
2038 if {$is_submodule} {
@@ -2049,13 +2060,11 @@ proc do_gitk {revs {is_submodule false}} {
2060 # TODO we could make life easier (start up faster?) for gitk
2061 # by setting these to the appropriate values to allow gitk
2062 # to skip the heuristics to find their proper value
2052 - unset env(GIT_DIR)
2053 - unset env(GIT_WORK_TREE)
2063 + unset_gitdir_vars
2064 }
2065 safe_exec_bg [concat $cmd $revs "--" "--"]
2066
2057 - set env(GIT_DIR) $_gitdir
2058 - set env(GIT_WORK_TREE) $_gitworktree
2067 + set_gitdir_vars
2068 cd $pwd
2069
2070 if {[info exists main_status]} {
@@ -2078,21 +2087,16 @@ proc do_git_gui {} {
2087 if {$exe eq {}} {
2088 error_popup [mc "Couldn't find git gui in PATH"]
2089 } else {
2081 - global env
2082 - global _gitdir _gitworktree
2083 -
2090 # see note in do_gitk about unsetting these vars when
2091 # running tools in a submodule
2086 - unset env(GIT_DIR)
2087 - unset env(GIT_WORK_TREE)
2092 + unset_gitdir_vars
2093
2094 set pwd [pwd]
2095 cd $current_diff_path
2096
2097 safe_exec_bg [concat $exe gui]
2098
2094 - set env(GIT_DIR) $_gitdir
2095 - set env(GIT_WORK_TREE) $_gitworktree
2099 + set_gitdir_vars
2100 cd $pwd
2101
2102 set status_operation [$::main_status \