Est-il possible de choisir un commit depuis un autre dépôt git?

726

Je travaille avec un référentiel git qui a besoin d'une validation d'un autre référentiel git qui ne sait rien du premier.

En règle générale, je choisirais le cerise en utilisant le HEAD@{x}dans le reflog, mais parce que cela .gitne sait rien de cette entrée de reflog (répertoire physique différent), comment puis-je le choisir, ou puis-je?

J'utilise git-svn. Ma première branche utilise git-svndu trunkrepo Subversion, et la branche suivante utilise git-svnune branche Subversion.

gitcoder182
la source
2
C'est la raison donnée par Ben Lee pour ouvrir une prime sur cette question: "Je vais attribuer la prime à la bonne réponse, plutôt à la réponse acceptée. Je dois juste attendre 24 [heures] pour le faire." Cependant, je ne comprends pas laquelle de ces réponses est censée être "la bonne réponse", et pourquoi la réponse acceptée n'est pas "correcte".
1
La nature du problème n'est pas claire. Comment ces différents référentiels sont-ils liés, le cas échéant? L'un est-il une fourchette d'un autre? Ou s'agit-il en fait de deux projets complètement distincts et sans rapport?
@Cupcake, la réponse acceptée est bonne et a clairement aidé le PO, elle devrait donc être acceptée. Par «juste», je voulais vraiment dire «juste pour moi» (et à en juger par les commentaires, juste pour plusieurs autres personnes aussi). Je pensais juste que celui à qui j'avais donné la prime méritait autant de répétitions que la réponse acceptée.
Ben Lee

Réponses:

557

Vous devrez ajouter l'autre référentiel en tant que télécommande, puis récupérer ses modifications. De là, vous voyez le commit et vous pouvez le sélectionner.

Comme ça:

git remote add other https://example.link/repository.git
git fetch other

Vous avez maintenant toutes les informations à faire git cherry-pick.

Plus d'informations sur le travail avec les télécommandes ici: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes

CharlesB
la source
1
Et si j'utilise git-svn? ma première branche utilise git-svn du tronc et la suivante utilise le git-svn sur une branche (merci pour la réponse rapide)
gitcoder182
1
lorsque vous clonez le référentiel Subversion pour la première fois, assurez-vous de cloner l' intégralité du référentiel, pas seulement le tronc. Assurez-vous également d'utiliser l' --stdlayoutoption de git-svn si vous utilisez la disposition standard de tronc / branches / balises dans Subversion. La branche Subversion sera alors une simple branche git distante.
wilhelmtell
33
Si vous utilisez Github, vous pouvez extraire le correctif en ajoutant .patch à l'URL de validation, puis en l'appliquant avec git am < d821j8djd2dj812.patch. En dehors de GH, des concepts similaires pourraient être appliqués comme indiqué dans la réponse alternative ci-dessous.
radicand
2
@radicand dont la réponse ci-dessous est "alternative"? Veuillez vous y connecter.
7
Étapes détaillées pour choisir un autre dépôt
T. Kim Nguyen
854

La réponse, comme indiqué, est d'utiliser format-patch mais comme la question était de savoir comment choisir à partir d'un autre dossier, voici un morceau de code pour le faire:

$ git --git-dir=../<some_other_repo>/.git \
format-patch -k -1 --stdout <commit SHA> | \
git am -3 -k

(explication de @cong ma )

La git format-patchcommande crée un patch à partir some_other_repodu commit spécifié par son SHA ( -1pour un seul commit seul). Ce correctif est canalisé git am, ce qui applique le correctif localement ( -3signifie essayer la fusion à trois si le correctif ne s'applique pas proprement). J'espère que cela explique.

Robert Wahler
la source
18
C'est parfait, mais ce serait génial si quelqu'un pouvait développer cela - une ventilation de ce qui se passe exactement (en particulier avec ces drapeaux) serait incroyablement utile.
Nick F
46
@NickF, la git format-patchcommande crée un patch à partir some_other_repodu commit spécifié par son SHA ( -1pour un seul commit seul). Ce correctif est canalisé git am, ce qui applique le correctif localement ( -3signifie essayer la fusion à trois si le correctif ne s'applique pas proprement). J'espère que cela explique.
Cong Ma
3
erreur: échec du correctif: somefile.cs: 85 erreur: certainsfile.cs: le correctif ne s'applique pas Avez-vous modifié manuellement votre correctif? Elle ne s'applique pas aux blobs enregistrés dans son index. Impossible de revenir à la fusion à trois. Le patch a échoué à 0001 Ajout de parties d'interface graphique. La copie du patch qui a échoué se trouve dans: <some_other_repo> /.git/rebase-apply/patch Une fois ce problème résolu, exécutez "git am --continue". Si vous préférez ignorer ce correctif, exécutez plutôt "git am --skip". Pour restaurer la branche d'origine et arrêter les correctifs, exécutez "git am --abort".
Tom
8
@Tom essayez d'utiliser --ignore-whitespace. Commande complète: git --git-dir=../<some_other_repo>/.git format-patch -k -1 --stdout <commit SHA> | git am -3 -k --ignore-whitespace
Jake Graham Arnold
7
@BoomShadow Parce que c'est beaucoup plus simple. L'ajout de la télécommande et la récupération apportent toutes les modifications de l'autre dépôt. Cette ligne de commande est une action unique.
Jonathon Reinhart
152

Voici un exemple de fusion-extraction à distance.

cd /home/you/projectA
git remote add projectB /home/you/projectB
git fetch projectB

Ensuite vous pouvez:

git cherry-pick <first_commit>..<last_commit>

ou vous pouvez même fusionner toute la branche

git merge projectB/master
Brian
la source
54
git merge projectB/master est très, très mal , parce que vous n'êtes pas appliquer les modifications d'un seul commit (comme une écrémer serait), vousfusionner dans tous les changements dansprojectB/masterqui ne figurent pas dans votre propremasterbranche.
4
Je pensais que c'était l'intention de l'affiche originale. Sinon, oui, ce n'est pas la bonne option pour eux.
Brian
5
Cela fonctionne parfaitement lorsque les deux référentiels sont liés.
Ronny Ager-Wick
1
J'ai créé une copie à partir d'un référentiel git (juste pour "jouer" sans casser le dépôt d'origine) et pour le garder à jour avec sa source, la réponse de Brian est exactement ce dont j'avais besoin, alors, Cupcake, je je dois dire que ce n'est pas "faux", mais un autre cas d'utilisation. Mais c'est gentil de votre part de signaler le désastre potentiel: D
ferrari2k
6
OMI, cela doit être la solution acceptée. De plus, si vous souhaitez supprimer la télécommande une fois que vous en avez fini avec la sélection, utilisez git remote rm projectB. Utilisez également cette option git tag -d tag-namepour supprimer les balises récupérées dans le référentiel distant. Les validations à distance n'apparaîtront plus dans votre historique et l'élagage les supprimera éventuellement du stockage.
ADTC
130

Vous pouvez le faire, mais cela nécessite deux étapes. Voici comment:

git fetch <remote-git-url> <branch> && git cherry-pick FETCH_HEAD

Remplacez <remote-git-url>par l'URL ou le chemin d'accès au référentiel à partir duquel vous souhaitez choisir.

Remplacez-le <branch>par le nom de la branche ou de la balise que vous souhaitez sélectionner dans le référentiel distant.

Vous pouvez remplacer FETCH_HEADpar un git SHA de la branche.

Mise à jour: modifiée sur la base des commentaires de @ pkalinow.

docwhat
la source
8
Il fonctionne avec un nom de branche, mais pas avec SHA. Si vous voulez écrémer un commettras désigné par son hachage, utilisez plutôt: git fetch <repo-url> <branch> && git cherry-pick <sha>.
pkalinow
Merci. C'est exactement ce dont j'avais besoin pour insérer un certain nombre de validations d'un référentiel à un autre, que j'ai créées à cet effet.
wojciii
C'était exactement ce dont j'avais besoin avec de nombreuses implémentations personnalisées de notre code pour différents clients (qui ont chacun leurs propres référentiels / fourches), nous avions besoin d'un moyen pour obtenir des validations spécifiques dans notre base / tronc. MERCI!
RedSands
Cela devrait être la réponse acceptée pour un choix de cerise en un coup sur les dépôts. Je l'utilise tout le temps lors du choix entre des référentiels qui sont déjà locaux, l'URL distante n'est alors qu'un chemin de système de fichiers local.
Amedee Van Gasse
61

Voici les étapes pour ajouter une télécommande, récupérer des branches et sélectionner un commit

# Cloning our fork
$ git clone [email protected]:ifad/rest-client.git

# Adding (as "endel") the repo from we want to cherry-pick
$ git remote add endel git://github.com/endel/rest-client.git

# Fetch their branches
$ git fetch endel

# List their commits
$ git log endel/master

# Cherry-pick the commit we need
$ git cherry-pick 97fedac

Source: https://coderwall.com/p/sgpksw

jaredwilli
la source
17

Voir Comment créer et appliquer un patch avec Git . (D'après le libellé de votre question, j'ai supposé que cet autre référentiel est pour une base de code entièrement différente. S'il s'agit d'un référentiel pour la même base de code, vous devez l'ajouter en tant que télécommande comme suggéré par @CharlesB. Même si c'est pour un autre base de code, je suppose que vous pouvez toujours l'ajouter en tant que télécommande, mais vous ne voudrez peut-être pas obtenir la branche entière dans votre référentiel ...)

Aasmund Eldhuset
la source
11

Vous pouvez le faire sur une seule ligne comme suit. J'espère que vous êtes dans le référentiel git qui a besoin du changement choisi et que vous avez vérifié pour corriger la branche.

git fetch ssh://[email protected]:7999/repo_to_get_it_from.git branchToPickFrom && git cherry-pick 02a197e9533
# 

git fetch [URL de branche] [Branche vers laquelle choisir depuis] && git cherry-pick [ID de validation]

Don
la source
1
Vive, n'a pas eu besoin de la ssh://pièce, seulement pourhttps://
Leo
5

Oui. Récupérez le référentiel, puis sélectionnez-le dans la branche distante.

wilhelmtell
la source
1

En supposant Aest le repo que vous voulez cerise choisir, et Best celui que vous voulez écrémer le , vous pouvez le faire en ajoutant </path/to/repo/A/>/.git/objectsà </path/to/repo/B>/.git/objects/info/alternates. Créez ces alternatesfichiers s'il n'existe pas.

Cela permettra au repo B d'accéder à tous les objets git du repo A, et fera fonctionner la sélection de cerises pour vous.

pranavk
la source
0

Ma situation était que j'avais un repo nu vers lequel l'équipe poussait, et un clone de celui assis juste à côté. Cet ensemble de lignes dans un Makefile fonctionne correctement pour moi:

git reset --hard
git remote update --prune
git pull --rebase --all
git cherry-pick -n remotes/origin/$(BRANCH)

En gardant le maître du repo nu à jour, nous sommes en mesure de choisir un changement proposé publié sur le repo nu. Nous avons également un moyen (plus compliqué) de sélectionner plusieurs braches pour un examen et des tests consolidés.

Si "ne sait rien" signifie "ne peut pas être utilisé comme une télécommande", alors cela n'aide pas, mais cette question SO est venue alors que je cherchais pour trouver ce flux de travail, alors j'ai pensé que je contribuerais en retour.

Paul Hulett
la source
-n signifie non-commit selon git docs et je pense qu'il est très important de voir les changements avant de faire un commit
canbax
0

Si vous souhaitez sélectionner plusieurs validations pour un fichier donné jusqu'à ce que vous atteigniez une validation donnée, utilisez ce qui suit.

# Directory from which to cherry-pick
GIT_DIR=...
# Pick changes only for this file
FILE_PATH=...
# Apply changes from this commit
FIST_COMMIT=master
# Apply changes until you reach this commit
LAST_COMMIT=...

for sha in $(git --git-dir=$GIT_DIR log --reverse --topo-order --format=%H $LAST_COMMIT_SHA..master -- $FILE_PATH ) ; do 
  git --git-dir=$GIT_DIR  format-patch -k -1 --stdout $sha -- $FILE_PATH | 
    git am -3 -k
done
Diomidis Spinellis
la source