Il y a 2 étapes pour y parvenir:
- Créer un nouveau commit vide
- Réécrire l'historique pour commencer à partir de ce commit vide
Nous allons mettre le nouveau commit vide sur une branche temporaire newroot
pour plus de commodité.
1. Créez un nouveau commit vide
Il existe plusieurs façons de procéder.
Utiliser uniquement de la plomberie
L'approche la plus propre consiste à utiliser la plomberie de Git pour simplement créer un commit directement, ce qui évite de toucher la copie de travail ou l'index ou la branche qui est extraite, etc.
Créez un objet arborescent pour un répertoire vide:
tree=`git hash-object -wt tree --stdin < /dev/null`
Enveloppez un commit autour de lui:
commit=`git commit-tree -m 'root commit' $tree`
Créez-y une référence:
git branch newroot $commit
Vous pouvez bien sûr réorganiser toute la procédure en une seule ligne si vous connaissez bien votre coque.
Sans plomberie
Avec les commandes porcelaine classiques, vous ne pouvez pas créer un commit vide sans vérifier la newroot
branche et mettre à jour l'index et la copie de travail à plusieurs reprises, sans raison valable. Mais certains peuvent trouver cela plus facile à comprendre:
git checkout --orphan newroot
git rm -rf .
git clean -fd
git commit --allow-empty -m 'root commit'
Notez que sur les très anciennes versions de Git qui n'ont pas le --orphan
commutateur checkout
, vous devez remplacer la première ligne par ceci:
git symbolic-ref HEAD refs/heads/newroot
2. Réécrire l'historique pour commencer à partir de ce commit vide
Vous avez deux options ici: le rebasage ou une réécriture de l'historique propre.
Rebasing
git rebase --onto newroot --root master
Cela a la vertu de la simplicité. Cependant, il mettra également à jour le nom et la date du committer à chaque dernier commit sur la branche.
En outre, avec certains historiques de cas de bord, il peut même échouer en raison de conflits de fusion - malgré le fait que vous rebasiez sur une validation qui ne contient rien.
Réécriture de l'histoire
L'approche la plus propre consiste à réécrire la branche. Contrairement à with git rebase
, vous devrez rechercher à partir de quel commit votre branche commence:
git replace <currentroot> --graft newroot
git filter-branch master
La réécriture se produit dans la deuxième étape, évidemment; c'est la première étape qui a besoin d'explications. Qu'est git replace
- ce que c'est, il dit à Git que chaque fois qu'il voit une référence à un objet que vous souhaitez remplacer, Git devrait plutôt regarder le remplacement de cet objet.
Avec le --graft
commutateur, vous lui dites quelque chose de légèrement différent de la normale. Vous dites que vous n'avez pas encore d'objet de remplacement, mais vous souhaitez remplacer l' <currentroot>
objet de validation par une copie exacte de lui-même, à l' exception que les validations parentes du remplacement doivent être celles que vous avez répertoriées (c'est-à-dire la newroot
validation ). Puis git replace
va de l'avant et crée ce commit pour vous, puis déclare ce commit comme remplacement de votre commit d'origine.
Maintenant, si vous faites un git log
, vous verrez que les choses ressemblent déjà à ce que vous voulez: la branche démarre newroot
.
Cependant, notez que git replace
cela ne modifie pas réellement l'historique - ni ne se propage hors de votre référentiel. Il ajoute simplement une redirection locale vers votre référentiel d'un objet à un autre. Cela signifie que personne d'autre ne voit l'effet de ce remplacement - seulement vous.
C'est pourquoi l' filter-branch
étape est nécessaire. Avec git replace
vous créez une copie exacte avec des validations parent ajustées pour la validation racine; git filter-branch
répète ensuite ce processus pour toutes les validations suivantes également. C'est là que l'histoire est réellement réécrite pour que vous puissiez la partager.