git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: "D. Ben Knoble" <ben.knoble@gmail.com>
To: git@vger.kernel.org
Subject: libexec/git-core on PATH in editors and other subprocesses (and a fix for vim)
Date: Thu, 21 May 2020 16:31:35 -0400	[thread overview]
Message-ID: <CALnO6CDtGRRav8zK2GKi1oHTZWrHFTxZNmnOWu64-ab+oY3_Lw@mail.gmail.com> (raw)

Hello all,

I noticed something odd today--I was working in vim and spawned a new terminal
with `:terminal`. My shell startup files, which use the location of the git
binary to reconstruct paths to things like
`etc/bash_completion.d/git-prompt.sh` and `contrib/git-jump`, suddenly choked.
The location of the git program was suddenly different than usual!

After some debugging, I came to determine that this occurred, not because of
vim, but because vim was launched from a git-invoked process (in this case,
`contrib/git-jump/git-jump`).

The salient git code is `setup_path()` in exec-cmd.c [1] and it's call in git.c
[2]. They appear to coordinate to prepend the libexec dir to PATH. This causes
the location of the git binary to be (e.g.) /usr/local/libexec/git-core/git, and
not (e.g.) /usr/local/bin/git; since I traverse up two directories from the
location of git, the former breaks my startup scripts. (You would be well
withing your rights to argue that I should not use the location of git to find
these scripts. I have my reasons.)

Anyway, the net result is that if I run, say, `git jump grep foo` and then try
to invoke `:terminal` or `:shell`, my shell complains.

Unfortunately, this modification propagates to all child processes, as this
simple test-case demonstrates:

    $ printf '%s\n' '#!/bin/sh' "printenv PATH | tr : '\n' | grep
git-core" > git-show-env
    $ chmod u+x git-show-env
    $ PATH=.:$PATH git show-env
    /usr/local/Cellar/git/2.26.2/libexec/git-core

While it would be *nice* if git didn't modify PATH in such a way that it
affected all subprocesses (i.e., if it was somehow scoped to only processes that
need it), I suspect this is at best difficult and at worst highly-error prone or
likely to break things.

In the (possibly eternal) interim, I would like to share some vimscript that
"fixes" $PATH in vim when it detects this case. The easiest use is to drop the
code in your vimrc file (usually ~/.vim/vimrc or ~/.vimrc). I've tried to keep
it portable in terms of path separators and file paths, but I do not have a
Windows box to test on.

Actually, it's a little more aggressive than I suggested; it strips out *all*
PATH entries ending in libexec/git-core, not just the first. But I never have
libexec/git-core on my PATH anyway, so I'm not bothered by that. One could
modify this function to only check the first entry (the one git would have
prepended).

Best,
Ben Knoble

P.S. Does anyone know what the libexec/git-core equivalent is on Windows? [3]
alludes to libexec\git-core, which I *think* is handled by my code.

P.P.S. If your vim is old and does not have `const`, you can use `let` instead.
You may need to change out the lambda {_, d -> ... } for a "v:val" string as
well.

[1]: https://github.com/git/git/blob/87680d32efb6d14f162e54ad3bda4e3d6c908559/exec-cmd.c#L304
[2]: https://github.com/git/git/blob/87680d32efb6d14f162e54ad3bda4e3d6c908559/git.c#L868
[3]: https://wilsonmar.github.io/git-custom-commands/

--- VIM CODE

" When git starts up, it prepends it's libexec dir to PATH to allow it to find
" external commands.
"
" Thus, if vim is invoked via a git process (such as the contrib git-jump, my
" own git-ed, or any other usage of GIT_EDITOR/VISUAL/EDITOR in git commands, be
" they scripts or internals--with the exception of manually invoking the script
" yourself, without using git: sh .../git-jump), $PATH will contain something
" like libexec/git-core.
"
" We don't generally want it in vim's $PATH, though, as it is passed down to
" *all* subprocesses, including shells started with :terminal or :shell.
function s:fix_git_path() abort
  const slash = has('win32') ? '\' : '/'
  const git_core_base = printf('libexec%sgit-core', slash)
  " optimization: early return
  if $PATH !~# '.*'.git_core_base.'.*'
    return
  endif
  const path_sep = has('win32') ? ';' : ':'
  const path = split($PATH, path_sep)
  const path_sans_libexec_git_core = filter(path, {_, d -> d !~#
'.*'.git_core_base})
  const new_path = join(path_sans_libexec_git_core, path_sep)
  let $PATH = new_path
endfunction

augroup fix_git_path
  autocmd!
  autocmd VimEnter * call s:fix_git_path()
augroup END

--- END VIM CODE

                 reply	other threads:[~2020-05-21 20:31 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CALnO6CDtGRRav8zK2GKi1oHTZWrHFTxZNmnOWu64-ab+oY3_Lw@mail.gmail.com \
    --to=ben.knoble@gmail.com \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).