]> asedeno.scripts.mit.edu Git - git.git/blobdiff - lib/checkout_op.tcl
git-gui: Add hotkeys for "Unstage from commit" and "Revert changes"
[git.git] / lib / checkout_op.tcl
index f07262ca00876d885954ae15310a0faa197aa5ff..9e7412c446f715588b9cfe21654a3447e8680e12 100644 (file)
@@ -9,6 +9,7 @@ field w_cons   {}; # embedded console window object
 field new_expr   ; # expression the user saw/thinks this is
 field new_hash   ; # commit SHA-1 we are switching to
 field new_ref    ; # ref we are updating/creating
+field old_hash   ; # commit SHA-1 that was checked out when we started
 
 field parent_w      .; # window that started us
 field merge_type none; # type of merge to apply to existing branch
@@ -16,6 +17,7 @@ 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 remote_source {}; # same as fetch_spec, to setup tracking
 
 field reset_ok      0; # did the user agree to reset?
 field fetch_ok      0; # did the fetch succeed?
@@ -44,6 +46,10 @@ method enable_fetch {spec} {
        set fetch_spec $spec
 }
 
+method remote_source {spec} {
+       set remote_source $spec
+}
+
 method enable_checkout {co} {
        set checkout $co
 }
@@ -124,7 +130,7 @@ method _finish_fetch {ok} {
                }
                if {[catch {set new_hash [git rev-parse --verify "$l_trck^0"]} err]} {
                        set ok 0
-                       $w_cons insert "fatal: Cannot resolve $l_trck"
+                       $w_cons insert [mc "fatal: Cannot resolve %s" $l_trck]
                        $w_cons insert $err
                }
        }
@@ -145,7 +151,7 @@ method _finish_fetch {ok} {
 }
 
 method _update_ref {} {
-       global null_sha1 current_branch
+       global null_sha1 current_branch repo_config
 
        set ref $new_ref
        set new $new_hash
@@ -172,6 +178,23 @@ method _update_ref {} {
 
                set reflog_msg "branch: Created from $new_expr"
                set cur $null_sha1
+
+               if {($repo_config(branch.autosetupmerge) eq {true}
+                       || $repo_config(branch.autosetupmerge) eq {always})
+                       && $remote_source ne {}
+                       && "refs/heads/$newbranch" eq $ref} {
+
+                       set c_remote [lindex $remote_source 1]
+                       set c_merge [lindex $remote_source 2]
+                       if {[catch {
+                                       git config branch.$newbranch.remote $c_remote
+                                       git config branch.$newbranch.merge  $c_merge
+                               } err]} {
+                               _error $this [strcat \
+                               [mc "Failed to configure simplified git-pull for '%s'." $newbranch] \
+                               "\n\n$err"]
+                       }
+               }
        } elseif {$create && $merge_type eq {none}} {
                # We were told to create it, but not do a merge.
                # Bad.  Name shouldn't have existed.
@@ -236,7 +259,7 @@ method _update_ref {} {
                if {[catch {
                                git update-ref -m $reflog_msg $ref $new $cur
                        } err]} {
-                       _error $this [append [mc "Failed to update '%s'." $newbranch] "\n\n$err"]
+                       _error $this [strcat [mc "Failed to update '%s'." $newbranch] "\n\n$err"]
                        return 0
                }
        }
@@ -258,11 +281,11 @@ method _start_checkout {} {
 
        # -- Our in memory state should match the repository.
        #
-       repository_state curType curHEAD curMERGE_HEAD
+       repository_state curType old_hash curMERGE_HEAD
        if {[string match amend* $commit_type]
                && $curType eq {normal}
-               && $curHEAD eq $HEAD} {
-       } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} {
+               && $old_hash eq $HEAD} {
+       } elseif {$commit_type ne $curType || $HEAD ne $old_hash} {
                info_popup [mc "Last scanned state does not match repository state.
 
 Another Git program has modified this repository since the last scan.  A rescan must be performed before the current branch can be changed.
@@ -275,12 +298,12 @@ The rescan will be automatically started now.
                return
        }
 
-       if {$curHEAD eq $new_hash} {
+       if {$old_hash eq $new_hash} {
                _after_readtree $this
        } elseif {[is_config_true gui.trustmtime]} {
                _readtree $this
        } else {
-               ui_status {Refreshing file status...}
+               ui_status [mc "Refreshing file status..."]
                set fd [git_read update-index \
                        -q \
                        --unmerged \
@@ -319,8 +342,8 @@ method _readtree {} {
 
        set readtree_d {}
        $::main_status start \
-               "Updating working directory to '[_name $this]'..." \
-               {files checked out}
+               [mc "Updating working directory to '%s'..." [_name $this]] \
+               [mc "files checked out"]
 
        set fd [git_read --stderr read-tree \
                -m \
@@ -351,7 +374,7 @@ method _readtree_wait {fd} {
                set err $readtree_d
                regsub {^fatal: } $err {} err
                $::main_status stop [mc "Aborted checkout of '%s' (file level merging is required)." [_name $this]]
-               warn_popup [append [mc "File level merge required."] "
+               warn_popup [strcat [mc "File level merge required."] "
 
 $err
 
@@ -431,23 +454,57 @@ method _after_readtree {} {
 If you wanted to be on a branch, create one now starting from 'This Detached Checkout'."]
        }
 
+       # -- Run the post-checkout hook.
+       #
+       set fd_ph [githook_read post-checkout $old_hash $new_hash 1]
+       if {$fd_ph ne {}} {
+               global pch_error
+               set pch_error {}
+               fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
+               fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph]
+       } else {
+               _update_repo_state $this
+       }
+}
+
+method _postcheckout_wait {fd_ph} {
+       global pch_error
+
+       append pch_error [read $fd_ph]
+       fconfigure $fd_ph -blocking 1
+       if {[eof $fd_ph]} {
+               if {[catch {close $fd_ph}]} {
+                       hook_failed_popup post-checkout $pch_error 0
+               }
+               unset pch_error
+               _update_repo_state $this
+               return
+       }
+       fconfigure $fd_ph -blocking 0
+}
+
+method _update_repo_state {} {
        # -- Update our repository state.  If we were previously in
        #    amend mode we need to toss the current buffer and do a
        #    full rescan to update our file lists.  If we weren't in
        #    amend mode our file lists are accurate and we can avoid
        #    the rescan.
        #
+       global selected_commit_type commit_type HEAD MERGE_HEAD PARENT
+       global ui_comm
+
        unlock_index
+       set name [_name $this]
        set selected_commit_type new
        if {[string match amend* $commit_type]} {
                $ui_comm delete 0.0 end
                $ui_comm edit reset
                $ui_comm edit modified false
-               rescan [list ui_status "Checked out '$name'."]
+               rescan [list ui_status [mc "Checked out '%s'." $name]]
        } else {
                repository_state commit_type HEAD MERGE_HEAD
                set PARENT $HEAD
-               ui_status "Checked out '$name'."
+               ui_status [mc "Checked out '%s'." $name]
        }
        delete_this
 }
@@ -575,7 +632,7 @@ method _toplevel {title} {
 }
 
 method _fatal {err} {
-       error_popup [append [mc "Failed to set current branch.
+       error_popup [strcat [mc "Failed to set current branch.
 
 This working directory is only partially switched.  We successfully updated your files, but failed to update an internal Git file.