Comment fusionner des fichiers spécifiques à partir de branches Git

179

J'ai 2 branches git branch1 et branch2 et je veux fusionner file.py dans branch2 dans file.py dans branch1 et uniquement ce fichier.

En substance, je veux juste travailler sur le file.py dans branch1 mais je veux profiter de la commande de fusion. Quelle est la meilleure façon de procéder?

rwolst
la source

Réponses:

207

Lorsque le contenu provient file.pyde branch2 qui ne s'applique plus à branch1 , il faut sélectionner certaines modifications et en laisser d'autres. Pour un contrôle total, effectuez une fusion interactive à l'aide du --patchcommutateur:

$ git checkout --patch branch2 file.py

La section du mode interactif de la page de manuel pour git-add(1)explique les touches à utiliser:

y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk nor any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk nor any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

La commande Split est particulièrement utile.

pdp
la source
3
Comment pouvons-nous utiliser patch et en même temps utiliser un outil de fusion? au lieu des éléments clés
Gabriel
@Gabriel J'ai utilisé Git même avec des fichiers de correctifs et des archives tar parce qu'il est si facile de créer un repo ( git init <dir>) et finalement de le jeter ( rm -r <dir>).
pdp du
105

Bien qu'il ne s'agisse pas d'une fusion en soi, le contenu entier d'un autre fichier sur une autre branche est parfois nécessaire. Le billet de blog de Jason Rudolph fournit un moyen simple de copier des fichiers d'une branche à une autre. Appliquez la technique comme suit:

$ git checkout branch1 # ensure in branch1 is checked out and active
$ git checkout branch2 file.py

Maintenant file.pyest maintenant dans branch1 .

Matthew Turner
la source
91
Facile, mais ce n'est pas vraiment une fusion . Il remplace simplement file.pyce qui se trouve dans la branche 2.
Greg Hewgill
Que faire si vous fusionnez le fichier de branch1 à branch2? Vous aurez un conflit!
Amir
Est-ce que cela retient l'histoire des engagements?
Beez
18

Aucune des autres réponses actuelles ne «fusionnera» réellement les fichiers, comme si vous utilisiez la commande de fusion. (Au mieux, ils vous demanderont de choisir manuellement les différences.) Si vous voulez réellement profiter de la fusion en utilisant les informations d'un ancêtre commun, vous pouvez suivre une procédure basée sur celle trouvée dans la section "Fusion avancée" du git Manuel de référence.

Pour ce protocole, je suppose que vous souhaitez fusionner le fichier 'chemin / vers / fichier.txt' de l'origine / maître dans HEAD - modifiez-le si nécessaire. (Vous n'avez pas besoin d'être dans le répertoire supérieur de votre référentiel, mais cela aide.)

# Find the merge base SHA1 (the common ancestor) for the two commits:
git merge-base HEAD origin/master

# Get the contents of the files at each stage
git show <merge-base SHA1>:path/to/file.txt > ./file.common.txt
git show HEAD:path/to/file.txt > ./file.ours.txt
git show origin/master:path/to/file.txt > ./file.theirs.txt

# You can pre-edit any of the files (e.g. run a formatter on it), if you want.

# Merge the files
git merge-file -p ./file.ours.txt ./file.common.txt ./file.theirs.txt > ./file.merged.txt

# Resolve merge conflicts in ./file.merged.txt
# Copy the merged version to the destination
# Clean up the intermediate files

git merge-file devrait utiliser tous vos paramètres de fusion par défaut pour le formatage et autres.

Notez également que si votre "nôtre" est la version de la copie de travail et que vous ne voulez pas être trop prudent, vous pouvez agir directement sur le fichier:

git merge-base HEAD origin/master
git show <merge-base SHA1>:path/to/file.txt > ./file.common.txt
git show origin/master:path/to/file.txt > ./file.theirs.txt
git merge-file path/to/file.txt ./file.common.txt ./file.theirs.txt
RM
la source
15

Toutes les modifications apportées à file.pyin branch2dans leurs propres commits sont-elles distinctes des modifications apportées aux autres fichiers? Si tel est le cas, vous pouvez simplement effectuer cherry-pickles changements:

git checkout branch1
git cherry-pick <commit-with-changes-to-file.py>

Sinon, mergene fonctionne pas sur des chemins individuels ... vous pouvez tout aussi bien créer un git diffpatch de file.pymodifications depuis branch2et git applyvers branch1:

git checkout branch2
git diff <base-commit-before-changes-to-file.py> -- file.py > my.patch
git checkout branch1
git apply my.patch

la source
8

Vous pouvez stashet stash pople fichier:

git checkout branch1
git checkout branch2 file.py
git stash
git checkout branch1
git stash pop
Martin G
la source
Cela remplace branch1 / file.py par le contenu de branch2 / file.py au lieu d'une fusion qui devrait déclencher un conflit de fusion à résoudre.
plumSemPy
2

Pour ne fusionner que les modifications de branch2, supprimez file.pyles autres modifications.

git checkout -B wip branch2
git read-tree branch1
git checkout branch2 file.py
git commit -m'merging only file.py history from branch2 into branch1'
git checkout branch1
git merge wip

Merge ne regardera même jamais aucun autre fichier. Vous devrez peut-être «-f» les extractions si les arbres sont suffisamment différents.

Notez que cela laissera à branch1 l'impression que tout dans l'historique de branch2 a été fusionné jusqu'à ce point, ce qui peut ne pas être ce que vous voulez. Une meilleure version de la première vérification ci-dessus est probablement

git checkout -B wip `git merge-base branch1 branch2`

dans ce cas, le message de validation devrait probablement également être

git commit -m"merging only $(git rev-parse branch2):file.py into branch1"
jthill
la source
0

Je suis dans la même situation, je souhaite fusionner un fichier d'une branche qui contient de nombreux commits sur 2 branches. J'ai essayé de nombreuses façons ci-dessus et d'autres que j'ai trouvées sur Internet et toutes ont échoué (parce que l'historique des validations est complexe), alors je décide de faire mon chemin (de manière folle).

git merge <other-branch>
cp file-to-merge file-to-merge.example
git reset --hard HEAD (or HEAD^1 if no conflicts happen)
cp file-to-merge.example file-to-merge
Trac Nguyen
la source
0

Ce que j'ai fait est un peu manuel, mais je:

  1. Fusionné les branches normalement; Annulé la fusion avec revert;
  2. J'ai vérifié tous mes fichiers HEAD~1, c'est-à-dire leur état dans le commit de fusion;
  3. Rebasé mes engagements pour cacher ce piratage de l'historique des commit

Laid? Oui. Facile à retenir? Oui aussi.

Lucas Lima
la source