Supposons que j'ai l'historique de validation suivant sur ma branche locale uniquement:
A -- B -- C
Comment insérer un nouveau commit entre A
et B
?
Supposons que j'ai l'historique de validation suivant sur ma branche locale uniquement:
A -- B -- C
Comment insérer un nouveau commit entre A
et B
?
Réponses:
C'est encore plus facile que dans la réponse d'OP.
git rebase -i <any earlier commit>
. Cela affiche une liste de commits dans votre éditeur de texte configuré.a1b2c3d
). Dans votre éditeur, pour cette ligne, changez pick
en edit
.a1b2c3d
) comme si elle venait d'être validée .git commit
( PAS de modification, contrairement à la plupart des edit
s). Cela crée un nouveau commit après celui que vous avez choisi.git rebase --continue
. Cela relit les commits successifs, laissant votre nouveau commit inséré au bon endroit.Sachez que cela réécrira l'histoire et brisera quiconque essaiera de tirer.
A -- B -- C -- D
au lieu de désirée A -- D -- B -- C
.
D
pourrait être un commit n'importe où. Supposons que nous ayons A - B - C
et que nous ayons un commit D
qui n'est même pas dans cette branche. Nous connaissons son SHA cependant, nous pouvons le faire git rebase -i HEAD~3
. Maintenant, entre les lignes A
et B
pick
, nous insérons une nouvelle pick
ligne qui dit pick SHA
, en donnant le hachage du désiré D
. Il n'est pas nécessaire que ce soit le hachage complet, mais simplement le hachage raccourci. git rebase -i
cerise choisit simplement les validations listées par pick
lignes dans le tampon; il n'est pas nécessaire qu'ils soient les originaux répertoriés pour vous.
break
mot - clé dans l'éditeur sur sa propre ligne entre deux commits (ou sur la première ligne, pour insérer un commit avant votre commit spécifié).
S'avère être assez simple, la réponse trouvée ici . Supposons que vous soyez sur une branche branch
. Suivez ces étapes:
créez une branche temporaire à partir du commit après avoir voulu insérer le nouveau commit (dans ce cas commit A
):
git checkout -b temp A
effectuez les changements et validez-les, en créant un commit, appelons-le N
:
git commit -a -m "Message"
(ou git add
suivi de git commit
)
rebase les commits que vous voulez avoir après le nouveau commit (dans ce cas commits B
et C
) sur le nouveau commit:
git rebase temp branch
(vous devez peut-être utiliser -p
pour conserver les fusions, s'il y en avait - grâce à un commentaire qui n'existe plus de ciekawy )
supprimer la branche temporaire:
git branch -d temp
Après cela, l'historique se présente comme suit:
A -- N -- B -- C
Il est bien sûr possible que certains conflits apparaissent lors du rebasage.
Dans le cas où votre branche n'est pas uniquement locale, cela introduira un historique de réécriture, ce qui pourrait entraîner de graves problèmes.
git push --force
changer le dépôt distant.
git rebase temp branch -Xtheirs
. Réponse utile pour l'injection dans un script!
git rebase temp branch
, mais avant git branch -d temp
, tout ce que vous avez à faire est de résoudre et de mettre en scène les conflits et les problèmes de fusion git rebase --continue
, c'est-à-dire pas besoin de commettre quoi que ce soit, etc.
Solution encore plus simple:
Créez votre nouveau commit à la fin, D. Maintenant vous avez:
A -- B -- C -- D
Puis exécutez:
$ git rebase -i hash-of-A
Git ouvrira votre éditeur et il ressemblera à ceci:
pick 8668d21 B
pick 650f1fc C
pick 74096b9 D
Déplacez simplement D vers le haut comme ceci, puis enregistrez et quittez
pick 74096b9 D
pick 8668d21 B
pick 650f1fc C
Maintenant, vous aurez:
A -- D -- B -- C
En supposant que l'historique de validation est preA -- A -- B -- C
, si vous souhaitez insérer une validation entre A
et B
, les étapes sont les suivantes:
git rebase -i hash-of-preA
Git ouvrira votre éditeur. Le contenu peut aimer ceci:
pick 8668d21 A
pick 650f1fc B
pick 74096b9 C
Remplacez le premier pick
par edit
:
edit 8668d21 A
pick 650f1fc B
pick 74096b9 C
Sauvegarder et quitter.
Modifiez votre code puis git add . && git commit -m "I"
git rebase --continue
Maintenant, votre historique de commit Git est preA -- A -- I -- B -- C
Si vous rencontrez un conflit, Git s'arrêtera à ce commit. Vous pouvez utiliser git diff
pour localiser les marqueurs de conflit et les résoudre. Après avoir résolu tous les conflits, vous devez utiliser git add <filename>
pour indiquer à Git que le conflit a été résolu, puis réexécutergit rebase --continue
.
Si vous souhaitez annuler le rebase, utilisez git rebase --abort
.
Voici une stratégie qui évite de faire un "edit hack" lors du rebase vu dans les autres réponses que j'ai lues.
En utilisant, git rebase -i
vous obtenez une liste des validations depuis cette validation. Ajoutez simplement un "break" en haut du fichier, cela provoquera la rupture du rebase à ce stade.
break
pick <B's hash> <B's commit message>
pick <C's hash> <C's commit message>
Une fois lancé, git rebase
va maintenant s'arrêter au point de la "pause". Vous pouvez maintenant éditer vos fichiers et créer votre commit normalement. Vous pouvez ensuite continuer le rebase avec git rebase --continue
. Cela peut provoquer des conflits que vous devrez résoudre. Si vous vous perdez, n'oubliez pas que vous pouvez toujours annuler l'utilisation de git rebase --abort
.
Cette stratégie peut être généralisée pour insérer un commit n'importe où, il suffit de mettre le "break" à l'endroit où vous voulez insérer un commit.
Après avoir réécrit l'histoire, n'oubliez pas de le faire git push -f
. Les avertissements habituels concernant d'autres personnes qui récupèrent votre branche s'appliquent.
rebase
ici. Ce n'est pas beaucoup de différence que vous créiez le commit pendant le rebase ou avant.
Beaucoup de bonnes réponses ici déjà. Je voulais juste ajouter une solution "no rebase", en 4 étapes faciles.
Résumé
git checkout A
git commit -am "Message for commit D"
git cherry-pick A..C
git branch -f master HEAD
Explication
(Remarque: l'un des avantages de cette solution est que vous ne touchez pas votre branche avant l'étape finale, lorsque vous êtes sûr à 100% que vous êtes d'accord avec le résultat final, vous avez donc une étape de «pré-confirmation» très pratique permettant des tests AB .)
État initial (j'ai supposé master
le nom de votre succursale)
A -- B -- C <<< master <<< HEAD
1) Commencez par pointer HEAD au bon endroit
git checkout A
B -- C <<< master
/
A <<< detached HEAD
(Optionnellement ici, plutôt que de détacher HEAD, nous aurions pu créer une branche temporaire avec git checkout -b temp A
, que nous aurions besoin de supprimer à la fin du processus. Les deux variantes fonctionnent, faites comme vous préférez car tout le reste reste le même)
2) Créez le nouveau commit D à insérer
# at this point, make the changes you wanted to insert between A and B, then
git commit -am "Message for commit D"
B -- C <<< master
/
A -- D <<< detached HEAD (or <<< temp <<< HEAD)
3) Ensuite, apportez des copies des derniers commits manquants B et C (serait la même ligne s'il y avait plus de commits)
git cherry-pick A..C
# (if any, resolve any potential conflicts between D and these last commits)
B -- C <<< master
/
A -- D -- B' -- C' <<< detached HEAD (or <<< temp <<< HEAD)
(test AB confortable ici si nécessaire)
Le moment est venu d'inspecter votre code, de tester tout ce qui doit être testé, et vous pouvez également comparer / comparer / inspecter ce que vous aviez et ce que vous obtiendriez après les opérations.
4) En fonction de vos tests entre C
et C'
, soit c'est OK, soit c'est KO.
(SOIT) 4-OK) Enfin, déplacez la référence demaster
git branch -f master HEAD
B -- C <<< (B and C are candidates for garbage collection)
/
A -- D -- B' -- C' <<< master
(OU) 4-KO) Laissez simplement master
inchangé
Si vous avez créé une branche temporaire, supprimez-la simplement avec git branch -d <name>
, mais si vous avez opté pour la route HEAD détachée, aucune action n'est nécessaire à ce stade, les nouveaux commits seront éligibles pour le ramasse-miettes juste après que vous les reconnectiez HEAD
avec ungit checkout master
Dans ces deux cas (OK ou KO), à ce stade, il suffit de vérifier à master
nouveau pour le rattacher HEAD
.