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?
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
Dans les versions récentes de git, vous pouvez utiliser git rebase --root -i
.
Pour chaque commit sauf le premier, changez pick
en squash
.
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'
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.
Pas besoin d'écraser, utilisez git commit-tree
pour créer un commit Orphan et continuez.
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 .
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.
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.
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:
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:
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:
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
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.
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"
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
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
git checkout --Orphan new_root_branch && git commit
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
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
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:
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
')
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.