web-dev-qa-db-fra.com

Comment appliquer un patch git d'un référentiel à un autre?

J'ai deux référentiels, l'un est le référentiel principal d'une bibliothèque et l'autre est un projet utilisant cette bibliothèque.

Si je corrige le dans le projet subservient, j'aimerais un moyen facile d'appliquer ce correctif en amont.

L'emplacement du fichier est différent dans chaque référentiel.

  • Repo principal: www.playdar.org/static/playdar.js
  • Projet: playlick.com/lib/playdar.js

J'ai essayé d'utiliser git format-patch -- lib/playdar.js sur le projet playlick, puis git am sur le dépôt principal de playdar, mais les différents emplacements de fichier dans le fichier de correctif ont généré une erreur.

Existe-t-il un moyen simple d'appliquer le patch d'un commit donné sur un fichier donné à un autre fichier arbitraire ailleurs?

Pour les points bonus, que se passe-t-il si le fichier auquel vous souhaitez appliquer le patch n'est pas dans un référentiel git?

74
James Wheare

Si l'édition manuelle du fichier de patch est hors de question ou irréalisable, cela peut être fait avec des options standard (disponibles dans git apply, git format-patch et GNU patch).

  1. -p<n> supprime n les principaux répertoires des chemins du correctif.

  2. Après le traitement -p, --directory=<root> ajoute root à chacun des chemins du patch avant de l'appliquer.

Exemple

Donc, pour votre exemple, pour prendre un patch qui était à l'origine sur static/playdar.js et l'appliquer à lib/playdar.js, vous exécuteriez:

$ cat patch_file | git am     \ 
          -p1                 \ # remove 1 leading directory ('static/')
         --directory='lib/'     # prepend 'lib/'
101
vergenzt

Le patch produit par git format-patch est simplement un fichier texte - vous pouvez éditer les en-têtes diff afin qu'il modifie un chemin différent.

Ainsi, par exemple, cela aurait produit quelque chose comme ceci:

diff --git a/lib/playdar.js b/lib/playdar.js
index 1234567..89abcde
-- a/lib/playdar.js
++ b/lib/playdar.js

Tout ce que vous avez à faire est de changer lib/playdar.js à static/playdar.js, puis exécutez le correctif via git am"

Le patch doit être lisible par l'utilitaire de patch standard GNU pour les personnes qui n'ont pas git--- mais qui n'exécutent pas format-patch avec le -M, -C etc. options pour produire des correctifs de renommage dans ce cas, car leur prise en charge n'est pas universelle.

37
araqnid

En supposant que les deux projets sont des projets git, il semble que sous-modules serait la solution idéale pour vous. Cela permet à un projet git de se lier dynamiquement à un autre projet git, essentiellement en préparant un dépôt git directement dans un autre dépôt git, les deux ayant leurs propres vies distinctes.

En d'autres termes, ajoutez "référentiel principal" comme sous-module dans "projet". Chaque fois que vous validez/poussez de nouvelles choses dans le "repo principal", vous venez de git pull les replacer dans "projet".

4
Henrik Paul

Pour terminer réponse d'Henrik , et aller chercher le point bonus

que faire si le fichier auquel vous souhaitez appliquer le correctif n'est pas dans un référentiel git?

Si vous avez accès aux répertoires du fichier candidat pour un patch provenant d'un dépôt git, vous pouvez d'abord transformer cette arborescence de répertoires/fichiers en un dépôt git lui-même! ('git init ': un dépôt git est juste un .git dans un répertoire racine après tout).
Ensuite, vous définiriez ce dépôt comme un sous-module pour votre projet principal.

2
VonC

Vous pouvez ajouter une nouvelle télécommande et en tirer. Article avec détails.

$ cd <path-to-repoB>
$ git remote add repoA <git-URL-for-repoA>
$ git pull repoA
1
Der_Meister

L'utilisation de l'option --relative Pour format-patch Peut améliorer l'abstraction (masquer les détails non pertinents sur le référentiel à partir duquel le correctif a été généré).

[repository-with-changes]
git format-patch --relative=(path-to-library) (base-commit-for-patch) ## 'HEAD~1'

J'ai trouvé l'option --3way Requise lors de l'application du patch (pour éviter l'erreur does not exist in index) - votre kilométrage peut varier. L'utilisation de --directory=(...) n'est probablement nécessaire que si votre chemin cible n'est pas la racine du référentiel.

[repository-to-update]
git am --3way --directory=(path-to-library) (patch-file)

  • format-patch Créera un fichier de patch par commit sur la branche courante depuis 'base'.

  • La documentation de l'option --relative Semble être manquante dans certains cas , mais elle semble quand même fonctionner (à partir de la version 2.7.4).

0
nobar

Vous pouvez simplement supprimer (renommer) temporairement le référentiel principal.

cd to/main/project
mv .git .git_
cd to/sub/project
git apply patchname
cd -
mv .git_ .git
0
ya.teck

Je pense que subtree est la meilleure solution pour votre problème

Tutoriel 1

Tuorial 2

0
Mauro