Wie wende ich einen Git-Patch von einem Repository auf ein anderes an?


80

Ich habe zwei Repositorys, eines ist das Haupt-Repo für eine Bibliothek und das andere ist ein Projekt, das diese Bibliothek verwendet.

Wenn ich das untergeordnete Projekt behebe, möchte ich diesen Patch auf einfache Weise wieder stromaufwärts anwenden.

Der Speicherort der Datei ist in jedem Repository unterschiedlich.

  • Hauptrepo: www.playdar.org/static/playdar.js
  • Projekt: playlick.com/lib/playdar.js

Ich habe versucht, git format-patch -- lib/playdar.jsdas Playlick-Projekt und dann git amdas Haupt-Playdar-Repo zu verwenden, aber die unterschiedlichen Dateispeicherorte in der Patch-Datei haben einen Fehler ausgelöst.

Gibt es eine einfache Möglichkeit, den Patch von einem bestimmten Commit für eine bestimmte Datei auf eine andere beliebige Datei an einer anderen Stelle anzuwenden?

Was passiert, wenn sich die Datei, auf die Sie den Patch anwenden möchten, nicht in einem Git-Repository befindet?


Antworten:


116

Wenn manuelles Bearbeiten der Patch - Datei von der Frage oder undurchführbar ist out, kann dies mit Standardoptionen (erhältlich in getan werden git apply, git format-patchund GNU patch).

  1. -p<n>Entfernt nführende Verzeichnisse aus den Pfaden im Patch.

  2. Nach der Verarbeitung -p, --directory=<root>prepends rootzu jedem der Pfade in dem Pflaster vor der Anwendung.

Beispiel

Um in Ihrem Beispiel einen Patch zu verwenden, auf den er ursprünglich static/playdar.jsangewendet wurde lib/playdar.js, würden Sie Folgendes ausführen:

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

1
Gibt es eine Chance, diese Top-Antwort zu geben? Dies ist weitaus einfacher als das manuelle Bearbeiten einer Patch-Datei.
Weston

Sicher, dies ist eine bessere / einfachere Antwort, obwohl die Antwort von @ araqnid immer noch gut zu wissen ist.
James Wheare

Relevant für das Anpassen des Verzeichnisses nach dem ersten Versuch ohne --directory: stackoverflow.com/questions/24121709/…
Ioannis Filippidis

38

Der von erstellte Patch git format-patchist einfach eine Textdatei. Sie können die Diff-Header so bearbeiten, dass ein anderer Pfad geändert wird.

So hätte es zum Beispiel so etwas hervorgebracht:

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

Alles , was Sie tun müssen , ist der Wandel lib/playdar.jszu static/playdar.jsund führen Sie dann den Patch durchgit am"

Der Patch sollte von dem Standard GNU Patch - Werkzeug für Menschen lesbar sein, die nicht über git--- aber nicht lief format-patchmit den -M, -Cusw. Optionen zu produzieren Umbenennungs Patches in diesem Fall , da die Unterstützung für sie nicht universell ist.


1
Später diese Seite erneut besuchen ... Dies ist eine bessere Antwort auf die gestellte Frage als der vorherige "Gewinner", der Submodule vorgeschlagen hat.
James Wheare

4

Angenommen, beide Projekte sind Git-Projekte, dann klingt es so, als würden Submodule perfekt zu Ihnen passen. Auf diese Weise kann ein Git-Projekt dynamisch mit einem anderen Git-Projekt verknüpft werden, wobei im Wesentlichen ein Git-Repo direkt in einem anderen Git-Repo gebacken wird, wobei beide ein eigenes Leben haben.

Mit anderen Worten, fügen Sie "main repo" als Submodul in "project" hinzu. Wann immer Sie neue Sachen in "main repo" festschreiben / pushen, kehren Sie sie einfach git pullin "project" zurück.


Hmm, nachdem ich die Submodul-Dokumente gelesen habe, klingt dies nicht nach "einem einfachen Weg", obwohl es möglicherweise der robusteste ist. Es sieht so aus, als müsste ich ein Submodul erstellen, das nur die playdar.jsDatei enthält, und dann in beiden anderen Projekten (ich möchte nicht alles andere aus www.playdar.orgdem playlick.comProjekt) einschließen, dass ich die Patch-Dateien vorerst nur manuell bearbeiten muss, um ehrlich zu sein . Oder kopieren Sie weiterhin das Einfügen zwischen den beiden. Prost.
James Wheare

Hier ist ein klares und gründliches Tutorial und der Einstieg in das Git-Submodul für alle anderen, die auf diese Frage stoßen
James Wheare

2

Um Henriks Antwort zu vervollständigen und den Bonuspunkt zu erhalten

Was ist, wenn sich die Datei, auf die Sie den Patch anwenden möchten, nicht in einem Git-Repository befindet?

Wenn Sie Zugriff auf die Verzeichnisse des Dateikandidaten für einen Patch haben, der aus einem Git-Repository stammt, können Sie diesen Baum von Verzeichnissen / Dateien zuerst in ein Git-Repository selbst umwandeln! (' git init': Ein Git-Repository ist schließlich nur ein Git in einem Stammverzeichnis).
Dann würden Sie dieses Repo als Submodul für Ihr Hauptprojekt festlegen.


2

Mit der --relativeOption format-patchkönnen Sie die Abstraktion verbessern (irrelevante Details über das Repository ausblenden, aus dem der Patch generiert wurde).

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

Ich habe festgestellt, dass die --3wayOption beim Anwenden des Patches erforderlich ist (um does not exist in indexFehler zu vermeiden ) - Ihr Kilometerstand kann variieren. Die Verwendung --directory=(...)ist wahrscheinlich nur erforderlich, wenn Ihr Zielpfad nicht das Stammverzeichnis des Repositorys ist.

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

  • format-patch erstellt eine Patch-Datei pro Commit für den aktuellen Zweig seit 'base'.

  • Die Dokumentation für die --relativeOption scheint in einigen Fällen zu fehlen , scheint aber trotzdem zu funktionieren (ab Version 2.7.4).


1

Sie können eine neue Fernbedienung hinzufügen und daraus ziehen. Artikel mit Details.

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

1

Sie können das Haupt-Repository einfach vorübergehend entfernen (umbenennen).

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.