gitk: Unify handling of merge diffs with normal 2-way diffs
This adds code to getblobdiffline to make it able to recognize and display merge diffs (i.e. N-way diffs for N >= 3) as well as normal two-way diffs. This means that it can also correctly display the 3-way diff of the local changes when the git repository is in the middle of a merge with conflicts. This also removes getmergediffline and changes mergediff to invoke getblobdiffline rather than getmergediffline. Signed-off-by: Paul Mackerras <paulus@samba.org>
Paul Mackerras committed
Nov 2, 2008 at 22:34 UTC
8b07dca18a498c5900edc717d216e841d6c15dc9
1 file changed
+99
-171
gitk
+99
-171
@@ -2098,7 +2098,7 @@ proc makewindow {} {
2098
$ctext tag conf filesep -font textfontbold -back "#aaaaaa"
2099
$ctext tag conf hunksep -fore [lindex $diffcolors 2]
2100
$ctext tag conf d0 -fore [lindex $diffcolors 0]
2101
- $ctext tag conf d1 -fore [lindex $diffcolors 1]
2101
+ $ctext tag conf dresult -fore [lindex $diffcolors 1]
2102
$ctext tag conf m0 -fore red
2103
$ctext tag conf m1 -fore blue
2104
$ctext tag conf m2 -fore green
@@ -3217,7 +3217,7 @@ proc find_hunk_blamespec {base line} {
3217
}
3218
3219
proc external_blame_diff {} {
3220
- global currentid diffmergeid cmitmode
3220
+ global currentid cmitmode
3221
global diff_menu_txtpos diff_menu_line
3222
global diff_menu_filebase flist_menu_file
3223
@@ -6668,130 +6668,16 @@ proc mark_ctext_line {lnum} {
6668
}
6669
6670
proc mergediff {id} {
6671
- global diffmergeid mdifffd
6671
+ global diffmergeid
6672
global diffids treediffs
6673
- global parents
6674
- global diffcontext
6675
- global diffencoding
6676
- global limitdiffs vfilelimit curview
6677
- global targetline
6673
+ global parents curview
6674
6675
set diffmergeid $id
6676
set diffids $id
6677
set treediffs($id) {}
6682
- set targetline {}
6683
- # this doesn't seem to actually affect anything...
6684
- set cmd [concat | git diff-tree --no-commit-id --cc -U$diffcontext $id]
6685
- if {$limitdiffs && $vfilelimit($curview) ne {}} {
6686
- set cmd [concat $cmd -- $vfilelimit($curview)]
6687
- }
6688
- if {[catch {set mdf [open $cmd r]} err]} {
6689
- error_popup "[mc "Error getting merge diffs:"] $err"
6690
- return
6691
- }
6692
- fconfigure $mdf -blocking 0 -encoding binary
6693
- set mdifffd($id) $mdf
6678
set np [llength $parents($curview,$id)]
6695
- set diffencoding [get_path_encoding {}]
6679
settabs $np
6697
- filerun $mdf [list getmergediffline $mdf $id $np]
6698
-}
6699
-
6700
-proc getmergediffline {mdf id np} {
6701
- global diffmergeid ctext cflist mergemax
6702
- global difffilestart mdifffd treediffs
6703
- global ctext_file_names ctext_file_lines
6704
- global diffencoding jump_to_here targetline diffline
6705
-
6706
- $ctext conf -state normal
6707
- set nr 0
6708
- while {[incr nr] <= 1000 && [gets $mdf line] >= 0} {
6709
- if {![info exists diffmergeid] || $id != $diffmergeid
6710
- || $mdf != $mdifffd($id)} {
6711
- close $mdf
6712
- return 0
6713
- }
6714
- if {[regexp {^diff --cc (.*)} $line match fname]} {
6715
- # start of a new file
6716
- set fname [encoding convertfrom $fname]
6717
- $ctext insert end "\n"
6718
- set here [$ctext index "end - 1c"]
6719
- lappend difffilestart $here
6720
- lappend treediffs($id) $fname
6721
- add_flist [list $fname]
6722
- lappend ctext_file_names $fname
6723
- lappend ctext_file_lines [lindex [split $here "."] 0]
6724
- set diffencoding [get_path_encoding $fname]
6725
- set l [expr {(78 - [string length $fname]) / 2}]
6726
- set pad [string range "----------------------------------------" 1 $l]
6727
- $ctext insert end "$pad $fname $pad\n" filesep
6728
- set targetline {}
6729
- if {$jump_to_here ne {} && [lindex $jump_to_here 0] eq $fname} {
6730
- set targetline [lindex $jump_to_here 1]
6731
- }
6732
- set diffline 0
6733
- } elseif {[regexp {^@@} $line]} {
6734
- set line [encoding convertfrom $diffencoding $line]
6735
- $ctext insert end "$line\n" hunksep
6736
- if {[regexp { \+(\d+),\d+ @@} $line m nl]} {
6737
- set diffline $nl
6738
- }
6739
- } elseif {[regexp {^[0-9a-f]{40}$} $line] || [regexp {^index} $line]} {
6740
- # do nothing
6741
- } else {
6742
- set line [encoding convertfrom $diffencoding $line]
6743
- # parse the prefix - one ' ', '-' or '+' for each parent
6744
- set spaces {}
6745
- set minuses {}
6746
- set pluses {}
6747
- set isbad 0
6748
- for {set j 0} {$j < $np} {incr j} {
6749
- set c [string range $line $j $j]
6750
- if {$c == " "} {
6751
- lappend spaces $j
6752
- } elseif {$c == "-"} {
6753
- lappend minuses $j
6754
- } elseif {$c == "+"} {
6755
- lappend pluses $j
6756
- } else {
6757
- set isbad 1
6758
- break
6759
- }
6760
- }
6761
- set tags {}
6762
- set num {}
6763
- if {!$isbad && $minuses ne {} && $pluses eq {}} {
6764
- # line doesn't appear in result, parents in $minuses have the line
6765
- set num [lindex $minuses 0]
6766
- } elseif {!$isbad && $pluses ne {} && $minuses eq {}} {
6767
- # line appears in result, parents in $pluses don't have the line
6768
- lappend tags mresult
6769
- set num [lindex $spaces 0]
6770
- }
6771
- if {$num ne {}} {
6772
- if {$num >= $mergemax} {
6773
- set num "max"
6774
- }
6775
- lappend tags m$num
6776
- }
6777
- $ctext insert end "$line\n" $tags
6778
- if {$targetline ne {} && $minuses eq {}} {
6779
- if {$diffline == $targetline} {
6780
- set here [$ctext index "end - 1 line"]
6781
- mark_ctext_line [lindex [split $here .] 0]
6782
- set targetline {}
6783
- } else {
6784
- incr diffline
6785
- }
6786
- }
6787
- }
6788
- }
6789
- $ctext conf -state disabled
6790
- if {[eof $mdf]} {
6791
- close $mdf
6792
- return 0
6793
- }
6794
- return [expr {$nr >= 1000? 2: 1}]
6680
+ getblobdiffs $id
6681
}
6682
6683
proc startdiff {ids} {
@@ -6971,9 +6857,9 @@ proc getblobdiffs {ids} {
6857
global diffcontext
6858
global ignorespace
6859
global limitdiffs vfilelimit curview
6974
- global diffencoding targetline
6860
+ global diffencoding targetline diffnparents
6861
6976
- set cmd [diffcmd $ids "-p -C --no-commit-id -U$diffcontext"]
6862
+ set cmd [diffcmd $ids "-p -C --cc --no-commit-id -U$diffcontext"]
6863
if {$ignorespace} {
6864
append cmd " -w"
6865
}
@@ -6981,10 +6867,11 @@ proc getblobdiffs {ids} {
6867
set cmd [concat $cmd -- $vfilelimit($curview)]
6868
}
6869
if {[catch {set bdf [open $cmd r]} err]} {
6984
- puts "error getting diffs: $err"
6870
+ error_popup [mc "Error getting diffs: %s" $err]
6871
return
6872
}
6873
set targetline {}
6874
+ set diffnparents 0
6875
set diffinhdr 0
6876
set diffencoding [get_path_encoding {}]
6877
fconfigure $bdf -blocking 0 -encoding binary
@@ -7006,9 +6893,11 @@ proc setinlist {var i val} {
6893
}
6894
6895
proc makediffhdr {fname ids} {
7009
- global ctext curdiffstart treediffs
6896
+ global ctext curdiffstart treediffs diffencoding
6897
global ctext_file_names jump_to_here targetline diffline
6898
6899
+ set fname [encoding convertfrom $fname]
6900
+ set diffencoding [get_path_encoding $fname]
6901
set i [lsearch -exact $treediffs($ids) $fname]
6902
if {$i >= 0} {
6903
setinlist difffilestart $i $curdiffstart
@@ -7028,7 +6917,7 @@ proc getblobdiffline {bdf ids} {
6917
global diffids blobdifffd ctext curdiffstart
6918
global diffnexthead diffnextnote difffilestart
6919
global ctext_file_names ctext_file_lines
7031
- global diffinhdr treediffs
6920
+ global diffinhdr treediffs mergemax diffnparents
6921
global diffencoding jump_to_here targetline diffline
6922
6923
set nr 0
@@ -7038,47 +6927,63 @@ proc getblobdiffline {bdf ids} {
6927
close $bdf
6928
return 0
6929
}
7041
- if {![string compare -length 11 "diff --git " $line]} {
7042
- # trim off "diff --git "
7043
- set line [string range $line 11 end]
7044
- set diffinhdr 1
6930
+ if {![string compare -length 5 "diff " $line]} {
6931
+ if {![regexp {^diff (--cc|--git) } $line m type]} {
6932
+ set line [encoding convertfrom $line]
6933
+ $ctext insert end "$line\n" hunksep
6934
+ continue
6935
+ }
6936
# start of a new file
6937
+ set diffinhdr 1
6938
$ctext insert end "\n"
6939
set curdiffstart [$ctext index "end - 1c"]
6940
lappend ctext_file_names ""
6941
lappend ctext_file_lines [lindex [split $curdiffstart "."] 0]
6942
$ctext insert end "\n" filesep
7051
- # If the name hasn't changed the length will be odd,
7052
- # the middle char will be a space, and the two bits either
7053
- # side will be a/name and b/name, or "a/name" and "b/name".
7054
- # If the name has changed we'll get "rename from" and
7055
- # "rename to" or "copy from" and "copy to" lines following this,
7056
- # and we'll use them to get the filenames.
7057
- # This complexity is necessary because spaces in the filename(s)
7058
- # don't get escaped.
7059
- set l [string length $line]
7060
- set i [expr {$l / 2}]
7061
- if {!(($l & 1) && [string index $line $i] eq " " &&
7062
- [string range $line 2 [expr {$i - 1}]] eq \
7063
- [string range $line [expr {$i + 3}] end])} {
7064
- continue
7065
- }
7066
- # unescape if quoted and chop off the a/ from the front
7067
- if {[string index $line 0] eq "\""} {
7068
- set fname [string range [lindex $line 0] 2 end]
6943
+
6944
+ if {$type eq "--cc"} {
6945
+ # start of a new file in a merge diff
6946
+ set fname [string range $line 10 end]
6947
+ if {[lsearch -exact $treediffs($ids) $fname] < 0} {
6948
+ lappend treediffs($ids) $fname
6949
+ add_flist [list $fname]
6950
+ }
6951
+
6952
} else {
7070
- set fname [string range $line 2 [expr {$i - 1}]]
6953
+ set line [string range $line 11 end]
6954
+ # If the name hasn't changed the length will be odd,
6955
+ # the middle char will be a space, and the two bits either
6956
+ # side will be a/name and b/name, or "a/name" and "b/name".
6957
+ # If the name has changed we'll get "rename from" and
6958
+ # "rename to" or "copy from" and "copy to" lines following
6959
+ # this, and we'll use them to get the filenames.
6960
+ # This complexity is necessary because spaces in the
6961
+ # filename(s) don't get escaped.
6962
+ set l [string length $line]
6963
+ set i [expr {$l / 2}]
6964
+ if {!(($l & 1) && [string index $line $i] eq " " &&
6965
+ [string range $line 2 [expr {$i - 1}]] eq \
6966
+ [string range $line [expr {$i + 3}] end])} {
6967
+ continue
6968
+ }
6969
+ # unescape if quoted and chop off the a/ from the front
6970
+ if {[string index $line 0] eq "\""} {
6971
+ set fname [string range [lindex $line 0] 2 end]
6972
+ } else {
6973
+ set fname [string range $line 2 [expr {$i - 1}]]
6974
+ }
6975
}
7072
- set fname [encoding convertfrom $fname]
7073
- set diffencoding [get_path_encoding $fname]
6976
makediffhdr $fname $ids
6977
7076
- } elseif {[regexp {^@@ -([0-9]+)(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@(.*)} \
7077
- $line match f1l f1c f2l f2c rest]} {
6978
+ } elseif {![string compare -length 2 "@@" $line]} {
6979
+ regexp {^@@+} $line ats
6980
set line [encoding convertfrom $diffencoding $line]
6981
$ctext insert end "$line\n" hunksep
6982
+ if {[regexp { \+(\d+),\d+ @@} $line m nl]} {
6983
+ set diffline $nl
6984
+ }
6985
+ set diffnparents [expr {[string length $ats] - 1}]
6986
set diffinhdr 0
7081
- set diffline $f2l
6987
6988
} elseif {$diffinhdr} {
6989
if {![string compare -length 12 "rename from " $line]} {
@@ -7097,8 +7002,6 @@ proc getblobdiffline {bdf ids} {
7002
if {[string index $fname 0] eq "\""} {
7003
set fname [lindex $fname 0]
7004
}
7100
- set fname [encoding convertfrom $fname]
7101
- set diffencoding [get_path_encoding $fname]
7005
makediffhdr $fname $ids
7006
} elseif {[string compare -length 3 $line "---"] == 0} {
7007
# do nothing
@@ -7111,28 +7014,53 @@ proc getblobdiffline {bdf ids} {
7014
7015
} else {
7016
set line [encoding convertfrom $diffencoding $line]
7114
- set x [string range $line 0 0]
7115
- set here [$ctext index "end - 1 chars"]
7116
- if {$x == "-" || $x == "+"} {
7117
- set tag [expr {$x == "+"}]
7118
- $ctext insert end "$line\n" d$tag
7119
- } elseif {$x == " "} {
7120
- $ctext insert end "$line\n"
7017
+ # parse the prefix - one ' ', '-' or '+' for each parent
7018
+ set prefix [string range $line 0 [expr {$diffnparents - 1}]]
7019
+ set tag [expr {$diffnparents > 1? "m": "d"}]
7020
+ if {[string trim $prefix " -+"] eq {}} {
7021
+ # prefix only has " ", "-" and "+" in it: normal diff line
7022
+ set num [string first "-" $prefix]
7023
+ if {$num >= 0} {
7024
+ # removed line, first parent with line is $num
7025
+ if {$num >= $mergemax} {
7026
+ set num "max"
7027
+ }
7028
+ $ctext insert end "$line\n" $tag$num
7029
+ } else {
7030
+ set tags {}
7031
+ if {[string first "+" $prefix] >= 0} {
7032
+ # added line
7033
+ lappend tags ${tag}result
7034
+ if {$diffnparents > 1} {
7035
+ set num [string first " " $prefix]
7036
+ if {$num >= 0} {
7037
+ if {$num >= $mergemax} {
7038
+ set num "max"
7039
+ }
7040
+ lappend tags m$num
7041
+ }
7042
+ }
7043
+ }
7044
+ if {$targetline ne {}} {
7045
+ if {$diffline == $targetline} {
7046
+ set seehere [$ctext index "end - 1 chars"]
7047
+ set targetline {}
7048
+ } else {
7049
+ incr diffline
7050
+ }
7051
+ }
7052
+ $ctext insert end "$line\n" $tags
7053
+ }
7054
} else {
7055
# "\ No newline at end of file",
7056
# or something else we don't recognize
7057
$ctext insert end "$line\n" hunksep
7058
}
7126
- if {$targetline ne {} && ($x eq " " || $x eq "+")} {
7127
- if {$diffline == $targetline} {
7128
- mark_ctext_line [lindex [split $here .] 0]
7129
- set targetline {}
7130
- } else {
7131
- incr diffline
7132
- }
7133
- }
7059
}
7060
}
7061
+ if {[info exists seehere]} {
7062
+ mark_ctext_line [lindex [split $seehere .] 0]
7063
+ }
7064
$ctext conf -state disabled
7065
if {[eof $bdf]} {
7066
close $bdf
@@ -7145,7 +7073,7 @@ proc changediffdisp {} {
7073
global ctext diffelide
7074
7075
$ctext tag conf d0 -elide [lindex $diffelide 0]
7148
- $ctext tag conf d1 -elide [lindex $diffelide 1]
7076
+ $ctext tag conf dresult -elide [lindex $diffelide 1]
7077
}
7078
7079
proc highlightfile {loc cline} {
@@ -9817,7 +9745,7 @@ proc doprefs {} {
9745
label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
9746
button $top.diffnewbut -text [mc "Diff: new lines"] -font optionfont \
9747
-command [list choosecolor diffcolors 1 $top.diffnew "diff new lines" \
9820
- [list $ctext tag conf d1 -foreground]]
9748
+ [list $ctext tag conf dresult -foreground]]
9749
grid x $top.diffnewbut $top.diffnew -sticky w
9750
label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
9751
button $top.hunksepbut -text [mc "Diff: hunk header"] -font optionfont \