530 votes

Sélection partielle d'un commit avec Git

Je travaille sur 2 branches différentes : libérer et développement .

J'ai remarqué que je devais encore intégrer certaines modifications qui ont été apportées à la base de données de l'UE. libérer dans la branche développement branche.

Le problème est que je n'ai pas besoin de tout le commit, seulement de quelques morceaux dans certains fichiers, donc un simple

git cherry-pick bc66559

ne fait pas l'affaire.

Quand je fais un

git show bc66559

Je peux voir la différence mais je ne connais pas vraiment une bonne façon de l'appliquer partiellement à mon arbre de travail actuel.

860voto

Jefromi Points 127932

La chose essentielle que vous allez vouloir ici est git add -p ( -p est un synonyme de --patch ). Il s'agit d'un moyen interactif d'enregistrer le contenu, qui vous permet de décider si chaque élément doit être intégré, et même de modifier manuellement le patch si nécessaire.

Pour l'utiliser en combinaison avec le cherry-pick :

git cherry-pick -n <commit> # get your patch, but don't commit (-n = --no-commit)
git reset                   # unstage the changes from the cherry-picked commit
git add -p                  # make all your choices (add the changes you do want)
git commit                  # make the commit!

(Merci à Tim Henigan de m'avoir rappelé que git-cherry-pick possède une option --no-commit, et merci à Felix Rabe de m'avoir fait remarquer qu'il fallait réinitialiser ! Si vous voulez seulement laisser quelques éléments en dehors du commit, vous pouvez utiliser git reset <path>... pour déstocker uniquement ces fichiers).

Vous pouvez bien sûr fournir des chemins spécifiques à add -p si nécessaire. Si vous commencez avec un patch, vous pouvez remplacer le fichier cherry-pick avec apply .


Si vous voulez vraiment un git cherry-pick -p <commit> (cette option n'existe pas), vous pouvez utiliser l'option suivante

git checkout -p <commit>

Cela fera une différence entre le commit actuel et le commit que vous avez spécifié, et vous permettra d'appliquer les hunks de cette différence individuellement. Cette option peut être plus utile si le commit que vous tirez a des conflits de fusion dans une partie du commit qui ne vous intéresse pas. (Notez, cependant, que checkout diffère de cherry-pick : checkout essaie d'appliquer <commit> entièrement le contenu du site, cherry-pick applique la différence entre le commit spécifié et son parent. Cela signifie que checkout peut appliquer plus que ce commit, ce qui pourrait être plus que ce que vous voulez).

1 votes

En fait, si je suis les conseils avec git 1.7.5.4, 'git add -p' dit 'No changes' parce que tout est déjà dans l'index. Je dois faire un 'git reset HEAD' avant 'git add' - y a-t-il un moyen d'éviter ce reset avec une option ?

0 votes

@FelixRabe : Je suis en fait surpris qu'à un certain moment cherry-pick -n apparemment n'a pas laisser les changements échelonnés - la convention est définitivement que --no-commit arrêt des options droite avant le commit, c'est-à-dire avec toutes les modifications mises en place. Je vais ajouter la réinitialisation dans la réponse.

2 votes

@Blixt C'est-à-dire, si les commits qui sont sur l'autre branche mais pas sur votre branche actuelle sont A-B-C-D-E-F, git checkout -p <F> fait pas ne vous donne que les changements à partir de F, il vous donne ABCDEF tout mélangé et vous laisse choisir quelle partie vous voulez. Réduire cela à quelques changements de F est une douleur. D'un autre côté, git cherry-pick -n <F> ne vous donne que les changements de F - et si certains de ces changements entrent en conflit, il vous le signale de manière utile afin que vous puissiez trouver comment fusionner correctement.

78voto

Mike Monkiewicz Points 907

Je sais que je réponds à une vieille question, mais il semble qu'il y ait une nouvelle façon de procéder avec le contrôle interactif des sorties :

git checkout -p bc66559

Crédit à Puis-je choisir interactivement des hunks à partir d'un autre commit git ?

36voto

Jay Swain Points 424

En supposant que les changements que vous voulez sont à la tête de la branche dont vous voulez les changements, utilisez git checkout

pour un seul fichier :

git checkout branch_that_has_the_changes_you_want path/to/file.rb

pour plusieurs fichiers, il suffit de les enchaîner :

git checkout branch_that_has_the_changes_you_want path/to/file.rb path/to/other_file.rb

5 votes

Cela copie l'ensemble du fichier : pas seulement les modifications.

1 votes

Cette réponse, comme toute autre réponse ici jusqu'à présent, a un gros inconvénient : elle ne préserve pas l'auteur original de la modification, mais s'engage sous votre nom. Si une modification est bonne, vous volez le crédit de quelqu'un, si une modification est mauvaise, vous vous mettez sur le feu. Il semble qu'il n'y ait pas d'autre moyen que d'avoir git cherry-pick -p, et la honte est toujours là.

15voto

Christian.D Points 381

Construire sur Mike Monkiewicz vous pouvez également spécifier un seul ou plusieurs fichiers à extraire de la branche sha1 fournie.

git checkout -p bc66559 -- path/to/file.java 

Cela vous permettra de choisir de manière interactive les modifications que vous souhaitez voir appliquer à votre version actuelle du fichier.

1voto

jimbo1qaz Points 690

Si vous voulez spécifier une liste de fichiers sur la ligne de commande, et obtenir le tout en une seule commande atomique, essayez :

git apply --3way <(git show -- list-of-files)

--3way : Si un patch ne s'applique pas proprement, Git créera un conflit de fusion pour que vous puissiez exécuter git mergetool . Omettre --3way fera en sorte que Git abandonne les correctifs qui ne s'appliquent pas proprement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X