¿Git bash-completion con soporte de nombre de file?

¿Hay una secuencia de commands bash-completion que admita la finalización del nombre del file? Uso principalmente mercurial y allí puedo escribir:

hg diff test/test_<tab> 

y mostrará / completará todos los files de testing modificados. Funciona para la mayoría de los subcommands, es decir, hg add <tab><tab> solo mostrará los files sin seguimiento. Es realmente útil.

El script bash de git contrib parece no ser compatible con esto. ¿Hay alguna alternativa o cómo trabajas con git en la línea de command?

Editar 2015

git-completion.bash admite la git-completion.bash completa del nombre de file desde ~ 1.8.2

Entonces, veamos cómo el script de finalización bash de Mercurial hace esto.

Esta es la parte importante :

 _hg_status() { local files="$(_hg_cmd status -n$1 .)" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) } 

Se llama aquí :

 _hg_command_specific() { case "$cmd" in [...] diff) _hg_status "mar" ;; [...] esac return 0 } 

Por lo tanto, es simplemente una llamada de hg status -nmar , y usar el resultado como una list de files para completar.

Creo que no sería muy difícil parchear algo similar en el script de finalización de git – tendríamos que modificar __git_diff aquí para no hacer un nombre de file simple + terminación de bifurcación, sino llamar al git status lugar.


Los commands

 git status --porcelain | grep '^.[^ ?]' | cut -b 4- 

(para git diff --cached ) y

 git status --porcelain | grep '^[^ ?]' | cut -b 4- 

(para git diff ) parece dar la salida correcta (si no hay cambios de nombre).

Sin embargo, no son útiles cuando difieren en algo más que HEAD.

Una forma más general sería usar

 git diff --relative --name-only [--cached] [commit1] [commit2]] 

donde commit1 y commit2 (y quizás --cached ) provienen de la línea de command diff ya dada.


Implementé la idea descrita anteriormente en bash y parcheé en git-completion.bash . Si no desea cambiar su git-completion.bash , agregue estas dos funciones a algún file bash y encuéntrelo después del git-completion.bash original. Ahora debería funcionar con commands como

 git diff -- <tab> git diff --cached -- <tab> git diff HEAD^^ -- <tab> git diff origin/master master -- <tab> 

Envié esto como un parche a la list de correo git, veamos los resultados de esto. (Actualizaré esta respuesta ya que recibo comentarios).

 # Completion for the file argument for git diff. # It completes only files actually changed. This might be useful # as completion for other commands as well. # # The idea comes from the bash completion for Mercurial (hg), # which does something similar (but more simple, only difference of # working directory to HEAD and/or index, if I understand right). # It (the idea) was brought to us by the question # http://stackoverflow.com/q/6034472/600500 # from "olt". __git_complete_changed_files() { # # We use "git diff --name-only --relative" to generate the list, # but this needs the same --cached and <commit> arguments as the # command line being constructed. # # first grab arguments like --cached and any commit arguments. local -a args=() local finish=false for (( i=1 ; i < cword ; i++)) do local current_arg=${words[$i]} # echo checking $current_arg >&2 case $current_arg in --cached) args+=( $current_arg ) ;; --) # finish parsing arguments, the rest are file names break ;; -*) # other options are ignonetworking ;; *) if git cat-file -e $current_arg 2> /dev/null then case $( git cat-file -t $current_arg ) in commit|tag) # commits and tags are added to the command line. args+=( $current_arg ) # echo adding $current_arg >&2 ;; *) esac fi ;; esac done # now we can call `git diff` COMPREPLY=( $( compgen \ -W "$( git diff --name-only --relative "${args[@]}" -- )" -- $cur ) ) } _git_diff () { if __git_has_doubledash then # complete for the file part: only changed files __git_complete_changed_files else case "$cur" in --*) __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex --base --ours --theirs --no-index $__git_diff_common_options " return ;; esac __git_complete_revlist_file fi } 

Actualización: Parece que este parche no se desea de esta forma, ya que la forma actual de completar files es más útil para las personas que desean verificar si hay cambios en algún subdirectory (por ejemplo, completar cuando la salida de diff puede estar vacía). Puede ser aceptado si está vinculado a alguna variable de configuration (siendo el comportamiento pnetworkingeterminado el pnetworkingeterminado). Además, el sangrado debe adaptarse al estándar (ver la respuesta de Junio ​​C Hamano ).

Podría intentarlo otra vez, pero no puedo garantizar esto para el futuro cercano. Si alguien más quiere hacerlo, puede tomar mi código, cambiarlo y enviarlo nuevamente.

Esto resuelve el problema de git diff <tab> para mí, ponga lo siguiente en .bashrc :

 alias gid='git diff' __gdiff () { local cur prev opts COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" opts=$(git status --porcelain | grep '^.[^ ?]' | cut -b 4-) case "${prev}" in gid) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) ;; esac } complete -F __gdiff gid 

Y luego haga gid <tab> lugar de git diff <tab> . Puede ser simplificado, pero parece funcionar bien como una solución rápida.

No es realmente su respuesta deseada, pero quería hacerle saber que soon fish (caparazón amigable e interactivo) le dará soporte para la finalización del nombre de file de git de la caja. Actualmente está en master con una versión 2.3.0 próximamente.

https://github.com/fish-shell/fish-shell/issues/901
https://github.com/fish-shell/fish-shell/pull/2364
https://github.com/fish-shell/fish-shell/commit/c5c59d4acb00674bc37198468b5978f69484c628

Si tienes un estado como este:

 $ git status modified: ../README.md $ git add <tab> :/README.md 

enter image description here

También puede simplemente escribir README y presionar tabulación y lo insertá si es la única coincidencia. Friggin agradable!