Skip to content

Commit a4fa2f0

Browse files
committed
git-gui: allow undoing last revert
Accidental clicks on the revert hunk/lines buttons can cause loss of work, and can be frustrating. So, allow undoing the last revert. Right now, a stack or deque are not being used for the sake of simplicity, so only one undo is possible. Any reverts before the previous one are lost. Signed-off-by: Pratyush Yadav <[email protected]>
1 parent 2ccdfb1 commit a4fa2f0

File tree

2 files changed

+66
-5
lines changed

2 files changed

+66
-5
lines changed

git-gui.sh

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,8 @@ set is_submodule_diff 0
13501350
set is_conflict_diff 0
13511351
set selected_commit_type new
13521352
set diff_empty_count 0
1353+
set last_revert {}
1354+
set last_revert_enc {}
13531355
13541356
set nullid "0000000000000000000000000000000000000000"
13551357
set nullid2 "0000000000000000000000000000000000000001"
@@ -3601,6 +3603,11 @@ $ctxm add command \
36013603
-command {apply_or_revert_range_or_line $cursorX $cursorY 1; do_rescan}
36023604
set ui_diff_revertline [$ctxm index last]
36033605
lappend diff_actions [list $ctxm entryconf $ui_diff_revertline -state]
3606+
$ctxm add command \
3607+
-label [mc "Undo Last Revert"] \
3608+
-command {undo_last_revert; do_rescan}
3609+
set ui_diff_undorevert [$ctxm index last]
3610+
lappend diff_actions [list $ctxm entryconf $ui_diff_undorevert -state]
36043611
$ctxm add separator
36053612
$ctxm add command \
36063613
-label [mc "Show Less Context"] \
@@ -3680,7 +3687,7 @@ proc has_textconv {path} {
36803687
}
36813688
36823689
proc popup_diff_menu {ctxm ctxmmg ctxmsm x y X Y} {
3683-
global current_diff_path file_states
3690+
global current_diff_path file_states last_revert
36843691
set ::cursorX $x
36853692
set ::cursorY $y
36863693
if {[info exists file_states($current_diff_path)]} {
@@ -3694,6 +3701,7 @@ proc popup_diff_menu {ctxm ctxmmg ctxmsm x y X Y} {
36943701
tk_popup $ctxmsm $X $Y
36953702
} else {
36963703
set has_range [expr {[$::ui_diff tag nextrange sel 0.0] != {}}]
3704+
set u [mc "Undo Last Revert"]
36973705
if {$::ui_index eq $::current_diff_side} {
36983706
set l [mc "Unstage Hunk From Commit"]
36993707
set h [mc "Revert Hunk"]
@@ -3739,12 +3747,20 @@ proc popup_diff_menu {ctxm ctxmmg ctxmsm x y X Y} {
37393747
}
37403748
}
37413749
3750+
if {$last_revert eq {}} {
3751+
set undo_state disabled
3752+
} else {
3753+
set undo_state normal
3754+
}
3755+
37423756
$ctxm entryconf $::ui_diff_applyhunk -state $s -label $l
37433757
$ctxm entryconf $::ui_diff_applyline -state $s -label $t
37443758
$ctxm entryconf $::ui_diff_revertline -state $revert_state \
37453759
-label $r
37463760
$ctxm entryconf $::ui_diff_reverthunk -state $revert_state \
37473761
-label $h
3762+
$ctxm entryconf $::ui_diff_undorevert -state $undo_state \
3763+
-label $u
37483764
37493765
tk_popup $ctxm $X $Y
37503766
}

lib/diff.tcl

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ proc read_diff {fd conflict_size cont_info} {
569569

570570
proc apply_or_revert_hunk {x y revert} {
571571
global current_diff_path current_diff_header current_diff_side
572-
global ui_diff ui_index file_states
572+
global ui_diff ui_index file_states last_revert last_revert_enc
573573

574574
if {$current_diff_path eq {} || $current_diff_header eq {}} return
575575
if {![lock_index apply_hunk]} return
@@ -610,18 +610,25 @@ proc apply_or_revert_hunk {x y revert} {
610610
set e_lno end
611611
}
612612

613+
set wholepatch "$current_diff_header[$ui_diff get $s_lno $e_lno]"
614+
613615
if {[catch {
614616
set enc [get_path_encoding $current_diff_path]
615617
set p [eval git_write $apply_cmd]
616618
fconfigure $p -translation binary -encoding $enc
617-
puts -nonewline $p $current_diff_header
618-
puts -nonewline $p [$ui_diff get $s_lno $e_lno]
619+
puts -nonewline $p $wholepatch
619620
close $p} err]} {
620621
error_popup "$failed_msg\n\n$err"
621622
unlock_index
622623
return
623624
}
624625

626+
if {$revert} {
627+
# Save a copy of this patch for undoing reverts.
628+
set last_revert $wholepatch
629+
set last_revert_enc $enc
630+
}
631+
625632
$ui_diff conf -state normal
626633
$ui_diff delete $s_lno $e_lno
627634
$ui_diff conf -state disabled
@@ -653,7 +660,7 @@ proc apply_or_revert_hunk {x y revert} {
653660

654661
proc apply_or_revert_range_or_line {x y revert} {
655662
global current_diff_path current_diff_header current_diff_side
656-
global ui_diff ui_index file_states
663+
global ui_diff ui_index file_states last_revert
657664

658665
set selected [$ui_diff tag nextrange sel 0.0]
659666

@@ -852,5 +859,43 @@ proc apply_or_revert_range_or_line {x y revert} {
852859
return
853860
}
854861

862+
if {$revert} {
863+
# Save a copy of this patch for undoing reverts.
864+
set last_revert $current_diff_header$wholepatch
865+
set last_revert_enc $enc
866+
}
867+
868+
unlock_index
869+
}
870+
871+
# Undo the last line/hunk reverted. When hunks and lines are reverted, a copy
872+
# of the diff applied is saved. Re-apply that diff to undo the revert.
873+
#
874+
# Right now, we only use a single variable to hold the copy, and not a
875+
# stack/deque for simplicity, so multiple undos are not possible. Maybe this
876+
# can be added if the need for something like this is felt in the future.
877+
proc undo_last_revert {} {
878+
global last_revert current_diff_path current_diff_header
879+
global last_revert_enc
880+
881+
if {$last_revert eq {}} return
882+
if {![lock_index apply_hunk]} return
883+
884+
set apply_cmd {apply --whitespace=nowarn}
885+
set failed_msg [mc "Failed to undo last revert."]
886+
887+
if {[catch {
888+
set enc $last_revert_enc
889+
set p [eval git_write $apply_cmd]
890+
fconfigure $p -translation binary -encoding $enc
891+
puts -nonewline $p $last_revert
892+
close $p} err]} {
893+
error_popup "$failed_msg\n\n$err"
894+
unlock_index
895+
return
896+
}
897+
898+
set last_revert {}
899+
855900
unlock_index
856901
}

0 commit comments

Comments
 (0)