git: appliquer les modifications introduites par commit dans un dépôt à un autre dépôt

115

J'ai une machine locale repo1et repo2sur. Ils sont très similaires, mais ce dernier est une sorte d'autre branche ( repo1n'est plus maintenue).

/path/to/repo1 $ git log HEAD~5..HEAD~4
<some_sha> Add: Introduce feature X

Comment appliquer les modifications apportées par engagement <some_sha>dans repo1la repo2?

Dois-je préparer un patch, ou est-il possible d'en faire cherry-pickentre les dépôts?

Que diriez-vous de faire la même chose mais pour une gamme de commits?

prend
la source
2
Vous ne pouvez pas simplement passer de repo1 à repo2?
zwol du
pour le cas un peu plus spécifique où vous cherchez à appliquer des modifications à un fichier ou à des fichiers qui ont été déplacés dans l'un des référentiels, regardez ici: stackoverflow.com/questions/3491270/…
Braham Snyder

Réponses:

31

En guise de hack, vous pouvez essayer de modifier la recette pour comparer les commits dans deux référentiels différents sur la page GitTips , c'est-à-dire:

GIT_ALTERNATE_OBJECT_DIRECTORIES=../repo/.git/objects \
git cherry-pick $(git --git-dir=../repo/.git rev-parse --verify <commit>)

../repoest le chemin vers l'autre référentiel.

Avec Git moderne, vous pouvez utiliser plusieurs révisions et plages de révisions avec cherry-pick .

Le $(git --git-dir=../repo/.git rev-parse --verify <commit>) est là pour traduire <commit>(par exemple HEAD, ou v0.2, ou master~2, qui sont des valeurs dans le deuxième référentiel à partir duquel vous copiez) en identifiant SHA-1 de commit. Si vous connaissez SHA-1 d'un changement que vous souhaitez sélectionner, ce n'est pas nécessaire.

Notez cependant que Git peut ignorer la copie d'objets depuis le référentiel source, car il ne sait pas que le référentiel d'objets alternatifs n'est que temporaire, pour une opération. Vous devrez peut-être copier des objets du deuxième référentiel avec:

GIT_ALTERNATE_OBJECT_DIRECTORIES=../repo/.git/objects git repack -a -d -f

Cela place les objets empruntés au deuxième référentiel dans le stockage du référentiel d'origine

Pas testé.


Une solution pas si hacky est de suivre la réponse tricotée :

  • Accédez au deuxième référentiel à partir duquel vous souhaitez copier les validations et générez des correctifs à partir des validations souhaitées avec git format-patch
  • En option, copiez les correctifs (0001- * etc.) dans votre référentiel
  • Utilisez git am --3waypour appliquer des correctifs
Jakub Narębski
la source
1
Fonctionne bien. Si vous avez des problèmes avec la validation, faites 'git reset HEAD; git add. '.
gumik
5
c'est génial - comment feriez-vous une gamme de commits? juste sha1 ... sha2?
hvgotcodes
Je reçois aussi fatal: unable to read tree ...mais après git reset HEAD^tout fonctionne bien
jmarceli
@hvgotcodes cela a fonctionné pour moi simplement en passant la plage en tant que <commit>mais la rev-parse --verifycommande ne l'aime pas car elle n'accepte que des valeurs de validation uniques. Mais comme cherry-pickaccepte les valeurs de validation simples et de plage, je demande: pourquoi est-il rev-parsenécessaire?
Chuim
1
@Chuim: git rev-parseest nécessaire si vous voulez faire référence à un commit par son nom basé ref dans un autre dépôt, par exemple master, HEAD^^ou quelque chose comme ça; rev-parse le transforme en identifiant universel SHA-1.
Jakub Narębski
207

Vous voudrez probablement utiliser git format-patchpuis git amappliquer ce correctif à votre référentiel.

/path/to/1 $ git format-patch sha1^..sha1
/path/to/1 $ cd /path/to/2
/path/to/2 $ git am -3 /path/to/1/0001-…-….patch

Ou, en une seule ligne:

/path/to/2 $ git --git-dir=/path/to/1/.git format-patch --stdout sha1^..sha1 | git am -3
tricot
la source
9
Cette solution s'est avérée plus simple et plus sûre que la réponse acceptée de la sélection directe à l'aide de cerises GIT_ALTERNATE_OBJECT_DIRECTORIES(celle-ci corromprait mon référentiel).
Chuim
2
En cas de conflit, cela ne fonctionnera pas car il ne parvient pas à trouver les validations sur l'autre branche.
Roger Far
2
L'ajout --ignore-whitespaceà la git amcommande peut résoudre les conflits et éviter de devoir effectuer une fusion à
trois
98

Vous pouvez le faire cherry-picksi vous ajoutez le deuxième dépôt en tant que distant au premier (puis fetch).

wRAR
la source
11
C'est en fait la bonne façon de procéder.
Wilbert
5
Cela me semble également être la bonne manière. Et je l'ai juste utilisé et cela a bien fonctionné pour moi.
Ricky Nelson
11
Je dirais plutôt: faites git fetch [remote-name]dans le deuxième repo et ensuite git cherry-pick [sha1].
5
Cette approche a très bien fonctionné pour moi, merci. Étant donné que le deuxième dépôt était également local, il suffisait d'utiliser un URI de fichier lors de l'ajout en tant que distant.
palimpsestor
2
Dans mon cas, j'ai deux clones d'un gigantesque référentiel git distant (pour permettre le travail en parallèle), ce qui signifie que toute son histoire est déjà téléchargée et stockée deux fois sur mon HD. Si je devais également avoir à ajouter chacun comme télécommande de l'autre, cela créerait encore deux copies supplémentaires de la même histoire et nécessiterait potentiellement des synchronisations entre elles avant que je ne puisse le faire cherry-pick. Donc, même si cela peut sembler être la «bonne» façon, ce n'est pas toujours la plus pratique.
Chuim