From 3f71c97e180de4a9286ad2d7d19dfe4a22f2dd8b Mon Sep 17 00:00:00 2001 From: Mark Levedahl Date: Sat, 16 Sep 2023 17:01:31 -0400 Subject: [PATCH 1/2] git-gui - re-enable use of hook scripts Earlier, commit aae9560a introduced search in $PATH to find executables before running them, avoiding an issue where on Windows a same named file in the current directory can be executed in preference to anything in a directory in $PATH. This search is intended to find an absolute path for a bare executable ( e.g, a function "foo") by finding the first instance of "foo" in a directory given in $PATH, and this search works correctly. The search is explicitly avoided for an executable named with an absolute path (e.g., /bin/sh), and that works as well. Unfortunately, the search is also applied to commands named with a relative path. A hook script (or executable) $HOOK is usually located relative to the project directory as .git/hooks/$HOOK. The search for this will generally fail as that relative path will (probably) not exist on any directory in $PATH. This means that git hooks in general now fail to run. Considerable mayhem could occur should a directory on $PATH be git controlled. If such a directory includes .git/hooks/$HOOK, that repository's $HOOK will be substituted for the one in the current project, with unknown consequences. This lookup failure also occurs in worktrees linked to a remote .git directory using git-new-workdir. However, a worktree using a .git file pointing to a separate git directory apparently avoids this: in that case the hook command is resolved to an absolute path before being passed down to the code introduced in aae9560a. Fix this by replacing the test for an "absolute" pathname to a check for a command name having more than one pathname component. This limits the search and absolute pathname resolution to bare commands. The new test uses tcl's "file split" command. Experiments on Linux and Windows, using tclsh, show that command names with relative and absolute paths always give at least two components, while a bare command gives only one. Linux: puts [file split {foo}] ==> foo Linux: puts [file split {/foo}] ==> / foo Linux: puts [file split {.git/foo}] ==> .git foo Windows: puts [file split {foo}] ==> foo Windows: puts [file split {c:\foo}] ==> c:/ foo Windows: puts [file split {.git\foo}] ==> .git foo The above results show the new test limits search and replacement to bare commands on both Linux and Windows. Signed-off-by: Mark Levedahl Signed-off-by: Junio C Hamano --- git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui.sh b/git-gui.sh index 8bc8892c400a08..8603437e723deb 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -118,7 +118,7 @@ proc sanitize_command_line {command_line from_index} { set i $from_index while {$i < [llength $command_line]} { set cmd [lindex $command_line $i] - if {[file pathtype $cmd] ne "absolute"} { + if {[llength [file split $cmd]] < 2} { set fullpath [_which $cmd] if {$fullpath eq ""} { throw {NOT-FOUND} "$cmd not found in PATH" From 0730a5a3a5e69e4b5fa0fbf6edd7fcbd7a08c992 Mon Sep 17 00:00:00 2001 From: Mark Levedahl Date: Sun, 17 Sep 2023 15:24:31 -0400 Subject: [PATCH 2/2] git-gui - use git-hook, honor core.hooksPath git-gui currently runs some hooks directly using its own code written before 2010, long predating git v2.9 that added the core.hooksPath configuration to override the assumed location at $GIT_DIR/hooks. Thus, git-gui looks for and runs hooks including prepare-commit-msg, commit-msg, pre-commit, post-commit, and post-checkout from $GIT_DIR/hooks, regardless of configuration. Commands (e.g., git-merge) that git-gui invokes directly do honor core.hooksPath, meaning the overall behaviour is inconsistent. Furthermore, since v2.36 git exposes its hook execution machinery via `git-hook run`, eliminating the need for others to maintain code duplicating that functionality. Using git-hook will both fix git-gui's current issues on hook configuration and (presumably) reduce the maintenance burden going forward. So, teach git-gui to use git-hook. Signed-off-by: Mark Levedahl Signed-off-by: Junio C Hamano --- git-gui.sh | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index 8603437e723deb..3e5907a4609b15 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -661,31 +661,8 @@ proc git_write {args} { } proc githook_read {hook_name args} { - set pchook [gitdir hooks $hook_name] - lappend args 2>@1 - - # On Windows [file executable] might lie so we need to ask - # the shell if the hook is executable. Yes that's annoying. - # - if {[is_Windows]} { - upvar #0 _sh interp - if {![info exists interp]} { - set interp [_which sh] - } - if {$interp eq {}} { - error "hook execution requires sh (not in PATH)" - } - - set scr {if test -x "$1";then exec "$@";fi} - set sh_c [list $interp -c $scr $interp $pchook] - return [_open_stdout_stderr [concat $sh_c $args]] - } - - if {[file executable $pchook]} { - return [_open_stdout_stderr [concat [list $pchook] $args]] - } - - return {} + set cmd [concat git hook run --ignore-missing $hook_name -- $args 2>@1] + return [_open_stdout_stderr $cmd] } proc kill_file_process {fd} {