¿Cómo aplastar todos los commits de git en uno?


¿Cómo se reduce todo el repositorio a la primera confirmación?

Puedo rebase a la primera confirmación, pero eso me dejaría con 2 confirmaciones. ¿Hay alguna manera de hacer referencia a la confirmación antes de la primera?

Author: Jacek Laskowski, 2009-11-01

15 answers

Quizás la forma más fácil es simplemente crear un nuevo repositorio con el estado actual de la copia de trabajo. Si desea mantener todos los mensajes de confirmación, primero puede hacer git log > original.log y luego editar eso para su mensaje de confirmación inicial en el nuevo repositorio:

rm -rf .git
git init
git add .
git commit

O

git log > original.log
# edit original.log as desired
rm -rf .git
git init
git add .
git commit -F original.log
 118
Author: Pat Notz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-01 14:23:33

En versiones recientes de git, puedes usar git rebase --root -i.

Para cada confirmación excepto la primera, cambie pick a squash.

 497
Author: Jordan Lewis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-19 04:46:15

Actualizar

He creado un alias git squash-all.
Ejemplo de uso: git squash-all "a brand new start".

[alias]
  squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} -m \"${1:-A new start}\");};f"

Advertencia : recuerde proporcionar un comentario, de lo contrario se usaría el mensaje de confirmación predeterminado "A new start".

O puede crear el alias con el siguiente comando:

git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} -m "${1:-A new start}");};f'

Un revestimiento

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

Nota : aquí "A new start" es solo un ejemplo, siéntase libre de usar su propio idioma.

TL;DR

No hay necesidad de aplastar, use git commit-tree para crear un commit huérfano e ir con él.

Explicar

  1. Crea un solo commit a través de git commit-tree

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

    Crea un nuevo objeto commit basado en el objeto árbol proporcionado y emite el nuevo id de objeto de confirmación en stdout. El mensaje de registro es lea desde la entrada estándar, a menos que se den las opciones-m o-F.

    La expresión HEAD^{tree} significa el objeto de árbol correspondiente a HEAD, es decir, la punta de su rama actual. ver Tree-Objectsy Commit-Objects.

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

    Luego {[12] } simplemente restablezca la rama actual a la rama recién creada confirmar objeto.

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

Variación: Nuevo Repo de a Plantilla de proyecto

Esto es útil para crear el "commit inicial" en un nuevo proyecto usando otro repositorio como la plantilla/arquetipo/seed/skeleton. 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 un control remoto (origin o de otro modo) y contrae el historial del repositorio de plantilla en su confirmación inicial.

 231
Author: ryenus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-17 13:35:33

Si todo lo que quieres hacer es aplastar todas tus confirmaciones a la confirmación raíz, entonces mientras

git rebase --interactive --root

Puede funcionar, no es práctico para un gran número de commits (por ejemplo, cientos de commits), porque la operación rebase probablemente se ejecutará muy lentamente para generar la lista de commits del editor de rebase interactivo, así como ejecutar la propia rebase.

Aquí hay dos soluciones más rápidas y eficientes cuando estás aplastando un gran número de commits:

Solución Alternativa #1: ramas huérfanas

Simplemente puede crear una nueva rama huérfana en la punta (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, que es efectivamente equivalente a aplastar todas tus 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:

Solución alternativa # 2: restablecimiento suave

Otra solución eficiente es para simplemente usar un reinicio mixto o suave a la confirmación root <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:

 126
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-03 02:13:28
echo "message" | git commit-tree HEAD^{tree}

Esto creará un commit huérfano con el árbol de HEAD, y mostrará su nombre (SHA-1) en stdout. Entonces restablece tu sucursal allí.

git reset SHA-1
 45
Author: kusma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-23 15:04:21

La forma más fácil es usar el comando 'plumbing' update-ref para eliminar la rama actual.

No puede usar git branch -D ya que tiene una válvula de seguridad para evitar que elimine la rama actual.

Esto te devuelve al estado de 'confirmación inicial' donde puedes comenzar con una confirmación inicial nueva.

git update-ref -d refs/heads/master
git commit -m "New initial commit"
 32
Author: CB Bailey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-02 13:17:06

Así es como terminé haciendo esto, por si acaso funciona para alguien más:

Recuerde que siempre hay riesgo en hacer cosas como esta, y nunca es una mala idea crear una rama save antes de comenzar.

Comience por registrar

git log --oneline

Desplácese hasta la primera confirmación, copie SHA

git reset --soft <#sha#>

Reemplazar <#sha#> con el SHA copiado del log

git status

Asegúrate de que todo esté verde, de lo contrario ejecuta git add -A

git commit --amend

Modificar todos los cambios actuales a actual primero commit

Ahora fuerza a empujar esta rama y sobrescribirá lo que hay allí.

 32
Author: Logan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-05 16:04:50

Leí algo sobre el uso de injertos, pero nunca lo investigué mucho.

De todos modos, puedes aplastar esas últimas 2 confirmaciones manualmente con algo como esto:

git reset HEAD~1
git add -A
git commit --amend
 21
Author: R. Martinho Fernandes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-01 10:27:43

Primero, aplasta todos tus commits en un solo commit usando git rebase --interactive. Ahora te quedan dos confirmaciones para aplastar. Para hacerlo, lea cualquiera de

 16
Author: Frerich Raabe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:27

Para aplastar usando injertos

Agregue un archivo .git/info/grafts, ponga allí el hash de confirmación que desea que se convierta en su raíz

git log ahora comenzará a partir de ese commit

Para hacerlo 'real' ejecutar git filter-branch

 3
Author: dimus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-05 19:12:11

"Solución alternativa #1: ramas huérfanas" me ayuda.

"git rebase interactive interactive root root" atascado en el conflicto de archivos gitignored.

 2
Author: sasha-ch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-26 13:17:19

Esta respuesta mejora a un par de anteriores (por favor vote hacia arriba), asumiendo que además de crear el commit único (no-parents no-history), usted también desea retener todos los datos del commit de ese commit:

  • Autor (nombre y correo electrónico)
  • Fecha de autor
  • Commiter (nombre y correo electrónico)
  • Fecha de compromiso
  • Mensaje de registro de comunicación

Por supuesto, el commit-SHA del commit nuevo/único cambiará, porque representa un nuevo (non-)history, convirtiéndose en un parentless / root-commit.

Esto se puede hacer leyendo git log y estableciendo algunas variables para git commit-tree. Suponiendo que desea crear un solo commit desde master en una nueva rama one-commit, conservando los datos de commit anteriores:

git checkout -b one-commit master ## create new branch to reset
git reset --hard \
$(eval "$(git log master -n1 --format='\
COMMIT_MESSAGE="%B" \
GIT_AUTHOR_NAME="%an" \
GIT_AUTHOR_EMAIL="%ae" \
GIT_AUTHOR_DATE="%ad" \
GIT_COMMITTER_NAME="%cn" \
GIT_COMMITTER_EMAIL="%ce" \
GIT_COMMITTER_DATE="%cd"')" 'git commit-tree master^{tree} <<COMMITMESSAGE
$COMMIT_MESSAGE
COMMITMESSAGE
')
 1
Author: javabrett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-28 17:27:50

Normalmente lo hago así:

  • Asegúrese de que todo está confirmado, y anote el último id de confirmación en caso de que algo salga mal, o cree una rama separada como copia de seguridad

  • Ejecute git reset --soft `git rev-list --max-parents=0 --abbrev-commit HEAD` para restablecer su head a la primera confirmación, pero deje su índice sin cambios. Todos los cambios desde la primera confirmación aparecerán listos para ser confirmados.

  • Ejecute git commit --amend -m "initial commit" para modificar su confirmación a la primera confirmación y cambiar el mensaje de confirmación, o si desea mantenga el mensaje de confirmación existente, puede ejecutar git commit --amend --no-edit

  • Ejecute git push -f para forzar el empuje de sus cambios

 0
Author: Kent Munthe Caspersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-18 13:13:28

Crear una copia de seguridad

git branch backup

Restablecer a la confirmación especificada

git reset --soft <root>

Agregue todos los archivos a staging

git add .

Confirmar sin actualizar el mensaje

git commit --amend --no-edit

Empuje una nueva rama con confirmaciones aplastadas a repo

git push -f
 0
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-19 14:12:55

En una línea de 6 palabras

git checkout --orphan new_root_branch  &&  git commit
 0
Author: kyb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-15 21:57:00