Excluir una sola confirmación de un “git diff”

3 minutos de lectura

Buenos días a todos, digamos que tengo una serie de confirmaciones de la siguiente manera:

  • abc000
  • def111
  • abc222
  • def333
  • abc444
  • def555

Sé que puedo usar

$ git diff -c --binary abc000..def555 > /tmp/abc000_def555.patch

para producir un parche para actualizar un sistema de abc000 a def555.

Pero, ¿y si quisiera (por razones demasiado aburridas para entrar)? excluir def333 del parche – ¿cómo puedo hacer esto? Tenga en cuenta que no quiero revertir def333, es solo que no quiero que el parche incorpore este compromiso.

Gracias

Realmente todos git diffs son commit-pair-wise: lo anterior compara los árboles/archivos en abc000 contra los que están en def555. Si por ejemplo def333 cambios dir/file pero no hay cambios en dir/file Entre abc000 y def555 (por ejemplo, el cambio en def333 es cancelado por algo en el camino) es posible que no veas dir/file allí en absoluto.

En general, sin embargo, los cambios realizados en def333 habrá alterado dir/file de una manera que se muestra al comparar la versión en abc000 contra el que esta en def555. Así que lo harás probablemente ver ese cambio.

La forma más fácil de obtener una diferencia que muestre “qué def555 se vería como si def333 fueron revertidos” es hacer exactamente eso: crear un árbol (en una rama temporal) con el cambio revertido. Para hacerlo con una rama con nombre real, puede hacer algo como esto:

git checkout def555 # by ID, so that you get a "detached HEAD"
git checkout -b temp-branch
git revert --no-edit def333
git diff [options] abc000
git checkout somebranch; git branch -D temp-branch

¿Qué pasa si no quieres una rama temporal? Bueno, eso es trivial: simplemente no crees uno. Obtenga una “CABEZA separada” como arriba, haga la reversión como arriba, y luego git checkout somebranch. No hay una rama temporal para eliminar, a excepción de la sin nombre que git le advertirá que está dejando atrás… que es justo lo que quería.

  • También podrías usar revert --no-commitentonces no necesitarías una rama (o una cabeza separada) y no dejarías nada atrás.

    – Bergi

    14/03/2016 a las 14:40

  • @Bergi: cierto (aunque luego tendrás que git reset --hard para limpiar el árbol de trabajo una vez que haya terminado).

    – torek

    14/03/2016 a las 18:19

avatar de usuario
Elías Lynn

no es posible git diff y excluir una o más confirmaciones. Tienes que hacer una nueva rama, revertir las confirmaciones no deseadas, luego diferenciarla y hacer un parche:

git checkout --branch <branch-name>-diff-branch // Create a throwaway branch.
git revert <unwanted-sha> // Get rid of the unwanted commit. Do this as many times as necessary, you cannot revert multiple SHAs at once.
git diff > new.patch // Create your new patch.
git checkout - // Checkout previous branch, nice trick eh?!
git branch --delete --force <branch-name>-diff-branch // Delete the throwaway branch.

PD: no quería sacrificar demasiado la respuesta de Torek, así que publiqué una nueva que creo que es más concisa.

Diría que creas una nueva rama, seleccionas las confirmaciones que necesitas y luego haces la diferencia

Puede intentar usar git rebase -i y luego eliminar la confirmación que no necesita. Otra forma es seleccionar las confirmaciones que necesita en una rama diferente.

Pregunta anterior, sin embargo, necesitaba hacer esto para inspeccionar visualmente la diferencia entre dos confirmaciones y quería excluir algunas de las confirmaciones.

La forma más efectiva y fácil que encontré fue usar primero el comando git-format-patch para generar todas las confirmaciones en archivos de parches en el disco en un directorio dedicado; y luego use un comando para buscar y eliminar los archivos que contenían números de confirmación que quería eliminar. Finalmente, concatené todos los archivos de parche restantes en un solo archivo, que es lo que solicita el OP.

En un sistema Linux con Bash, puede hacer lo siguiente:

git format-patch --full-index <start-commit>..<end-commit>
mkdir all_patches
mv *.patch all_patches/
cd all_patches/
rm -rf `egrep -lsr "commit1-to-exclude|commit2-to-exclude|commit3-to-exclude" . `
cat * >> final.diff

¿Ha sido útil esta solución?