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

  1. #1
    Nouveau Candidat au Club
    Git plusieurs branches : supprimer un fichier d'une branche
    Bonjour à tous,

    Très simplement, j'ai un dépôt qui est sur la branche « master ».

    A partir de cette branche master, j'ai créé une branche « mabranche » sur laquelle j'ai fait quelques modifs légères. Cette branche « mabranche » n'a pas vocation à recevoir d'autre modif. Par contre, la branche master peut être sujette à des mises à jour. Du coup, je bascule sur la branche master pour les mises à jour, avec un pull, puis je repasse sur « mabranche » et fait un rebase de mabranche sur master afin de profiter des mises à jour de master tout en conservant les petites modifs faites sur mabranche. Tout ceci fonctionne.

    Mon problème est le suivant : j'ai modifié un fichier sans le vouloir sur mabranche puis commité cette modif involontaire avec d'autres qui étaient prévues, toujours sur mabbranche.

    Du coup, le fichier modifié par erreur sur mabranche ne se met plus à jour avec master comme cela devrait être le cas puisqu'il est écrasé lors du rebase de mabranche sur master.
    J'aimerais donc retirer CE ficher de mabranche pour conserver la version de master.

    Comment puis je faire ?
    J'espère avoir été assez clair ?
    Par avance merci.
    Bonne journée.
    Reynald.

  2. #2
    Modérateur

    Bonjour,

    C'est en effet classique et il y a plusieurs manières de s'en sortir. Avant toute chose, note les identifiants SHA1 actuels de tes branches master et mabranche ou met un tag sur chacune d'elle si tu es à l'aise avec, de façon à pouvoir facilement revenir à l'état dans lequel tu te trouves actuellement si quelque chose tourne mal.

    Ensuite, le plus simple (si le problème se situe sur le dernier commit en date de la branche mabranche et que c'est à ce moment-là que tu as ajouté le fichier indu) consiste à revenir d'un commit en arrière et de recommencer :

    • Saute sur ta branche mabranche : git checkout mabranche
    • Remonte d'un commit en arrière en mode mixed (par défaut) : git reset @^
    • Ceci ramène le pointeur de ta branche sur le commit précédent mais sans nettoyer le répertoire de travail, qui contient donc toutes les modifications du dernier commit en date. Git les voit alors comme des nouveautés, apparaissant en rouge dans git status ;
    • Utilise git add <fichier> pour ajouter un par un les fichiers qui doivent l'être, en prenant soin d'exclure le fichier qui te gène ; Tu peux également essayer git add -p pour faire une sélection plus fine. À l'inverse n'utilise pas git add -u ni git add -A qui embarqueront tout ce qui traîne ;
    • Fais un git commit pour reconstruire le sommet de ta branche en ayant exclu le fichier concerné.


    À ce stade, il restera encore les modifications que tu as apportées au fichier concerné. À toi d'en disposer comme bon te semble. Si tu comptes les utiliser ailleurs, tu peux utiliser git stash pour les remiser et les redéballer sur une autre branche. Sinon, tu peux utiliser git checkout <fichier> pour lire la dernière version en date enregistrée de ce fichier en particulier (hormis bien sûr celle que l'on vient d'annuler) ce qui aura pour effet d'écraser son contenu et de le remplacer par cette version.

    Prudence donc, car ceci peut te faire perdre les informations de ce fichier mais si c'est bien ce que tu veux, il sera devenu identique à la dernière version, donc considéré comme inchangé. Il n'apparaitra plus dans git status et tu pourras alors changer de branche comme il te semble, et faire facilement tes rebase.

  3. #3
    Nouveau Candidat au Club
    Merci beaucoup pour l'aide.
    Je vais essayer .
    Dans l'attente d'avoir un avis j'avais finalement opté pour cette solution :
    1) passage sur mabranche
    2) git diff avec master, la branche de rebase, afin de visualiser les fichiers modifiés sur mabranche
    3) copie de ces fichiers dans un dossier en dehors du dépôt local.
    3 bis) passage sur master
    4) suppression de mabranche
    5) suppression du dossier de rebase sous .git
    6) ajout de mabranche, nouvelle version
    7) passage sur mabranche
    8) copie de tous les fichiers placés de côté au point 3 sur mabranche en ne copiant pas le(s) fichier(s) indésirable.
    9) commit mabranche
    Bon je sais c'est un bricolage, MAIS ca fonctionne .

    Je vais essayer la méthode Obsidian désormais.
    Merci encore.

  4. #4
    Modérateur

    Citation Envoyé par Reynald_34 Voir le message
    5) suppression du dossier de rebase sous .git
    Ouille ! Tu es allé jusqu'à modifier l'intérieur du dépôt .git pour t'en sortir ? :-) Autant copier les fichiers à l'extérieur et reconstruire est assez classique (et plutôt sain) quand on ne maîtrise pas encore l'outil, autant tu ne devrais jamais avoir eu à aller jusque là pour faire le ménage. Et pourtant, j'encourage généralement les gens à aller en explorer le contenu quand même car il est propre et bien architecturé, contrairement à la plupart des autres SCM qui ne le considèrent que comme un « internal ».

    Si tu en es là, je te conseille forcément de jeter un œil aux fondamentaux de Git, car c'est un système à snapshots et si l'on vient d'un système à différentiels, comme CVS, cela peut contribuer à l'incompréhension de la chose. Assure-toi simplement d'avoir compris comment fonctionnent :

    • Le système d'objet ;
    • L'index ;
    • Le reflog (à la limite).


    Une fois que les deux premiers concepts sont clairs, tout le reste découle de lui-même et Git, qui était cryptique jusqu'ici, apparaît soudainement limpide.

  5. #5
    Nouveau Candidat au Club
    Oui j'en suis là, car je ne pouvais plus rebaser ma nouvelle branche sur mon master.
    Après quelques recherches, je me suis résolu à supprimer le dossier de rebase qui me bloquait.
    Ensuite tout est rentré dans l'ordre mais je suis bien conscient que c'est un bricolage.

  6. #6
    Modérateur

    Ce que je veux dire, c'est que (par exemple) dans CVS, pour chaque fichier « toto » suivi, on va avoir un fichier « toto,v » dans le module concerné (côté dépôt CVS, pas dans le répertoire de travail) qui va contenir les détails du fichier et toutes les versions successives sous forme de différentiel. Et toutes les modifications du même fichier sont dedans, quelle que soit la branche.

    Avec Git (et sans doute avec tous les systèmes à screenshot), la totalité de ton fichier est ré-enregistrée à chaque fois qu'elle change ne serait-ce que d'un octet. Mais attention : cela se fait de manière intelligente : son contenu est stocké dans un fichier propre à Git nommé « objet » et qui est nommé d'après la somme SHA1 de ce que cet objet contient. Ce qui veut dire que si après avoir modifié ton fichier, tu reviens à l'état antérieur, tu obtiendras automatiquement l'ancienne somme et Git se rendra compte qu'il possède déjà l'objet. Et même s'il ne le faisait pas, il réécrirait ce même contenu dans un objet portant le même nom, ce qui fait qu'une même version d'un fichier ne sera jamais dupliquée.

    Une fois ceci posé, il suffit de se souvenir qu'il n'existe que quatre types d'objets sous Git : les tags (servant en fait aux annotated tags en particulier, donc on peut les ignorer pour le moment), les blobs (pour enregistrer le contenu d'un fichier en entier et rien que lui, sans aucune méta-donnée annexe), les tree, qui sont des « arborescences » (sous forme d'un fichier texte), c'est-à-dire une liste de fichiers avec leur chemin d'accès complet dans le répertoire de travail, associés chacun à la somme SHA1 du blob qui recèle leur contenu et les commits, qui sont eux-aussi un petit fichier texte, contenant les informations du commit tel que l'auteur, la date, le texte de log écrit au moment du commit et surtout : 1) l'identifiant du tree qui référence tous les fichiers proposés par la révision concernée et une ou plusieurs entrées « parent » qui donnent : l'identifiant de l'objet « commit » précédent. Le dernier en date, celui à partir duquel on a fait celui-ci.

    On comprend ainsi que l'historique d'un dépôt n'est pas consigné en tant que tel quelque part, mais est formé par les références successives des commits à leur(s) précédéceur(s). Cela les rend extrêmement difficiles à corrompre : si plusieurs objets sont manquants dans le dépôt, cela ne nous empêche aucunement d'utiliser ceux qui restent. En plus, comme chaque commit contient dans ses données l'identifiant SHA1 du précédent, cela influe sur le calcul de sa propre somme, ce qui les rend inaltérables. Ceci, au passage, est exactement le principe de la blockchain, mais était déjà en place bien avant que l'on en parle.

    En outre, ce modèle est implicitement un « graphe ». L'avantage est que pour suivre une branche, il suffit de partir de son sommet et « tirer le fil ». C'est pourquoi les tags, les branches et autres références sont tous rassemblés sous « .git/refs » et sont formés par de simples fichiers texte, qui contiennent exclusivement la somme SHA1 des révisions ciblées et rien d'autre.

    Donc, en fait, pour supprimer une branche, il suffit de faire « git branch -d <nomdelabranche> » mais en réalité, cette commande elle-même ne fait que supprimer l'étiquette concernée décrite ci-dessus. Les objets associés, eux, finiront par être éliminés avec le temps par un garbage collector.

###raw>template_hook.ano_emploi###