Si je souhaite fusionner dans une branche Git les modifications apportées uniquement à certains des fichiers modifiés dans un commit particulier, y compris les modifications apportées à plusieurs fichiers, comment peut-on y parvenir?
Supposons que la validation Git appelée stuff
modifie les fichiers A
, B
, C
et D
, mais que je souhaite fusionner uniquement les modifications de stuff
aux fichiers A
et B
. Cela ressemble à un travail pour git cherry-pick
mais cherry-pick
ne sait comment fusionner que des validations entières, pas un sous-ensemble des fichiers.
Je le ferais avec cherry-pick -n
(--no-commit
) qui vous permet d'inspecter (et de modifier) le résultat avant de valider:
git cherry-pick -n <commit>
# unstage modifications you don't want to keep, and remove the
# modifications from the work tree as well.
# this does work recursively!
git checkout HEAD <path>
# commit; the message will have been stored for you by cherry-pick
git commit
Si la grande majorité des modifications sont des choses que vous ne voulez pas, au lieu d'extraire des chemins individuels (l'étape intermédiaire), vous pouvez tout réinitialiser, puis ajouter ce que vous voulez:
# unstage everything
git reset HEAD
# stage the modifications you do want
git add <path>
# make the work tree match the index
# (do this from the top level of the repo)
git checkout .
Les autres méthodes ne fonctionnaient pas pour moi car le commit avait beaucoup de modifications et de conflits pour beaucoup d'autres fichiers. Ce que je suis venu avec était simplement
git show SHA -- file1.txt file2.txt | git apply -
En fait, add
ne contient pas les fichiers et ne fait pas de commit pour vous. Vous devrez peut-être en faire le suivi avec
git add file1.txt file2.txt
git commit -c SHA
Ou si vous voulez ignorer l’ajout, vous pouvez utiliser l’argument --cached
pour git apply
git show SHA -- file1.txt file2.txt | git apply --cached -
J'utilise habituellement l'indicateur -p
avec une extraction git de l'autre branche que je trouve plus facile et plus granulaire que la plupart des autres méthodes que j'ai rencontrées.
En principe:
git checkout <other_branch_name> <files/to/grab in/list/separated/by/spaces> -p
exemple:
git checkout mybranch config/important.yml app/models/important.rb -p
Vous obtenez alors une boîte de dialogue vous demandant quels changements vous souhaitez dans les "blobs", cela revient pratiquement à chaque morceau de changement de code continu que vous pouvez ensuite signaler y
(Oui) n
(Non), etc. chaque morceau de code.
L'option -p
ou patch
fonctionne pour une variété de commandes dans git, y compris git stash save -p
qui vous permet de choisir ce que vous voulez cacher dans votre travail actuel.
J'utilise parfois cette technique lorsque j'ai effectué beaucoup de travail et que je souhaite la séparer et la valider en plusieurs commits basés sur des sujets, en utilisant git add -p
et en choisissant ce que je veux pour chaque commit :)
Peut-être que l’avantage de cette méthode par rapport à réponse de Jefromi est que vous n’aurez pas à vous souvenir du comportement de git reset est le bon :)
# Create a branch to throw away, on which we'll do the cherry-pick:
git checkout -b to-discard
# Do the cherry-pick:
git cherry-pick stuff
# Switch back to the branch you were previously on:
git checkout -
# Update the working tree and the index with the versions of A and B
# from the to-discard branch:
git checkout to-discard -- A B
# Commit those changes:
git commit -m "Cherry-picked changes to A and B from [stuff]"
# Delete the temporary branch:
git branch -D to-discard
Le choix des cerises consiste à sélectionner les modifications d'un "commit" spécifique. La solution la plus simple est de choisir toutes les modifications de certains fichiers
git checkout source_branch <paths>...
Par exemple:
$ git branch
* master
Twitter_integration
$ git checkout Twitter_integration app/models/avatar.rb db/migrate/20090223104419_create_avatars.rb test/unit/models/avatar_test.rb test/functional/models/avatar_test.rb
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: app/models/avatar.rb
# new file: db/migrate/20090223104419_create_avatars.rb
# new file: test/functional/models/avatar_test.rb
# new file: test/unit/models/avatar_test.rb
#
$ git commit -m "'Merge' avatar code from 'Twitter_integration' branch"
[master]: created 4d3e37b: "'Merge' avatar code from 'Twitter_integration' branch"
4 files changed, 72 insertions(+), 0 deletions(-)
create mode 100644 app/models/avatar.rb
create mode 100644 db/migrate/20090223104419_create_avatars.rb
create mode 100644 test/functional/models/avatar_test.rb
create mode 100644 test/unit/models/avatar_test.rb
Sources et explications complètes http://jasonrudolph.com/blog/2009/02/25/git-tip-how-to-merge-specific-files-from-another-branch/
MISE À JOUR:
Avec cette méthode, git ne fusionnera pas le fichier, il remplacera simplement toute autre modification effectuée sur la branche de destination. Vous devrez fusionner les modifications manuellement:
$ git diff HEAD nom_fichier
Utilisez git merge --squash branch_name
, tous les changements seront apportés par l’autre branche et prépareront un commit. Supprimez maintenant toutes les modifications inutiles et laissez celle que vous souhaitez. Et git ne saura pas qu'il y avait une fusion.
Je voudrais simplement tout sélectionner, puis faire ceci:
git reset --soft HEAD^
Ensuite, je reviendrais sur les modifications que je ne voulais pas, puis ferais un nouveau commit.
La situation:
Vous êtes sur votre branche, disons master
et vous avez votre commit sur n'importe quelle autre branche. Vous devez choisir un seul fichier de ce commit.
L'approche:
Étape 1: Commander sur la branche requise.
git checkout master
Étape 2: Assurez-vous d'avoir copié le hachage de validation requis.
git checkout commit_hash path\to\file
Étape 3: Vous avez maintenant les modifications du fichier requis sur votre branche souhaitée. Vous devez juste les ajouter et les valider.
git add path\to\file
git commit -m "Your commit message"
J'ai trouvé un autre moyen d'éviter toute fusion conflictuelle entre le choix du pion cherry et l'OMI, facile à mémoriser et à comprendre. Étant donné que vous ne sélectionnez pas un commit, mais que vous en faites partie, vous devez d'abord le scinder, puis créer un commit qui conviendra à vos besoins et le sélectionner.
Commencez par créer une branche à partir du commit que vous souhaitez scinder et extrayez-la:
$ git checkout COMMIT-TO-SPLIT-SHA -b temp
Puis annulez le commit précédent:
$ git reset HEAD~1
Ajoutez ensuite les fichiers/modifications que vous souhaitez sélectionner:
$ git add FILE
et le commettre:
$ git commit -m "pick me"
notez le commit hachage, appelons-le PICK-SHA et revenons à votre branche principale, maître par exemple en forçant la commande:
$ git checkout -f master
et sélectionnez le commit:
$ git cherry-pick PICK-SHA
maintenant, vous pouvez supprimer la branche temporaire:
$ git branch -d temp -f
Fusionner une branche dans une nouvelle (squash) et supprimer les fichiers inutiles:
git checkout master
git checkout -b <branch>
git merge --squash <source-branch-with-many-commits>
git reset HEAD <not-needed-file-1>
git checkout -- <not-needed-file-1>
git reset HEAD <not-needed-file-2>
git checkout -- <not-needed-file-2>
git commit