tipos tag remove practices etiquetas crear best git formatting githooks pre-commit-hook

remove - git tag best practices



git preajuste el formato del código del gancho con confirmación parcial? (2)

Haría esto haciendo el trabajo con los comandos de "plomería" de bajo nivel, mi primer intento sería algo parecido a

git ls-files --stage /*.c | while read mode object stage path; do case $mode in 10*) formatted=`git show $object | indent | git hash-object -w --stdin` git update-index --cacheinfo $mode $formatted "$path" ;; esac done

Para evitar el procesamiento redundante, comience desde git diff-index --name-only --diff-filter=AM output como @torek sugiere.

¿Hay alguna forma de tener un astyle automáticamente el código (por ejemplo, con astyle ) pero que no destruya un compromiso parcial?

Flujo de trabajo:

# edit a file.txt git add -p file.txt # add one chunk, but not another git commit -m ''a message'' [PRE_COMMIT_HOOK] Formatting source code git status # the "another" chunk is still not added

Mi problema es que si haces un git add dentro del gancho de precompromiso, que es necesario después de que el script formateó el código fuente, también se agrega el "otro" fragmento. Pero no quiero eso.

¿Hay una manera de lograr esto?


Hay (más o menos) una forma de hacerlo. No lo haría, pero si realmente lo deseas, sigue estas líneas.

Primero, necesita separar los dos elementos que tiene ahora:

  • los cambios escalonados
  • los elementos del árbol de trabajo no escalonados

Además, desea que el primer conjunto esté disponible para volver a formatear.

Esto se puede hacer con git stash , como mostré en la respuesta a ¿Cómo administro apropiadamente los staws / pop en pre-commit hooks para obtener un árbol de trabajo limpio para las pruebas? (ver la advertencia allí sobre un error en el alijo git también, sin embargo).

Básicamente, desea llegar al punto en el script donde se ejecutan las pruebas:

# Run tests status=...

Una vez que esté en este estado, puede ejecutar elementos del árbol de trabajo a través de formateadores y git add el resultado en un enlace precompromiso (como ya descubrió). Esto evitará formatear el "otro" fragmento porque no estaba en la versión del directorio de trabajo. Luego puede dejar que la confirmación continúe (es decir, el resto del guión no se aplica aquí).

El problema ahora es restaurar la versión del árbol de trabajo del alijo. Debido a que modificó el índice, no puede volver a esto, incluso después de que termine la confirmación:

# Restore changes git reset --hard -q && git stash apply --index -q && git stash drop -q

En cambio, lo que desea es encontrar la diferencia entre el índice stash^1 ( stash^1 ) y el árbol de trabajo stash ( stash ), y aplicarlo al nuevo commit de HEAD . Hay al menos dos formas de hacerlo sin usar los comandos de git plomería. Es probable que ambos generen conflictos debido al reformateo de la versión comprometida:

  1. git diff stash^1 stash | git apply --reject git diff stash^1 stash | git apply --reject (y eventualmente git stash drop )
  2. git stash branch tempbranch; git commit -m for-cherry-pick; git checkout prev-branch; git cherry-pick -n tempbranch; git branch -D tempbranch

El Método 1 es más simple pero desordenado, ya que los cambios que tendrían los conflictos de combinación se descartan en archivos de "rechazo". El Método 2 usa la maquinaria de fusión, por lo que los cambios obtienen marcadores de conflicto en su lugar, si es necesario. (Si no hay conflictos, la -n impide una confirmación para que pueda hacer lo suyo con un mensaje real, en lugar de copiar el mensaje ficticio for-cherry-pick ).

Por supuesto que no he probado nada de esto. Además, existen métodos para hacerlo sin usar git stash , como revisar las versiones de índice de los archivos git add -ed en un directorio separado, formatear las cosas allí y luego volver a agregar las versiones formateadas, de modo que nada de este proceso afecta el directorio de trabajo actual. Esto es probablemente superior de todos modos, si realmente está decidido a hacer esto. Aquí hay un script para ese método (que tampoco se ha probado realmente; necesita un poco de robustez, usando -z y xargs -0 quizás para manejar nombres de archivos que contengan espacios en blanco, en la salida de la sección de salida de diff-index):

# make a directory for formatting files WORKDIR=$(mktemp -d -t reformat) || exit 1 # clean it up when we leave trap "rm -rf $WORKDIR 0 1 2 3 15" # for files Added or Modified in the index, copy them to $WORKDIR git --work-tree=$WORKDIR checkout -- / $(git diff-index --cached --name-only --no-renames --diff-filter=AM HEAD) # reformat files in the work-dir (cd $WORKDIR; ...) # for each file in the work-dir, re-"add" that version to this tree # (this assumes the reformatter did not leave extraneous files!) git --work-tree=$WORKDIR add --ignore-removal .

Sin embargo, esto es lo que recomendaría en su lugar: en lugar de formatear el código en ese punto del enlace precompromiso, simplemente verifique si está formateado. Si es así, permita la confirmación. Si no, rechazarlo. Esto es mucho más en el espíritu de un gancho precompromiso, y permite usar el guión en esa otra respuesta . Básicamente, en el punto donde dice:

status=...

simplemente ejecute algo que verifique si el formateador podría cambiar algo (tal vez permitiendo que el formateador haga su trabajo y vea si el resultado es diferente de lo que está en el índice que se debe comprometer). Eso te da tu estado. Luego haces el resto de lo que está en el guión, con el git reset --hard -q && git stash apply --index -q && git stash drop -q restaurando todo tal como estaba cuando se creó el alijo.