Je travaillais avec un ami sur un projet, et il a édité un tas de fichiers qui n'auraient pas dû être édités. D'une manière ou d'une autre, j'ai fusionné son travail dans le mien, soit lorsque je l'ai retiré, soit lorsque j'ai essayé de choisir les fichiers spécifiques que je voulais. Je cherche et joue depuis longtemps, essayant de comprendre comment supprimer les validations qui contiennent les modifications de ces fichiers, il semble que ce soit un basculement entre revenir et rebaser, et il n'y a pas d'exemples simples, et le les docs supposent que j'en sais plus que moi.
Voici donc une version simplifiée de la question:
Étant donné le scénario suivant, comment supprimer la validation 2?
$ mkdir git_revert_test && cd git_revert_test
$ git init
Initialized empty Git repository in /Users/josh/deleteme/git_revert_test/.git/
$ echo "line 1" > myfile
$ git add -A
$ git commit -m "commit 1"
[master (root-commit) 8230fa3] commit 1
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 myfile
$ echo "line 2" >> myfile
$ git commit -am "commit 2"
[master 342f9bb] commit 2
1 files changed, 1 insertions(+), 0 deletions(-)
$ echo "line 3" >> myfile
$ git commit -am "commit 3"
[master 1bcb872] commit 3
1 files changed, 1 insertions(+), 0 deletions(-)
Le résultat attendu est
$ cat myfile
line 1
line 3
Voici un exemple de la façon dont j'ai essayé de revenir
$ git revert 342f9bb
Automatic revert failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>' or 'git rm <paths>'
and commit the result.
la source
Réponses:
L'algorithme que Git utilise pour calculer les différences à inverser nécessite que
La définition de "adjacent" est basée sur le nombre de lignes par défaut d'un diff de contexte, qui est 3. Donc, si "monfichier" a été construit comme ceci:
Ensuite, tout fonctionne comme prévu.
La deuxième réponse était très intéressante. Il existe une fonctionnalité qui n'a pas encore été officiellement publiée (bien qu'elle soit disponible dans Git v1.7.2-rc2) appelée Revert Strategy. Vous pouvez invoquer git comme ceci:
et il devrait mieux comprendre ce que vous vouliez dire. Je ne connais pas la liste des stratégies disponibles ni la définition d'une stratégie.
la source
perl -p
est utile pour écrire des programmes très courts (une ligne) qui bouclent et transmettent leur entrée à la sortie, semblable à sed.perl -i
est utilisé pour éditer les fichiers en place .perl -e
est de savoir comment soumettre le code à évaluer .Il y a quatre façons de procéder:
Manière propre, en revenant mais gardez dans le journal le retour:
De manière dure, supprimez uniquement le dernier commit:
Remarque: Évitez
git reset --hard
car cela supprimera également toutes les modifications apportées aux fichiers depuis le dernier commit. Si--soft
cela ne fonctionne pas, essayez plutôt--mixed
ou--keep
.Rebase (affichez le journal des 5 dernières validations et supprimez les lignes que vous ne voulez pas, ou réorganisez, ou écrasez plusieurs validations en une seule, ou faites tout ce que vous voulez, c'est un outil très polyvalent):
Et si une erreur est commise:
Rebase rapide: supprimez uniquement un commit spécifique en utilisant son identifiant:
Alternatives: vous pouvez également essayer:
Encore une autre alternative:
En dernier recours, si vous avez besoin d'une totale liberté de modification de l'historique (par exemple, parce que git ne vous permet pas de modifier ce que vous voulez), vous pouvez utiliser cette application open source très rapide : reposurgeon .
Remarque: bien sûr, toutes ces modifications sont effectuées localement, vous devez
git push
ensuite appliquer les modifications à la télécommande. Et dans le cas où votre référentiel ne souhaite pas supprimer le commit ("pas d'avance rapide autorisée", ce qui se produit lorsque vous souhaitez supprimer un commit que vous avez déjà poussé), vous pouvez utilisergit push -f
pour forcer le push des modifications.Remarque 2: si vous travaillez sur une branche et que vous devez forcer le push, vous devez absolument l'éviter
git push --force
car cela peut écraser d'autres branches (si vous y avez apporté des modifications, même si votre paiement actuel est sur une autre branche). Vous préférez toujours spécifier la branche à distance lorsque vous forcez poussée :git push --force origin your_branch
.la source
git rebase -i HEAD~5
travaillé pour moi. Ensuite, je viens de supprimer le (s) commit (s) dont je n'avais pas besoin et j'ai pu résoudre le problème en moins de 30 secondes. Je vous remercie.Voici une solution simple:
(Remarque:
x
est le nombre de validations)lors de l'exécution du fichier bloc-notes s'ouvrira. Entrez en
drop
plus de votre commit.Si vous ne connaissez pas Vim, cliquez simplement sur chaque sélection de mots que vous souhaitez modifier, puis appuyez sur la touche "I" (pour le mode insertion). Une fois que vous avez fini de taper, appuyez sur la touche "esc" pour quitter le mode d'insertion.
et c'est tout, vous avez terminé ... Synchronisez simplement le tableau de bord git et les modifications seront poussées à distance.
Si le commit que vous supprimez était déjà sur la télécommande, vous devrez forcer le push. Puisque --force est considéré comme dangereux , utilisez
git push --force-with-lease
.la source
Vous avez le choix entre
Vous devez choisir (1) si la modification erronée a été détectée par quelqu'un d'autre et (2) si l'erreur est limitée à une branche privée non poussée.
Git revert est un outil automatisé à faire (1), il crée un nouveau commit annulant un commit précédent. Vous verrez l'erreur et la suppression dans l'historique du projet, mais les personnes qui tirent de votre référentiel ne rencontreront pas de problèmes lors de la mise à jour. Cela ne fonctionne pas de manière automatisée dans votre exemple, vous devez donc modifier «monfichier» (pour supprimer la ligne 2), faire
git add myfile
etgit commit
gérer le conflit. Vous vous retrouverez alors avec quatre commits dans votre historique, avec le commit 4 revenant au commit 2.Si personne ne se soucie que votre historique change, vous pouvez le réécrire et supprimer le commit 2 (choix 2). La manière la plus simple de le faire est d'utiliser
git rebase -i 8230fa3
. Cela vous déposera dans un éditeur et vous pouvez choisir de ne pas inclure la validation erronée en supprimant la validation (et en gardant "pick" à côté des autres messages de validation. Lisez les conséquences de cette opération .la source
Approch 1
Obtenez d'abord le hachage de validation (ex: 1406cd61) que vous devez rétablir. la solution simple sera sous la commande,
si vous avez validé plus de modifications liées aux fichiers 1406cd61 après la validation 1406cd61, la commande ci-dessus ne fonctionnera pas. Ensuite, vous devez faire les étapes ci-dessous, qui sont la cueillette des cerises.
Approch 2
Veuillez suivre ci-dessous la description des actions, puisque nous utilisons --force, vous devez avoir des droits d'administrateur sur le dépôt git pour ce faire.
Étape 1: recherchez le commit avant le commit que vous souhaitez supprimer
git log
Étape 2: retirer cet engagement
git checkout <commit hash>
Étape 3: créer une nouvelle branche à l'aide de votre validation de paiement actuelle
git checkout -b <new branch>
Étape 4: Maintenant, vous devez ajouter le commit après le commit supprimé
git cherry-pick <commit hash>
Étape 5: Répétez maintenant l'étape 4 pour tous les autres commits que vous souhaitez conserver.
Étape 6: Une fois que tous les validations ont été ajoutées à votre nouvelle branche et validées. Vérifiez que tout est dans le bon état et fonctionne comme prévu. Vérifiez que tout a bien été commis:
git status
Étape 7: passez à votre branche cassée
git checkout <broken branch>
Étape 8: Maintenant, effectuez une réinitialisation matérielle sur la branche cassée du commit avant celle que vous souhaitez supprimer
git reset --hard <commit hash>
Étape 9: fusionnez votre branche fixe dans cette branche
git merge <branch name>
Étape 10: Remettez les modifications fusionnées à l'origine. AVERTISSEMENT: cela écrasera le dépôt à distance!
git push --force origin <branch name>
Vous pouvez effectuer le processus sans créer de nouvelle branche en remplaçant les étapes 2 et 3 par l'étape 8, puis ne pas exécuter les étapes 7 et 9.
la source
Vous pouvez supprimer les commits indésirables avec
git rebase
. Supposons que vous ayez inclus des validations d'une branche de rubrique d'un collègue dans votre branche de rubrique, mais décidez plus tard que vous ne souhaitez pas ces validations.À ce stade, votre éditeur de texte ouvrira la vue de rebase interactive. Par exemple
Si le rebase n'a pas réussi, supprimez la branche temporaire et essayez une autre stratégie. Sinon, continuez avec les instructions suivantes.
Si vous poussez votre branche de sujet vers une télécommande, vous devrez peut-être forcer la poussée car l'historique de validation a changé. Si d'autres travaillent sur la même branche, prévenez-les.
la source
D'après les autres réponses ici, j'étais un peu confus avec la façon dont
git rebase -i
pourrait être utilisé pour supprimer un commit, donc j'espère que c'est OK de noter mon cas de test ici (très similaire à l'OP).Voici un
bash
script que vous pouvez coller pour créer un référentiel de test dans le/tmp
dossier:À ce stade, nous avons un
file.txt
avec ces contenus:À ce stade, HEAD est au 5ème commit, HEAD ~ 1 serait le 4ème - et HEAD ~ 4 serait le 1er commit (donc HEAD ~ 5 n'existerait pas). Disons que nous voulons supprimer le 3e commit - nous pouvons émettre cette commande dans le
myrepo_git
répertoire:( Notez que les
git rebase -i HEAD~5
résultats avec "fatal: Besoin d'une seule révision; invalide en amont HEAD ~ 5". ) Un éditeur de texte (voir capture d'écran dans la réponse de @Dennis ) s'ouvrira avec ces contenus:Nous obtenons donc tous les commits depuis (mais sans inclure ) notre HEAD demandé ~ 4. Supprimez la ligne
pick 448c212 3rd git commit
et enregistrez le fichier; vous obtiendrez cette réponse degit rebase
:À ce stade, ouvrez myrepo_git /
folder/file.txt
dans un éditeur de texte; vous verrez qu'il a été modifié:Fondamentalement,
git
voit que lorsque HEAD est arrivé au 2e commit, il y avait du contenu deaaaa
+bbbb
; puis il a un patch decccc
+ ajoutédddd
qu'il ne sait pas comment ajouter au contenu existant.Donc, ici,
git
vous ne pouvez pas décider pour vous - c'est vous qui devez prendre une décision: en supprimant le 3e commit, soit vous gardez les changements introduits par lui (ici, la lignecccc
) - soit vous ne le faites pas. Si vous ne le faites pas, supprimez simplement les lignes supplémentaires - y compris lecccc
- enfolder/file.txt
utilisant un éditeur de texte, pour qu'il ressemble à ceci:... puis enregistrez
folder/file.txt
. Vous pouvez maintenant exécuter les commandes suivantes dans lemyrepo_git
répertoire:Ah - donc pour marquer que nous avons résolu le conflit, nous devons
git add
lefolder/file.txt
, avant de fairegit rebase --continue
:Ici, un éditeur de texte s'ouvre à nouveau, montrant la ligne
4th git commit
- ici, nous avons une chance de changer le message de validation (qui dans ce cas pourrait être significativement changé en4th (and removed 3rd) commit
ou similaire). Disons que vous ne voulez pas - alors quittez simplement l'éditeur de texte sans enregistrer; une fois que vous faites cela, vous obtiendrez:À ce stade, vous avez maintenant un historique comme celui-ci (que vous pouvez également inspecter avec disons
gitk .
ou d'autres outils) du contenu defolder/file.txt
(avec, apparemment, des horodatages inchangés des commits originaux):Et si précédemment, nous avions décidé de conserver la ligne
cccc
(le contenu du 3ème commit git que nous avions supprimé), nous aurions eu:Eh bien, c'était le genre de lecture que j'espérais avoir trouvé, pour commencer à chercher comment
git rebase
fonctionne en termes de suppression de commits / révisions; alors j'espère que ça pourrait aider les autres aussi ...la source
Il semble donc que le mauvais commit ait été incorporé dans un commit de fusion à un moment donné. Votre commit de fusion a-t-il été retiré? Si oui, alors vous voudrez utiliser
git revert
; vous devrez serrer les dents et surmonter les conflits. Si non, vous pouvez éventuellement soit rebaser, soit revenir en arrière, mais vous pouvez le faire avant la validation de la fusion, puis refaire la fusion.Il n'y a pas vraiment d'aide que nous puissions vous apporter pour le premier cas, vraiment. Après avoir essayé le rétablissement et constaté que l'échec automatique, vous devez examiner les conflits et les corriger de manière appropriée. C'est exactement le même processus que la résolution des conflits de fusion; vous pouvez utiliser
git status
pour voir où se trouvent les conflits, modifier les fichiers non fusionnés, trouver les mecs en conflit, découvrir comment les résoudre, ajouter les fichiers en conflit et enfin valider. Si vous utilisezgit commit
seul (non-m <message>
), le message qui apparaît dans votre éditeur doit être le message modèle créé pargit revert
; vous pouvez ajouter une note sur la façon dont vous avez résolu les conflits, puis enregistrer et quitter pour valider.Pour le deuxième cas, qui résout le problème avant votre fusion, il existe deux sous-cas, selon que vous avez effectué plus de travail depuis la fusion. Si ce n'est pas le cas, vous pouvez simplement
git reset --hard HEAD^
annuler la fusion, revenir en arrière, puis refaire la fusion. Mais je suppose que oui. Vous finirez donc par faire quelque chose comme ceci:git rebase -i <something before the bad commit> <temporary branch>
pour supprimer le mauvais commit)git rebase --onto <temporary branch> <old merge commit> <real branch>
la source
Donc, vous avez fait un peu de travail et poussé, appelons-les commits A et B. Votre collègue a également fait du travail, valide C et D. aussi (commit F), et a découvert que votre collègue a changé certaines choses qu'il ne devrait pas avoir.
Donc, votre historique de commit ressemble à ceci:
Vous voulez vraiment vous débarrasser de C, D et D '. Puisque vous dites que vous avez fusionné vos collègues de travail avec les vôtres, ces validations sont déjà "là-bas", donc supprimer les validations en utilisant par exemple git rebase est un non-non. Croyez-moi, j'ai essayé.
Maintenant, je vois deux solutions:
si vous n'avez pas encore envoyé E et F à votre collègue ou à quelqu'un d'autre (généralement votre serveur "d'origine"), vous pouvez toujours les supprimer de l'historique pour le moment. C'est votre travail que vous souhaitez sauvegarder. Cela peut être fait avec un
(remplacez D 'par le hachage de validation réel que vous pouvez obtenir
git log
À ce stade, les validations E et F ont disparu et les modifications sont à nouveau des modifications non validées dans votre espace de travail local. À ce stade, je les déplacerais vers une branche ou les transformerais en patch et les enregistrer pour plus tard. Maintenant, inversez le travail de votre collègue, soit automatiquement avec un,
git revert
soit manuellement. Lorsque vous avez fait cela, rejouez votre travail en plus. Vous pouvez avoir des conflits de fusion, mais au moins ils seront dans le code que vous avez écrit, au lieu du code de votre collègue.Si vous avez déjà poussé le travail que vous avez fait après les validations de votre collègue, vous pouvez toujours essayer d'obtenir un «patch inversé» manuellement ou en utilisant
git revert
, mais puisque votre travail est «dans la voie», pour ainsi dire, vous obtiendrez probablement plus de conflits de fusion et plus de confusions. On dirait que c'est dans ça que vous vous êtes retrouvé ...la source
git revert --strategy resolver si commit est une fusion: utilisez git revert --strategy resolver -m 1
la source