web-dev-qa-db-fra.com

git merge: Supprimer les fichiers que je veux conserver!

Comment pouvez-vous fusionner deux branches dans git, en conservant les fichiers nécessaires d'une branche?

Lors de la fusion de deux branches, si un fichier a été supprimé dans une branche et non dans une autre, le fichier est finalement supprimé.

Par exemple:

  • Un fichier existe en maître lorsque vous créez une nouvelle branche
  • vous supprimez le fichier maître car nous n'en avons pas (encore) besoin
  • vous apportez des modifications dans la branche pour ajouter une fonctionnalité, qui s'appuie sur le fichier existant
  • vous corrigez un bogue dans master (ne peut pas être jeté)
  • vous fusionnez un jour, et le fichier est parti!

Comment reproduire:

  1. Créez un dépôt Git avec un fichier.

    git init
    echo "test" > test.txt
    git add .
    git commit -m "initial commit"
    
  2. Créer une branche

    git branch branchA
    
  3. Supprimer le fichier en master

    git rm test.txt
    git commit -m "removed file from master"
    
  4. Effectuez TOUTE modification dans branchA qui ne touche pas le fichier supprimé (il doit rester inchangé pour éviter les conflits).

    git checkout branchA
    touch something.txt
    git add .
    git commit -m "some branch changes"
    

À partir de là, quelle que soit la méthode utilisée pour fusionner ces deux branches, le fichier test.txt est supprimé. En supposant que nous utilisions sur le fichier pour branchA, il s’agit d’un gros problème.


Exemples d'échec:

Fusionner 1

git checkout branchA
git merge master
ls test.txt

Fusionner 2

git checkout master
git merge branchA
ls test.txt

Rebase 1

git checkout branchA
git rebase master
ls test.txt
49
drfloob

C'est un problème intéressant. Étant donné que vous avez supprimé le fichier après la création de BranchA, puis que vous avez fusionné master dans BranchA, je ne sais pas comment Git pourrait se rendre compte qu'il existe un conflit.

Après la mauvaise fusion, vous pouvez annuler, puis fusionner à nouveau, mais rajouter le fichier:

git checkout HEAD@{1} .
git merge --no-commit master
git checkout master test.txt
git add test.txt
git commit
27
cmcginty

Pour une solution rapide dans ce cas, "git revert" le commit qui a supprimé le fichier.

Lorsque cette situation se présente à l'avenir, la meilleure façon de la gérer est de s'assurer que la création du nouveau fichier a bien lieu sur la branche. Ensuite, il est ajouté sur master lorsque vous fusionnez, mais vous n'avez pas le fichier traîner dans master entre-temps.

6
Phil

L'exemple de Casey ne fonctionnait pas dans mon cas. Je ne pouvais pas extraire test.txt de master, car il ne se trouvait plus dans cette branche:

$ git checkout master test.txt
error: pathspec 'test.txt' did not match any file(s) known to git.

Heureusement, je pouvais extraire le fichier de branchA's propre HEAD:

$ git checkout branchA
$ git merge --no-commit master
$ git checkout HEAD test.txt
$ git add test.txt
$ git commit
4
Alex Dean

Vous devez modifier le fichier dans la branche afin qu'il y ait un conflit de fusion avec la suppression dans le coffre.

La même chose se produira si, par exemple, vous supprimez une déclaration pour quelque chose dans un fichier d’en-tête dans le coffre (car rien n’en a besoin) et que vous ajoutez une dépendance à cette déclaration dans un ou plusieurs fichiers autres que ceux de la branche. Lorsque vous fusionnez, étant donné que la branche ne touche pas (cette partie de) l'en-tête, elle supprimera simplement la déclaration et les choses se casseront.

Chaque fois que vous avez des éléments interdépendants situés à plusieurs endroits et qui doivent rester synchronisés, il est très facile pour une fusion d’introduire des problèmes en silence. C’est l’une des choses que vous devez connaître et vérifier lors de la fusion. Idéalement, vous utilisez des assertions au moment de la compilation ou d'autres vérifications de la compilation qui rendront immédiatement évidentes les échecs.

2
Chris Dodd

Ma solution à cela était simplement de modifier les fichiers que je devais conserver (avec un commentaire nécessaire de toute façon) et de valider ces modifications sur la branche cible, générant ainsi un conflit de fusion pouvant être facilement résolu avec un git add et une validation normale.

Mon histoire a quelque chose comme ça. Les noms des branches ont été modifiés pour protéger les innocents.

  1. créer et valider des fichiers pour une nouvelle fonctionnalité à maîtriser
  2. réaliser cet ajout va être plus impliqué que prévu à l'origine, donc, branchée à feature_branch
  3. Suppression des fichiers du maître afin de ne pas perturber le flux de travail normal avec les RB et autres
  4. Le temps passe, plus de commits sur maître, aucun sur feature_branch
  5. Reprendre le travail sur la fonctionnalité, git merge master sur feature_branch entraîne la suppression des fichiers d'origine (bien sûr), git reset --hard avant la fusion
  6. Appliqué la solution décrite ci-dessus
1
Alex S