git-gui: Implement "Stage/Unstage Line"
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
@@ -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
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.