¿Cómo agrupar todos los compromisos de git en uno?

Resuelto Verhogen asked hace 14 años • 25 respuestas

¿Cómo comprimes todo tu repositorio hasta la primera confirmación?

Puedo cambiar la base a la primera confirmación, pero eso me dejaría con 2 confirmaciones. ¿Hay alguna manera de hacer referencia al compromiso antes del primero?

Verhogen avatar Nov 01 '09 15:11 Verhogen
Aceptado

A partir de git 1.6.2 , puedes usargit rebase --root -i

Para cada confirmación excepto la primera, cambie picka squashen el editor que aparece.

Jordan Lewis avatar Feb 13 '2012 00:02 Jordan Lewis

Una sola línea (para Bash/Zsh)

Puedes crear un compromiso de squash-all directamente desde HEAD, sin ningún tipo de rebase , simplemente ejecuta:

git reset $(git commit-tree HEAD^{tree} -m "A new start")

Nota : esto requiere un shell compatible con POSIX como bash/zsh o Git Bash en Windows .

Crear un alias en~/.gitconfig

[alias]
  squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} \"$@\");};f"

Entonces simplemente ejecuta:git squash-all -m "a brand new start"

Nota : proporcione el mensaje de confirmación desde la entrada estándar o mediante las opciones -m/ -F, como el comando git commit . Consulte el manual de git-commit-tree .

Alternativamente, puede crear el alias con el siguiente comando:

git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} "$@");};f'

Explicar

  1. crear una única confirmación a través degit commit-tree

    Lo que git commit-tree HEAD^{tree} -m "A new start"hace es:

    Crea un nuevo objeto de confirmación basado en el objeto de árbol proporcionado y emite la nueva identificación del objeto de confirmación en la salida estándar. El mensaje de registro se lee desde la entrada estándar, a menos que se proporcionen las opciones -m o -F.

    La expresión HEAD^{tree}representa el objeto de árbol correspondiente a HEAD, es decir, la punta de su rama actual. consulte Objetos de árbol y Objetos de confirmación .

  2. restablecer la rama actual a la nueva confirmación

    Luego git resetsimplemente restablezca la rama actual al objeto de confirmación recién creado.

    De esta manera, no se toca nada en el espacio de trabajo, ni hay necesidad de rebase/aplastar, lo que lo hace realmente rápido. Y el tiempo necesario es irrelevante para el tamaño del repositorio o la profundidad del historial.


Variación: nuevo repositorio a partir de una plantilla de proyecto

Esto es útil para crear el "compromiso inicial" en un nuevo proyecto usando otro repositorio como plantilla/arquetipo/semilla/esqueleto. Por ejemplo:

cd my-new-project
git init
git fetch --depth=1 -n https://github.com/toolbear/panda.git
git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m "initial commit")

Esto evita agregar el repositorio de plantilla como remoto ( origino de otro modo) y colapsa el historial del repositorio de plantilla en su confirmación inicial.

ryenus avatar May 06 '2014 05:05 ryenus

Si todo lo que quiere hacer es aplastar todas sus confirmaciones hasta la confirmación raíz, entonces, mientras

git rebase --interactive --root

puede funcionar, no es práctico para una gran cantidad de confirmaciones (por ejemplo, cientos de confirmaciones), porque la operación de rebase probablemente se ejecutará muy lentamente para generar la lista de confirmaciones del editor de rebase interactivo, así como también ejecutará la rebase en sí.

Aquí hay dos soluciones más rápidas y eficientes cuando estás eliminando una gran cantidad de confirmaciones:

Solución alternativa n.° 1: ramas huérfanas

Simplemente puede crear una nueva rama huérfana al final (es decir, la confirmación más reciente) de su rama actual. Esta rama huérfana forma la confirmación raíz inicial de un árbol de historial de confirmaciones completamente nuevo y separado, lo que efectivamente equivale a aplastar todas sus confirmaciones:

git checkout --orphan new-master master
git commit -m "Enter commit message for your new initial commit"

# Overwrite the old master branch reference with the new one
git branch -M new-master master

Documentación:

  • git-checkout(1) Página del manual .

Solución alternativa n.° 2: reinicio parcial

Otra solución eficaz es simplemente utilizar un reinicio mixto o parcial de la confirmación raíz <root>:

git branch beforeReset

git reset --soft <root>
git commit --amend

# Verify that the new amended root is no different
# from the previous branch state
git diff beforeReset

Documentación:

  • git-reset(1) Página del manual .
 avatar Jun 11 '2014 03:06