Zsh git nombre de file completado con "–git-dir = … –work-tree = …": no es un repository de git

Rastreo mis files dotfiles usando este método:

  • Un repository desnudo reside en $HOME/repos/dotfiles .
  • Todos mis files dotfiles residen en su location normal, por ejemplo $HOME/.vim/vimrc , no $HOME/repos/dotfiles/vimrc .
  • git --git-dir=$HOME/repos/dotfiles --work-tree=$HOME ... para administrar cosas.

(En realidad, tengo una function g() que se expande al command anterior cuando estoy en $HOME , y de otra manera simplemente git ).

Todo funciona bien, excepto …

El problema: la finalización del nombre de file de Zsh git no funciona.

Ejemplo:

 % pwd /home/brian % g status ~ On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: .vim/vimrc modified: .xmonad/xmonad.hs no changes added to commit (use "git add" and/or "git commit -a") % g add <Tab> Completing not a git repository 

(El elemento "Completar …" se debe a zstyle ':completion:*' format $'%{\e[0;31m%}Completing %B%d%b%{\e[0m%}' .)

Notablemente, no sería suficiente decirle de alguna manera a la terminación de --work-tree zsh que "se mueva a / siga" el valor dado de --work-tree , como si se llamara a git desde ese directory, porque hacerlo explícitamente tampoco funciona:

 % cd repos/dotfiles % g status fatal: This operation must be run in a work tree % g add <Tab> Completing not a git repository 

La pregunta: ¿hay alguna manera fácil de extender la finalización de gsh de zsh a este tipo de caso?

Lamentablemente, es un error en la finalización de zsh para git. Puede encontrar la discusión en la list de correo 'zsh' aquí .

Daniel Shahaf proporcionó un parche para '_git':

 diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git index 518e6d198..45a0fa622 100644 --- a/Completion/Unix/Command/_git +++ b/Completion/Unix/Command/_git @@ -6609,20 +6609,33 @@ __git_files_relative () { (( $+functions[__git_files] )) || __git_files () { local compadd_opts opts tag description gitcdup gitprefix files expl + local pref zparseopts -D -E -a compadd_opts V: J: 1 2 nf X: M: P: S: r: R: q F: zparseopts -D -E -a opts -- -cached -deleted -modified -others -ignonetworking -unmerged -killed x+: --exclude+: tag=$1 description=$2; shift 2 - gitcdup=$(_call_program gitcdup git rev-parse --show-cdup 2>/dev/null) - __git_command_successful $pipestatus || return 1 + case $(_call_program gitinworktree git rev-parse --is-inside-work-tree 2>/dev/null) in + (true) + gitcdup=$(_call_program gitcdup git rev-parse --show-cdup 2>/dev/null) + __git_command_successful $pipestatus || return 1 - gitprefix=$(_call_program gitprefix git rev-parse --show-prefix 2>/dev/null) - __git_command_successful $pipestatus || return 1 + gitprefix=$(_call_program gitprefix git rev-parse --show-prefix 2>/dev/null) + __git_command_successful $pipestatus || return 1 + + local pref=$gitcdup$gitprefix$PREFIX + ;; + (false) + local pref= + ;; + (*) + # XXX what to do? + return 1 + ;; + esac # TODO: --directory should probably be added to $opts when --others is given. - local pref=$gitcdup$gitprefix$PREFIX # First allow ls-files to pattern-match in case of remote repository files=(${(0)"$(_call_program files git ls-files -z --exclude-standard ${(q)opts} -- ${(q)${pref:+$pref\\\*}} 2>/dev/null)"}) @@ -7585,7 +7598,8 @@ _git() { ;; (option-or-argument) curcontext=${curcontext%:*:*}:git-$words[1]: - (( $+opt_args[--git-dir] )) && local -x GIT_DIR=$opt_args[--git-dir] + (( $+opt_args[--git-dir] )) && local -x GIT_DIR=${(e)opt_args[--git-dir]} + (( $+opt_args[--work-tree] )) && local -x GIT_WORK_TREE=${(e)opt_args[--work-tree]} if ! _call_function ret _git-$words[1]; then if zstyle -T :completion:$curcontext: use-fallback; then _default && ret=0 

Se aplica claramente a zsh 5.4.1 pero no funcionó de mí, YMMV.

Actualizaré esta respuesta ya que se está trabajando en el problema.

EDITAR:

Con el parche anterior funciona, pero donde pones add es importante, tiene que ser al final:

 git --git-dir=$HOME/.dotfiles --work-tree=$HOME/ add 

Una cosa más que vale la pena notar, es algo lento.