web-dev-qa-db-fra.com

Annulation de validations spécifiques depuis git

J'ai un arbre git avec beaucoup de commits et beaucoup de fichiers. Maintenant, je souhaite annuler les validations spécifiques qui ne concernent qu'un fichier. Expliquer:

> git init
Initialized empty Git repository in /home/psankar/specific/.git/
> echo "File a" > a
> git add a ; git commit -m "File a"
[master (root-commit) 5267c21] File a
 1 file changed, 1 insertion(+)
 create mode 100644 a
> echo "File b" > b
> git add b; git commit -m "File b"
[master 7b560ae] File b
 1 file changed, 1 insertion(+)
 create mode 100644 b
> echo "File c" > c
> git add c; git commit -m "File c"
[master fd6c132] File c
 1 file changed, 1 insertion(+)
 create mode 100644 c
> echo "b and c modified" > b ; cp b c
> git commit -a -m "b and c modified"
[master 1d8b062] b and c modified
 2 files changed, 2 insertions(+), 2 deletions(-)
> echo "a modified" > a
> git commit -a -m "a modified"
[master 5b7e0cd] a modified
 1 file changed, 1 insertion(+), 1 deletion(-)
> echo "c modified" > c
> git commit -a -m "c modified"
[master b49eb8e] c modified
 1 file changed, 1 insertion(+), 1 deletion(-)
> git log --pretty=oneline c
> git log --pretty=oneline c | cat
b49eb8e03af331bddf90342af7d076f831282bc9 c modified
1d8b062748f23d5b75a77f120930af6610b8ff98 b and c modified
fd6c13282ae887598d39bcd894c050878c53ccf1 File c

Maintenant, je veux annuler uniquement les deux validations b49eb8 et 1d8b06 sans annuler les modifications apportées à a. IOW ne rétablit que les validations d'un fichier (sans annuler d'autres validations intermédiaires (qui peuvent être des milliers) dans différents fichiers) Comment est-ce possible?

47
Sankar

Vous pouvez utiliser git revert avec le --no-commit option. Dans votre exemple:

$ git revert --no-commit b49eb8e 1d8b062
# Files that were modified in those 2 commits will be changed in your working directory
# If any of those 2 commits had changed the file 'a' then you could discard the revert for it:
$ git checkout a
$ git commit -a -m "Revert commits b49eb8e and 1d8b062"

Si vous ne fournissez pas de message de validation, un message préparé sera disponible au démarrage de l'éditeur de message de validation.

Si vous omettez le --no-commit, les modifications des validations que vous spécifiez seront annulées. Ceci est réalisé en appliquant l'inverse des modifications dans les validations spécifiées et en les validant. Il en résulte un nouveau commit, à la fois le commit d'origine et le commit annulé seront dans l'historique de votre référentiel.

80
mamapitufo

Il y a deux cas ici:

  1. Lorsque vous avez déjà poussé votre arbre git quelque part et que vous ne voulez pas modifier l'historique. Dans ce cas, vous aurez besoin d'une nouvelle validation exprimant les modifications que vous avez apportées lors de la restauration des validations précédentes. Vous devez utiliser la réponse de @ mamapitufo.

  2. Si vous n'avez jamais poussé la branche sur laquelle les modifications sont activées, vous pouvez modifier l'historique. Dans ce cas, vous pouvez supprimer complètement les commits indésirables. Cela va nettoyer l'histoire et signifie que vous ne poussez pas un mauvais virage vers vos collègues ou le public.

Dans le second cas, vous devez faire git rebase -i. Trouvez un commit qui précède tout historique que vous souhaitez modifier. Il peut s'agir du hachage de la validation ou du nom de la branche ou de la balise. Par exemple, vous pourriez faire

git rebase -i 23def8231

ou si vous êtes parti de la branche Origin/dev_branch et a fait le travail qui comprend les bits à supprimer sur votre branche appelé dev_branch, vous pourriez faire

git rebase -i Origin/dev_branch

Maintenant, vous serez envoyé dans une fenêtre d'éditeur où vous pourrez voir une liste de tous les commits que vous rebaserez. Cela peut être vim - si vous ne modifiez pas habituellement dans le terminal, il peut être défini comme valeur par défaut. Vous aurez probablement besoin d'un guide de démarrage rapide pour vim et d'un esprit ouvert si tel est le cas.

Maintenant, la chose la plus simple à faire est de supprimer les commits. Pour ce faire, supprimez la ligne ou ajoutez un # qui indique un commentaire au début de la ligne. (Il y a déjà quelques commentaires dans le fichier, pour vous expliquer les choses. Les ignorer ou les supprimer n'a aucun effet.)

Lorsque vous avez terminé, enregistrez le fichier et quittez l'éditeur. Le rebase se produit comme ceci: git revient au commit que vous avez nommé. Il parcourt la liste que vous avez enregistrée et rejoue chaque commit de cette liste. Ensuite, il fait du résultat de ce processus la nouvelle version de la branche sur laquelle vous étiez à l'origine.

Choses importantes à retenir:

  • Si vous vous perdez ou supprimez trop de lignes, vous pouvez annuler le rebase en supprimant chaque ligne de validation du fichier et en l'enregistrant. Le processus de rebase se terminera avec rien changé du tout.
  • Il est possible de créer des conflits. Par exemple, si vous supprimez une validation qui modifie un fichier et que vous la laissez dans une validation ultérieure qui modifie le même emplacement. Le commit ultérieur ne s'appliquera plus correctement et vous devrez le modifier à la main ou dans un outil de fusion pour obtenir la version souhaitée.

Vous pouvez également effectuer de nombreuses autres manipulations dans git rebase -i. Par exemple, changer l'ordre des validations, en regrouper plusieurs en une, ajouter des modifications supplémentaires entre les validations ou modifier les messages. C'est très utile. Le cas d'utilisation classique consiste à nettoyer votre succursale locale avant de la repousser vers un endroit où d'autres personnes examineront vos modifications.

11
jwg