Skip to content

Commit 042c232

Browse files
angavrilovspearce
authored andcommitted
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>
1 parent 700e560 commit 042c232

File tree

2 files changed

+190
-60
lines changed

2 files changed

+190
-60
lines changed

git-gui.sh

Lines changed: 92 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,6 +2713,51 @@ $ui_diff tag raise sel
27132713
27142714
# -- Diff Body Context Menu
27152715
#
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+
27162761
set ctxm .vpane.lower.diff.body.ctxm
27172762
menu $ctxm -tearoff 0
27182763
$ctxm add command \
@@ -2726,73 +2771,60 @@ $ctxm add command \
27262771
set ui_diff_applyline [$ctxm index last]
27272772
lappend diff_actions [list $ctxm entryconf $ui_diff_applyline -state]
27282773
$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} {
27712794
global current_diff_path file_states
27722795
set ::cursorX $x
27732796
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]
27772799
} 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
27882804
} 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
27902825
}
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
27942826
}
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]
27962828
27972829
# -- Status Bar
27982830
#

lib/mergetool.tcl

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

0 commit comments

Comments
 (0)