Skip to content

Commit ed76cb7

Browse files
committed
git-gui: Consolidate hook execution code into a single function
The code we use to test if a hook is executable or not differs on Cygwin from the normal POSIX case. Rather then repeating that for all three hooks we call in our commit code path we can place the common logic into a global procedure and invoke it when necessary. This also lets us get rid of the ugly "|& cat" we were using before as we can now rely on the Tcl 8.4 feature of "2>@1" or fallback to the "|& cat" when necessary. The post-commit hook is now run through the same API, but its outcome does not influence the commit status. As a result we now show any of the errors from the post-commit hook in a dialog window, instead of on the user's tty that was used to launch git-gui. This resolves a long standing bug related to not getting errors out of the post-commit hook when launched under git-gui. Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
1 parent c87238e commit ed76cb7

File tree

3 files changed

+63
-46
lines changed

3 files changed

+63
-46
lines changed

git-gui.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,34 @@ proc git_write {args} {
438438
return [open [concat $opt $cmdp $args] w]
439439
}
440440
441+
proc githook_read {hook_name args} {
442+
set pchook [gitdir hooks $hook_name]
443+
lappend args 2>@1
444+
445+
# On Cygwin [file executable] might lie so we need to ask
446+
# the shell if the hook is executable. Yes that's annoying.
447+
#
448+
if {[is_Cygwin]} {
449+
upvar #0 _sh interp
450+
if {![info exists interp]} {
451+
set interp [_which sh]
452+
}
453+
if {$interp eq {}} {
454+
error "hook execution requires sh (not in PATH)"
455+
}
456+
457+
set scr {if test -x "$1";then exec "$@";fi}
458+
set sh_c [list | $interp -c $scr $interp $pchook]
459+
return [_open_stdout_stderr [concat $sh_c $args]]
460+
}
461+
462+
if {[file executable $pchook]} {
463+
return [_open_stdout_stderr [concat [list | $pchook] $args]]
464+
}
465+
466+
return {}
467+
}
468+
441469
proc sq {value} {
442470
regsub -all ' $value "'\\''" value
443471
return "'$value'"

lib/commit.tcl

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -212,26 +212,14 @@ A good commit message has the following format:
212212

213213
# -- Run the pre-commit hook.
214214
#
215-
set pchook [gitdir hooks pre-commit]
216-
217-
# On Cygwin [file executable] might lie so we need to ask
218-
# the shell if the hook is executable. Yes that's annoying.
219-
#
220-
if {[is_Cygwin] && [file isfile $pchook]} {
221-
set pchook [list sh -c [concat \
222-
"if test -x \"$pchook\";" \
223-
"then exec \"$pchook\" 2>&1;" \
224-
"fi"]]
225-
} elseif {[file executable $pchook]} {
226-
set pchook [list $pchook |& cat]
227-
} else {
215+
set fd_ph [githook_read pre-commit]
216+
if {$fd_ph eq {}} {
228217
commit_commitmsg $curHEAD $msg_p
229218
return
230219
}
231220

232221
ui_status {Calling pre-commit hook...}
233222
set pch_error {}
234-
set fd_ph [open "| $pchook" r]
235223
fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
236224
fileevent $fd_ph readable \
237225
[list commit_prehook_wait $fd_ph $curHEAD $msg_p]
@@ -262,26 +250,14 @@ proc commit_commitmsg {curHEAD msg_p} {
262250

263251
# -- Run the commit-msg hook.
264252
#
265-
set pchook [gitdir hooks commit-msg]
266-
267-
# On Cygwin [file executable] might lie so we need to ask
268-
# the shell if the hook is executable. Yes that's annoying.
269-
#
270-
if {[is_Cygwin] && [file isfile $pchook]} {
271-
set pchook [list sh -c [concat \
272-
"if test -x \"$pchook\";" \
273-
"then exec \"$pchook\" \"$msg_p\" 2>&1;" \
274-
"fi"]]
275-
} elseif {[file executable $pchook]} {
276-
set pchook [list $pchook $msg_p |& cat]
277-
} else {
253+
set fd_ph [githook_read commit-msg $msg_p]
254+
if {$fd_ph eq {}} {
278255
commit_writetree $curHEAD $msg_p
279256
return
280257
}
281258

282259
ui_status {Calling commit-msg hook...}
283260
set pch_error {}
284-
set fd_ph [open "| $pchook" r]
285261
fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
286262
fileevent $fd_ph readable \
287263
[list commit_commitmsg_wait $fd_ph $curHEAD $msg_p]
@@ -415,17 +391,13 @@ A rescan will be automatically started now.
415391

416392
# -- Run the post-commit hook.
417393
#
418-
set pchook [gitdir hooks post-commit]
419-
if {[is_Cygwin] && [file isfile $pchook]} {
420-
set pchook [list sh -c [concat \
421-
"if test -x \"$pchook\";" \
422-
"then exec \"$pchook\";" \
423-
"fi"]]
424-
} elseif {![file executable $pchook]} {
425-
set pchook {}
426-
}
427-
if {$pchook ne {}} {
428-
catch {exec $pchook &}
394+
set fd_ph [githook_read post-commit]
395+
if {$fd_ph ne {}} {
396+
upvar #0 pch_error$cmt_id pc_err
397+
set pc_err {}
398+
fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
399+
fileevent $fd_ph readable \
400+
[list commit_postcommit_wait $fd_ph $cmt_id]
429401
}
430402

431403
$ui_comm delete 0.0 end
@@ -481,3 +453,18 @@ A rescan will be automatically started now.
481453
reshow_diff
482454
ui_status [mc "Created commit %s: %s" [string range $cmt_id 0 7] $subject]
483455
}
456+
457+
proc commit_postcommit_wait {fd_ph cmt_id} {
458+
upvar #0 pch_error$cmt_id pch_error
459+
460+
append pch_error [read $fd_ph]
461+
fconfigure $fd_ph -blocking 1
462+
if {[eof $fd_ph]} {
463+
if {[catch {close $fd_ph}]} {
464+
hook_failed_popup post-commit $pch_error 0
465+
}
466+
unset pch_error
467+
return
468+
}
469+
fconfigure $fd_ph -blocking 0
470+
}

lib/error.tcl

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ proc ask_popup {msg} {
6262
eval $cmd
6363
}
6464

65-
proc hook_failed_popup {hook msg} {
65+
proc hook_failed_popup {hook msg {is_fatal 1}} {
6666
set w .hookfail
6767
toplevel $w
6868

@@ -77,14 +77,16 @@ proc hook_failed_popup {hook msg} {
7777
-width 80 -height 10 \
7878
-font font_diff \
7979
-yscrollcommand [list $w.m.sby set]
80-
label $w.m.l2 \
81-
-text [mc "You must correct the above errors before committing."] \
82-
-anchor w \
83-
-justify left \
84-
-font font_uibold
8580
scrollbar $w.m.sby -command [list $w.m.t yview]
8681
pack $w.m.l1 -side top -fill x
87-
pack $w.m.l2 -side bottom -fill x
82+
if {$is_fatal} {
83+
label $w.m.l2 \
84+
-text [mc "You must correct the above errors before committing."] \
85+
-anchor w \
86+
-justify left \
87+
-font font_uibold
88+
pack $w.m.l2 -side bottom -fill x
89+
}
8890
pack $w.m.sby -side right -fill y
8991
pack $w.m.t -side left -fill both -expand 1
9092
pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10

0 commit comments

Comments
 (0)