field parent_w .; # window that started us
field merge_type none; # type of merge to apply to existing branch
+field merge_base {}; # merge base if we have another ref involved
field fetch_spec {}; # refetch tracking branch if used?
field checkout 1; # actually checkout the branch?
field create 0; # create the branch if it doesn't exist?
field reset_ok 0; # did the user agree to reset?
field fetch_ok 0; # did the fetch succeed?
+field readtree_d {}; # buffered output from read-tree
field update_old {}; # was the update-ref call deferred?
field reflog_msg {}; # log message for the update-ref call
set r_head [lindex $fetch_spec 2]
regsub ^refs/heads/ $r_head {} r_name
+ set cmd [list git fetch $remote]
+ if {$l_trck ne {}} {
+ lappend cmd +$r_head:$l_trck
+ } else {
+ lappend cmd $r_head
+ }
+
_toplevel $this {Refreshing Tracking Branch}
set w_cons [::console::embed \
$w.console \
"Fetching $r_name from $remote"]
pack $w.console -fill both -expand 1
- $w_cons exec \
- [list git fetch $remote +$r_head:$l_trck] \
- [cb _finish_fetch]
+ $w_cons exec $cmd [cb _finish_fetch]
bind $w <$M1B-Key-w> break
bind $w <$M1B-Key-W> break
method _finish_fetch {ok} {
if {$ok} {
set l_trck [lindex $fetch_spec 0]
+ if {$l_trck eq {}} {
+ set l_trck FETCH_HEAD
+ }
if {[catch {set new_hash [git rev-parse --verify "$l_trck^0"]} err]} {
set ok 0
$w_cons insert "fatal: Cannot resolve $l_trck"
# No merge would be required, don't compute anything.
#
} else {
- set mrb {}
- catch {set mrb [git merge-base $new $cur]}
- switch -- $merge_type {
- ff {
- if {$mrb eq $new} {
- # The current branch is actually newer.
- #
- set new $cur
- } elseif {$mrb eq $cur} {
- # The current branch is older.
- #
- set reflog_msg "merge $new_expr: Fast-forward"
- } else {
- _error $this "Branch '$newbranch' already exists.\n\nIt cannot fast-forward to $new_expr.\nA merge is required."
- return 0
+ catch {set merge_base [git merge-base $new $cur]}
+ if {$merge_base eq $cur} {
+ # The current branch is older.
+ #
+ set reflog_msg "merge $new_expr: Fast-forward"
+ } else {
+ switch -- $merge_type {
+ ff {
+ if {$merge_base eq $new} {
+ # The current branch is actually newer.
+ #
+ set new $cur
+ set new_hash $cur
+ } else {
+ _error $this "Branch '$newbranch' already exists.\n\nIt cannot fast-forward to $new_expr.\nA merge is required."
+ return 0
+ }
}
- }
- reset {
- if {$mrb eq $cur} {
- # The current branch is older.
- #
- set reflog_msg "merge $new_expr: Fast-forward"
- } else {
+ reset {
# The current branch will lose things.
#
if {[_confirm_reset $this $cur]} {
return 0
}
}
- }
- default {
- _error $this "Only 'ff' and 'reset' merge is currently supported."
- return 0
- }
+ default {
+ _error $this "Merge strategy '$merge_type' not supported."
+ return 0
+ }
+ }
}
}
if {[lock_index checkout_op]} {
after idle [cb _start_checkout]
} else {
- _error $this "Index is already locked."
+ _error $this "Staging area (index) is already locked."
delete_this
}
}
return
}
- if {[is_config_true gui.trustmtime]} {
+ if {$curHEAD eq $new_hash} {
+ _after_readtree $this
+ } elseif {[is_config_true gui.trustmtime]} {
_readtree $this
} else {
ui_status {Refreshing file status...}
- set cmd [list git update-index]
- lappend cmd -q
- lappend cmd --unmerged
- lappend cmd --ignore-missing
- lappend cmd --refresh
- set fd [open "| $cmd" r]
+ set fd [git_read update-index \
+ -q \
+ --unmerged \
+ --ignore-missing \
+ --refresh \
+ ]
fconfigure $fd -blocking 0 -translation binary
fileevent $fd readable [cb _refresh_wait $fd]
}
method _readtree {} {
global HEAD
- ui_status "Updating working directory to '[_name $this]'..."
- set cmd [list git read-tree]
- lappend cmd -m
- lappend cmd -u
- lappend cmd --exclude-per-directory=.gitignore
- lappend cmd $HEAD
- lappend cmd $new_hash
- set fd [open "| $cmd" r]
+ set readtree_d {}
+ $::main_status start \
+ "Updating working directory to '[_name $this]'..." \
+ {files checked out}
+
+ set fd [git_read --stderr read-tree \
+ -m \
+ -u \
+ -v \
+ --exclude-per-directory=.gitignore \
+ $HEAD \
+ $new_hash \
+ ]
fconfigure $fd -blocking 0 -translation binary
fileevent $fd readable [cb _readtree_wait $fd]
}
method _readtree_wait {fd} {
- global selected_commit_type commit_type HEAD MERGE_HEAD PARENT
- global current_branch is_detached
- global ui_comm
+ global current_branch
+
+ set buf [read $fd]
+ $::main_status update_meter $buf
+ append readtree_d $buf
- # -- We never get interesting output on stdout; only stderr.
- #
- read $fd
fconfigure $fd -blocking 1
if {![eof $fd]} {
fconfigure $fd -blocking 0
return
}
- set name [_name $this]
-
- # -- The working directory wasn't in sync with the index and
- # we'd have to overwrite something to make the switch. A
- # merge is required.
- #
- if {[catch {close $fd} err]} {
+ if {[catch {close $fd}]} {
+ set err $readtree_d
regsub {^fatal: } $err {} err
+ $::main_status stop "Aborted checkout of '[_name $this]' (file level merging is required)."
warn_popup "File level merge required.
$err
Staying on branch '$current_branch'."
- ui_status "Aborted checkout of '$name' (file level merging is required)."
unlock_index
delete_this
return
}
+ $::main_status stop
+ _after_readtree $this
+}
+
+method _after_readtree {} {
+ global selected_commit_type commit_type HEAD MERGE_HEAD PARENT
+ global current_branch is_detached
+ global ui_comm
+
+ set name [_name $this]
set log "checkout: moving"
if {!$is_detached} {
append log " from $current_branch"
set rn [string length $rh]
if {[string equal -length $rn $rh $new_ref]} {
set new_branch [string range $new_ref $rn end]
- append log " to $new_branch"
-
- if {[catch {
- git symbolic-ref -m $log HEAD $new_ref
- } err]} {
- _fatal $this $err
+ if {$is_detached || $current_branch ne $new_branch} {
+ append log " to $new_branch"
+ if {[catch {
+ git symbolic-ref -m $log HEAD $new_ref
+ } err]} {
+ _fatal $this $err
+ }
+ set current_branch $new_branch
+ set is_detached 0
}
- set current_branch $new_branch
- set is_detached 0
} else {
- append log " to $new_expr"
-
- if {[catch {
- _detach_HEAD $log $new_hash
- } err]} {
- _fatal $this $err
+ if {$new_hash ne $HEAD} {
+ append log " to $new_expr"
+ if {[catch {
+ _detach_HEAD $log $new_hash
+ } err]} {
+ _fatal $this $err
+ }
}
set current_branch HEAD
set is_detached 1
pack $w.buttons.cancel -side right -padx 5
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
- set fd [open "| git rev-list --pretty=oneline $cur ^$new_hash" r]
+ set fd [git_read rev-list --pretty=oneline $cur ^$new_hash]
while {[gets $fd line] > 0} {
set abbr [string range $line 0 7]
set subj [string range $line 41 end]