Skip to contentSkip to conversation

git-gui: Implement "Stage/Unstage Line"

PATCH In review Johannes Sixt 2 participants 2 messages Jun 15, 2016 Library code

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 git-gui: Implement "Stage/Unstage Line"

From: Johannes Sixt <[email protected]>

This adds a context menu entry below "Stage/Unstage Hunk" that stages or unstages just the line under the mouse pointer.

This is by itself useful, for example, if there are unrelated changes in the same hunk and the hunk cannot be split by reducing the context.

The feature can also be used to split a hunk by staging a number of additions (or unstaging a number of removals) until there are enough context lines that the hunk gets split.

The implementation reads the complete hunk that the line lives in, and constructs a new hunk by picking existing context lines, removing unneeded change lines and transforming other change lines to context lines. The resulting hunk is fed through 'git apply' just like in the "Stage/Unstage Hunk" case.

---
Disclaimer: I'm Tcl/Tk illiterate. Feel free to munge the patch to your taste.

The 'do_rescan' is probably a bit heavy-weight. But editing the diff window like we do in "Stage Hunk" would be a bit complex, and just redisplaying the diff is easier.

Furthermore, I don't know why I have to do the loop until "end - 1 chars". If it goes until "end", then the hunk contains an extra line, so that the patch in general does not apply. Is there an extra newline in the diff view that is not in the git diff output?

-- Hannes

 git-gui.sh   |    8 +++++
 lib/diff.tcl |   87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+), 0 deletions(-)
git-gui.sh +8 -0
index 1bbae15..d89f156 100755
@@ -2666,6 +2666,11 @@ $ctxm add command \
 	-command {apply_hunk $cursorX $cursorY}
 set ui_diff_applyhunk [$ctxm index last]
 lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state]
+$ctxm add command \
+	-label [mc "Apply/Reverse Line"] \
+	-command {apply_line $cursorX $cursorY; do_rescan}
+set ui_diff_applyline [$ctxm index last]
+lappend diff_actions [list $ctxm entryconf $ui_diff_applyline -state]
 $ctxm add separator
 $ctxm add command \
 	-label [mc "Show Less Context"] \
@@ -2714,8 +2719,10 @@ proc popup_diff_menu {ctxm x y X Y} {
 	set ::cursorY $y
 	if {$::ui_index eq $::current_diff_side} {
 		set l [mc "Unstage Hunk From Commit"]
+		set t [mc "Unstage Line From Commit"]
 	} else {
 		set l [mc "Stage Hunk For Commit"]
+		set t [mc "Stage Line For Commit"]
 	}
 	if {$::is_3way_diff
 		|| $current_diff_path eq {}
@@ -2726,6 +2733,7 @@ proc popup_diff_menu {ctxm x y X Y} {
 		set s normal
 	}
 	$ctxm entryconf $::ui_diff_applyhunk -state $s -label $l
+	$ctxm entryconf $::ui_diff_applyline -state $s -label $t
 	tk_popup $ctxm $X $Y
 }
 bind_button3 $ui_diff [list popup_diff_menu $ctxm %x %y %X %Y]
lib/diff.tcl +87 -0

90 lines not on this page · raw message

Signature · 1 line
1.5.6.918.g8a69
#1 lore raw
Quoted 4 lines · Johannes Sixt

From: Johannes Sixt <[email protected]>

This adds a context menu entry below "Stage/Unstage Hunk" that stages or unstages just the line under the mouse pointer.

Thanks! After some brief testing this is in now my tree on repo.or.cz.

Quoted 2 lines

Disclaimer: I'm Tcl/Tk illiterate. Feel free to munge the patch to your taste.

I wouldn't say illiterate, given this contribution. :)

Quoted 3 lines

The 'do_rescan' is probably a bit heavy-weight. But editing the diff window like we do in "Stage Hunk" would be a bit complex, and just redisplaying the diff is easier.

Yea, I see why you are doing a do_rescan at the end. I was going to suggest just calling reshow_diff but that doesn't get the lists updated properly when a file is being initially staged as a result of the current line being added.

Editing the Tk widget is possible, but it can be a pain.

Quoted 5 lines

Furthermore, I don't know why I have to do the loop until "end - 1 chars". If it goes until "end", then the hunk contains an extra line, so that the patch in general does not apply. Is there an extra newline in the diff view that is not in the git diff output?

Yup. Tk text widgets have an extra "\n" at the end of the content that was inserted into it. Thus an empty text widget has a single LF as its content. Weird, I know.

Signature · 1 line
Shawn.