IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

GIT Discussion :

Commande Git revert


Sujet :

GIT

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    902
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 902
    Par défaut Commande Git revert
    Bonjour à tous,
    Je voudrais tester la commande revert de GIT en faisant comme ceçi dans GitBash

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $ mkdir git_revert_test
    $ cd git_revert_test
    $ git init .
    
    $ touch revert.md
    $ git add revert.md
    $ git commit -am"initial commit"
    J'ai ensuite modifié le fichier revert.md avec notepad++
    puis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $ git commit -am"Initial Content"
    J'ai ensuite remodifié le fichier revert.md avec notepad++
    puis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $ git commit -am"prepend content to demo file"
    puis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $ git log  --oneline
    4d00263 (HEAD -> master) Prepend content to demo file
    eef57da Initial Content
    43dcbad Initial Commit
    puis ensuite je fais le revert pour annuler le dernier commit
    et j'ai l'erreur suivante :

    error: your local changes would be overwritten by revert.
    hint: commit your changes or stash them to proceed.
    fatal: revert failed

    Si quelqu'un a une idée MERCI

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 487
    Par défaut
    Bonjour,

    Effectivement, Git considère qu'il y a des choses qui, malgré tes commandes, sont encore en suspens et n'ont pas été commités. Peut-être as-tu modifié une fois de plus le fichier en question ou peut-être en as-tu ajouté d'autres à côté ?

    Quoi qu'il en soit : git status et git diff te diront de quoi il s'agit.

    Rappel : tu le sais sans doute, mais git revert est une annulation « à la wikipédia » d'un commit donné, c'est-à-dire qu'il ne va pas supprimer le dernier commit en date mais appliquer le différentiel inverse, ce qui va prendre la forme d'un nouveau commit dans l'historique et dont l'effet est d'annuler tout ce que le commit ciblé a introduit.

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    902
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 902
    Par défaut
    Bjr j'ai exécuté git diff voiçi sa réponse :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ git diff
    diff --git a/revert.md b/revert.md
    index 18fa135..5697b3a 100644
    --- a/revert.md
    +++ b/revert.md
    @@ -1 +1 @@
    -revert Iniitial content
    \ No newline at end of file
    +revert Prepended line content
    \ No newline at end of file
    Apparement il y aurait un problème entre le 2ème commit et le dernier (HEAD) (No newline)

    quand je fais git status :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ git status
    On branch master
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
            modified:   revert.md
    
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
            modified:   revert.md
    Qu'en penses tu ?Quoi faire ?

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 487
    Par défaut
    Si je reprends tes réponses et que j'y ajoute la couleur, que tu devrais voir dans ton terminal, on obtient en principe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ git status
    On branch master
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
            modified:   revert.md
    
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
            modified:   revert.md
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ git diff
    diff --git a/revert.md b/revert.md
    index 18fa135..5697b3a 100644
    --- a/revert.md
    +++ b/revert.md
    @@ -1 +1 @@
    -revert Iniitial content
    \ No newline at end of file
    +revert Prepended line content
    \ No newline at end of file
    Cela signifie deux choses : tu as d'une part porté des modifications au fichier revert.md et tu as effectué un git add dessus pour les ajouter au prochain commit. Elles sont actuellement dans l'index, et tu dois pouvoir voir de quelles modifications il s'agit à l'aide de « git diff --cached », même si tu as de nouveau modifié le fichier entretemps, d'ailleurs.

    Tu as d'autre part porté de nouvelles modifications à ce même fichier, qui elles n'ont pas encore ajoutées avec git add (alors même que les précédentes sont dans l'index mais pas encore commitées). Ce sont celles que tu vois dans le deuxième paragraphe.

    Le fait d'avoir des choses en suspens dans l'index (chose que Git voit au fait que le contenu de l'index est différent du contenu du dernier commit en date) suffit à empêcher l'opération car celle-ci modifiera cet index. Mais il est également possible, même avec un index propre, que l'opération git revert cible le fichier également en question en écrasant les lignes que tu as modifiées, ce qui, là aussi, empêcherait l'opération de se faire.

    Comme il est indiqué dans le message d'erreur de ton message initial, il faut soit commiter tes changements pour de bon, soit les mettre de côté avec git stash pour y revenir plus tard.

    error: your local changes would be overwritten by revert.
    hint: commit your changes or stash them to proceed.
    fatal: revert failed
    ATTENTION : la situation dans laquelle tu trouves est très courante. C'est l'exploitation normale d'un dépôt Git. Par contre, il faut maintenant que l'on sache pourquoi tu veux effectuer git revert. Si c'est juste essayer la commande ou pour annuler légitimement les effets d'un ancien commit, alors règle simplement la situation de ton fichier pour pouvoir continuer.

    Si, en revanche, c'est précisément pour abandonner tout ce que tu as en suspens de ce côté et revenir au dernier état propre en date que tu t'es tourné vers git revert, alors ce n'est pas la manière de procéder (contrairement à Mercurial qui propose une commande qui porte le même nom mais ne fait pas du tout la même chose). Dans ce dernier cas, il faudra passer en revue les subtilités de git checkout et git reset. On peut également évoquer git restore mais comme cette dernière commande est encore relativement récente, on ne l'évoquera quand dans un second temps.

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    902
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 902
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Cela signifie deux choses : tu as d'une part porté des modifications au fichier revert.md et tu as effectué un git add dessus pour les ajouter au prochain commit. Elles sont actuellement dans l'index, et tu dois pouvoir voir de quelles modifications il s'agit à l'aide de « git diff --cached », même si tu as de nouveau modifié le fichier entretemps, d'ailleurs.
    Bjr et merci pour ton aide,
    J'aimerais reprendre pas à pas tes remarques car il y a des choses que je ne comprends pas dans ta première remarque :
    en effet tu parles d'index j'ai regardé l'index est "une zone d'assemblage entre votre répertoire de travail et votre dépôt."
    Voilà ce que donne git diff --cached
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ git diff --cached
    diff --git a/revert.md b/revert.md
    index 5697b3a..18fa135 100644
    --- a/revert.md
    +++ b/revert.md
    @@ -1 +1 @@
    -revert Prepended line content
    \ No newline at end of file
    +revert Iniitial content
    \ No newline at end of file
    Mais à quoi correspondent concrètement ces index et comment voir les modifications ?

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 487
    Par défaut
    Citation Envoyé par xeron33 Voir le message
    Voilà ce que donne git diff --cached

    […]
    Si tu regardes attentivement le différentiel présenté, tu verras qu'il est en fait l'inverse de celui présenté par git diff seul. revert va faire un travail similaire mais ici, c'est simplement un hasard.

    On voit en fait que tu as modifié une ligne, que tu as ajouté cette modification avec add pour commit, puis que tu as annulé à la main cette modification en modifiant à nouveau ton fichier pour le faire revenir à l'état antérieur, avant d'avoir commité.


    Mais à quoi correspondent concrètement ces index et comment voir les modifications ?
    Effectivement, tu arrives au stade où il devient nécessaire de se former proprement à Git et on avait déjà évoqué le sujet dans un autre fil.

    Le principe est relativement simple une fois qu'on l'a saisi et respecte globalement ce qui se fait avec les autres VCS, sauf que Git va le faire de manière beaucoup plus intelligente. Le tutoriel que tu évoques et qui fait état d'une « zone d'assemblage entre… » fait référence à la « staging area » qui est le nom que l'on donne souvent à l'index de Git en particulier. En fait, c'est l'approche adoptée qui en fait « de facto » une staging area et c'est présenté comme cela dans la documentation aussi.

    « L'index » (parce qu'il n'y en a qu'un par dépôt) est simplement la liste des fichiers qui sont suivis par le dépôt et c'est comme cela que ça fonctionne avec les autres SCM depuis RCS et CVS. On estime (en majeure partie à raison) que le working directory d'un dépôt lui appartient totalement et on pense que lorsque que l'on fait un checkout vers une révision donnée, il l'efface complètement et le ré-remplit avec les fichiers concernés. En réalité, le VCS ne travaille que sur les fichiers qu'il suit officiellement et laisse tous les autres intacts. Il est donc sûr, en principe, de passer d'une version à l'autre tout en maintenant des fichiers non suivis (ou non encore suivis) en parallèle dans le même dépôt.

    Sous Git, il s'agit d'un unique fichier qui se trouve sous .git :

    Code Shell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    $ ls .git
    branches/
    COMMIT_EDITMSG
    config
    description
    FETCH_HEAD
    HEAD
    hooks/
    index            ← Lui
    info/
    logs/
    modules/
    objects/
    ORIG_HEAD
    packed-refs
    refs/

    Et précisément, on ajoute à cette liste, au fur et à mesure du développement, les fichiers que l'on souhaite suivre avec la fameuse commande « add » (généralement la même dans la majorité des VCS). De ce point de vue, un nouveau fichier était donc ajouté « une fois pour toutes » avec add au début de son existence, puis n'avait plus besoin de l'être explicitement ensuite. Ça fonctionne d'ailleurs toujours comme cela avec Mercurial et avec d'autres VCS contemporains. Git est une exception notable et il y a de très bonnes raisons à cela, que l'on va développer.

    À ce stade, en revanche, la plupart des VCS se contentaient de vérifier à chaque commit si le contenu des fichiers suivis avait changé ou non (parfois même en se contentant d'examiner la date de modification). Cela signifie qu'à chaque commit, l'intégralité des fichiers suivis ayant été modifiés étaient re-enregistrés tels quels sans possibilité de distinction. Un commit était alors un simple « checkpoint », donc un instantané de l'état du dépôt entier à une date donnée, même si on ajoute toujours un message expliquant en principe les modifications apportées et pourquoi on les a faites.

    C'est d'ailleurs l'origine du mot « commit », qui est en fait un verbe, et qui ici signifie « s'engager » : on modifie à loisir un dépôt existant, généralement partagé avec d'autres collaborateurs ou contributeurs, et lorsque l'on veut « arrêter » ces modifications et les graver dans le marbre, on signe ses actes. Le dépôt est alors réputé avoir changé de version et l'ensemble de la communauté s'aligne sur ces mises à jour. CVS tenait d'ailleurs un numéro de version auto-incrémenté à chaque commit même s'il ne correspondait pas forcément à celui que l'on donnait au projet hébergé, s'il en avait un.

    Avec Git, cela est toujours vrai, et un commit va toujours correspondre à l'état du dépôt entier, en particulier lorsque tu vas rétablir une révision donnée avec git checkout mais il faut se souvenir qu'il a été conçu pour les besoins du développement du noyau Linux. Celui-ci se fait historiquement en envoyant des patches sur la LKML et il est demandé aux développeurs de regrouper les modifications en « unités logiques » (un patch = un objectif précis), ce qui permet aux mainteneurs d'accepter au besoin certains patches et d'en refuser d'autres en l'état.

    En outre, le modèle initial présenté ci-dessus rend difficile l'exploitation de branches. Pour reprendre les propos de Linus Torvalds lui-même : « 1) qui dans l'assemblée a déjà utilisé des branches avec CVS ? 2) Qui a aimé ça ? ». Sous CVS, faire une branche revenait surtout à effectuer un fork à partir d'une position donnée et re-fusionner deux branches était un exercice délicat. Sans compter les numéros de version qui commençaient à devenir cryptiques. Outre CVS, c'est BitKeeper qui a été utilisé sérieusement pendant un temps dans le développement du noyau. C'est le changement de politique et une modification de ses conditions d'utilisation qui ont poussé à la rédaction de Git tel qu'on le connaît et qui ont accéléré son développement.

    Ceci exposé, pour saisir le fonctionnement de l'index, il faut d'abord parler des objets de Git et de la manière dont il enregistre ses données au premier lieu :

    Les objets sous Git

    Git enregistre toutes les données du dépôt proprement dit (donc pas ses propres méta-données) sous forme d'objets localisés dans .git/objects. Ces objets prennent chacun la forme d'un fichier ordinaire compressé en .gz et dont le nom correspond à la somme SHA1 de leur contenu avant compression. Ceci en fait d'ailleurs des objets immuables puisque la moindre modification de leur contenu modifierait profondément, par définition, leur signature SHA1.

    Il n'existe que quatre types d'objet :

    • blob : il s'agit simplement d'une séquence de données de longueur arbitraire. Ce sont ces objets qui reçoivent le contenu proprement dit des fichiers suivis et parfois d'autres sources non structurées ;
    • tree : décrit une arborescence. C'est une liste qui, pour chaque entrée, associe un nom de fichier complet (avec ses modes d'accès et son chemin) à la signature SHA1 d'un blob qui en recèle le contenu ;
    • commit : forme un commit complet. Il contient le nom et l'adresse e-mail de l'auteur, celle du mainteneur le cas échéant (ou celui qui a effectué le commit), la date et l'heure où cela a eu lieu, plusieurs headers, le message associé, ainsi que la signature d'un objet tree représentant l'état du dépôt au moment du commit et la signature du ou des objets commits « parents », c'est-à-dire le commit auquel succède celui-ci. Un seul parent dans la majorité des cas, mais il peut y en avoir plusieurs en cas de fusion d'une ou plusieurs branches, et zéro dans le cas du commit initial ;
    • tag : un objet spécial pour les « tags annotés » dont nous ne parlerons pas ici (les tags ordinaires sont de simples étiquettes).


    On remarque que les objets contenant des références à d'autres objets, et ces objets étant tous signés, il n'est pas possible d'en modifier ou remplacer un sans modifier tous ceux qui s'y réfèrent, directement ou indirectement. Pour faire court, ceci forme de fait une blockchain, et ce depuis 2005, c'est-à-dire bien avant que Bitcoin n'en popularise le concept. C'est ce qui permet à Git d'être sûr qu'un contenu portant une même signature sera le même partout et aux développeurs de faire évoluer un même édifice sans avoir besoin d'un autorité de confiance centralisée ;

    On constate également qu'un même fichier répliqué dix fois (par exemple) dans le working directory n'aura pas besoin de l'être également dans le dépôt des objets : l'arborescence (l'objet tree) qui liste ces fichiers devra faire référence à dix blobs possédant tous le même contenu et, donc, la même signature. Et en conséquence, ce sera le même objet sur le disque. Donc le fichier en dix exemplaire ne le sera qu'en un seul dans la liste des objets, sans que Git ait besoin de mécanisme dédié pour en faire le contrôle. Cela se produira automatiquement de part même l'architecture du système.

    L'index

    C'est là que Git, déjà assez intelligent dans le concept, va se révéler particulièrement brillant : lorsque tu appelles git add, Git ne se contente pas d'ajouter le fichier à la liste mais il va également directement y associer son contenu. Il va donc créer un objet blob à la volée qui va recevoir le contenu du fichier tel qu'il est au moment où tu appelles la commande.

    En ce sens, l'index est donc un « tree ». Il n'utilise pas exactement le même format que les objets tree pour des raisons d'efficacité, mais c'est lui qui va former l'arborescence associée au prochain commit. Cela signifie que lorsque tu appelles git commit, c'est l'état de l'index qui est enregistré et pas directement celui du working directory.

    À chaque fois que tu appelles git add, même avec un fichier qui a déjà été ajouté, l'entrée est mise à jour et le blob associé est remplacé par celui qui correspond au contenu courant du fichier. C'est pour cela que, sous Git, on appelle git add pour soumettre chaque nouvelle modification, là où les autres se contentent d'enregistrer tout ce qui est suivi à chaque nouveau commit, sans distinction.

    Ceci te permet déjà de choisir, fichier par fichier, ce que tu souhaites enregistrer dans le prochain commit, les autres fichiers étant considérés comme inchangés (même s'il le sont en pratique dans le working directory). Tu peux ensuite choisir plus finement, au sein d'un même fichier, ce que tu souhaites sélectionner ou non en utilisant git add -p plutôt que git add seul. On y reviendra.

    Et c'est également ce même système qui va permettre à Git de savoir ce qui a changé ou non dans ton dépôt sans avoir à en tenir explicitement la trace avec des flags : il lui suffit de comparer entre eux les états du dernier commit en date (ou plus précisément celui qui est déployé par git checkout et référencé par HEAD), de l'index et du working directory :

    Cas 1 : le commit en vigueur, l'index et les fichiers du working directory sont tous identiques : cela indique que le contenu du working directory est conforme à celui du commit et que rien n'a été ajouté à l'index. Ton dépôt est « propre » et c'est ce que t'indique git status.

    Cas 2 : le commit en vigueur et l'index sont identiques, mais le working directory diffère : cela signifie que des modifications ont été apportées mais qu'elles n'ont pas encore été prises en compte. git status te les affiche en rouge et ce sont elles que tu vois avec git diff. Il faut utiliser git add pour les préparer à l'intégration.

    Cas 3 : l'index et le working directory sont identiques, mais le commit en vigueur diffère : cela signifie que tu as fait des modifications au working directory et que tu les as toutes ajoutées à l'index. git status te les affiche en vert et te dit qu'elles seront enregistrées avec le prochain commit. git diff ne t'indique plus rien car il n'y a plus de modification en suspens, mais aussi et surtout parce que pour connaître ces différences, git applique un diff entre le working directory et l'index (pas directement sur le commit en vigueur) ;

    Cas 4 : l'index, le working directory et le commit en vigueur sont tous différents : tu as à la fois des modifications qui ont été ajoutés avec git add et des modifications qui ne le sont pas encore. git status te présente à la fois du rouge et du vert. Les modifications en rouge peuvent être aussi bien des modifications déjà présentes mais pas encore ajoutées, soit des modifications qui ont été portées a posteriori après un add, éventuellement sur les mêmes lignes. Cela ne fait aucune différence pour Git, qui les traite de la même façon.

    C'est dans ce cas n°4 que tu te trouvais à ton dernier commentaire.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 231
    Dernier message: 03/02/2023, 10h36
  2. Réponses: 0
    Dernier message: 17/11/2017, 17h27
  3. Commande git archive exporter
    Par mickeys dans le forum GIT
    Réponses: 1
    Dernier message: 21/06/2016, 13h50
  4. git reset et git revert
    Par geforce dans le forum GIT
    Réponses: 2
    Dernier message: 10/12/2015, 11h22
  5. [IntelliJ +GIT] Utilisation de la commande Git add
    Par menzlitsh dans le forum IntelliJ
    Réponses: 1
    Dernier message: 19/12/2012, 16h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo