web-dev-qa-db-fra.com

Comment écraser tous les git commits en un?

Comment écrasez-vous l'intégralité de votre référentiel jusqu'au premier commit?

Je peux me baser sur le premier commit, mais cela me laisserait avec 2 commits. Existe-t-il un moyen de référencer le commit avant le premier?

408
Verhogen

Le moyen le plus simple consiste peut-être simplement à créer un nouveau référentiel avec l’état actuel de la copie de travail. Si vous souhaitez conserver tous les messages de validation, vous pouvez d'abord faire git log > original.log, puis le modifier pour votre message de validation initial dans le nouveau référentiel:

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

ou

git log > original.log
# edit original.log as desired
rm -rf .git
git init
git add .
git commit -F original.log
124
Pat Notz

Dans les versions récentes de git, vous pouvez utiliser git rebase --root -i.

Pour chaque commit sauf le premier, changez pick en squash.

591
Jordan Lewis

Mise à jour

J'ai créé un alias git squash-all.
Exemple d'utilisation : git squash-all "a brand new start".

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

Avertissement : n'oubliez pas de fournir un commentaire, sinon le message de validation par défaut "Un nouveau départ" serait utilisé.

Ou vous pouvez créer l'alias avec la commande suivante:

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

Bon mot

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

Remarque : ici "A new start" n'est qu'un exemple, n'hésitez pas à utiliser votre propre langue.

TL; DR

Pas besoin d'écraser, utilisez git commit-tree pour créer un commit Orphan et continuez.

Explique

  1. créer un seul commit via git commit-tree

    Qu'est-ce que git commit-tree HEAD^{tree} -m "A new start" fait, c'est:

    Crée un nouvel objet de validation basé sur l'objet d'arborescence fourni et émet le nouvel ID d'objet de validation sur la sortie standard. Le message de journal est lu à partir de l'entrée standard, à moins que les options -m ou -F ne soient fournies.

    L'expression HEAD^{tree} désigne l'objet d'arborescence correspondant à HEAD, à savoir le sommet de votre branche actuelle. voir Tree-Objects et Commit-Objects .

  2. réinitialiser la branche actuelle sur le nouveau commit

    Ensuite, git reset réinitialise simplement la branche actuelle au nouvel objet de validation créé.

De cette façon, rien dans l'espace de travail n'est touché, il n'y a pas besoin de rebase/squash, ce qui le rend vraiment rapide. Et le temps nécessaire est sans importance pour la taille du référentiel ou la profondeur de l'historique.

Variation: Nouveau dépôt d'un modèle de projet

Ceci est utile pour créer le "commit initial" dans un nouveau projet en utilisant un autre référentiel comme template/archetype/seed/skeleton. Par exemple:

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")

Cela évite d'ajouter le référentiel de modèles en tant que télécommande (Origin ou autrement) et réduit l'historique de ce référentiel dans votre validation initiale.

272
ryenus

Si tout ce que vous voulez faire est d’écraser tous vos commits jusqu’au root, alors

git rebase --interactive --root

peut fonctionner, ce n'est pas pratique pour un grand nombre de validations (par exemple, des centaines de validations), car l'opération de rebase s'exécutera probablement très lentement pour générer la liste de validations interactive de l'éditeur de rebase, ainsi que pour exécuter la rebase elle-même.

Voici deux solutions plus rapides et plus efficaces lorsque vous écrasez un grand nombre de commits:

Solution alternative n ° 1: branches orphelines

Vous pouvez simplement créer une nouvelle branche orpheline à la pointe (c’est-à-dire le dernier commit) de votre branche actuelle. Cette branche orpheline constitue la validation racine initiale d'un arbre historique entièrement nouveau et distinct, qui équivaut en réalité à écraser toutes vos validations:

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

Documentation:

Solution alternative n ° 2: réinitialisation logicielle

Une autre solution efficace consiste simplement à utiliser une réinitialisation mixte ou logicielle à la validation de racine <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

Documentation:

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

Cela créera un commit orphelin avec l’arbre de HEAD, et affichera son nom (SHA-1) sur stdout. Ensuite, il suffit de réinitialiser votre branche là-bas.

git reset SHA-1
47
kusma

Voici comment j'ai fini par le faire, juste au cas où cela fonctionnerait pour quelqu'un d'autre:

Rappelez-vous qu'il est toujours risqué de faire de telles choses et que ce n'est jamais une mauvaise idée de créer une branche de sauvegarde avant de commencer.

Commencez par vous connecter

git log --oneline

Faites défiler jusqu'au premier commit, copiez SHA

git reset --soft <#sha#>

Remplacez <#sha#> w/le SHA copié à partir du journal

git status

Assurez-vous que tout est vert, sinon lancez git add -A

git commit --amend

Modifier toutes les modifications actuelles au premier commit actuel

Forcez maintenant cette branche et elle écrasera ce qu’elle contient.

37
Logan

Le moyen le plus simple consiste à utiliser la commande 'plomberie' update-ref pour supprimer la branche actuelle.

Vous ne pouvez pas utiliser git branch -D car il possède une soupape de sécurité pour vous empêcher de supprimer la branche actuelle.

Cela vous remet dans l'état de 'validation initiale' où vous pouvez commencer avec une nouvelle validation initiale.

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

J'ai lu quelque chose sur l'utilisation de greffes mais je n'y ai jamais beaucoup enquêté.

Quoi qu'il en soit, vous pouvez écraser manuellement ces 2 derniers commits avec quelque chose comme ceci:

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

Tout d’abord, réduisez tous vos commits en un seul à l’aide de git rebase --interactive. Il ne vous reste plus que deux commits à squash. Pour ce faire, lisez l’un des

16
Frerich Raabe

En une ligne de 6 mots

git checkout --Orphan new_root_branch  &&  git commit
12
kyb

Pour écraser en utilisant des greffes

Ajoutez un fichier .git/info/grafts, mettez-y le hachage de validation que vous voulez devenir votre racine

git log va maintenant démarrer à partir de ce commit

Pour le rendre réel, exécutez git filter-branch

4
dimus

créer une sauvegarde

git branch backup

réinitialiser au commit spécifié

git reset --soft <#root>

puis ajoutez tous les fichiers à la mise en scène

git add .

commettre sans mettre à jour le message

git commit --amend --no-edit

Poussez nouvelle branche avec commets écrasés à repo

git Push -f
3
David

Cette réponse améliore un couple ci-dessus (veuillez les voter), en supposant qu'en plus de créer le commit (no-parents no-history), vous aussi voulez conserver toutes les données de commit. de ce commit:

  • Auteur (nom et email)
  • Date de création
  • Commiter (nom et email)
  • Date engagée
  • Envoyer le message du journal

Bien sûr, le commit-SHA du nouveau/single commit va changer, car il représente un nouvel (non) historique, devenant un commit/root sans parent.

Cela peut être fait en lisant git log et en définissant des variables pour git commit-tree. En supposant que vous souhaitiez créer un seul commit à partir de master dans une nouvelle branche one-commit, en conservant les données de validation ci-dessus:

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
javabrett

Je le fais habituellement comme ça:

  • Assurez-vous que tout est validé et notez le dernier identifiant de validation en cas de problème ou créez une branche distincte comme sauvegarde.

  • Exécutez git reset --soft `git rev-list --max-parents=0 --abbrev-commit HEAD` pour réinitialiser votre tête au premier commit, mais laissez votre index inchangé. Tous les changements depuis le premier commit apparaîtront désormais prêts à être validés.

  • Exécutez git commit --amend -m "initial commit" pour modifier votre validation en premier et modifier le message de validation, ou si vous souhaitez conserver le message de validation existant, vous pouvez exécuter git commit --amend --no-edit.

  • Exécutez git Push -f pour forcer l'application de vos modifications.

0