ver repositorio que origin modificados crear comandos archivos git squash git-squash

repositorio - git ver archivos modificados



Aplasta mis últimos X confines juntos usando Git (30)

WARNING️ ADVERTENCIA: "Mis últimas X confirmaciones" pueden ser ambiguas.

(MASTER) Fleetwood Mac Fritz ║ ║ Add Danny Lindsey Stevie Kirwan Buckingham Nicks ║ ╚═══╦══════╝ Add Christine ║ Perfect Buckingham ║ Nicks LA1974══════════╝ ║ ║ Bill <══════ YOU ARE EDITING HERE Clinton (CHECKED OUT, CURRENT WORKING DIRECTORY)

En esta historia muy abreviada del repositorio https://github.com/fleetwood-mac , ha abierto una solicitud de extracción para fusionar el compromiso de Bill Clinton en el compromiso original ( MASTER ) Fleetwoodd Mac.

Abriste una solicitud de extracción y en GitHub ves esto:

Cuatro cometidos:

  • Añadir Danny Kirwan
  • Añadir Christine Perfect
  • LA1974
  • Bill Clinton

Pensando que a nadie le importaría leer el historial completo del repositorio. (En realidad hay un repositorio, haga clic en el enlace de arriba). Decide aplastar estos compromisos. Así que ve y ejecuta git reset --soft HEAD~4 && git commit . Luego git push --force en GitHub para limpiar tus relaciones públicas.

¿Y que pasa? Acabas de hacer un solo compromiso de Fritz a Bill Clinton. Porque olvidas que ayer estabas trabajando en la versión de Buckingham Nicks de este proyecto. Y el git log no coincide con lo que ves en GitHub.

🐻 MORAL DE LA HISTORIA

  1. Encuentra los archivos exactos que deseas, y git checkout ellos
  2. Encuentre la confirmación anterior exacta que desea mantener en el historial y git reset --soft that
  3. Haga un git commit que deforme directamente desde el al al

¿Cómo puedo aplastar mis últimas X confirmaciones juntas en una confirmación usando Git?


¿Qué tal una respuesta para la pregunta relacionada con un flujo de trabajo como este?

  1. muchos compromisos locales, mezclados con múltiples combinaciones de maestro ,
  2. finalmente un empuje a distancia,
  3. PR y fusionar A master por revisor . (Sí, sería más fácil para el desarrollador merge --squash después de las relaciones públicas, pero el equipo pensó que eso ralentizaría el proceso).

No he visto un flujo de trabajo como ese en esta página. (Eso puede ser lo que veo). Si entiendo correctamente la rebase , las rebase múltiples requerirán múltiples resoluciones de conflicto . ¡NO quiero ni siquiera pensar en eso!

Entonces, esto parece funcionar para nosotros.

  1. git pull master
  2. git checkout -b new-branch
  3. git checkout -b new-branch-temp
  4. Editar y cometer mucho localmente, fusionar master regularmente
  5. git checkout new-branch
  6. git merge --squash new-branch-temp // coloca todos los cambios en la etapa
  7. git commit ''one message to rule them all''
  8. git push
  9. Revisor hace PR y se fusiona para dominar.

1) Identificar el hash corto cometer

# git log --pretty=oneline --abbrev-commit abcd1234 Update to Fix for issue B cdababcd Fix issue B deab3412 Fix issue A ....

Aquí incluso git log --oneline también se puede utilizar para obtener un hash corto.

2) Si quiere aplastar (fusionar) las dos últimas confirmaciones

# git rebase -i deab3412

3) Esto abre un editor nano para la fusión. Y se ve abajo

.... pick cdababcd Fix issue B pick abcd1234 Update to Fix for issue B ....

4) Renombra la palabra pick to squash que está presente antes de abcd1234 . Después de cambiar el nombre debe ser como a continuación.

.... pick cdababcd Fix issue B squash abcd1234 Update to Fix for issue B ....

5) Ahora guarda y cierra el editor nano . Presione ctrl + o y presione Enter para guardar. Y luego presione ctrl + x para salir del editor.

6) Luego, nano editor se abre nuevamente para actualizar los comentarios, si es necesario, actualícelo.

7) Ahora que está aplastado correctamente, puede verificarlo revisando los registros.

# git log --pretty=oneline --abbrev-commit 1122abcd Fix issue B deab3412 Fix issue A ....

8) Ahora empuja a repo. Nota para agregar el signo + antes del nombre de la rama. Esto significa empuje forzado.

# git push origin +master

Nota: Esto se basa en el uso de git en el shell de ubuntu . Si está utilizando un Windows diferente ( Windows o Mac ), los comandos anteriores son los mismos, excepto el editor. Usted puede obtener editor diferente.


Además de otras respuestas excelentes, me gustaría agregar que git rebase -i siempre me confunde con la orden de compromiso- ¿anterior a la más reciente o viceversa? Así que este es mi flujo de trabajo:

  1. git rebase -i HEAD~[N] , donde N es el número de confirmaciones a las que quiero unirme, a partir de la más reciente . Por lo tanto, git rebase -i HEAD~5 significaría "aplastar las últimas 5 confirmaciones en una nueva";
  2. Aparece el editor, mostrando la lista de confirmaciones que quiero fusionar. Ahora se muestran en orden inverso : el compromiso anterior está en la parte superior. Marque como "squash" o "s" todas las confirmaciones allí excepto la primera / anterior : se usará como punto de partida. Guarda y cierra el editor;
  3. El editor vuelve a aparecer con un mensaje predeterminado para la nueva confirmación: cámbielo según sus necesidades, guárdelo y ciérrelo. Squash completado!

Fuentes y lecturas adicionales: #1 , #2 .


Basado en este artículo , encontré este método más fácil para mi caso de uso.

Mi rama ''dev'' estaba por delante de ''origin / dev'' con 96 confirmaciones (por lo que estas confirmaciones aún no se han enviado al control remoto).

Quería aplastar estos compromisos en uno antes de impulsar el cambio. Prefiero restablecer la rama al estado de ''origen / dev'' (esto dejará sin cambios todos los cambios de las 96 confirmaciones) y luego los confirmo a la vez:

git reset origin/dev git add --all git commit -m ''my commit message''


Basado en la respuesta de Chris Johnsen ,

Agrega un alias de "squash" global desde bash: (o Git Bash en Windows)

git config --global alias.squash ''!f(){ git reset --soft HEAD~${1} && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"; };f''

... o usando el símbolo del sistema de Windows:

git config --global alias.squash "!f(){ git reset --soft HEAD~${1} && git commit --edit -m/"$(git log --format=%B --reverse HEAD..HEAD@{1})/"; };f"


Tu ~/.gitconfig ahora debería contener este alias:

[alias] squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m/"$(git log --format=%B --reverse HEAD..HEAD@{1})/"; };f"


Uso:

git squash N

... que aplasta automáticamente las últimas N confirmaciones, inclusive.

Nota: El mensaje de confirmación resultante es una combinación de todas las confirmaciones aplastadas, en orden. Si no está satisfecho con eso, siempre puede git commit --amend para modificarlo manualmente. (O, edite el alias para que coincida con sus gustos).


Cambie a la rama maestra y asegúrese de estar al día:

sh git checkout master && git fetch && git pull

Combine su rama de función en la rama maestra localmente:

sh git merge feature_branch

Restablecer la rama maestra local al estado de origen:

sh git reset origin/master

Ahora todos tus cambios son considerados como cambios no escalonados. Puedes escalonarlos y comprometerlos en uno o más compromisos.

sh git add . --all git commit


Creo que la forma más fácil de hacer esto es crear una nueva rama a partir del maestro y hacer una fusión --squash de la rama característica.

git checkout master git checkout -b feature_branch_squashed git merge --squash feature_branch

Entonces tienes todos los cambios listos para cometer.


Echa un vistazo a esta esencia:

Gist - Fácil git-squash

Tendrás que escribir, por ejemplo, git-squash 3 y eso es todo. Las tres últimas confirmaciones se fusionaron en una con sus mensajes concatenados.


En cuestión podría ser ambiguo lo que se entiende por "último".

por ejemplo, git log --graph produce lo siguiente (simplificado):

* commit H0 | * merge |/ | * commit B0 | | | * commit B1 | | * | commit H1 | | * | commit H2 |/ |

Luego las últimas confirmaciones por tiempo son H0, fusionar, B0. Para aplastarlos, tendrá que volver a clasificar su rama fusionada en el commit H1.

El problema es que H0 contiene H1 y H2 (y generalmente más confirmaciones antes de la combinación y después de la derivación) mientras que B0 no lo hace. Así que tienes que administrar los cambios desde H0, fusionar, H1, H2, B0 al menos.

Es posible usar rebase pero de manera diferente a continuación, en otras respuestas mencionadas:

rebase -i HEAD~2

Esto le mostrará las opciones de elección (como se menciona en otras respuestas):

pick B1 pick B0 pick H0

Poner squash en lugar de escoger a H0:

pick B1 pick B0 s H0

Después de guardar y salir, se aplicarán las confirmaciones sucesivamente después de H1. Eso significa que le pedirá que vuelva a resolver los conflictos (donde HEAD será H1 al principio y luego acumulará los compromisos a medida que se apliquen).

Después de que finalice la rebase, puede elegir el mensaje para H0 y B0 aplastados:

* commit squashed H0 and B0 | * commit B1 | * commit H1 | * commit H2 |

PD: Si simplemente reinicia a BO: (por ejemplo, utilizando reset --mixed que se explica con más detalle aquí https://.com/a/18690845/2405850 ):

git reset --mixed hash_of_commit_B0 git add . git commit -m ''some commit message''

luego aplastas los cambios B0 de H0, H1, H2 (perdiendo completamente las confirmaciones de cambios después de la ramificación y antes de combinarlas).


En la rama en la que te gustaría combinar las confirmaciones, ejecuta:

git rebase -i HEAD~(n number of commits back to review)

Esto abrirá el editor de texto y usted debe cambiar la ''selección'' delante de cada confirmación con ''squash'' si desea que estas confirmaciones se fusionen. Por ejemplo, si busca fusionar todos los compromisos en uno, el ''pick'' es el primer compromiso que realizó y todos los futuros (colocados debajo del primero) deben configurarse como ''squash''. Si usa vim, use : x en el modo de inserción para guardar y salir del editor.

Luego para terminar el rebase:

git rebase --continue

Para obtener más información sobre esta y otras formas de volver a escribir su historial de confirmación, consulte esta útil publicación.


Encuentro que una solución más genérica no es especificar los ''N'' confirmados, sino más bien la rama / cometer-id que desea aplastar encima. Esto es menos propenso a errores que contar los compromisos hasta un compromiso específico; solo especifique la etiqueta directamente, o si realmente desea contar puede especificar HEAD ~ N.

En mi flujo de trabajo, comienzo una rama, y ​​mi primer confirmación en esa rama resume el objetivo (es decir, generalmente es lo que presionaré como el mensaje ''final'' de la característica al repositorio público). Entonces, cuando termine, todo Quiero hacer que git squash master vuelva al primer mensaje y luego estoy listo para empujar.

Yo uso el alias:

squash = !EDITOR="/"_() { sed -n ''s/^pick //p'' /"//$1/"; sed -i .tmp ''2,//$s/^pick/f/'' /"//$1/"; }; _/"" git rebase -i

Esto hará que se descargue el historial antes de que lo haga, lo que le da la oportunidad de recuperarse extrayendo un ID de confirmación antiguo de la consola si desea revertirlo. (Los usuarios de Solaris notan que usa la opción sed- -i GNU, los usuarios de Mac y Linux deberían estar de acuerdo con esto).


Esto es super-duper kludgy, pero de una manera bastante genial, así que lo arrojaré al anillo:

GIT_EDITOR=''f() { if [ "$(basename $1)" = "git-rebase-todo" ]; then sed -i "2,/$s/pick/squash/" $1; else vim $1; fi }; f'' git rebase -i foo~5 foo

Traducción: proporcione un nuevo "editor" para git que, si el nombre de archivo que se va a editar es git-rebase-todo (el indicador de rebase interactivo) cambia todos menos el primer "pick" a "squash", y de lo contrario genera vim, de modo que cuando se le solicite que edite el mensaje de confirmación aplastado, obtendrá vim. (Y, obviamente, estaba aplastando los últimos cinco confirmaciones en Branch Foo, pero podrías cambiar eso como quieras).

Aunque probablemente haría lo que Mark Longair sugirió .


Gracias a esta útil publicación de blog , encontré que puedes usar este comando para aplastar los últimos 3 intentos:

git rebase -i HEAD~3

Esto es útil ya que funciona incluso cuando se encuentra en una sucursal local sin información de seguimiento / repositorio remoto.

El comando abrirá el editor de rebase interactivo que luego le permite reordenar, aplastar, reformular, etc. según lo normal.

Usando el editor de rebase interactivo:

El editor de rebase interactivo muestra las tres últimas confirmaciones. HEAD~3 determinó esta restricción al ejecutar el comando git rebase -i HEAD~3 .

La confirmación más reciente, HEAD , se muestra primero en la línea 1. Las líneas que comienzan con un # son comentarios / documentación.

La documentación mostrada es bastante clara. En cualquier línea, puede cambiar el comando de pick a un comando de su elección.

Prefiero usar la fixup comando ya que esto "aplasta" los cambios de confirmación en la confirmación en la línea anterior y descarta el mensaje de confirmación.

Como la confirmación en la línea 1 es HEAD , en la mayoría de los casos, debería dejar esto como pick . No puedes usar squash o fixup ya que no hay otro commit para aplastar el commit en.


Lo que puede ser realmente conveniente:
Encuentre el hash de confirmación que desea aplastar, diga d43e15 .

Ahora usa

git reset d43e15 git commit -am ''new commit name''


Otra forma de hacer esto si tienes un montón de confirmaciones es hacer un squash DESPUÉS de una confirmación como git rebase -i <hashbeforeyouwanttosquash>

Esto abrirá tu editor para elegir / squash como normal.

Consulte https://git-scm.com/docs/git-rebase#_interactive_mode


Para aplastar los últimos 10 commit en 1 solo commit:

git reset --soft HEAD~10 && git commit -m "squashed commit"

Si también desea actualizar la rama remota con la confirmación aplastada:

git push -f


Para hacer esto puedes usar el siguiente comando git.

git rebase -i HEAD~n

n (= 4 aquí) es el número de la última confirmación. Luego tienes las siguientes opciones,

pick 01d1124 Message.... pick 6340aaa Message.... pick ebfd367 Message.... pick 30e0ccb Message....

Actualizar como abajo,

p 01d1124 Message.... s 6340aaa Message.... s ebfd367 Message.... s 30e0ccb Message....

Para más detalles haga clic en el Link

¡¡Buena suerte!!


Primero descubro el número de confirmaciones entre mi rama de características y la rama principal actual por

git checkout master git rev-list master.. --count

Luego, creo otra rama basada en mi rama de características, mantengo my-feature rama de my-feature sin tocar.

Por ultimo corro

git checkout my-feature git checkout -b my-rebased-feature git checkout master git checkout my-rebased-feature git rebase master git rebase head^x -i // fixup/pick/rewrite git push origin my-rebased-feature -f // force, if my-rebased-feature was ever pushed, otherwise no need for -f flag // make a PR with clean history, delete both my-feature and my-rebased-feature after merge

Espero que ayude, gracias.


Puede usar git merge --squash para esto, que es un poco más elegante que git rebase -i . Supongamos que estás en master y quieres aplastar los últimos 12 compromisos en uno.

ADVERTENCIA: primero asegúrese de realizar su trabajo; verifique que el git status esté limpio (ya que git reset --hard eliminará los cambios en etapas y en etapas)

Entonces:

# Reset the current branch to the commit just before the last 12: git reset --hard HEAD~12 # HEAD@{1} is where the branch was just before the previous command. # This command sets the state of the index to be as it would just # after a merge from that commit: git merge --squash HEAD@{1} # Commit those squashed changes. The commit message will be helpfully # prepopulated with the commit messages of all the squashed commits: git commit

La documentación para git merge describe la opción --squash con más detalle.

Actualización: la única ventaja real de este método sobre el simple git reset --soft HEAD~12 && git commit sugerido por Chris Johnsen en su respuesta es que el mensaje de confirmación se rellena automáticamente con cada mensaje de confirmación que está eliminando.


Puedes hacerlo con bastante facilidad sin git rebase o git merge --squash . En este ejemplo, aplastaremos las 3 últimas confirmaciones.

Si desea escribir el nuevo mensaje de confirmación desde cero, esto es suficiente:

git reset --soft HEAD~3 && git commit

Si desea comenzar a editar el nuevo mensaje de confirmación con una concatenación de los mensajes de confirmación existentes (es decir, similar a lo que una lista de instrucciones pick / squash / squash /… / squash git rebase -i comenzaría con), entonces necesita extraer esos mensajes y pasarlos a git commit :

git reset --soft HEAD~3 && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"

Ambos métodos aplastan los últimos tres compromisos en un solo nuevo compromiso de la misma manera. El reinicio por software simplemente vuelve a apuntar a HEAD hasta la última confirmación que no desea aplastar. El índice no toca ni el índice ni el árbol de trabajo, lo que deja al índice en el estado deseado para su nuevo compromiso (es decir, ya tiene todos los cambios de los compromisos que está a punto de "tirar").


Recomiendo evitar el git reset de Git cuando sea posible, especialmente para los novatos de Git. A menos que realmente necesite automatizar un proceso basado en un número de confirmaciones, hay una forma menos exótica ...

  1. Ponga las confirmaciones en una rama en funcionamiento (si no lo están ya) - use gitk para esto
  2. Echa un vistazo a la rama de destino (por ejemplo, ''maestro'')
  3. git merge --squash (working branch name)
  4. git commit

El mensaje de confirmación se rellenará previamente en función de la calabaza.


Si desea aplastar cada compromiso en un solo compromiso (por ejemplo, al lanzar un proyecto públicamente por primera vez), intente:

git checkout --orphan <new-branch> git commit


Si está utilizando GitUp , seleccione la confirmación que desea fusionar con su padre y presione S. Debe hacerlo una vez por cada compromiso, pero es mucho más sencillo que crear el encantamiento correcto de la línea de comando. Especialmente si es algo que solo haces de vez en cuando.


Si estás en una rama remota (llamada feature-branch ) clonada desde un repositorio Golden ( golden_repo_name ), esta es la técnica para aplastar tus compromisos en uno:

  1. Revisa el repo dorado

    git checkout golden_repo_name

  2. Crea una nueva rama a partir de él (repo dorado) como sigue

    git checkout -b dev-branch

  3. Squash se fusiona con tu sucursal local que ya tienes

    git merge --squash feature-branch

  4. Confirma tus cambios (este será el único commit que va en dev-branch)

    git commit -m "My feature complete"

  5. Empuje la rama a su repositorio local

    git push origin dev-branch


Si usas TortoiseGit, puedes la función Combine to one commit :

  1. Abrir el menú contextual de TortoiseGit
  2. Seleccione Show Log
  3. Marque las confirmaciones relevantes en la vista de registro
  4. Seleccione Combine to one commit en el menú contextual

Esta función ejecuta automáticamente todos los pasos necesarios de git. Por desgracia solo disponible para Windows.


Simplemente agregue esta función bash a su archivo bash de .zshrc.

# Squash last X commits with a Commit message. # Usage: squash X ''COMMIT_MSG'' # where X= Number of last commits. # where COMMIT_MSG= New commit msg. function squash() { if [ -z "${1}" -o -z "${2}" ]; then echo "Usage: /`squash X COMMIT_MSG/`" echo "X= Number of last commits." echo "COMMIT_MSG= New commit msg." return 1 fi git reset --soft HEAD~"$1" git add . && git ci -m "$2" # With 100 emoji git push --force }

Entonces solo corre

squash X ''New Commit Message''

Y tu estas listo.


La respuesta de Anomies es buena, pero me sentí inseguro al respecto, así que decidí agregar un par de capturas de pantalla.

Paso 0: git log

Mira dónde estás con git log . Lo más importante es encontrar el hash de confirmación de la primera confirmación que no desea aplastar. Tan solo el:

Paso 1: Rebase Git

Ejecute git rebase -i [your hash] , en mi caso:

$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d

Paso 2: elige / aplasta lo que quieras

En mi caso, quiero aplastar todo lo que se cometió antes de tiempo. El orden es del primero al último, por lo que es exactamente lo contrario que en el git log . En mi caso, quiero:

Paso 3: Ajustar mensaje (s)

Si ha elegido solo un compromiso y ha eliminado el resto, puede ajustar un mensaje de confirmación:

Eso es. Una vez que guarde esto ( :wq ), :wq terminado. Échale un vistazo con git log .


Use git rebase -i <after-this-commit> y reemplace "pick" en la segunda y subsiguientes confirmaciones con "squash" o "fixup", como se describe en el manual .

En este ejemplo, <after-this-commit> es el hash SHA1 o la ubicación relativa desde la HEAD de la rama actual desde la cual se analizan las confirmaciones para el comando rebase. Por ejemplo, si el usuario desea ver 5 confirmaciones del HEAD actual en el pasado, el comando es git rebase -i HEAD~5 .


git rebase -i HEAD^^

donde el número de ^ ''s es X

(En este caso, aplasta los dos últimos commit).