git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v7 3/3] git-gui: handle GIT_DIR and GIT_WORK_TREE early

From
SMShroom Moo <egg_mushroomcow@foxmail.com>
Date
May 9, 2026, 13:37 UTC
Message-ID
<tencent_C4AD92361C8D7B76EB4C8A6F14EA33496805@qq.com>
In-Reply-To
<20260509133756.1367-1-egg_mushroomcow@foxmail.com>
Users expect these two invocations to be equivalent:
    GIT_WORK_TREE=/some/path GIT_DIR=/some/path/.git git gui
    git -C /some/path gui

Currently, the environment variable variant often brings up the repository picker or ignores the requested worktree because GIT_WORK_TREE is processed too late. Moreover, after determining the working tree, git-gui unconditionally exports GIT_WORK_TREE. When no worktree is found (e.g., in a bare repository with a read-only subcommand like blame), an empty value is exported, which confuses commands like `git branch --show-current`.

Fix both issues:
- Introduce resolve_initial_environment, which is called before any
  repository detection.  When both GIT_DIR and GIT_WORK_TREE are
  set, it changes to the specified worktree, verifies that it is a
  valid worktree, and adopts the given GIT_DIR.  In this case, the
  subsequent automatic detection is skipped.  After successful
  validation, GIT_WORK_TREE is unset so that later steps do not
  inherit it.  Export the absolute GIT_DIR before changing directory
  to ensure Git commands see the intended repository.
- Introduce set_worktree_env and unset_worktree_env helper procedures
  to safely manage the GIT_WORK_TREE environment variable:
  set_worktree_env sets it only when $_gitworktree is non-empty,
  and unset_worktree_env removes the variable without error.
  Replace all direct manipulations of GIT_WORK_TREE with these
  helpers to avoid accidentally exporting an empty value or
  causing 'unset' errors.
- At the end of startup, use set_worktree_env instead of exporting
  GIT_WORK_TREE unconditionally.  This leaves the variable unset
  when no worktree exists (bare repository), fixing commands that
  would fail with an empty GIT_WORK_TREE.

When only GIT_DIR is set without GIT_WORK_TREE, the existing logic remains unchanged for backward compatibility. Setting only GIT_WORK_TREE is not a valid Git use-case and is silently ignored.

Helped-by: Mark Levedahl <mlevedahl@gmail.com>
Helped-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Shroom Moo <egg_mushroomcow@foxmail.com>
---
 git-gui/git-gui.sh | 103 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 79 insertions(+), 24 deletions(-)
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index ff022c5bbb..1123f9855b 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -1122,25 +1122,82 @@ unset argv0dir
 ##
 ## repository setup
 
+# Safely set/unset GIT_WORK_TREE
+proc set_worktree_env {} {
+    global _gitworktree
+    if {$_gitworktree ne {}} {
+        set ::env(GIT_WORK_TREE) $_gitworktree
+    }
+}
+
+proc unset_worktree_env {} {
+    catch {unset ::env(GIT_WORK_TREE)}
+}
+
+proc resolve_initial_environment {} {
+	global _gitdir env
+
+	# Only act if both GIT_DIR and GIT_WORK_TREE are set
+	if {[info exists env(GIT_DIR)] && [info exists env(GIT_WORK_TREE)]} {
+		# Validate GIT_DIR by resolving its absolute path
+		if {[catch {set _abs [git rev-parse --absolute-git-dir]} err]} {
+			catch {wm withdraw .}
+			error_popup [strcat [mc "Invalid GIT_DIR:"] "\n\n$err"]
+			exit 1
+		}
+		set env(GIT_DIR) $_abs
+
+		# Change current directory to GIT_WORK_TREE
+		if {[catch {cd $env(GIT_WORK_TREE)} err]} {
+			catch {wm withdraw .}
+			error_popup [strcat [mc "Cannot change to GIT_WORK_TREE:"] "\n\n$err"]
+			exit 1
+		}
+
+		# Verify that GIT_WORK_TREE is a valid Git worktree
+		if {[catch {git rev-parse --show-toplevel} err]} {
+			catch {wm withdraw .}
+			error_popup [strcat [mc "GIT_WORK_TREE is not a valid worktree:"] "\n\n$err"]
+			exit 1
+		}
+
+		# Use repository path specified by environment variables
+		set _gitdir $_abs
+		set ::_prefix {}
+
+		# Unset GIT_WORK_TREE to prevent it from being inherited by child processes
+		unset_worktree_env
+
+		return 1
+	}
+
+	# Other cases (only GIT_DIR, only GIT_WORK_TREE, or neither):
+	# Do nothing here and let the existing logic handle it later
+	return 0
+}
+set force_gitdir [resolve_initial_environment]
+
 set picked 0
-if {[catch {
-		set _gitdir $env(GIT_DIR)
-		set _prefix {}
-		}]
-	&& [catch {
-		# beware that from the .git dir this sets _gitdir to .
-		# and _prefix to the empty string; this is handled by
-		# the startup safety checks below
-		set _gitdir [git rev-parse --git-dir]
-		set _prefix [git rev-parse --show-prefix]
-	} err]} {
-	load_config 1
-	apply_config
-	choose_repository::pick
-	if {![file isdirectory $_gitdir]} {
-		exit 1
+if {!$force_gitdir} {
+	if {[catch {
+			set _gitdir $env(GIT_DIR)
+			set _prefix {}
+			}]
+		&& [catch {
+			# beware that from the .git dir this sets _gitdir to .
+			# and _prefix to the empty string; this is handled by
+			# the startup safety checks below
+			set _gitdir [git rev-parse --git-dir]
+			set _prefix [git rev-parse --show-prefix]
+		} err]} {
+		load_config 1
+		apply_config
+		choose_repository::pick
+		if {![file isdirectory $_gitdir]} {
+			exit 1
+		}
+		set picked 1
 	}
-	set picked 1
 }
 
 if {![file isdirectory $_gitdir]} {
@@ -1228,9 +1285,7 @@ if {[lindex $_reponame end] eq {.git}} {
 
 # Export the final paths
 set env(GIT_DIR) $_gitdir
-if {$_gitworktree ne {}} {
-	set env(GIT_WORK_TREE) $_gitworktree
-}
+set_worktree_env
 
 ######################################################################
 ##
@@ -2077,12 +2132,12 @@ proc do_gitk {revs {is_submodule false}} {
 			# 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_worktree_env
 		}
 		safe_exec_bg [concat $cmd $revs "--" "--"]
 
 		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		set_worktree_env
 		cd $pwd
 
 		if {[info exists main_status]} {
@@ -2111,7 +2166,7 @@ proc do_git_gui {} {
 		# 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_worktree_env
 
 		set pwd [pwd]
 		cd $current_diff_path
@@ -2119,7 +2174,7 @@ proc do_git_gui {} {
 		safe_exec_bg [concat $exe gui]
 
 		set env(GIT_DIR) $_gitdir
-		set env(GIT_WORK_TREE) $_gitworktree
+		set_worktree_env
 		cd $pwd
 
 		set status_operation [$::main_status \
-- 
2.52.0.windows.1
Previous: Shroom MooNext: Shroom Moo
Message 32 of 134 in “git-gui: handle bare repo or missing worktree”
  1. git-gui: handle bare repo or missing worktreeShroom Moo, Apr 21, 2026
  2. Johannes SixtApr 29, 2026
  3. 1/1 git-gui: protect rev-parse --show-toplevel callShroom Moo, Apr 29, 2026
  4. Shroom MooApr 29, 2026
  5. Mark LevedahlApr 29, 2026
  6. 1/1 git-gui: handle missing worktree and separated gitdirShroom Moo, Apr 30, 2026
  7. Mark LevedahlApr 30, 2026
  8. Shroom MooMay 1, 2026
  9. 1/1 git-gui: handle missing worktree and separated gitdirShroom Moo, May 1, 2026
  10. Johannes SixtMay 1, 2026
  11. Mark LevedahlMay 1, 2026
  12. Mark LevedahlMay 2, 2026
  13. Johannes SixtMay 3, 2026
  14. 1/1 git-gui: restructure repository startupShroom Moo, May 4, 2026
  15. Mark LevedahlMay 4, 2026
  16. Mark LevedahlMay 5, 2026
  17. Johannes SixtMay 6, 2026
  18. Johannes SixtMay 6, 2026
  19. Mark LevedahlMay 6, 2026
  20. Johannes SixtMay 6, 2026
  21. Mark LevedahlMay 6, 2026
  22. 0/3 git-gui: robustify startup and fix environment handlingShroom Moo, May 6, 2026
  23. 2/3 git-gui: disable gitk visualization when no worktree availableShroom Moo, May 6, 2026
  24. 1/3 git-gui: restructure repository startupShroom Moo, May 6, 2026
  25. 3/3 git-gui: handle GIT_DIR and GIT_WORK_TREE earlyShroom Moo, May 6, 2026
  26. Mark LevedahlMay 7, 2026
  27. Mark LevedahlMay 7, 2026
  28. Aina BootMay 9, 2026
  29. Shroom MooMay 9, 2026
  30. 0/3 git-gui: robustify startup and fix environment handlingShroom Moo, May 9, 2026
  31. 1/3 git-gui: restructure repository startupShroom Moo, May 9, 2026
  32. 3/3 git-gui: handle GIT_DIR and GIT_WORK_TREE earlyShroom Moo, May 9, 2026
  33. 2/3 git-gui: disable gitk visualization when no worktree availableShroom Moo, May 9, 2026
  34. Mark LevedahlMay 14, 2026
  35. 00/11 Improve git gui operation without a worktreeMark Levedahl, May 14, 2026
  36. 01/11 git-gui: allow specifying path '.' to the browserMark Levedahl, May 14, 2026
  37. 02/11 git-gui: refactor browser / blame argument parsingMark Levedahl, May 14, 2026
  38. 04/11 git-gui: put choose_repository::pick in a procMark Levedahl, May 14, 2026
  39. 05/11 git-gui: use --absolute-git-dirMark Levedahl, May 14, 2026
  40. 03/11 git-gui: guard set/unset of GIT_DIR and GIT_WORK_TREEMark Levedahl, May 14, 2026
  41. 06/11 git gui: GIT_DIR / GIT_WORK_TREE make any discovery error fatalMark Levedahl, May 14, 2026
  42. 07/11 git-gui: use rev-parse exclusively to find a repositoryMark Levedahl, May 14, 2026
  43. 08/11 git-gui: simplify [is_bare] to report if a worktree is knownMark Levedahl, May 14, 2026
  44. 09/11 git-gui: support using repository parent dir as a worktreeMark Levedahl, May 14, 2026
  45. 10/11 git-gui: improve worktree discoveryMark Levedahl, May 14, 2026
  46. 11/11 git-gui: add gui and pick as explicit subcommandsMark Levedahl, May 14, 2026
  47. Johannes SixtMay 15, 2026
  48. Johannes SixtMay 15, 2026
  49. Johannes SixtMay 15, 2026
  50. Aina BootMay 15, 2026
  51. Mark LevedahlMay 15, 2026
  52. Johannes SixtMay 15, 2026
  53. Johannes SixtMay 15, 2026
  54. Johannes SixtMay 15, 2026
  55. Johannes SixtMay 15, 2026
  56. Johannes SixtMay 15, 2026
  57. Johannes SixtMay 15, 2026
  58. Johannes SixtMay 16, 2026
  59. Johannes SixtMay 16, 2026
  60. Johannes SixtMay 16, 2026
  61. Johannes SixtMay 16, 2026
  62. Johannes SixtMay 16, 2026
  63. Mark LevedahlMay 16, 2026
  64. Mark LevedahlMay 16, 2026
  65. Mark LevedahlMay 16, 2026
  66. Mark LevedahlMay 16, 2026
  67. Mark LevedahlMay 16, 2026
  68. Mark LevedahlMay 16, 2026
  69. Mark LevedahlMay 16, 2026
  70. Mark LevedahlMay 16, 2026
  71. Mark LevedahlMay 16, 2026
  72. Johannes SixtMay 19, 2026
  73. Johannes SixtMay 19, 2026
  74. Mark LevedahlMay 19, 2026
  75. Mark LevedahlMay 19, 2026
  76. Johannes SixtMay 19, 2026
  77. 00/11 Improve git gui operation without a worktreeMark Levedahl, May 20, 2026
  78. 01/11 git-gui: guard set/unset of GIT_DIR and GIT_WORK_TREEMark Levedahl, May 20, 2026
  79. 02/11 git-gui: return status from choose_repository::pickMark Levedahl, May 20, 2026
  80. 04/11 git-gui: use rev-parse exclusively to find a repositoryMark Levedahl, May 20, 2026
  81. 05/11 git-gui: simplify [is_bare] to report if a worktree is knownMark Levedahl, May 20, 2026
  82. 06/11 git-gui: use git rev-parse for worktree discoveryMark Levedahl, May 20, 2026
  83. 07/11 git-gui: try harder to find worktree from gitdirMark Levedahl, May 20, 2026
  84. 03/11 git-gui: use --absolute-git-dirMark Levedahl, May 20, 2026
  85. 08/11 git-gui: use HEAD as current branch when detached (bug fix)Mark Levedahl, May 20, 2026
  86. 09/11 git-gui: allow specifying path '.' to the browserMark Levedahl, May 20, 2026
  87. 10/11 git-gui: adapt blame/browser parsing for bare operationMark Levedahl, May 20, 2026
  88. 11/11 git-gui: add gui and pick as explicit subcommandsMark Levedahl, May 20, 2026
  89. Shroom MooMay 21, 2026
  90. Shroom MooMay 21, 2026
  91. Mark LevedahlMay 21, 2026
  92. Mark LevedahlMay 21, 2026
  93. Johannes SixtMay 22, 2026
  94. Johannes SixtMay 22, 2026
  95. Johannes SixtMay 22, 2026
  96. Johannes SixtMay 22, 2026
  97. Mark LevedahlMay 22, 2026
  98. Mark LevedahlMay 22, 2026
  99. Shroom MooMay 22, 2026
  100. Shroom MooMay 22, 2026
  101. Mark LevedahlMay 22, 2026
  102. Mark LevedahlMay 22, 2026
  103. Johannes SixtMay 23, 2026
  104. Johannes SixtMay 23, 2026
  105. Aina BootMay 23, 2026
  106. Shroom MooMay 23, 2026
  107. Johannes SixtMay 23, 2026
  108. Johannes SixtMay 23, 2026
  109. Johannes SixtMay 23, 2026
  110. Johannes SixtMay 23, 2026
  111. Mark LevedahlMay 23, 2026
  112. Mark LevedahlMay 23, 2026
  113. Mark LevedahlMay 23, 2026
  114. fixup git-gui: allow blame to show uncommitted changesMark Levedahl, May 23, 2026
  115. Johannes SixtMay 23, 2026
  116. Johannes SixtMay 24, 2026
  117. Johannes SixtMay 24, 2026
  118. Mark LevedahlMay 25, 2026
  119. 00/12 Improve git gui operation without a worktreeMark Levedahl, May 31, 2026
  120. 01/12 git-gui: use HEAD as current branch when detachedMark Levedahl, May 31, 2026
  121. 02/12 git-gui: remove unnecessary 'cd $_gitworktree' from do_gitkMark Levedahl, May 31, 2026
  122. 03/12 git-gui: guard set/unset of GIT_DIR and GIT_WORK_TREEMark Levedahl, May 31, 2026
  123. 04/12 git-gui: do not change global vars in choose_repository::pickMark Levedahl, May 31, 2026
  124. 05/12 git-gui: use --absolute-git-dirMark Levedahl, May 31, 2026
  125. 06/12 git-gui: use rev-parse exclusively to find a repositoryMark Levedahl, May 31, 2026
  126. 07/12 git-gui: use git rev-parse for worktree discoveryMark Levedahl, May 31, 2026
  127. 08/12 git-gui: simplify [is_bare] to report if a worktree is knownMark Levedahl, May 31, 2026
  128. 09/12 git-gui: try harder to find worktree from gitdirMark Levedahl, May 31, 2026
  129. 10/12 git-gui: allow specifying path '.' to the browserMark Levedahl, May 31, 2026
  130. 11/12 git-gui: check browser/blame arguments carefullyMark Levedahl, May 31, 2026
  131. 12/12 git-gui: add gui and pick as explicit subcommandsMark Levedahl, May 31, 2026
  132. Johannes SixtJun 2, 2026
  133. Mark LevedahlJun 2, 2026
  134. Johannes SixtJun 2, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.