Comment écraser tous les git commits en un seul?

comment écraser tout votre dépôt jusqu'à la première propagation?

je peux rebaptiser le premier commit, mais cela me laisserait avec 2 commits. Est-il un moyen de faire référence à la validation avant le premier?

336
demandé sur Jacek Laskowski 2009-11-01 11:38:06

15 réponses

la manière la plus simple est peut-être de créer un nouveau dépôt avec l'état actuel de la copie de travail. Si vous voulez conserver tous les messages de propagation, vous pouvez tout d'abord faire git log > original.log et éditer celui-ci pour votre message de propagation initial dans le nouveau dépôt:

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
118
répondu Pat Notz 2009-11-01 14:23:33

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

pour chaque propagation sauf la première, remplacer pick par squash .

497
répondu Jordan Lewis 2013-12-19 04:46:15

mise à Jour

j'ai créé un alias git squash-all .

exemple d'usage : git squash-all "a brand new start" .

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

Caveat : n'oubliez pas de fournir un commentaire, sinon le message de propagation 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'

One Liner

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

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

TL; DR

pas besoin de squash, utilisez git commit-tree pour créer un orphelin commettre et aller avec elle.

expliquer

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

    quoi git commit-tree HEAD^{tree} -m "A new start" n'est:

    crée un nouvel objet commit basé sur l'arbre fourni et émet le nouvel identifiant d'objet commit sur stdout. Le message de log est lire à partir de l'entrée standard, à moins que les options-m ou-F ne soient données.

    l'expression HEAD^{tree} signifie l'objet arborescent correspondant à HEAD , à savoir la pointe de votre branche courante. voir Arbre-Objets et Commit-Objects .

  2. réinitialisation de la branche courante dans le nouveau commit

    puis git reset réinitialisez simplement la branche courante à la nouvelle branche créée objet commit.

de cette façon, rien dans l'espace de travail n'est touché, besoin de rebase/squash, ce qui le rend très rapide. Et le temps nécessaire est sans rapport avec la taille du dépôt ou la profondeur de l'historique.

Variation: nouveau report à partir d'un modèle de projet

c'est utile pour créer le" commit initial " dans un nouveau projet en utilisant un autre référentiel comme le 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 template repo en tant que remote ( origin ou autrement) et de faire s'effondrer l'historique du template repo dans votre commit initial.

231
répondu ryenus 2017-10-17 13:35:33

si tout ce que vous voulez faire est d'écraser tous vos commits jusqu'à la propagation racine, alors que

git rebase --interactive --root

peut fonctionner, c'est peu pratique pour un grand nombre de commits (par exemple, des centaines de commits), parce que l'opération de rebase va probablement fonctionner très lentement pour générer la liste de commit interactive de l'éditeur de rebase, ainsi que pour exécuter le rebase lui-même.

voici deux solutions plus rapides et plus efficaces lorsque vous écrasez un grand nombre of commits:

solution Alternative #1: orphelin branches

vous pouvez simplement créer une nouvelle branche orpheline à la pointe (c.-à-d. la plus récente commit) de votre branche actuelle. Cette branche orpheline forme le commit racine initial d'un arbre d'histoire de commit entièrement nouveau et séparé, qui est effectivement équivalent à écraser tous vos commits:

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

de la Documentation:

Alternative solution #2: soft reset

une autre solution efficace consiste simplement à utiliser une réinitialisation mélangée ou douce à la racine 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

de la Documentation:

126
répondu 2014-08-03 02:13:28
echo "message" | git commit-tree HEAD^{tree}

cela créera un commit orphelin avec l'arbre de la tête, et afficher son nom (SHA-1) sur stdout. Alors Réinitialisez votre branche là-bas.

git reset SHA-1
45
répondu kusma 2014-07-23 15:04:21

la façon La plus simple est d'utiliser la "plomberie" commande update-ref pour supprimer la branche courante.

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

cela vous replace dans l'état de 'commit initial' où vous pouvez commencer avec une nouvelle commit initiale.

git update-ref -d refs/heads/master
git commit -m "New initial commit"
32
répondu CB Bailey 2009-11-02 13:17:06

voilà comment j'ai fini par faire ça, juste au cas où ça marcherait pour quelqu'un d'autre:

rappelez-vous qu'il y a toujours un risque à faire des choses comme ça, et que c'est une bonne idée de créer une branche de sauvegarde avant de commencer.

Commencez par vous identifier

git log --oneline

faites Défiler jusqu'à la première validation, copie SHA

git reset --soft <#sha#>

Remplacer <#sha#> w/ 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 à la première propagation actuelle

maintenant, poussez cette branche et elle écrasera ce qui est là.

32
répondu Logan 2015-11-05 16:04:50

j'ai lu quelque chose à propos de l'utilisation de greffons, mais je n'ai jamais beaucoup étudié.

de toute façon, vous pouvez écraser ces 2 dernières propagations manuellement avec quelque chose comme ceci:

git reset HEAD~1
git add -A
git commit --amend
21
répondu R. Martinho Fernandes 2009-11-01 10:27:43

tout d'abord, exécutez toutes vos commits en une seule commit en utilisant git rebase --interactive . Il ne vous reste plus que deux commits à écraser. Pour ce faire, lisez l'un des

16
répondu Frerich Raabe 2017-05-23 12:26:27

À la courge à l'aide de greffes

Ajouter un fichier .git/info/grafts , mettre là le hachage de propagation que vous voulez devenir votre racine

git log va maintenant commencer à partir de ce commit

""
3
répondu dimus 2017-07-05 19:12:11

"solution Alternative #1: orphelin branches" aide-moi.

"git rebase --interactive --root" collé sur gitignored fichiers conflit.

2
répondu sasha-ch 2018-03-26 13:17:19

cette réponse améliore sur un couple ci-dessus (s'il vous plaît votez-les vers le haut), en supposant qu'en plus de créer l'un commit (no-parents no-history), vous également voulez conserver toutes les données de commit de cette commit:

  • Auteur (nom et courriel)
  • date D'écriture
  • Commiter (nom et email)
  • "1519100920 Commis" date
  • Commmit log message

bien sûr le commit-SHA du nouveau/single commit va changer, parce qu'il représente une nouvelle (non-)histoire, devenant un parentless/root-commit.

cela peut être fait en lisant git log et en définissant quelques variables pour git commit-tree . En supposant que vous voulez créer une seule propagation à partir de master dans une nouvelle branche one-commit , en conservant les données de propagation 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
répondu javabrett 2017-01-28 17:27:50

je le fais habituellement comme ceci:

  • assurez-vous que tout est engagé, et notez la dernière propagation au cas où quelque chose tourne mal, ou créez une branche séparée comme la sauvegarde

  • Exécuter git reset --soft `git rev-list --max-parents=0 --abbrev-commit HEAD` pour réinitialiser votre tête à la première livraison, mais laissez votre indice inchangé. Tous les changements depuis le premier commit apparaîtront maintenant prêts à être engagés.

  • Exécuter git commit --amend -m "initial commit" pour modifier votre s'engager à le premier à valider et modifier le message de commit, ou si vous voulez conserver le message de commit, vous pouvez exécuter git commit --amend --no-edit

  • Exécuter git push -f à force de pousser vos modifications

0
répondu Kent Munthe Caspersen 2018-04-18 13:13:28

créer une sauvegarde

git branch backup

réinitialiser les paramètres spécifiés commettre

git reset --soft <root>

ajouter tous les fichiers à la mise en scène

git add .

commit sans mettre à jour le message

git commit --amend --no-edit

push nouvelle succursale écrasé s'engage à repo

git push -f
0
répondu David 2018-07-19 14:12:55

en une ligne de 6 mots

git checkout --orphan new_root_branch  &&  git commit
0
répondu kyb 2018-08-15 21:57:00