Comment modifier un ancien Git commit?

J’ai fait 3 commits Git, mais je n’ai pas été poussé. Comment modifier les plus anciens (ddc6859af44) et (47175e84c), qui n’est pas le plus récent?

$git log commit f4074f289b8a49250b15a4f25ca4b46017454781 Date: Tue Jan 10 10:57:27 2012 -0800 commit ddc6859af448b8fd2e86dd0437c47b6014380a7f Date: Mon Jan 9 16:29:30 2012 -0800 commit 47175e84c2cb7e47520f7dde824718eae3624550 Date: Mon Jan 9 13:13:22 2012 -0800 

 git rebase -i HEAD^^^ 

Maintenant, cochez ceux que vous souhaitez modifier avec edit ou e (remplacez pick ). Maintenant, sauvegardez et quittez.

Maintenant, apportez vos modifications, puis

 git add -A git commit --amend --no-edit git rebase --continue 

Si vous souhaitez append une suppression supplémentaire, supprimez les options de la commande commit. Si vous souhaitez ajuster le message, omettez simplement l’option --no-edit .

J’ai préparé mon commit que je voulais modifier avec un plus ancien et j’ai été surpris de voir que rebase -i se plaignait d’avoir des modifications non validées. Mais je ne voulais pas modifier à nouveau en spécifiant l’option d’édition de l’ancien commit. La solution était donc simple et directe:

  1. préparer votre mise à jour avec un ancien commit, l’append et valider
  2. git rebase -i ^ – notez le ^ donc vous voyez le dit commit dans l’éditeur de texte
  3. vous obtiendrez quelque chose comme ceci:

     pick 8c83e24 use substitution instead of separate subsystems file to avoid jgroups.xml and jgroups-e2.xml going out of sync pick 799ce28 generate ec2 configuration out of subsystems-ha.xml and subsystems-full-ha.xml to avoid discrepancies pick e23d23a fix indentation of jgroups.xml 
  4. Maintenant, pour combiner e23d23a avec 8c83e24, vous pouvez changer l’ordre des lignes et utiliser le squash comme ceci:

     pick 8c83e24 use substitution instead of separate subsystems file to avoid jgroups.xml and jgroups-e2.xml going out of sync squash e23d23a fix indentation of jgroups.xml pick 799ce28 generate ec2 configuration out of subsystems-ha.xml and subsystems-full-ha.xml to avoid discrepancies 
  5. écrire et quitter le fichier, vous serez présent avec un éditeur pour fusionner les messages de validation. Faites-le et enregistrez / quittez le document texte

  6. Vous avez terminé, vos commits sont modifiés

le crédit va à: http://git-scm.com/book/en/Git-Tools-Rewriting-Hist Il y a aussi une autre magie git démontrée utile.

Vous pouvez utiliser git rebase pour réécrire l’historique des validations. Cela peut être potentiellement destructeur pour vos modifications, donc utilisez-le avec précaution.

Commencez par commettre votre modification “modifier” en tant que validation normale. Faites ensuite un rebase interactif en commençant par le parent de votre engagement le plus ancien

 git rebase -i 47175e84c2cb7e47520f7dde824718eae3624550^ 

Cela déclenchera votre éditeur avec tous les commits. Réorganisez-les pour que votre commit “modifier” passe en dessous de celui que vous souhaitez modifier. Remplacez ensuite le premier mot de la ligne par le commit “amender” avec s qui le combinera avec la validation précédente. Enregistrez et quittez votre éditeur et suivez les instructions.

Vous pouvez utiliser git rebase --interactive utilisant la commande edit sur la validation à modifier.

J’ai utilisé un autre moyen pour quelques fois. En fait, il s’agit d’une git rebase -i manuelle git rebase -i et elle est utile lorsque vous souhaitez réorganiser plusieurs validations, y compris en écrasant ou en fractionnant certaines. Le principal avantage est que vous n’avez pas à décider du destin de chaque engagement à un moment donné. Vous aurez également toutes les fonctionnalités de Git disponibles pendant le processus, contrairement à une rebase. Par exemple, vous pouvez afficher le journal de l’historique original et de l’historique réécrit à tout moment, ou même procéder à un autre rebase!

Je vais me référer aux commits de la manière suivante, donc c’est lisible facilement:

 C # good commit after a bad one B # bad commit A # good commit before a bad one 

Votre histoire au début ressemble à ceci:

 x - A - B - C | | | master | origin/master 

Nous allons le recréer de cette façon:

 x - A - B*- C' | | | master | origin/master 

Procédure

 git checkout B # get working-tree to the state of commit B git reset --soft A # tell Git that we are working before commit B git checkout -b rewrite-history # switch to a new branch for alternative history 

Améliorez votre ancien commit en utilisant git add ( git add -i , git stash etc.) maintenant. Vous pouvez même diviser votre ancien engagement en deux ou plus.

 git commit # recreate commit B (result = B*) git cherry-pick C # copy C to our new branch (result = C') 

Résultat intermédiaire:

 x - A - B - C | \ | | \ master | \ | B*- C' | | | rewrite-history | origin/master 

Finissons:

 git checkout master git reset --hard rewrite-history # make this branch master 

Ça y est, vous pouvez push vos progrès maintenant.

Si l’OP veut écraser les 2 commits spécifiés dans 1, voici une autre manière de le faire sans changer de nom.

 git checkout HEAD^ # go to the first commit you want squashed git reset --soft HEAD^ # go to the second one but keep the tree and index the same git commit --amend -C HEAD@{1} # use the message from first commit (omit this to change) git checkout HEAD@{3} -- . # get the tree from the commit you did not want to touch git add -A # add everything git commit -C HEAD@{3} # commit again using the message from that commit 

La syntaxe de @{N) est pratique car elle vous permettra de référencer l’historique de vos références. Dans ce cas, c’est HEAD qui représente votre commit actuel.