VundleVim / Vundle.vim

Vundle, the plug-in manager for Vim
http://github.com/VundleVim/Vundle.Vim
MIT License
23.93k stars 2.57k forks source link

When invoked via git hook and installed as a sub-submodule, Vundle updates wrong repo #807

Open shippy opened 7 years ago

shippy commented 7 years ago

I recognize that this is the edgiest of edge cases (and also a case of shooting myself in the foot), but bear with me. (Edit: I started filing this issue while debugging, and now I'm not so sure this is a bug in Vundle; filing nonetheless.)

I started version-controlling my vim dotfiles before all other dotfiles. This has led to a somewhat idiosyncratic setup: Vundle is a submodule of dotvim, which is in turn a submodule of dotfiles. Consequently, it lives in ~/dotfiles/.git/modules/dotvim/modules/bundle.

Description of the problem:

Recently, I wanted to automate the plugin update / cleanup after every git pull, so I created a post-checkout git hook for the dotvim repo. Since dotvim is itself a submodule, the hook lives to ~/dotfiles/.git/modules/dotvim/hooks/post-checkout rather than ~/.vim/.git/hooks. The hook is simple:

#!/usr/bin/env bash
exec vim -c VundleUpdate -c PluginClean! -c quitall &> /dev/null
# Presence or absence of `exec` doesn't change the outcome

...which results in Vundle properly updating the plugins, but also changing the remote and updating the contents of my dotvim submodule rather than of the plugins in dotvim/bundle. (You can watch it happen live with cd ~/.vim && watch -n 1 "git remote -v".) The origin URL of dotvim ends up pointing at the remote of the last plugin that Vundle touched when the hook finishes.

Conditions:

This only happens in the git hook for submodule-of-a-submodule situation. It doesn't happen when:

Debugging:

(You can replicate my setup by running this gist.)

When I change the command to exec vim -c VundleUpdate -c PluginClean! and access the log, it starts with:

[2017-04-12 17:00:08] Plugin URI change detected for Plugin Vundle.vim
[2017-04-12 17:00:08] >  Plugin Vundle.vim old URI: https://github.com/shippy/dotvim.git
[2017-04-12 17:00:08] >  Plugin Vundle.vim new URI: https://github.com/VundleVim/Vundle.vim.git

The weird thing is, I stepped through the debugger and all those commands make sense! This is the command right before it's run through system in s:system:

>echo a:cmd
cd '/Users/sp576/.vim/bundle/Vundle.vim' && git remote set-url origin 'https://github.c
om/VundleVim/Vundle.vim.git' && git fetch && git reset --hard origin/HEAD && git submod
ule update --init --recursive

I tried running it from the command line; it did the expected thing. At first, I thought that what seems to be happening is that system isn't processing the directory change command (for whatever godforsaken reason), but no:

>call system('cd /Users/sp576/.vim/bundle/Vundle.vim')
>echo system('pwd')
/Users/sp576/.vim
>echo system('cd /Users/sp576/.vim/bundle/Vundle.vim && git remote get-url origin && pw
d')
https://github.com/VundleVim/Vundle.vim.git
/Users/sp576/.vim/bundle/Vundle.vim

Rather, it seems that it's something about vim calling git that's going screwy:

>echo system('cd ''/Users/sp576/.vim/bundle/Vundle.vim'' && pwd -P && ls -la && git rev
-parse --show-toplevel')
/private/tmp/bugtest/dotvim/bundle/Vundle.vim
total 96
drwxr-xr-x  15 sp576  wheel   510 Apr 12 17:53 .
drwxr-xr-x   3 sp576  wheel   102 Apr 12 17:29 ..
-rw-r--r--   1 sp576  wheel    63 Apr 12 17:29 .git
-rw-r--r--   1 sp576  wheel    20 Apr 12 17:29 .gitignore
-rw-r--r--   1 sp576  wheel  6191 Apr 12 17:29 CONTRIBUTING.md
-rw-r--r--   1 sp576  wheel  1068 Apr 12 17:29 LICENSE-MIT.txt
-rw-r--r--   1 sp576  wheel  6182 Apr 12 17:29 README.md
-rw-r--r--   1 sp576  wheel  7020 Apr 12 17:29 README_ZH_CN.md
-rw-r--r--   1 sp576  wheel  6935 Apr 12 17:29 README_ZH_TW.md
drwxr-xr-x   4 sp576  wheel   136 Apr 12 17:29 autoload
-rw-r--r--   1 sp576  wheel   809 Apr 12 17:29 changelog.md
drwxr-xr-x   3 sp576  wheel   102 Apr 12 17:29 doc
drwxr-xr-x   3 sp576  wheel   102 Apr 12 17:29 ftplugin
drwxr-xr-x   3 sp576  wheel   102 Apr 12 17:29 syntax
drwxr-xr-x   5 sp576  wheel   170 Apr 12 17:29 test
/private/tmp/bugtest/dotvim

...compared with the direct shell call:

 % cd ''/Users/sp576/.vim/bundle/Vundle.vim'' && pwd -P && ls -la && git rev-parse --show-toplevel
/private/tmp/bugtest/dotvim/bundle/Vundle.vim
total 96
drwxr-xr-x  15 sp576  wheel   510 Apr 12 17:53 .
drwxr-xr-x   3 sp576  wheel   102 Apr 12 17:29 ..
-rw-r--r--   1 sp576  wheel    63 Apr 12 17:29 .git
-rw-r--r--   1 sp576  wheel    20 Apr 12 17:29 .gitignore
-rw-r--r--   1 sp576  wheel  6191 Apr 12 17:29 CONTRIBUTING.md
-rw-r--r--   1 sp576  wheel  1068 Apr 12 17:29 LICENSE-MIT.txt
-rw-r--r--   1 sp576  wheel  6182 Apr 12 17:29 README.md
-rw-r--r--   1 sp576  wheel  7020 Apr 12 17:29 README_ZH_CN.md
-rw-r--r--   1 sp576  wheel  6935 Apr 12 17:29 README_ZH_TW.md
drwxr-xr-x   4 sp576  wheel   136 Apr 12 17:29 autoload
-rw-r--r--   1 sp576  wheel   809 Apr 12 17:29 changelog.md
drwxr-xr-x   3 sp576  wheel   102 Apr 12 17:29 doc
drwxr-xr-x   3 sp576  wheel   102 Apr 12 17:29 ftplugin
drwxr-xr-x   3 sp576  wheel   102 Apr 12 17:29 syntax
drwxr-xr-x   5 sp576  wheel   170 Apr 12 17:29 test
/private/tmp/bugtest/dotvim/bundle/Vundle.vim

I'm stumped as to what it is, though. A quick check says that both calls invoke the same git executable and share the same path; I'll dig further.

shippy commented 7 years ago

Got it! It's the $GIT_DIR environment value set by the git hook! Debugger output (stepping through the call initiated by the git hook):

# vim debugger
>echo $GIT_DIR
/private/tmp/bugtest/.git/modules/dotvim

Shell output:

# shell
 % pwd
/private/tmp/bugtest/dotvim/bundle/Vundle.vim
 % git rev-parse --show-toplevel
/private/tmp/bugtest/dotvim/bundle/Vundle.vim
 % echo $GIT_DIR

 % GIT_DIR=/tmp/bugtest/.git/modules/dotvim git rev-parse --show-toplevel
/private/tmp/bugtest/dotvim

GIT_DIR sets the working directory, as far as git is concerned, so that git commands will know what repo to operate on even if pwd is different. That's why the command goes awry. The upside is that there's an easy fix: env -u GIT_DIR or unset GIT_DIR will take GIT_DIR out of the environment for one command:

# vim debugger
>echo system('cd ''/Users/sp576/.vim/bundle/Vundle.vim'' && env -u GIT_DIR git rev-pars
e --show-toplevel')
/private/tmp/bugtest/dotvim/bundle/Vundle.vim
>echo $GIT_DIR
/private/tmp/bugtest/.git/modules/dotvim
>echo system('unset GIT_DIR; cd ''/Users/sp576/.vim/bundle/Vundle.vim'' && git rev-pars
e --show-toplevel')
/private/tmp/bugtest/dotvim/bundle/Vundle.vim
>echo $GIT_DIR
/private/tmp/bugtest/.git/modules/dotvim
>echo system('echo $GIT_DIR')
/private/tmp/bugtest/.git/modules/dotvim

I don't foresee any circumstance under which Vundle would need to know what $GIT_DIR says, so I'll file a PR that prefaces all relevant commands with unset GIT_DIR;.