Subject: [PATCH v2] git-gui: run post-checkout hook on checkout

From: Jens Lehmann <[email-masked]>
Date: Mon, 30 Mar 2009 21:46:17 +0200

git-gui is using "git-read-tree -u" for checkout which doesn't
invoke the post-checkout hook as a plain git-checkout would.
So git-gui must call the hook itself.

Signed-off-by: Jens Lehmann <[email-masked]>
---

Thanks to Shawn for the review of the first version, this one
tries to address all the issues raised.

 git-gui/lib/checkout_op.tcl |   43 +++++++++++++++++++++++++++++++++++++++----
 1 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/git-gui/lib/checkout_op.tcl b/git-gui/lib/checkout_op.tcl
index caca888..9e7412c 100644
--- a/git-gui/lib/checkout_op.tcl
+++ b/git-gui/lib/checkout_op.tcl
@@ -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
@@ -280,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.
@@ -297,7 +298,7 @@ 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
@@ -453,13 +454,47 @@ 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
-- 
1.6.2.1.414.g2daa3