Subject: [PATCH] fixup git-gui: allow blame to show uncommitted changes

From: Mark Levedahl <[email-masked]>
Date: Sat, 23 May 2026 14:19:50 -0400

Commit a0db0d61fb ("git-gui: Generate blame on uncommitted working tree
file", 2007-05-08) added ability for git-gui's blame to use uncommited
content in the worktree in the blame display. The specific mechanism
that allows this is passing head as {} to the blame constructor, and this
mode is enabled by specifying no head, which means the current branch is
used, and no swapping of head / path is possible. Path checking looks for the
path existing in the currently checked out branch, so files unknown to
git cannot be blamed. This mirrors git blame behavior. Both now will

    use the worktree contents of the file $path as the basis for blame,
        including showing an empty blame if the file exists and is empty.
    error if $path is remove from the worktree, even if it exists on the
          current branch.

The latter behavior is a change: before this patch, git-gui will show
the unknown file in its entirety with no annotations. The new behavior,
following git blame, reports that git knows nothing about the file.

Signed-off-by: Mark Levedahl <[email-masked]>
---
This patch will be squashed into 0011 in a v3, or kept separate. The
comment in patch 11 saying blame's use of the worktree is unaffected
is wrong, this fixes blame to do exactly what git-blame does with
worktree content. Slightly different than what git-gui did before
regarding unknown files, but I think git-blame's approach is correct.

 git-gui.sh | 29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/git-gui.sh b/git-gui.sh
index ae609f86f1..114511974a 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -3084,11 +3084,16 @@ blame {
 		}
 	}
 
-	# no swapping allowed if head not given, use current branch (HEAD)
+	# If head not given, use current branch (HEAD), no swapping allowed,
+	# and blame may use the worktree file content.
+	set use_worktree 0
 	if {$head eq {}} {
 		load_current_branch
 		set head $current_branch
 		set canswap 0
+		if {$subcommand eq {blame} && ![is_bare]} {
+			set use_worktree 1
+		}
 	}
 
 	# -- before "rev" arg means we got -- path head
@@ -3098,7 +3103,16 @@ blame {
 		set canswap 0
 	}
 
-	set objtype [find_path_type $head $path]
+	if {$use_worktree} {
+		if {[file isfile $path]} {
+			set objtype {blob}
+		} else {
+			set objtype {}
+		}
+	} else {
+		set objtype [find_path_type $head $path]
+	}
+
 	if {$objtype eq {} && $canswap} {
 		set objtype [find_path_type $althead $altpath]
 		if {$objtype ne {}} {
@@ -3108,7 +3122,7 @@ blame {
 	}
 	set current_branch $head
 
-	# check that path exists in head, and objtype matches need
+	# check objtype matches need
 	if {$objtype ne $required_objtype} {
 		switch -- $required_objtype {
 			tree {set err [strcat \
@@ -3130,8 +3144,13 @@ blame {
 	browser {
 		browser::new $head $path
 	}
-	blame {
-		blame::new $head $path $jump_spec
+
+	blame   {
+		if {$use_worktree} {
+			blame::new {} $path $jump_spec
+		} else {
+			blame::new $head $path $jump_spec
+		}
 	}
 	}
 	return
-- 
2.54.0.99.14