Merge updated git-gui and gitk that call each other
Merge git://repo.or.cz/git-gui and git://git.kernel.org/pub/scm/gitk/gitk * git://repo.or.cz/git-gui: git-gui: Show special diffs for complex conflict cases. git-gui: Make F5 reselect a diff, if an untracked file is selected. git-gui: Reimplement and enhance auto-selection of diffs. git-gui: Support conflict states _U & UT. git-gui: Support more merge tools. git-gui: Don't allow staging files with conflicts. git-gui: Support calling merge tools. git-gui: Support resolving conflicts via the diff context menu. git-gui: Mark forgotten strings for translation. git-gui: Allow specifying an initial line for git gui blame. git-gui: Better positioning in Blame Parent Commit git-gui: Support passing blame to a parent commit. git-gui: Support starting gitk from Gui Blame git-gui: Teach git gui about file type changes * git://git.kernel.org/pub/scm/gitk/gitk: gitk: Add menu item for calling git gui blame gitk: Add option to specify the default commit on command line
This commit is contained in:
commit
5fc3e67ac0
@ -657,6 +657,8 @@ proc apply_config {} {
|
||||
}
|
||||
|
||||
set default_config(branch.autosetupmerge) true
|
||||
set default_config(merge.tool) {}
|
||||
set default_config(merge.keepbackup) true
|
||||
set default_config(merge.diffstat) true
|
||||
set default_config(merge.summary) false
|
||||
set default_config(merge.verbosity) 2
|
||||
@ -668,6 +670,7 @@ set default_config(gui.pruneduringfetch) false
|
||||
set default_config(gui.trustmtime) false
|
||||
set default_config(gui.fastcopyblame) false
|
||||
set default_config(gui.copyblamethreshold) 40
|
||||
set default_config(gui.blamehistoryctx) 7
|
||||
set default_config(gui.diffcontext) 5
|
||||
set default_config(gui.commitmsgwidth) 75
|
||||
set default_config(gui.newbranchtemplate) {}
|
||||
@ -1323,6 +1326,8 @@ proc rescan_done {fd buf after} {
|
||||
unlock_index
|
||||
display_all_files
|
||||
if {$current_diff_path ne {}} reshow_diff
|
||||
if {$current_diff_path eq {}} select_first_diff
|
||||
|
||||
uplevel #0 $after
|
||||
}
|
||||
|
||||
@ -1619,6 +1624,15 @@ static unsigned char file_merge_bits[] = {
|
||||
0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
|
||||
} -maskdata $filemask
|
||||
|
||||
image create bitmap file_statechange -background white -foreground green -data {
|
||||
#define file_merge_width 14
|
||||
#define file_merge_height 15
|
||||
static unsigned char file_statechange_bits[] = {
|
||||
0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x62, 0x10,
|
||||
0x62, 0x10, 0xba, 0x11, 0xba, 0x11, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10,
|
||||
0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
|
||||
} -maskdata $filemask
|
||||
|
||||
set ui_index .vpane.files.index.list
|
||||
set ui_workdir .vpane.files.workdir.list
|
||||
|
||||
@ -1627,12 +1641,14 @@ set all_icons(A$ui_index) file_fulltick
|
||||
set all_icons(M$ui_index) file_fulltick
|
||||
set all_icons(D$ui_index) file_removed
|
||||
set all_icons(U$ui_index) file_merge
|
||||
set all_icons(T$ui_index) file_statechange
|
||||
|
||||
set all_icons(_$ui_workdir) file_plain
|
||||
set all_icons(M$ui_workdir) file_mod
|
||||
set all_icons(D$ui_workdir) file_question
|
||||
set all_icons(U$ui_workdir) file_merge
|
||||
set all_icons(O$ui_workdir) file_plain
|
||||
set all_icons(T$ui_workdir) file_statechange
|
||||
|
||||
set max_status_desc 0
|
||||
foreach i {
|
||||
@ -1643,6 +1659,9 @@ foreach i {
|
||||
{MM {mc "Portions staged for commit"}}
|
||||
{MD {mc "Staged for commit, missing"}}
|
||||
|
||||
{_T {mc "File type changed, not staged"}}
|
||||
{T_ {mc "File type changed, staged"}}
|
||||
|
||||
{_O {mc "Untracked, not staged"}}
|
||||
{A_ {mc "Staged for commit"}}
|
||||
{AM {mc "Portions staged for commit"}}
|
||||
@ -1652,10 +1671,12 @@ foreach i {
|
||||
{D_ {mc "Staged for removal"}}
|
||||
{DO {mc "Staged for removal, still present"}}
|
||||
|
||||
{_U {mc "Requires merge resolution"}}
|
||||
{U_ {mc "Requires merge resolution"}}
|
||||
{UU {mc "Requires merge resolution"}}
|
||||
{UM {mc "Requires merge resolution"}}
|
||||
{UD {mc "Requires merge resolution"}}
|
||||
{UT {mc "Requires merge resolution"}}
|
||||
} {
|
||||
set text [eval [lindex $i 1]]
|
||||
if {$max_status_desc < [string length $text]} {
|
||||
@ -1796,13 +1817,120 @@ proc do_rescan {} {
|
||||
rescan ui_ready
|
||||
}
|
||||
|
||||
proc ui_do_rescan {} {
|
||||
rescan {force_first_diff; ui_ready}
|
||||
}
|
||||
|
||||
proc do_commit {} {
|
||||
commit_tree
|
||||
}
|
||||
|
||||
proc next_diff {} {
|
||||
global next_diff_p next_diff_w next_diff_i
|
||||
show_diff $next_diff_p $next_diff_w $next_diff_i
|
||||
show_diff $next_diff_p $next_diff_w {}
|
||||
}
|
||||
|
||||
proc find_anchor_pos {lst name} {
|
||||
set lid [lsearch -sorted -exact $lst $name]
|
||||
|
||||
if {$lid == -1} {
|
||||
set lid 0
|
||||
foreach lname $lst {
|
||||
if {$lname >= $name} break
|
||||
incr lid
|
||||
}
|
||||
}
|
||||
|
||||
return $lid
|
||||
}
|
||||
|
||||
proc find_file_from {flist idx delta path mmask} {
|
||||
global file_states
|
||||
|
||||
set len [llength $flist]
|
||||
while {$idx >= 0 && $idx < $len} {
|
||||
set name [lindex $flist $idx]
|
||||
|
||||
if {$name ne $path && [info exists file_states($name)]} {
|
||||
set state [lindex $file_states($name) 0]
|
||||
|
||||
if {$mmask eq {} || [regexp $mmask $state]} {
|
||||
return $idx
|
||||
}
|
||||
}
|
||||
|
||||
incr idx $delta
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
proc find_next_diff {w path {lno {}} {mmask {}}} {
|
||||
global next_diff_p next_diff_w next_diff_i
|
||||
global file_lists ui_index ui_workdir
|
||||
|
||||
set flist $file_lists($w)
|
||||
if {$lno eq {}} {
|
||||
set lno [find_anchor_pos $flist $path]
|
||||
} else {
|
||||
incr lno -1
|
||||
}
|
||||
|
||||
if {$mmask ne {} && ![regexp {(^\^)|(\$$)} $mmask]} {
|
||||
if {$w eq $ui_index} {
|
||||
set mmask "^$mmask"
|
||||
} else {
|
||||
set mmask "$mmask\$"
|
||||
}
|
||||
}
|
||||
|
||||
set idx [find_file_from $flist $lno 1 $path $mmask]
|
||||
if {$idx eq {}} {
|
||||
incr lno -1
|
||||
set idx [find_file_from $flist $lno -1 $path $mmask]
|
||||
}
|
||||
|
||||
if {$idx ne {}} {
|
||||
set next_diff_w $w
|
||||
set next_diff_p [lindex $flist $idx]
|
||||
set next_diff_i [expr {$idx+1}]
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
proc next_diff_after_action {w path {lno {}} {mmask {}}} {
|
||||
global current_diff_path
|
||||
|
||||
if {$path ne $current_diff_path} {
|
||||
return {}
|
||||
} elseif {[find_next_diff $w $path $lno $mmask]} {
|
||||
return {next_diff;}
|
||||
} else {
|
||||
return {reshow_diff;}
|
||||
}
|
||||
}
|
||||
|
||||
proc select_first_diff {} {
|
||||
global ui_workdir
|
||||
|
||||
if {[find_next_diff $ui_workdir {} 1 {^_?U}] ||
|
||||
[find_next_diff $ui_workdir {} 1 {[^O]$}]} {
|
||||
next_diff
|
||||
}
|
||||
}
|
||||
|
||||
proc force_first_diff {} {
|
||||
global current_diff_path
|
||||
|
||||
if {[info exists file_states($current_diff_path)]} {
|
||||
set state [lindex $file_states($current_diff_path) 0]
|
||||
|
||||
if {[string index $state 1] ne {O}} return
|
||||
}
|
||||
|
||||
select_first_diff
|
||||
}
|
||||
|
||||
proc toggle_or_diff {w x y} {
|
||||
@ -1823,34 +1951,27 @@ proc toggle_or_diff {w x y} {
|
||||
$ui_index tag remove in_sel 0.0 end
|
||||
$ui_workdir tag remove in_sel 0.0 end
|
||||
|
||||
# Do not stage files with conflicts
|
||||
if {[info exists file_states($path)]} {
|
||||
set state [lindex $file_states($path) 0]
|
||||
} else {
|
||||
set state {__}
|
||||
}
|
||||
|
||||
if {[string first {U} $state] >= 0} {
|
||||
set col 1
|
||||
}
|
||||
|
||||
# Restage the file, or simply show the diff
|
||||
if {$col == 0 && $y > 1} {
|
||||
set i [expr {$lno-1}]
|
||||
set ll [expr {[llength $file_lists($w)]-1}]
|
||||
|
||||
if {$i == $ll && $i == 0} {
|
||||
set after {reshow_diff;}
|
||||
if {[string index $state 1] eq {O}} {
|
||||
set mmask {}
|
||||
} else {
|
||||
global next_diff_p next_diff_w next_diff_i
|
||||
|
||||
set next_diff_w $w
|
||||
|
||||
if {$i < $ll} {
|
||||
set i [expr {$i + 1}]
|
||||
set next_diff_i $i
|
||||
} else {
|
||||
set next_diff_i $i
|
||||
set i [expr {$i - 1}]
|
||||
}
|
||||
|
||||
set next_diff_p [lindex $file_lists($w) $i]
|
||||
|
||||
if {$next_diff_p ne {} && $current_diff_path ne {}} {
|
||||
set after {next_diff;}
|
||||
} else {
|
||||
set after {}
|
||||
}
|
||||
set mmask {[^O]}
|
||||
}
|
||||
|
||||
set after [next_diff_after_action $w $path $lno $mmask]
|
||||
|
||||
if {$w eq $ui_index} {
|
||||
update_indexinfo \
|
||||
"Unstaging [short_path $path] from commit" \
|
||||
@ -2113,7 +2234,7 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
|
||||
.mbar.commit add separator
|
||||
|
||||
.mbar.commit add command -label [mc Rescan] \
|
||||
-command do_rescan \
|
||||
-command ui_do_rescan \
|
||||
-accelerator F5
|
||||
lappend disable_on_lock \
|
||||
[list .mbar.commit entryconf [.mbar.commit index last] -state]
|
||||
@ -2281,10 +2402,15 @@ proc usage {} {
|
||||
switch -- $subcommand {
|
||||
browser -
|
||||
blame {
|
||||
set subcommand_args {rev? path}
|
||||
if {$subcommand eq "blame"} {
|
||||
set subcommand_args {[--line=<num>] rev? path}
|
||||
} else {
|
||||
set subcommand_args {rev? path}
|
||||
}
|
||||
if {$argv eq {}} usage
|
||||
set head {}
|
||||
set path {}
|
||||
set jump_spec {}
|
||||
set is_path 0
|
||||
foreach a $argv {
|
||||
if {$is_path || [file exists $_prefix$a]} {
|
||||
@ -2298,6 +2424,9 @@ blame {
|
||||
set path {}
|
||||
}
|
||||
set is_path 1
|
||||
} elseif {[regexp {^--line=(\d+)$} $a a lnum]} {
|
||||
if {$jump_spec ne {} || $head ne {}} usage
|
||||
set jump_spec [list $lnum]
|
||||
} elseif {$head eq {}} {
|
||||
if {$head ne {}} usage
|
||||
set head $a
|
||||
@ -2329,6 +2458,7 @@ blame {
|
||||
|
||||
switch -- $subcommand {
|
||||
browser {
|
||||
if {$jump_spec ne {}} usage
|
||||
if {$head eq {}} {
|
||||
if {$path ne {} && [file isdirectory $path]} {
|
||||
set head $current_branch
|
||||
@ -2344,7 +2474,7 @@ blame {
|
||||
puts stderr [mc "fatal: cannot stat path %s: No such file or directory" $path]
|
||||
exit 1
|
||||
}
|
||||
blame::new $head $path
|
||||
blame::new $head $path $jump_spec
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -2460,7 +2590,7 @@ pack .vpane.lower.commarea.buttons.l -side top -fill x
|
||||
pack .vpane.lower.commarea.buttons -side left -fill y
|
||||
|
||||
button .vpane.lower.commarea.buttons.rescan -text [mc Rescan] \
|
||||
-command do_rescan
|
||||
-command ui_do_rescan
|
||||
pack .vpane.lower.commarea.buttons.rescan -side top -fill x
|
||||
lappend disable_on_lock \
|
||||
{.vpane.lower.commarea.buttons.rescan conf -state}
|
||||
@ -2689,6 +2819,51 @@ $ui_diff tag raise sel
|
||||
|
||||
# -- Diff Body Context Menu
|
||||
#
|
||||
|
||||
proc create_common_diff_popup {ctxm} {
|
||||
$ctxm add command \
|
||||
-label [mc "Show Less Context"] \
|
||||
-command show_less_context
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add command \
|
||||
-label [mc "Show More Context"] \
|
||||
-command show_more_context
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add separator
|
||||
$ctxm add command \
|
||||
-label [mc Refresh] \
|
||||
-command reshow_diff
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add command \
|
||||
-label [mc Copy] \
|
||||
-command {tk_textCopy $ui_diff}
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add command \
|
||||
-label [mc "Select All"] \
|
||||
-command {focus $ui_diff;$ui_diff tag add sel 0.0 end}
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add command \
|
||||
-label [mc "Copy All"] \
|
||||
-command {
|
||||
$ui_diff tag add sel 0.0 end
|
||||
tk_textCopy $ui_diff
|
||||
$ui_diff tag remove sel 0.0 end
|
||||
}
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add separator
|
||||
$ctxm add command \
|
||||
-label [mc "Decrease Font Size"] \
|
||||
-command {incr_font_size font_diff -1}
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add command \
|
||||
-label [mc "Increase Font Size"] \
|
||||
-command {incr_font_size font_diff 1}
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add separator
|
||||
$ctxm add command -label [mc "Options..."] \
|
||||
-command do_options
|
||||
}
|
||||
|
||||
set ctxm .vpane.lower.diff.body.ctxm
|
||||
menu $ctxm -tearoff 0
|
||||
$ctxm add command \
|
||||
@ -2702,71 +2877,65 @@ $ctxm add command \
|
||||
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"] \
|
||||
-command show_less_context
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add command \
|
||||
-label [mc "Show More Context"] \
|
||||
-command show_more_context
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add separator
|
||||
$ctxm add command \
|
||||
-label [mc Refresh] \
|
||||
-command reshow_diff
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add command \
|
||||
-label [mc Copy] \
|
||||
-command {tk_textCopy $ui_diff}
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add command \
|
||||
-label [mc "Select All"] \
|
||||
-command {focus $ui_diff;$ui_diff tag add sel 0.0 end}
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add command \
|
||||
-label [mc "Copy All"] \
|
||||
-command {
|
||||
$ui_diff tag add sel 0.0 end
|
||||
tk_textCopy $ui_diff
|
||||
$ui_diff tag remove sel 0.0 end
|
||||
}
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add separator
|
||||
$ctxm add command \
|
||||
-label [mc "Decrease Font Size"] \
|
||||
-command {incr_font_size font_diff -1}
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add command \
|
||||
-label [mc "Increase Font Size"] \
|
||||
-command {incr_font_size font_diff 1}
|
||||
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
|
||||
$ctxm add separator
|
||||
$ctxm add command -label [mc "Options..."] \
|
||||
-command do_options
|
||||
proc popup_diff_menu {ctxm x y X Y} {
|
||||
create_common_diff_popup $ctxm
|
||||
|
||||
set ctxmmg .vpane.lower.diff.body.ctxmmg
|
||||
menu $ctxmmg -tearoff 0
|
||||
$ctxmmg add command \
|
||||
-label [mc "Run Merge Tool"] \
|
||||
-command {merge_resolve_tool}
|
||||
lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state]
|
||||
$ctxmmg add separator
|
||||
$ctxmmg add command \
|
||||
-label [mc "Use Remote Version"] \
|
||||
-command {merge_resolve_one 3}
|
||||
lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state]
|
||||
$ctxmmg add command \
|
||||
-label [mc "Use Local Version"] \
|
||||
-command {merge_resolve_one 2}
|
||||
lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state]
|
||||
$ctxmmg add command \
|
||||
-label [mc "Revert To Base"] \
|
||||
-command {merge_resolve_one 1}
|
||||
lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state]
|
||||
$ctxmmg add separator
|
||||
create_common_diff_popup $ctxmmg
|
||||
|
||||
proc popup_diff_menu {ctxm ctxmmg x y X Y} {
|
||||
global current_diff_path file_states
|
||||
set ::cursorX $x
|
||||
set ::cursorY $y
|
||||
if {$::ui_index eq $::current_diff_side} {
|
||||
set l [mc "Unstage Hunk From Commit"]
|
||||
set t [mc "Unstage Line From Commit"]
|
||||
if {[info exists file_states($current_diff_path)]} {
|
||||
set state [lindex $file_states($current_diff_path) 0]
|
||||
} else {
|
||||
set l [mc "Stage Hunk For Commit"]
|
||||
set t [mc "Stage Line For Commit"]
|
||||
set state {__}
|
||||
}
|
||||
if {$::is_3way_diff
|
||||
|| $current_diff_path eq {}
|
||||
|| ![info exists file_states($current_diff_path)]
|
||||
|| {_O} eq [lindex $file_states($current_diff_path) 0]} {
|
||||
set s disabled
|
||||
if {[string first {U} $state] >= 0} {
|
||||
tk_popup $ctxmmg $X $Y
|
||||
} else {
|
||||
set s normal
|
||||
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 {}
|
||||
|| {__} eq $state
|
||||
|| {_O} eq $state
|
||||
|| {_T} eq $state
|
||||
|| {T_} eq $state} {
|
||||
set s disabled
|
||||
} else {
|
||||
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
|
||||
}
|
||||
$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]
|
||||
bind_button3 $ui_diff [list popup_diff_menu $ctxm $ctxmmg %x %y %X %Y]
|
||||
|
||||
# -- Status Bar
|
||||
#
|
||||
@ -2842,9 +3011,9 @@ if {[is_enabled transport]} {
|
||||
bind . <$M1B-Key-P> do_push_anywhere
|
||||
}
|
||||
|
||||
bind . <Key-F5> do_rescan
|
||||
bind . <$M1B-Key-r> do_rescan
|
||||
bind . <$M1B-Key-R> do_rescan
|
||||
bind . <Key-F5> ui_do_rescan
|
||||
bind . <$M1B-Key-r> ui_do_rescan
|
||||
bind . <$M1B-Key-R> ui_do_rescan
|
||||
bind . <$M1B-Key-s> do_signoff
|
||||
bind . <$M1B-Key-S> do_signoff
|
||||
bind . <$M1B-Key-t> do_add_selection
|
||||
|
@ -58,7 +58,7 @@ field tooltip_t {} ; # Text widget in $tooltip_wm
|
||||
field tooltip_timer {} ; # Current timer event for our tooltip
|
||||
field tooltip_commit {} ; # Commit(s) in tooltip
|
||||
|
||||
constructor new {i_commit i_path} {
|
||||
constructor new {i_commit i_path i_jump} {
|
||||
global cursor_ptr
|
||||
variable active_color
|
||||
variable group_colors
|
||||
@ -259,6 +259,12 @@ constructor new {i_commit i_path} {
|
||||
$w.ctxm add command \
|
||||
-label [mc "Do Full Copy Detection"] \
|
||||
-command [cb _fullcopyblame]
|
||||
$w.ctxm add command \
|
||||
-label [mc "Show History Context"] \
|
||||
-command [cb _gitkcommit]
|
||||
$w.ctxm add command \
|
||||
-label [mc "Blame Parent Commit"] \
|
||||
-command [cb _blameparent]
|
||||
|
||||
foreach i $w_columns {
|
||||
for {set g 0} {$g < [llength $group_colors]} {incr g} {
|
||||
@ -332,7 +338,7 @@ constructor new {i_commit i_path} {
|
||||
wm protocol $top WM_DELETE_WINDOW "destroy $top"
|
||||
bind $top <Destroy> [cb _kill]
|
||||
|
||||
_load $this {}
|
||||
_load $this $i_jump
|
||||
}
|
||||
|
||||
method _kill {} {
|
||||
@ -787,19 +793,27 @@ method _load_commit {cur_w cur_d pos} {
|
||||
set lno [lindex [split [$cur_w index $pos] .] 0]
|
||||
set dat [lindex $line_data $lno]
|
||||
if {$dat ne {}} {
|
||||
lappend history [list \
|
||||
$commit $path \
|
||||
$highlight_column \
|
||||
$highlight_line \
|
||||
[lindex [$w_file xview] 0] \
|
||||
[lindex [$w_file yview] 0] \
|
||||
]
|
||||
set commit [lindex $dat 0]
|
||||
set path [lindex $dat 1]
|
||||
_load $this [list [lindex $dat 2]]
|
||||
_load_new_commit $this \
|
||||
[lindex $dat 0] \
|
||||
[lindex $dat 1] \
|
||||
[list [lindex $dat 2]]
|
||||
}
|
||||
}
|
||||
|
||||
method _load_new_commit {new_commit new_path jump} {
|
||||
lappend history [list \
|
||||
$commit $path \
|
||||
$highlight_column \
|
||||
$highlight_line \
|
||||
[lindex [$w_file xview] 0] \
|
||||
[lindex [$w_file yview] 0] \
|
||||
]
|
||||
|
||||
set commit $new_commit
|
||||
set path $new_path
|
||||
_load $this $jump
|
||||
}
|
||||
|
||||
method _showcommit {cur_w lno} {
|
||||
global repo_config
|
||||
variable active_color
|
||||
@ -905,10 +919,14 @@ method _showcommit {cur_w lno} {
|
||||
}
|
||||
}
|
||||
|
||||
method _copycommit {} {
|
||||
method _get_click_amov_info {} {
|
||||
set pos @$::cursorX,$::cursorY
|
||||
set lno [lindex [split [$::cursorW index $pos] .] 0]
|
||||
set dat [lindex $amov_data $lno]
|
||||
return [lindex $amov_data $lno]
|
||||
}
|
||||
|
||||
method _copycommit {} {
|
||||
set dat [_get_click_amov_info $this]
|
||||
if {$dat ne {}} {
|
||||
clipboard clear
|
||||
clipboard append \
|
||||
@ -918,6 +936,124 @@ method _copycommit {} {
|
||||
}
|
||||
}
|
||||
|
||||
method _format_offset_date {base offset} {
|
||||
set exval [expr {$base + $offset*24*60*60}]
|
||||
return [clock format $exval -format {%Y-%m-%d}]
|
||||
}
|
||||
|
||||
method _gitkcommit {} {
|
||||
set dat [_get_click_amov_info $this]
|
||||
if {$dat ne {}} {
|
||||
set cmit [lindex $dat 0]
|
||||
set radius [get_config gui.blamehistoryctx]
|
||||
set cmdline [list --select-commit=$cmit]
|
||||
|
||||
if {$radius > 0} {
|
||||
set author_time {}
|
||||
set committer_time {}
|
||||
|
||||
catch {set author_time $header($cmit,author-time)}
|
||||
catch {set committer_time $header($cmit,committer-time)}
|
||||
|
||||
if {$committer_time eq {}} {
|
||||
set committer_time $author_time
|
||||
}
|
||||
|
||||
set after_time [_format_offset_date $this $committer_time [expr {-$radius}]]
|
||||
set before_time [_format_offset_date $this $committer_time $radius]
|
||||
|
||||
lappend cmdline --after=$after_time --before=$before_time
|
||||
}
|
||||
|
||||
lappend cmdline $cmit
|
||||
|
||||
set base_rev "HEAD"
|
||||
if {$commit ne {}} {
|
||||
set base_rev $commit
|
||||
}
|
||||
|
||||
if {$base_rev ne $cmit} {
|
||||
lappend cmdline $base_rev
|
||||
}
|
||||
|
||||
do_gitk $cmdline
|
||||
}
|
||||
}
|
||||
|
||||
method _blameparent {} {
|
||||
set dat [_get_click_amov_info $this]
|
||||
if {$dat ne {}} {
|
||||
set cmit [lindex $dat 0]
|
||||
set new_path [lindex $dat 1]
|
||||
|
||||
if {[catch {set cparent [git rev-parse --verify "$cmit^"]}]} {
|
||||
error_popup [strcat [mc "Cannot find parent commit:"] "\n\n$err"]
|
||||
return;
|
||||
}
|
||||
|
||||
_kill $this
|
||||
|
||||
# Generate a diff between the commit and its parent,
|
||||
# and use the hunks to update the line number.
|
||||
# Request zero context to simplify calculations.
|
||||
if {[catch {set fd [eval git_read diff-tree \
|
||||
--unified=0 $cparent $cmit $new_path]} err]} {
|
||||
$status stop [mc "Unable to display parent"]
|
||||
error_popup [strcat [mc "Error loading diff:"] "\n\n$err"]
|
||||
return
|
||||
}
|
||||
|
||||
set r_orig_line [lindex $dat 2]
|
||||
|
||||
fconfigure $fd \
|
||||
-blocking 0 \
|
||||
-encoding binary \
|
||||
-translation binary
|
||||
fileevent $fd readable [cb _read_diff_load_commit \
|
||||
$fd $cparent $new_path $r_orig_line]
|
||||
set current_fd $fd
|
||||
}
|
||||
}
|
||||
|
||||
method _read_diff_load_commit {fd cparent new_path tline} {
|
||||
if {$fd ne $current_fd} {
|
||||
catch {close $fd}
|
||||
return
|
||||
}
|
||||
|
||||
while {[gets $fd line] >= 0} {
|
||||
if {[regexp {^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@} $line line \
|
||||
old_line osz old_size new_line nsz new_size]} {
|
||||
|
||||
if {$osz eq {}} { set old_size 1 }
|
||||
if {$nsz eq {}} { set new_size 1 }
|
||||
|
||||
if {$new_line <= $tline} {
|
||||
if {[expr {$new_line + $new_size}] > $tline} {
|
||||
# Target line within the hunk
|
||||
set line_shift [expr {
|
||||
($new_size-$old_size)*($tline-$new_line)/$new_size
|
||||
}]
|
||||
} else {
|
||||
set line_shift [expr {$new_size-$old_size}]
|
||||
}
|
||||
|
||||
set r_orig_line [expr {$r_orig_line - $line_shift}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {[eof $fd]} {
|
||||
close $fd;
|
||||
set current_fd {}
|
||||
|
||||
_load_new_commit $this \
|
||||
$cparent \
|
||||
$new_path \
|
||||
[list $r_orig_line]
|
||||
}
|
||||
} ifdeleted { catch {close $fd} }
|
||||
|
||||
method _show_tooltip {cur_w pos} {
|
||||
if {$tooltip_wm ne {}} {
|
||||
_open_tooltip $this $cur_w
|
||||
|
@ -151,7 +151,7 @@ method _enter {} {
|
||||
append p [lindex $n 1]
|
||||
}
|
||||
append p $name
|
||||
blame::new $browser_commit $p
|
||||
blame::new $browser_commit $p {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +149,9 @@ The rescan will be automatically started now.
|
||||
_? {continue}
|
||||
A? -
|
||||
D? -
|
||||
T_ -
|
||||
M? {set files_ready 1}
|
||||
_U -
|
||||
U? {
|
||||
error_popup [mc "Unmerged files cannot be committed.
|
||||
|
||||
@ -428,6 +430,7 @@ A rescan will be automatically started now.
|
||||
__ -
|
||||
A_ -
|
||||
M_ -
|
||||
T_ -
|
||||
D_ {
|
||||
unset file_states($path)
|
||||
catch {unset selected_paths($path)}
|
||||
|
@ -24,10 +24,16 @@ proc reshow_diff {} {
|
||||
set p $current_diff_path
|
||||
if {$p eq {}} {
|
||||
# No diff is being shown.
|
||||
} elseif {$current_diff_side eq {}
|
||||
|| [catch {set s $file_states($p)}]
|
||||
|| [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} {
|
||||
} elseif {$current_diff_side eq {}} {
|
||||
clear_diff
|
||||
} elseif {[catch {set s $file_states($p)}]
|
||||
|| [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} {
|
||||
|
||||
if {[find_next_diff $current_diff_side $p {} {[^O]}]} {
|
||||
next_diff
|
||||
} else {
|
||||
clear_diff
|
||||
}
|
||||
} else {
|
||||
set save_pos [lindex [$ui_diff yview] 0]
|
||||
show_diff $p $current_diff_side {} $save_pos
|
||||
@ -59,6 +65,7 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} {
|
||||
global is_3way_diff diff_active repo_config
|
||||
global ui_diff ui_index ui_workdir
|
||||
global current_diff_path current_diff_side current_diff_header
|
||||
global current_diff_queue
|
||||
|
||||
if {$diff_active || ![lock_index read]} return
|
||||
|
||||
@ -71,17 +78,74 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} {
|
||||
}
|
||||
if {$lno >= 1} {
|
||||
$w tag add in_diff $lno.0 [expr {$lno + 1}].0
|
||||
$w see $lno.0
|
||||
}
|
||||
|
||||
set s $file_states($path)
|
||||
set m [lindex $s 0]
|
||||
set is_3way_diff 0
|
||||
set diff_active 1
|
||||
set current_diff_path $path
|
||||
set current_diff_side $w
|
||||
set current_diff_header {}
|
||||
set current_diff_queue {}
|
||||
ui_status [mc "Loading diff of %s..." [escape_path $path]]
|
||||
|
||||
if {[string first {U} $m] >= 0} {
|
||||
merge_load_stages $path [list show_unmerged_diff $scroll_pos]
|
||||
} elseif {$m eq {_O}} {
|
||||
show_other_diff $path $w $m $scroll_pos
|
||||
} else {
|
||||
start_show_diff $scroll_pos
|
||||
}
|
||||
}
|
||||
|
||||
proc show_unmerged_diff {scroll_pos} {
|
||||
global current_diff_path current_diff_side
|
||||
global merge_stages ui_diff
|
||||
global current_diff_queue
|
||||
|
||||
if {$merge_stages(2) eq {}} {
|
||||
lappend current_diff_queue \
|
||||
[list "LOCAL: deleted\nREMOTE:\n" d======= \
|
||||
[list ":1:$current_diff_path" ":3:$current_diff_path"]]
|
||||
} elseif {$merge_stages(3) eq {}} {
|
||||
lappend current_diff_queue \
|
||||
[list "REMOTE: deleted\nLOCAL:\n" d======= \
|
||||
[list ":1:$current_diff_path" ":2:$current_diff_path"]]
|
||||
} elseif {[lindex $merge_stages(1) 0] eq {120000}
|
||||
|| [lindex $merge_stages(2) 0] eq {120000}
|
||||
|| [lindex $merge_stages(3) 0] eq {120000}} {
|
||||
lappend current_diff_queue \
|
||||
[list "LOCAL:\n" d======= \
|
||||
[list ":1:$current_diff_path" ":2:$current_diff_path"]]
|
||||
lappend current_diff_queue \
|
||||
[list "REMOTE:\n" d======= \
|
||||
[list ":1:$current_diff_path" ":3:$current_diff_path"]]
|
||||
} else {
|
||||
start_show_diff $scroll_pos
|
||||
return
|
||||
}
|
||||
|
||||
advance_diff_queue $scroll_pos
|
||||
}
|
||||
|
||||
proc advance_diff_queue {scroll_pos} {
|
||||
global current_diff_queue ui_diff
|
||||
|
||||
set item [lindex $current_diff_queue 0]
|
||||
set current_diff_queue [lrange $current_diff_queue 1 end]
|
||||
|
||||
$ui_diff conf -state normal
|
||||
$ui_diff insert end [lindex $item 0] [lindex $item 1]
|
||||
$ui_diff conf -state disabled
|
||||
|
||||
start_show_diff $scroll_pos [lindex $item 2]
|
||||
}
|
||||
|
||||
proc show_other_diff {path w m scroll_pos} {
|
||||
global file_states file_lists
|
||||
global is_3way_diff diff_active repo_config
|
||||
global ui_diff ui_index ui_workdir
|
||||
global current_diff_path current_diff_side current_diff_header
|
||||
|
||||
# - Git won't give us the diff, there's nothing to compare to!
|
||||
#
|
||||
if {$m eq {_O}} {
|
||||
@ -160,13 +224,29 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} {
|
||||
ui_ready
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
proc start_show_diff {scroll_pos {add_opts {}}} {
|
||||
global file_states file_lists
|
||||
global is_3way_diff diff_active repo_config
|
||||
global ui_diff ui_index ui_workdir
|
||||
global current_diff_path current_diff_side current_diff_header
|
||||
|
||||
set path $current_diff_path
|
||||
set w $current_diff_side
|
||||
|
||||
set s $file_states($path)
|
||||
set m [lindex $s 0]
|
||||
set is_3way_diff 0
|
||||
set diff_active 1
|
||||
set current_diff_header {}
|
||||
|
||||
set cmd [list]
|
||||
if {$w eq $ui_index} {
|
||||
lappend cmd diff-index
|
||||
lappend cmd --cached
|
||||
} elseif {$w eq $ui_workdir} {
|
||||
if {[string index $m 0] eq {U}} {
|
||||
if {[string first {U} $m] >= 0} {
|
||||
lappend cmd diff
|
||||
} else {
|
||||
lappend cmd diff-files
|
||||
@ -181,8 +261,12 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} {
|
||||
if {$w eq $ui_index} {
|
||||
lappend cmd [PARENT]
|
||||
}
|
||||
lappend cmd --
|
||||
lappend cmd $path
|
||||
if {$add_opts ne {}} {
|
||||
eval lappend cmd $add_opts
|
||||
} else {
|
||||
lappend cmd --
|
||||
lappend cmd $path
|
||||
}
|
||||
|
||||
if {[catch {set fd [eval git_read --nice $cmd]} err]} {
|
||||
set diff_active 0
|
||||
@ -203,6 +287,7 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} {
|
||||
proc read_diff {fd scroll_pos} {
|
||||
global ui_diff diff_active
|
||||
global is_3way_diff current_diff_header
|
||||
global current_diff_queue
|
||||
|
||||
$ui_diff conf -state normal
|
||||
while {[gets $fd line] >= 0} {
|
||||
@ -290,6 +375,12 @@ proc read_diff {fd scroll_pos} {
|
||||
|
||||
if {[eof $fd]} {
|
||||
close $fd
|
||||
|
||||
if {$current_diff_queue ne {}} {
|
||||
advance_diff_queue $scroll_pos
|
||||
return
|
||||
}
|
||||
|
||||
set diff_active 0
|
||||
unlock_index
|
||||
if {$scroll_pos ne {}} {
|
||||
@ -370,10 +461,9 @@ proc apply_hunk {x y} {
|
||||
}
|
||||
unlock_index
|
||||
display_file $current_diff_path $mi
|
||||
# This should trigger shift to the next changed file
|
||||
if {$o eq {_}} {
|
||||
clear_diff
|
||||
} else {
|
||||
set current_diff_path $current_diff_path
|
||||
reshow_diff
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,6 +99,7 @@ proc write_update_indexinfo {fd pathList totalCnt batch after} {
|
||||
switch -glob -- [lindex $s 0] {
|
||||
A? {set new _O}
|
||||
M? {set new _M}
|
||||
T_ {set new _T}
|
||||
D_ {set new _D}
|
||||
D? {set new _?}
|
||||
?? {continue}
|
||||
@ -162,6 +163,8 @@ proc write_update_index {fd pathList totalCnt batch after} {
|
||||
?D {set new D_}
|
||||
_O -
|
||||
AM {set new A_}
|
||||
_T {set new T_}
|
||||
_U -
|
||||
U? {
|
||||
if {[file exists $path]} {
|
||||
set new M_
|
||||
@ -231,6 +234,7 @@ proc write_checkout_index {fd pathList totalCnt batch after} {
|
||||
switch -glob -- [lindex $file_states($path) 0] {
|
||||
U? {continue}
|
||||
?M -
|
||||
?T -
|
||||
?D {
|
||||
puts -nonewline $fd "[encoding convertto $path]\0"
|
||||
display_file $path ?_
|
||||
@ -252,6 +256,7 @@ proc unstage_helper {txt paths} {
|
||||
switch -glob -- [lindex $file_states($path) 0] {
|
||||
A? -
|
||||
M? -
|
||||
T_ -
|
||||
D? {
|
||||
lappend pathList $path
|
||||
if {$path eq $current_diff_path} {
|
||||
@ -296,6 +301,7 @@ proc add_helper {txt paths} {
|
||||
_O -
|
||||
?M -
|
||||
?D -
|
||||
?T -
|
||||
U? {
|
||||
lappend pathList $path
|
||||
if {$path eq $current_diff_path} {
|
||||
@ -336,6 +342,7 @@ proc do_add_all {} {
|
||||
switch -glob -- [lindex $file_states($path) 0] {
|
||||
U? {continue}
|
||||
?M -
|
||||
?T -
|
||||
?D {lappend paths $path}
|
||||
}
|
||||
}
|
||||
@ -353,6 +360,7 @@ proc revert_helper {txt paths} {
|
||||
switch -glob -- [lindex $file_states($path) 0] {
|
||||
U? {continue}
|
||||
?M -
|
||||
?T -
|
||||
?D {
|
||||
lappend pathList $path
|
||||
if {$path eq $current_diff_path} {
|
||||
@ -409,11 +417,11 @@ proc do_revert_selection {} {
|
||||
|
||||
if {[array size selected_paths] > 0} {
|
||||
revert_helper \
|
||||
{Reverting selected files} \
|
||||
[mc "Reverting selected files"] \
|
||||
[array names selected_paths]
|
||||
} elseif {$current_diff_path ne {}} {
|
||||
revert_helper \
|
||||
"Reverting [short_path $current_diff_path]" \
|
||||
[mc "Reverting %s" [short_path $current_diff_path]] \
|
||||
[list $current_diff_path]
|
||||
}
|
||||
}
|
||||
|
373
git-gui/lib/mergetool.tcl
Normal file
373
git-gui/lib/mergetool.tcl
Normal file
@ -0,0 +1,373 @@
|
||||
# git-gui merge conflict resolution
|
||||
# parts based on git-mergetool (c) 2006 Theodore Y. Ts'o
|
||||
|
||||
proc merge_resolve_one {stage} {
|
||||
global current_diff_path
|
||||
|
||||
switch -- $stage {
|
||||
1 { set target [mc "the base version"] }
|
||||
2 { set target [mc "this branch"] }
|
||||
3 { set target [mc "the other branch"] }
|
||||
}
|
||||
|
||||
set op_question [mc "Force resolution to %s?
|
||||
Note that the diff shows only conflicting changes.
|
||||
|
||||
%s will be overwritten.
|
||||
|
||||
This operation can be undone only by restarting the merge." \
|
||||
$target [short_path $current_diff_path]]
|
||||
|
||||
if {[ask_popup $op_question] eq {yes}} {
|
||||
merge_load_stages $current_diff_path [list merge_force_stage $stage]
|
||||
}
|
||||
}
|
||||
|
||||
proc merge_add_resolution {path} {
|
||||
global current_diff_path ui_workdir
|
||||
|
||||
set after [next_diff_after_action $ui_workdir $path {} {^_?U}]
|
||||
|
||||
update_index \
|
||||
[mc "Adding resolution for %s" [short_path $path]] \
|
||||
[list $path] \
|
||||
[concat $after [list ui_ready]]
|
||||
}
|
||||
|
||||
proc merge_force_stage {stage} {
|
||||
global current_diff_path merge_stages
|
||||
|
||||
if {$merge_stages($stage) ne {}} {
|
||||
git checkout-index -f --stage=$stage -- $current_diff_path
|
||||
} else {
|
||||
file delete -- $current_diff_path
|
||||
}
|
||||
|
||||
merge_add_resolution $current_diff_path
|
||||
}
|
||||
|
||||
proc merge_load_stages {path cont} {
|
||||
global merge_stages_fd merge_stages merge_stages_buf
|
||||
|
||||
if {[info exists merge_stages_fd]} {
|
||||
catch { kill_file_process $merge_stages_fd }
|
||||
catch { close $merge_stages_fd }
|
||||
}
|
||||
|
||||
set merge_stages(0) {}
|
||||
set merge_stages(1) {}
|
||||
set merge_stages(2) {}
|
||||
set merge_stages(3) {}
|
||||
set merge_stages_buf {}
|
||||
|
||||
set merge_stages_fd [eval git_read ls-files -u -z -- $path]
|
||||
|
||||
fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary
|
||||
fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont]
|
||||
}
|
||||
|
||||
proc read_merge_stages {fd cont} {
|
||||
global merge_stages_buf merge_stages_fd merge_stages
|
||||
|
||||
append merge_stages_buf [read $fd]
|
||||
set pck [split $merge_stages_buf "\0"]
|
||||
set merge_stages_buf [lindex $pck end]
|
||||
|
||||
if {[eof $fd] && $merge_stages_buf ne {}} {
|
||||
lappend pck {}
|
||||
set merge_stages_buf {}
|
||||
}
|
||||
|
||||
foreach p [lrange $pck 0 end-1] {
|
||||
set fcols [split $p "\t"]
|
||||
set cols [split [lindex $fcols 0] " "]
|
||||
set stage [lindex $cols 2]
|
||||
|
||||
set merge_stages($stage) [lrange $cols 0 1]
|
||||
}
|
||||
|
||||
if {[eof $fd]} {
|
||||
close $fd
|
||||
unset merge_stages_fd
|
||||
eval $cont
|
||||
}
|
||||
}
|
||||
|
||||
proc merge_resolve_tool {} {
|
||||
global current_diff_path
|
||||
|
||||
merge_load_stages $current_diff_path [list merge_resolve_tool2]
|
||||
}
|
||||
|
||||
proc merge_resolve_tool2 {} {
|
||||
global current_diff_path merge_stages
|
||||
|
||||
# Validate the stages
|
||||
if {$merge_stages(2) eq {} ||
|
||||
[lindex $merge_stages(2) 0] eq {120000} ||
|
||||
[lindex $merge_stages(2) 0] eq {160000} ||
|
||||
$merge_stages(3) eq {} ||
|
||||
[lindex $merge_stages(3) 0] eq {120000} ||
|
||||
[lindex $merge_stages(3) 0] eq {160000}
|
||||
} {
|
||||
error_popup [mc "Cannot resolve deletion or link conflicts using a tool"]
|
||||
return
|
||||
}
|
||||
|
||||
if {![file exists $current_diff_path]} {
|
||||
error_popup [mc "Conflict file does not exist"]
|
||||
return
|
||||
}
|
||||
|
||||
# Determine the tool to use
|
||||
set tool [get_config merge.tool]
|
||||
if {$tool eq {}} { set tool meld }
|
||||
|
||||
set merge_tool_path [get_config "mergetool.$tool.path"]
|
||||
if {$merge_tool_path eq {}} {
|
||||
switch -- $tool {
|
||||
emerge { set merge_tool_path "emacs" }
|
||||
araxis { set merge_tool_path "compare" }
|
||||
default { set merge_tool_path $tool }
|
||||
}
|
||||
}
|
||||
|
||||
# Make file names
|
||||
set filebase [file rootname $current_diff_path]
|
||||
set fileext [file extension $current_diff_path]
|
||||
set basename [lindex [file split $current_diff_path] end]
|
||||
|
||||
set MERGED $current_diff_path
|
||||
set BASE "./$MERGED.BASE$fileext"
|
||||
set LOCAL "./$MERGED.LOCAL$fileext"
|
||||
set REMOTE "./$MERGED.REMOTE$fileext"
|
||||
set BACKUP "./$MERGED.BACKUP$fileext"
|
||||
|
||||
set base_stage $merge_stages(1)
|
||||
|
||||
# Build the command line
|
||||
switch -- $tool {
|
||||
kdiff3 {
|
||||
if {$base_stage ne {}} {
|
||||
set cmdline [list "$merge_tool_path" --auto --L1 "$MERGED (Base)" \
|
||||
--L2 "$MERGED (Local)" --L3 "$MERGED (Remote)" -o "$MERGED" "$BASE" "$LOCAL" "$REMOTE"]
|
||||
} else {
|
||||
set cmdline [list "$merge_tool_path" --auto --L1 "$MERGED (Local)" \
|
||||
--L2 "$MERGED (Remote)" -o "$MERGED" "$LOCAL" "$REMOTE"]
|
||||
}
|
||||
}
|
||||
tkdiff {
|
||||
if {$base_stage ne {}} {
|
||||
set cmdline [list "$merge_tool_path" -a "$BASE" -o "$MERGED" "$LOCAL" "$REMOTE"]
|
||||
} else {
|
||||
set cmdline [list "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"]
|
||||
}
|
||||
}
|
||||
meld {
|
||||
set cmdline [list "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"]
|
||||
}
|
||||
gvimdiff {
|
||||
set cmdline [list "$merge_tool_path" -f "$LOCAL" "$MERGED" "$REMOTE"]
|
||||
}
|
||||
xxdiff {
|
||||
if {$base_stage ne {}} {
|
||||
set cmdline [list "$merge_tool_path" -X --show-merged-pane \
|
||||
-R {Accel.SaveAsMerged: "Ctrl-S"} \
|
||||
-R {Accel.Search: "Ctrl+F"} \
|
||||
-R {Accel.SearchForward: "Ctrl-G"} \
|
||||
--merged-file "$MERGED" "$LOCAL" "$BASE" "$REMOTE"]
|
||||
} else {
|
||||
set cmdline [list "$merge_tool_path" -X --show-merged-pane \
|
||||
-R {Accel.SaveAsMerged: "Ctrl-S"} \
|
||||
-R {Accel.Search: "Ctrl+F"} \
|
||||
-R {Accel.SearchForward: "Ctrl-G"} \
|
||||
--merged-file "$MERGED" "$LOCAL" "$REMOTE"]
|
||||
}
|
||||
}
|
||||
opendiff {
|
||||
if {$base_stage ne {}} {
|
||||
set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED"]
|
||||
} else {
|
||||
set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$MERGED"]
|
||||
}
|
||||
}
|
||||
ecmerge {
|
||||
if {$base_stage ne {}} {
|
||||
set cmdline [list "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --default --mode=merge3 --to="$MERGED"]
|
||||
} else {
|
||||
set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" --default --mode=merge2 --to="$MERGED"]
|
||||
}
|
||||
}
|
||||
emerge {
|
||||
if {$base_stage ne {}} {
|
||||
set cmdline [list "$merge_tool_path" -f emerge-files-with-ancestor-command \
|
||||
"$LOCAL" "$REMOTE" "$BASE" "$basename"]
|
||||
} else {
|
||||
set cmdline [list "$merge_tool_path" -f emerge-files-command \
|
||||
"$LOCAL" "$REMOTE" "$basename"]
|
||||
}
|
||||
}
|
||||
winmerge {
|
||||
if {$base_stage ne {}} {
|
||||
# This tool does not support 3-way merges.
|
||||
# Use the 'conflict file' resolution feature instead.
|
||||
set cmdline [list "$merge_tool_path" -e -ub "$MERGED"]
|
||||
} else {
|
||||
set cmdline [list "$merge_tool_path" -e -ub -wl \
|
||||
-dl "Theirs File" -dr "Mine File" "$REMOTE" "$LOCAL" "$MERGED"]
|
||||
}
|
||||
}
|
||||
araxis {
|
||||
if {$base_stage ne {}} {
|
||||
set cmdline [list "$merge_tool_path" -wait -merge -3 -a1 \
|
||||
-title1:"'$MERGED (Base)'" -title2:"'$MERGED (Local)'" \
|
||||
-title3:"'$MERGED (Remote)'" \
|
||||
"$BASE" "$LOCAL" "$REMOTE" "$MERGED"]
|
||||
} else {
|
||||
set cmdline [list "$merge_tool_path" -wait -2 \
|
||||
-title1:"'$MERGED (Local)'" -title2:"'$MERGED (Remote)'" \
|
||||
"$LOCAL" "$REMOTE" "$MERGED"]
|
||||
}
|
||||
}
|
||||
p4merge {
|
||||
set cmdline [list "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED"]
|
||||
}
|
||||
vimdiff {
|
||||
error_popup [mc "Not a GUI merge tool: '%s'" $tool]
|
||||
return
|
||||
}
|
||||
default {
|
||||
error_popup [mc "Unsupported merge tool '%s'" $tool]
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
merge_tool_start $cmdline $MERGED $BACKUP [list $BASE $LOCAL $REMOTE]
|
||||
}
|
||||
|
||||
proc delete_temp_files {files} {
|
||||
foreach fname $files {
|
||||
file delete $fname
|
||||
}
|
||||
}
|
||||
|
||||
proc merge_tool_get_stages {target stages} {
|
||||
global merge_stages
|
||||
|
||||
set i 1
|
||||
foreach fname $stages {
|
||||
if {$merge_stages($i) eq {}} {
|
||||
file delete $fname
|
||||
catch { close [open $fname w] }
|
||||
} else {
|
||||
# A hack to support autocrlf properly
|
||||
git checkout-index -f --stage=$i -- $target
|
||||
file rename -force -- $target $fname
|
||||
}
|
||||
incr i
|
||||
}
|
||||
}
|
||||
|
||||
proc merge_tool_start {cmdline target backup stages} {
|
||||
global merge_stages mtool_target mtool_tmpfiles mtool_fd mtool_mtime
|
||||
|
||||
if {[info exists mtool_fd]} {
|
||||
if {[ask_popup [mc "Merge tool is already running, terminate it?"]] eq {yes}} {
|
||||
catch { kill_file_process $mtool_fd }
|
||||
catch { close $mtool_fd }
|
||||
unset mtool_fd
|
||||
|
||||
set old_backup [lindex $mtool_tmpfiles end]
|
||||
file rename -force -- $old_backup $mtool_target
|
||||
delete_temp_files $mtool_tmpfiles
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
# Save the original file
|
||||
file rename -force -- $target $backup
|
||||
|
||||
# Get the blobs; it destroys $target
|
||||
if {[catch {merge_tool_get_stages $target $stages} err]} {
|
||||
file rename -force -- $backup $target
|
||||
delete_temp_files $stages
|
||||
error_popup [mc "Error retrieving versions:\n%s" $err]
|
||||
return
|
||||
}
|
||||
|
||||
# Restore the conflict file
|
||||
file copy -force -- $backup $target
|
||||
|
||||
# Initialize global state
|
||||
set mtool_target $target
|
||||
set mtool_mtime [file mtime $target]
|
||||
set mtool_tmpfiles $stages
|
||||
|
||||
lappend mtool_tmpfiles $backup
|
||||
|
||||
# Force redirection to avoid interpreting output on stderr
|
||||
# as an error, and launch the tool
|
||||
lappend cmdline {2>@1}
|
||||
|
||||
if {[catch { set mtool_fd [_open_stdout_stderr $cmdline] } err]} {
|
||||
delete_temp_files $mtool_tmpfiles
|
||||
error_popup [mc "Could not start the merge tool:\n\n%s" $err]
|
||||
return
|
||||
}
|
||||
|
||||
ui_status [mc "Running merge tool..."]
|
||||
|
||||
fconfigure $mtool_fd -blocking 0 -translation binary -encoding binary
|
||||
fileevent $mtool_fd readable [list read_mtool_output $mtool_fd]
|
||||
}
|
||||
|
||||
proc read_mtool_output {fd} {
|
||||
global mtool_fd mtool_tmpfiles
|
||||
|
||||
read $fd
|
||||
if {[eof $fd]} {
|
||||
unset mtool_fd
|
||||
|
||||
fconfigure $fd -blocking 1
|
||||
merge_tool_finish $fd
|
||||
}
|
||||
}
|
||||
|
||||
proc merge_tool_finish {fd} {
|
||||
global mtool_tmpfiles mtool_target mtool_mtime
|
||||
|
||||
set backup [lindex $mtool_tmpfiles end]
|
||||
set failed 0
|
||||
|
||||
# Check the return code
|
||||
if {[catch {close $fd} err]} {
|
||||
set failed 1
|
||||
if {$err ne {child process exited abnormally}} {
|
||||
error_popup [strcat [mc "Merge tool failed."] "\n\n$err"]
|
||||
}
|
||||
}
|
||||
|
||||
# Check the modification time of the target file
|
||||
if {!$failed && [file mtime $mtool_target] eq $mtool_mtime} {
|
||||
if {[ask_popup [mc "File %s unchanged, still accept as resolved?" \
|
||||
[short_path $mtool_target]]] ne {yes}} {
|
||||
set failed 1
|
||||
}
|
||||
}
|
||||
|
||||
# Finish
|
||||
if {$failed} {
|
||||
file rename -force -- $backup $mtool_target
|
||||
delete_temp_files $mtool_tmpfiles
|
||||
ui_status [mc "Merge tool failed."]
|
||||
} else {
|
||||
if {[is_config_true merge.keepbackup]} {
|
||||
file rename -force -- $backup "$mtool_target.orig"
|
||||
}
|
||||
|
||||
delete_temp_files $mtool_tmpfiles
|
||||
|
||||
merge_add_resolution $mtool_target
|
||||
}
|
||||
}
|
@ -119,12 +119,14 @@ proc do_options {} {
|
||||
{b merge.summary {mc "Summarize Merge Commits"}}
|
||||
{i-1..5 merge.verbosity {mc "Merge Verbosity"}}
|
||||
{b merge.diffstat {mc "Show Diffstat After Merge"}}
|
||||
{t merge.tool {mc "Use Merge Tool"}}
|
||||
|
||||
{b gui.trustmtime {mc "Trust File Modification Timestamps"}}
|
||||
{b gui.pruneduringfetch {mc "Prune Tracking Branches During Fetch"}}
|
||||
{b gui.matchtrackingbranch {mc "Match Tracking Branches"}}
|
||||
{b gui.fastcopyblame {mc "Blame Copy Only On Changed Files"}}
|
||||
{i-20..200 gui.copyblamethreshold {mc "Minimum Letters To Blame Copy On"}}
|
||||
{i-0..300 gui.blamehistoryctx {mc "Blame History Context Radius (days)"}}
|
||||
{i-1..99 gui.diffcontext {mc "Number of Diff Context Lines"}}
|
||||
{i-0..99 gui.commitmsgwidth {mc "Commit Message Text Width"}}
|
||||
{t gui.newbranchtemplate {mc "New Branch Name Template"}}
|
||||
|
@ -418,10 +418,12 @@ proc stop_rev_list {view} {
|
||||
}
|
||||
|
||||
proc reset_pending_select {selid} {
|
||||
global pending_select mainheadid
|
||||
global pending_select mainheadid selectheadid
|
||||
|
||||
if {$selid ne {}} {
|
||||
set pending_select $selid
|
||||
} elseif {$selectheadid ne {}} {
|
||||
set pending_select $selectheadid
|
||||
} else {
|
||||
set pending_select $mainheadid
|
||||
}
|
||||
@ -1609,6 +1611,7 @@ proc getcommit {id} {
|
||||
proc readrefs {} {
|
||||
global tagids idtags headids idheads tagobjid
|
||||
global otherrefids idotherrefs mainhead mainheadid
|
||||
global selecthead selectheadid
|
||||
|
||||
foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
|
||||
catch {unset $v}
|
||||
@ -1655,6 +1658,12 @@ proc readrefs {} {
|
||||
set mainhead [string range $thehead 11 end]
|
||||
}
|
||||
}
|
||||
set selectheadid {}
|
||||
if {$selecthead ne {}} {
|
||||
catch {
|
||||
set selectheadid [exec git rev-parse --verify $selecthead]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# skip over fake commits
|
||||
@ -2205,6 +2214,8 @@ proc makewindow {} {
|
||||
-command {flist_hl 1}
|
||||
$flist_menu add command -label [mc "External diff"] \
|
||||
-command {external_diff}
|
||||
$flist_menu add command -label [mc "Blame parent commit"] \
|
||||
-command {external_blame 1}
|
||||
}
|
||||
|
||||
# Windows sends all mouse wheel events to the current focused window, not
|
||||
@ -3012,6 +3023,27 @@ proc external_diff {} {
|
||||
}
|
||||
}
|
||||
|
||||
proc external_blame {parent_idx} {
|
||||
global flist_menu_file
|
||||
global nullid nullid2
|
||||
global parentlist selectedline currentid
|
||||
|
||||
if {$parent_idx > 0} {
|
||||
set base_commit [lindex $parentlist $selectedline [expr {$parent_idx-1}]]
|
||||
} else {
|
||||
set base_commit $currentid
|
||||
}
|
||||
|
||||
if {$base_commit eq {} || $base_commit eq $nullid || $base_commit eq $nullid2} {
|
||||
error_popup [mc "No such commit"]
|
||||
return
|
||||
}
|
||||
|
||||
if {[catch {exec git gui blame $base_commit $flist_menu_file &} err]} {
|
||||
error_popup [mc "git gui blame: command failed: $err"]
|
||||
}
|
||||
}
|
||||
|
||||
# delete $dir when we see eof on $f (presumably because the child has exited)
|
||||
proc delete_at_eof {f dir} {
|
||||
while {[gets $f line] >= 0} {}
|
||||
@ -9865,6 +9897,9 @@ if {![file isdirectory $gitdir]} {
|
||||
exit 1
|
||||
}
|
||||
|
||||
set selecthead {}
|
||||
set selectheadid {}
|
||||
|
||||
set revtreeargs {}
|
||||
set cmdline_files {}
|
||||
set i 0
|
||||
@ -9876,6 +9911,9 @@ foreach arg $argv {
|
||||
set cmdline_files [lrange $argv [expr {$i + 1}] end]
|
||||
break
|
||||
}
|
||||
"--select-commit=*" {
|
||||
set selecthead [string range $arg 16 end]
|
||||
}
|
||||
"--argscmd=*" {
|
||||
set revtreeargscmd [string range $arg 10 end]
|
||||
}
|
||||
@ -9886,6 +9924,10 @@ foreach arg $argv {
|
||||
incr i
|
||||
}
|
||||
|
||||
if {$selecthead eq "HEAD"} {
|
||||
set selecthead {}
|
||||
}
|
||||
|
||||
if {$i >= [llength $argv] && $revtreeargs ne {}} {
|
||||
# no -- on command line, but some arguments (other than --argscmd)
|
||||
if {[catch {
|
||||
|
Loading…
Reference in New Issue
Block a user