Comment git-cherry-pick ne modifie que certains fichiers?
Si je veux fusionner en une branche Git les changements à certains des fichiers modifiés dans un commit qui comprend des modifications à plusieurs fichiers, comment cela peut-il être atteint?
supposons que la propagation de Git appelée stuff
a des changements dans les fichiers A
, B
, C
, et D
mais je veux fusionner seulement les modifications de stuff
aux fichiers A
et B
. Cela ressemble à un travail pour git cherry-pick
mais cherry-pick
seul sait comment fusionner ensemble s'engage, pas un sous-ensemble des fichiers.
10 réponses
je le ferais avec cherry-pick -n
( --no-commit
) qui vous permet d'inspecter (et modifier) le résultat avant de commettre:
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 de vérifier les chemins individuels (étape du milieu), 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 n'ont pas fonctionné pour moi puisque le commit a eu beaucoup de changements et de conflits avec beaucoup d'autres fichiers. Ce que j'ai trouvé était tout simplement
git show SHA -- file1.txt file2.txt | git apply -
Il ne fait pas add
les fichiers ou faire un commit pour vous afin que vous pouvez avoir besoin de suivre avec
git add file1.txt file2.txt
git commit -c SHA
ou si vous voulez sauter l'add, vous pouvez utiliser l'argument --cached
pour git apply
git show SHA -- file1.txt file2.txt | git apply --cached -
peut-être l'avantage de cette méthode sur la réponse de Jefromi est que vous ne devez pas vous rappeler quel 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
j'utilise habituellement le drapeau -p
avec une caisse 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 un dialogue vous demandant quels changements vous voulez dans "blobs" cela fonctionne assez bien à chaque morceau de code continu changement que vous pouvez ensuite signaler y
(Oui) n
(Non) etc pour chaque morceau de code.
l'option -p
ou patch
fonctionne pour une variété de commandes en git y compris git stash save -p
qui vous permet de choisir ce que vous voulez cacher de votre travail actuel
j'utilise parfois cette technique quand j'ai fait beaucoup de travail et que je voudrais la séparer et m'engager dans plus de sujets basés sur commits en utilisant git add -p
et le choix de ce que je veux pour chaque commit :)
git checkout source_branch <paths>...
dans l'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 explication complète 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 va juste annuler tout autre changement fait sur la branche de destination. Vous devrez fusionner les modifications manuellement:
$ git diff TÊTE de nom de fichier
je voudrais juste cherry-pick tout, puis faire ceci:
git reset --soft HEAD^
alors je retournerais les changements que je ne veux pas, puis je ferais un nouveau commit.
Utiliser git merge --squash branch_name
cela permettra d'obtenir toutes les modifications de l'autre branche et préparera un commit pour vous.
Maintenant, supprimez tous les changements inutiles et laissez celui que vous voulez. Et git ne saura pas qu'il y a eu une fusion.
j'ai trouvé un autre moyen qui empêche toute fusion conflictuelle sur cherry-picking qui IMO est en quelque sorte facile à se rappeler et à comprendre. Puisque vous n'êtes pas vraiment en train de choisir un commit, mais une partie de celui-ci, vous devez le partager d'abord et ensuite créer un commit qui conviendra à vos besoins et le choisir.
créer D'abord une branche à partir de la propagation que vous voulez diviser et la vérifier:
$ git checkout COMMIT-TO-SPLIT-SHA -b temp
puis revenir sur la Commission précédente:
$ git reset HEAD~1
puis ajoutez les fichiers / modifications que vous voulez sélectionner:
$ git add FILE
et de s'engager:
$ git commit -m "pick me"
notez le hachage de commit, appelons-le PICK-SHA et retournez à votre branche principale, maître par exemple forcer la caisse:
$ git checkout -f master
et de choisir le commettre:
$ git cherry-pick PICK-SHA
maintenant vous pouvez supprimer la branche temp:
$ 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
la situation:
Vous êtes sur votre branche, disons-le, master
et vous avez votre livraison sur toute autre branche. Vous ne devez choisir qu'un seul fichier de cette propagation particulière.
L'approche:
Étape 1: check-out sur la branche requise.
git checkout master
Étape 2: assurez-vous que vous avez copié la nécessaire commettre hachage.
git checkout commit_hash path\to\file
Étape 3: vous avez maintenant les changements du fichier requis sur votre branche désirée. Il suffit de les ajouter et de les engager.
git add path\to\file
git commit -m "Your commit message"