tag remove practices crear commands best git rebase git-rebase squash git-rewrite-history

remove - ¿Cómo aplastar todos los git commit en uno?



git tag commit id (15)

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

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


Aplastar utilizando injertos.

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

git log ahora comenzará a partir de ese compromiso

Para que sea ''real'' ejecute git filter-branch


Actualizar

He hecho 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 "Un nuevo comienzo".

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 trazador de líneas

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.

Explique

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

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

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

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

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

    Luego, git reset simplemente restablece la rama actual al objeto commit recién creado.

De esta manera, no se toca nada en el área de trabajo, ni hay necesidad de rebase / squash, 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 de una plantilla de proyecto

Esto es útil para crear el "compromiso inicial" en un nuevo proyecto utilizando otro repositorio como la 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 la plantilla como un control remoto ( origin u otro) y colapsa el historial del repositorio de la plantilla en su confirmación inicial.


En una linea de 6 palabras

git checkout --orphan new_root_branch && git commit


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

"git rebase --interactive --root" se atascó en el conflicto de archivos gitignored.


Así es como terminé haciendo esto, en caso de que funcione para otra persona:

Recuerde que siempre existe el riesgo de hacer cosas como esta, y nunca es una mala idea crear una rama guardada antes de comenzar.

Comience por el registro

git log --oneline

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

git reset --soft <#sha#>

Reemplace <#sha#> con el SHA copiado del registro

git status

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

git commit --amend

Modifique todos los cambios actuales al primer compromiso actual

Ahora fuerce empuje esta rama y sobrescribirá lo que está allí.


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

Para cada commit excepto el primero, cambia pick a squash .


Esta respuesta mejora en un par de los de arriba (por favor vota), asumiendo que además de crear el único compromiso (sin padres sin historial), también quieres conservar todos los datos de compromiso de ese compromiso:

  • Autor (nombre y correo electrónico)
  • Fecha de autor
  • Comisión (nombre y correo electrónico)
  • Fecha comprometida
  • Mensaje de registro de comision

Por supuesto, el commit-SHA del nuevo / single commit cambiará, ya que representa un nuevo historial (no), convirtiéndose en un parentless / root-commit.

Esto se puede hacer leyendo el git log y configurando algunas variables para git commit-tree . Suponiendo que desea crear una única confirmación desde el master en una nueva sucursal de one-commit , manteniendo los datos de confirmación 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 '')


La forma más fácil es usar el comando ''fontanería'' 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 le devuelve al estado de "confirmación inicial" donde puede comenzar con una confirmación inicial nueva.

git update-ref -d refs/heads/master git commit -m "New initial commit"


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

De todos modos, puedes aplastar los 2 últimos compromisos manualmente con algo como esto:

git reset HEAD~1 git add -A git commit --amend


Normalmente lo hago así:

  • Asegúrese de que todo esté confirmado, y escriba 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 cabeza 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 de la primera confirmación y cambiar el mensaje de confirmación, o si desea mantener el mensaje de confirmación existente, puede ejecutar git commit --amend --no-edit

  • Ejecuta git push -f para forzar empujar tus cambios



Quizás la forma más sencilla es 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 editarlo 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


Si todo lo que quieres hacer es aplastar todos tus compromisos hasta la confirmación de la 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), ya que la operación de rebase probablemente se ejecutará muy lentamente para generar la lista de confirmaciones del editor de rebase interactivo, así como para ejecutar la rebase.

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

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 de raíz inicial de un árbol de historial de confirmación completamente nuevo y separado, que es equivalente 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:

Solución alternativa # 2: reinicio suave

Otra solución eficiente es simplemente usar un reinicio mixto o suave en el root commit <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:


crear una copia de seguridad

git branch backup

restablecer a la confirmación especificada

git reset --soft <root>

agregar todos los archivos a la puesta en escena

git add .

cometer sin actualizar el mensaje

git commit --amend --no-edit

empujar nueva rama con compromisos aplastados para repo

git push -f


echo "message" | git commit-tree HEAD^{tree}

Esto creará una confirmación huérfana con el árbol de HEAD y generará su nombre (SHA-1) en la salida estándar. Entonces simplemente reinicia tu rama allí.

git reset SHA-1