git-gui: Support resolving conflicts via the diff context menu.
If the file has merge conflicts, show a special version of the diff context menu, which includes conflict resolution commands instead of Stage Hunk/Line. This patch only supports resolving by discarding all sides except one. Discarding is the only way to resolve conflicts involving symlinks and/or deletion, excluding manual editing. Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Alexander Gavrilov committed
Aug 31, 2008 at 00:55 UTC
042c232535c329f168e8a515588f38a4117954fb
2 files changed
+190
-60
git-gui.sh
+92
-60
@@ -2713,6 +2713,51 @@ $ui_diff tag raise sel
2713
2714
# -- Diff Body Context Menu
2715
#
2716
+
2717
+proc create_common_diff_popup {ctxm} {
2718
+ $ctxm add command \
2719
+ -label [mc "Show Less Context"] \
2720
+ -command show_less_context
2721
+ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2722
+ $ctxm add command \
2723
+ -label [mc "Show More Context"] \
2724
+ -command show_more_context
2725
+ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2726
+ $ctxm add separator
2727
+ $ctxm add command \
2728
+ -label [mc Refresh] \
2729
+ -command reshow_diff
2730
+ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2731
+ $ctxm add command \
2732
+ -label [mc Copy] \
2733
+ -command {tk_textCopy $ui_diff}
2734
+ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2735
+ $ctxm add command \
2736
+ -label [mc "Select All"] \
2737
+ -command {focus $ui_diff;$ui_diff tag add sel 0.0 end}
2738
+ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2739
+ $ctxm add command \
2740
+ -label [mc "Copy All"] \
2741
+ -command {
2742
+ $ui_diff tag add sel 0.0 end
2743
+ tk_textCopy $ui_diff
2744
+ $ui_diff tag remove sel 0.0 end
2745
+ }
2746
+ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2747
+ $ctxm add separator
2748
+ $ctxm add command \
2749
+ -label [mc "Decrease Font Size"] \
2750
+ -command {incr_font_size font_diff -1}
2751
+ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2752
+ $ctxm add command \
2753
+ -label [mc "Increase Font Size"] \
2754
+ -command {incr_font_size font_diff 1}
2755
+ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2756
+ $ctxm add separator
2757
+ $ctxm add command -label [mc "Options..."] \
2758
+ -command do_options
2759
+}
2760
+
2761
set ctxm .vpane.lower.diff.body.ctxm
2762
menu $ctxm -tearoff 0
2763
$ctxm add command \
@@ -2726,73 +2771,60 @@ $ctxm add command \
2771
set ui_diff_applyline [$ctxm index last]
2772
lappend diff_actions [list $ctxm entryconf $ui_diff_applyline -state]
2773
$ctxm add separator
2729
-$ctxm add command \
2730
- -label [mc "Show Less Context"] \
2731
- -command show_less_context
2732
-lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2733
-$ctxm add command \
2734
- -label [mc "Show More Context"] \
2735
- -command show_more_context
2736
-lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2737
-$ctxm add separator
2738
-$ctxm add command \
2739
- -label [mc Refresh] \
2740
- -command reshow_diff
2741
-lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2742
-$ctxm add command \
2743
- -label [mc Copy] \
2744
- -command {tk_textCopy $ui_diff}
2745
-lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2746
-$ctxm add command \
2747
- -label [mc "Select All"] \
2748
- -command {focus $ui_diff;$ui_diff tag add sel 0.0 end}
2749
-lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2750
-$ctxm add command \
2751
- -label [mc "Copy All"] \
2752
- -command {
2753
- $ui_diff tag add sel 0.0 end
2754
- tk_textCopy $ui_diff
2755
- $ui_diff tag remove sel 0.0 end
2756
- }
2757
-lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2758
-$ctxm add separator
2759
-$ctxm add command \
2760
- -label [mc "Decrease Font Size"] \
2761
- -command {incr_font_size font_diff -1}
2762
-lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2763
-$ctxm add command \
2764
- -label [mc "Increase Font Size"] \
2765
- -command {incr_font_size font_diff 1}
2766
-lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
2767
-$ctxm add separator
2768
-$ctxm add command -label [mc "Options..."] \
2769
- -command do_options
2770
-proc popup_diff_menu {ctxm x y X Y} {
2774
+create_common_diff_popup $ctxm
2775
+
2776
+set ctxmmg .vpane.lower.diff.body.ctxmmg
2777
+menu $ctxmmg -tearoff 0
2778
+$ctxmmg add command \
2779
+ -label [mc "Use Remote Version"] \
2780
+ -command {merge_resolve_one 3}
2781
+lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state]
2782
+$ctxmmg add command \
2783
+ -label [mc "Use Local Version"] \
2784
+ -command {merge_resolve_one 2}
2785
+lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state]
2786
+$ctxmmg add command \
2787
+ -label [mc "Revert To Base"] \
2788
+ -command {merge_resolve_one 1}
2789
+lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state]
2790
+$ctxmmg add separator
2791
+create_common_diff_popup $ctxmmg
2792
+
2793
+proc popup_diff_menu {ctxm ctxmmg x y X Y} {
2794
global current_diff_path file_states
2795
set ::cursorX $x
2796
set ::cursorY $y
2774
- if {$::ui_index eq $::current_diff_side} {
2775
- set l [mc "Unstage Hunk From Commit"]
2776
- set t [mc "Unstage Line From Commit"]
2797
+ if {[info exists file_states($current_diff_path)]} {
2798
+ set state [lindex $file_states($current_diff_path) 0]
2799
} else {
2778
- set l [mc "Stage Hunk For Commit"]
2779
- set t [mc "Stage Line For Commit"]
2780
- }
2781
- if {$::is_3way_diff
2782
- || $current_diff_path eq {}
2783
- || ![info exists file_states($current_diff_path)]
2784
- || {_O} eq [lindex $file_states($current_diff_path) 0]
2785
- || {_T} eq [lindex $file_states($current_diff_path) 0]
2786
- || {T_} eq [lindex $file_states($current_diff_path) 0]} {
2787
- set s disabled
2800
+ set state {__}
2801
+ }
2802
+ if {[string index $state 0] eq {U}} {
2803
+ tk_popup $ctxmmg $X $Y
2804
} else {
2789
- set s normal
2805
+ if {$::ui_index eq $::current_diff_side} {
2806
+ set l [mc "Unstage Hunk From Commit"]
2807
+ set t [mc "Unstage Line From Commit"]
2808
+ } else {
2809
+ set l [mc "Stage Hunk For Commit"]
2810
+ set t [mc "Stage Line For Commit"]
2811
+ }
2812
+ if {$::is_3way_diff
2813
+ || $current_diff_path eq {}
2814
+ || {__} eq $state
2815
+ || {_O} eq $state
2816
+ || {_T} eq $state
2817
+ || {T_} eq $state} {
2818
+ set s disabled
2819
+ } else {
2820
+ set s normal
2821
+ }
2822
+ $ctxm entryconf $::ui_diff_applyhunk -state $s -label $l
2823
+ $ctxm entryconf $::ui_diff_applyline -state $s -label $t
2824
+ tk_popup $ctxm $X $Y
2825
}
2791
- $ctxm entryconf $::ui_diff_applyhunk -state $s -label $l
2792
- $ctxm entryconf $::ui_diff_applyline -state $s -label $t
2793
- tk_popup $ctxm $X $Y
2826
}
2795
-bind_button3 $ui_diff [list popup_diff_menu $ctxm %x %y %X %Y]
2827
+bind_button3 $ui_diff [list popup_diff_menu $ctxm $ctxmmg %x %y %X %Y]
2828
2829
# -- Status Bar
2830
#
lib/mergetool.tcl
new
+98
@@ -0,0 +1,98 @@
1
+# git-gui merge conflict resolution
2
+# parts based on git-mergetool (c) 2006 Theodore Y. Ts'o
3
+
4
+proc merge_resolve_one {stage} {
5
+ global current_diff_path
6
+
7
+ switch -- $stage {
8
+ 1 { set target [mc "the base version"] }
9
+ 2 { set target [mc "this branch"] }
10
+ 3 { set target [mc "the other branch"] }
11
+ }
12
+
13
+ set op_question [mc "Force resolution to %s?
14
+Note that the diff shows only conflicting changes.
15
+
16
+%s will be overwritten.
17
+
18
+This operation can be undone only by restarting the merge." \
19
+ $target [short_path $current_diff_path]]
20
+
21
+ if {[ask_popup $op_question] eq {yes}} {
22
+ merge_load_stages $current_diff_path [list merge_force_stage $stage]
23
+ }
24
+}
25
+
26
+proc merge_add_resolution {path} {
27
+ global current_diff_path
28
+
29
+ if {$path eq $current_diff_path} {
30
+ set after {reshow_diff;}
31
+ } else {
32
+ set after {}
33
+ }
34
+
35
+ update_index \
36
+ [mc "Adding resolution for %s" [short_path $path]] \
37
+ [list $path] \
38
+ [concat $after [list ui_ready]]
39
+}
40
+
41
+proc merge_force_stage {stage} {
42
+ global current_diff_path merge_stages
43
+
44
+ if {$merge_stages($stage) ne {}} {
45
+ git checkout-index -f --stage=$stage -- $current_diff_path
46
+ } else {
47
+ file delete -- $current_diff_path
48
+ }
49
+
50
+ merge_add_resolution $current_diff_path
51
+}
52
+
53
+proc merge_load_stages {path cont} {
54
+ global merge_stages_fd merge_stages merge_stages_buf
55
+
56
+ if {[info exists merge_stages_fd]} {
57
+ catch { kill_file_process $merge_stages_fd }
58
+ catch { close $merge_stages_fd }
59
+ }
60
+
61
+ set merge_stages(0) {}
62
+ set merge_stages(1) {}
63
+ set merge_stages(2) {}
64
+ set merge_stages(3) {}
65
+ set merge_stages_buf {}
66
+
67
+ set merge_stages_fd [eval git_read ls-files -u -z -- $path]
68
+
69
+ fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary
70
+ fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont]
71
+}
72
+
73
+proc read_merge_stages {fd cont} {
74
+ global merge_stages_buf merge_stages_fd merge_stages
75
+
76
+ append merge_stages_buf [read $fd]
77
+ set pck [split $merge_stages_buf "\0"]
78
+ set merge_stages_buf [lindex $pck end]
79
+
80
+ if {[eof $fd] && $merge_stages_buf ne {}} {
81
+ lappend pck {}
82
+ set merge_stages_buf {}
83
+ }
84
+
85
+ foreach p [lrange $pck 0 end-1] {
86
+ set fcols [split $p "\t"]
87
+ set cols [split [lindex $fcols 0] " "]
88
+ set stage [lindex $cols 2]
89
+
90
+ set merge_stages($stage) [lrange $cols 0 1]
91
+ }
92
+
93
+ if {[eof $fd]} {
94
+ close $fd
95
+ unset merge_stages_fd
96
+ eval $cont
97
+ }
98
+}