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>
This commit is contained in:
Mark Levedahl
2026-05-31 19:02:16 -04:00
committed by Johannes Sixt
parent a7e5d89203
commit d4800b7a6e

View File

@@ -1125,6 +1125,20 @@ unset argv0dir
##
## repository setup
proc set_gitdir_vars {} {
global _gitdir _gitworktree env
set env(GIT_DIR) $_gitdir
if {$_gitworktree ne {}} {
set env(GIT_WORK_TREE) $_gitworktree
}
}
proc unset_gitdir_vars {} {
global env
catch {unset env(GIT_DIR)}
catch {unset env(GIT_WORK_TREE)}
}
set picked 0
if {[catch {
set _gitdir $env(GIT_DIR)
@@ -1210,8 +1224,8 @@ if {[lindex $_reponame end] eq {.git}} {
set _reponame [lindex $_reponame end]
}
set env(GIT_DIR) $_gitdir
set env(GIT_WORK_TREE) $_gitworktree
# Export the final paths
set_gitdir_vars
######################################################################
##
@@ -2010,7 +2024,6 @@ proc incr_font_size {font {amt 1}} {
proc do_gitk {revs {is_submodule false}} {
global current_diff_path file_states current_diff_side ui_index
global _gitdir _gitworktree
# -- Always start gitk through whatever we were loaded with. This
# lets us bypass using shell process on Windows systems.
@@ -2020,8 +2033,6 @@ proc do_gitk {revs {is_submodule false}} {
if {$exe eq {}} {
error_popup [mc "Couldn't find gitk in PATH"]
} else {
global env
set pwd [pwd]
if {$is_submodule} {
@@ -2049,13 +2060,11 @@ proc do_gitk {revs {is_submodule false}} {
# TODO we could make life easier (start up faster?) for gitk
# by setting these to the appropriate values to allow gitk
# to skip the heuristics to find their proper value
unset env(GIT_DIR)
unset env(GIT_WORK_TREE)
unset_gitdir_vars
}
safe_exec_bg [concat $cmd $revs "--" "--"]
set env(GIT_DIR) $_gitdir
set env(GIT_WORK_TREE) $_gitworktree
set_gitdir_vars
cd $pwd
if {[info exists main_status]} {
@@ -2078,21 +2087,16 @@ proc do_git_gui {} {
if {$exe eq {}} {
error_popup [mc "Couldn't find git gui in PATH"]
} else {
global env
global _gitdir _gitworktree
# see note in do_gitk about unsetting these vars when
# running tools in a submodule
unset env(GIT_DIR)
unset env(GIT_WORK_TREE)
unset_gitdir_vars
set pwd [pwd]
cd $current_diff_path
safe_exec_bg [concat $exe gui]
set env(GIT_DIR) $_gitdir
set env(GIT_WORK_TREE) $_gitworktree
set_gitdir_vars
cd $pwd
set status_operation [$::main_status \