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?
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
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
.
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
-
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 . -
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.
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:
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
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"
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à.
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
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
À 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
""
"solution Alternative #1: orphelin branches" aide-moi.
"git rebase --interactive --root" collé sur gitignored fichiers conflit.
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
')
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écutergit commit --amend --no-edit
-
Exécuter
git push -f
à force de pousser vos modifications
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
en une ligne de 6 mots
git checkout --orphan new_root_branch && git commit