Comment changer le commit passé pour inclure un fichier manqué?

98

J'ai commis une modification et j'ai oublié d'ajouter un fichier à l'ensemble de modifications. Après d'autres commits, j'ai réalisé que le fichier était maintenant absent d'un HEAD^4commit.

Comment réécrire un commit précédent pour inclure le fichier manquant?

Kolrie
la source
avez-vous poussé ces 4 commits?
mvp
@mvp non, ils sont uniquement sur mon référentiel git local.
kolrie

Réponses:

54

Utilisez git rebase --interactive HEAD~4et définissez l' editoption pour le commit que vous souhaitez modifier.

N'oubliez pas que vous ne devez pas modifier les validations transmises au référentiel distant de cette façon. Il est préférable d'ajouter un nouveau commit avec un fichier manquant dans ce cas.

Rafał Rawicki
la source
Merci. Est-ce le cas même si je suis le seul utilisateur du repo distant? Ne me permettrait-il pas de faire git push -fsi je suis sûr que l'amont n'a pas changé?
kolrie
1
Si vous êtes le seul utilisateur du référentiel distant, vous pouvez effectuer le push forcé.
Rafał Rawicki
7
Je pense que ces instructions ne sont pas assez détaillées. En l'essayant la première fois, on m'a dit "Impossible de rebase: votre index contient des modifications non validées." J'avais déjà add-ed les fichiers manquants, donc j'ai fait un commit avec "xxx" comme message. Ensuite, j'ai fait la commande rebase et j'ai changé le commit "xxx" de "pick" à "edit". Ensuite, j'ai fait "git rebase --continue". Maintenant, quand je regarde l'historique, j'ai "xxx" comme dernier commit, et le commit précédent auquel je voulais les ajouter est inchangé! Je me demande où était mon erreur?
Darren Cook
2
Ecraser le dernier commit ne placera pas le fichier dans HEAD ~ 4.
Justin le
1
git add editFiles; git commit -m "Blah"; git rebase -i HEAD ~ 5; // comme maintenant, un nouveau commit a été ajouté, nous devions donc rebaser avec 5 au lieu de 4. maintenant, déplacez le commit "Blah" sur la deuxième ligne et changez-le de "Pick" à "s" (squash) ce qui écrasera le commit avec HEAD ~ 5 car les commandes sont exécutées de haut en bas
zstring
274

Je me rends compte que les gens peuvent google et venir ici pour trouver une réponse plus simple: et si c'était juste le dernier commit? (La question d'OP est de réparer le 4ème commit dans l'histoire)

Dans le cas où vous vous engagez et réalisez que vous avez oublié d'ajouter un fichier immédiatement , faites simplement:

# edited file-that-i-remember.txt
git add file-that-i-remember.txt
git commit

# realize you forgot a file
git add file-that-i-forgot.txt
git commit --amend --no-edit

--no-editconservera le même message de validation.

Peasy facile!

Dr Beco
la source
21
Voilà la réponse.
Adam Bittlingmayer
5
Il convient de mentionner, si les validations ne sont pas transmises à la télécommande.
Ram Patra
1
Oui, cela vaut la peine de le mentionner ici dans les commentaires: c'est à utiliser avant push . Merci de l'avoir signalé.
Dr Beco
2
Un avis est que les commits avant et après --amendont des hachages différents
sonlexqt
6
Merci, mais ça ne peut pas être: OP a demandé HEAD^4. C'est ok comme ça, juste comme un addendum pour référence. ;)
Dr Beco
11

Si vous n'avez PAS poussé ces 4 commits, vous pouvez le faire comme suit:

Créez des fichiers de correctifs pour tous ces commits:

git format-patch -4

Rewind back de 4 commits:

git reset --hard HEAD~4

Ajouter un fichier manquant:

git add missing-file

Engagez-le avec --amend:

git commit --amend

Réappliquez tous les correctifs enregistrés:

git am *.patch

Si vous avez poussé, vous ne devez PAS utiliser cette méthode. Au lieu de cela, admettez simplement votre erreur et créez un autre commit au-dessus de HEAD qui résout ce problème.

mvp
la source
Si vous voulez faire cela étape par étape, il est plus facile de sélectionner les commits après celui modifié que de les exporter sous forme de patch.
Rafał Rawicki
1
C'est une question de goût. J'aime git format-patch/ git ambeaucoup mieux. Plus important encore, cela vous donne plus de confiance si vous gâchez quelque chose - le commit enregistré sous forme de patch dans un fichier physique est votre meilleur filet de sécurité.
mvp
La vraie confiance réside dans le fait que lorsque vous travaillez sur un référentiel git, vous ne supprimez jamais rien. Les anciens commits sont disponibles jusqu'à ce que vous git gc
exécutiez
C'est trivial et évident pour vous et moi. Mais, pour l'utilisateur qui ne fait que commencer et qui ne comprend probablement rien à git - ce fait n'est pas du tout évident.
mvp
2
Ces instructions semblaient longues, mais étaient assez simples et faciles à suivre. Merci. (Je voudrais ajouter une dernière étape: rm *.patch)
Darren Cook ,
9

Bien que la réponse acceptée soit correcte, il manque des instructions détaillées sur la façon de modifier un commit pendant un processus de rebase.

  • Commencez par lancer un processus de rebase:

    git rebase --interactive HEAD~4
    
  • Une liste des commits sera présenté, choisissez un commettras vous voulez modifier en changeant le mot pickpour editet enregistrez le fichier.

  • Apportez les modifications nécessaires à votre code (n'oubliez pas d'appeler git addpour les nouveaux fichiers)

  • Une fois toutes les modifications effectuées, émettez git commit --amend- cela modifiera un commit marqué commeedit

  • Appelez git rebase --continuequi terminera le processus (s'il y a plus de commits marqués comme edit, les étapes ci-dessus doivent être répétées)

Notes IMPORTANTES:

  • NE supprimez PAS les lignes marquées comme pickque vous ne souhaitez pas modifier - laissez-les telles quelles. La suppression de ces lignes entraînera la suppression des validations associées

  • GIT vous y oblige stashavant de rebaser si votre répertoire de travail n'est pas propre; vous pouvez cependant git stash pop / git stash applylors du rebase, afin de modifier ces changements (c'est-à-dire les changements cachés avant de démarrer le processus de rebase) en un commit marqué commeedit

  • si quelque chose s'est mal passé et que vous souhaitez annuler les modifications apportées pendant le processus de rebase avant qu'il ne soit terminé (c'est-à-dire que vous voulez revenir au point avant de commencer le rebase), utilisez git rebase --abort- lisez également: Comment annuler un rebase interactif si --abort ne le fait pas ' t travailler?

  • Comme indiqué dans la réponse acceptée:

    N'oubliez pas que vous ne devez pas modifier les validations transmises au référentiel distant de cette façon. Il est préférable d'ajouter un nouveau commit avec un fichier manquant dans ce cas.

    La réponse se trouve dans le Git Book (paragraphe intitulé " The Perils of Rebasing "):

    Ne rebasez pas les commits qui existent en dehors de votre référentiel.

    Si vous suivez cette directive, tout ira bien. Sinon, les gens vous détesteront et vous serez méprisé par vos amis et votre famille.

    Lorsque vous rebasez des éléments, vous abandonnez les commits existants et en créez de nouveaux qui sont similaires mais différents. Si vous poussez des commits quelque part et que d'autres les tirent vers le bas et basent le travail sur eux, puis vous réécrivez ces commits avec git rebase et les poussez à nouveau, vos collaborateurs devront re-fusionner leur travail et les choses deviendront désordonnées lorsque vous essayez de ramenez leur travail dans le vôtre.

    [...]

dominik
la source