Jak zastosować łatkę git z jednego repozytorium do drugiego?

80

Mam dwa repozytoria, jedno jest głównym repozytorium dla biblioteki, a drugie to projekt korzystający z tej biblioteki.

Jeśli naprawię w podległym projekcie, chciałbym mieć łatwy sposób na zastosowanie tej poprawki z powrotem w górę.

Lokalizacja pliku jest inna w każdym repozytorium.

  • Główne repozytorium: www.playdar.org/static/playdar.js
  • Projekt: playlick.com/lib/playdar.js

Próbowałem użyć git format-patch -- lib/playdar.jsw projekcie listy odtwarzania, a następnie git amw głównym repozytorium playdar, ale różne lokalizacje plików w pliku poprawki powodowały błąd.

Czy istnieje łatwy sposób na zastosowanie łatki z danego zatwierdzenia w danym pliku do innego dowolnego pliku w innym miejscu?

Jeśli chodzi o punkty bonusowe, co jeśli plik, do którego chcesz zastosować poprawkę, nie znajduje się w repozytorium git?

James Wheare
źródło
podobne: pytanie: stackoverflow.com/questions/3367254/ ...
koppor

Odpowiedzi:

117

Jeśli ręcznie edytując plik Patch jest wykluczone lub niewykonalne, można to zrobić za pomocą standardowych opcji (dostępne w git apply, git format-patchi GNU patch).

  1. -p<n>usuwa nwiodące katalogi ze ścieżek w łatce.

  2. Po przetworzeniu -p, --directory=<root>poprzedza rootdo każdej ścieżki w plastra przed zastosowaniem.

Przykład

Tak więc, na przykład, aby pobrać poprawkę, która była pierwotnie włączona static/playdar.jsi zastosować ją lib/playdar.js, uruchomisz:

$ cat patch_file | git am     \ 
          -p1                 \ # remove 1 leading directory ('static/')
         --directory='lib/'     # prepend 'lib/'
vergenzt
źródło
1
Czy jest jakaś szansa, aby znaleźć tę najlepszą odpowiedź? Jest to o wiele łatwiejsze niż ręczna edycja pliku poprawki.
weston
Jasne, jest to lepsza / łatwiejsza odpowiedź, chociaż odpowiedź @ araqnid jest nadal dobra.
James Wheare
Istotne dla dostosowania katalogu po pierwszej próbie bez --directory: stackoverflow.com/questions/24121709/ ...
Ioannis Filippidis
38

Łatka utworzona przez git format-patchjest po prostu plikiem tekstowym - możesz edytować nagłówki różnic, tak aby modyfikowały inną ścieżkę.

Na przykład dałoby to coś takiego:

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

Wszystko co musisz zrobić, to zmiana lib/playdar.jsna static/playdar.jsa następnie uruchom patcha przezgit am"

Plaster powinien być odczytywany przez standardowe narzędzia GNU poprawki dla ludzi, którzy nie mają git--- ale nie działają format-patchz -M, -Citp opcji do produkcji plastrów przemianowania w tym przypadku, ponieważ wsparcie dla nich nie jest uniwersalna.

araqnid
źródło
1
Wrócimy później na tę stronę… To lepsza odpowiedź na zadane pytanie niż poprzedni „zwycięzca”, który zasugerował moduły podrzędne.
James Wheare
4

Zakładając, że oba projekty są projektami git, wygląda na to, że submoduły byłyby dla Ciebie idealne. Pozwala to projektowi git dynamicznie łączyć się z innym projektem git, zasadniczo wypalając repozytorium git bezpośrednio w innym repozytorium git, oba mają własne, odrębne życie.

Innymi słowy, dodaj „repozytorium główne” jako moduł podrzędny w „projekcie”. Za każdym razem, gdy zatwierdzasz / wysyłasz nowe rzeczy w „głównym repozytorium”, po prostu umieszczasz git pullje z powrotem w „projekcie”.

Henrik Paul
źródło
Hmm, po przeczytaniu dokumentacji modułu podrzędnego nie brzmi to jak „łatwy sposób”, chociaż może być najbardziej solidny. Wygląda na to, że będę musiał stworzyć submodule zawierający tylko playdar.jsplik następnie m.in., że w obu pozostałych projektów (nie chcę od wszystkiego innego www.playdar.orgw playlick.comprojekcie) może po prostu uciec się do ręcznego edytowania plików patch do teraz, aby być uczciwym . Lub kontynuuj kopiowanie wklejania między nimi. Twoje zdrowie.
James Wheare
Oto jasny i dokładny samouczek oraz wprowadzenie do modułu podrzędnego
James Wheare
2

Uzupełnienie odpowiedzi Henrika i zdobycie dodatkowego punktu

co jeśli plik, do którego chcesz zastosować poprawkę, nie znajduje się w repozytorium git?

Jeśli masz dostęp do katalogów pliku kandydata na łatkę pochodzącego z repozytorium git, możesz najpierw przekształcić to drzewo katalogów / plików w samo repozytorium git! (' git init': repozytorium git to po prostu .git w katalogu głównym).
Następnie ustawisz to repozytorium jako podmoduł dla swojego głównego projektu.

VonC
źródło
2

Użycie --relativeopcji format-patchmoże poprawić abstrakcję (ukryć nieistotne szczegóły repozytorium, z którego łatka została wygenerowana).

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

Znalazłem --3wayopcję, która jest wymagana podczas nakładania łatki (aby uniknąć does not exist in indexbłędu) - Twój przebieg może się różnić. Użycie --directory=(...)jest prawdopodobnie konieczne tylko wtedy, gdy ścieżka docelowa nie jest katalogiem głównym repozytorium.

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

  • format-patch utworzy jeden plik łatki na każde zatwierdzenie do bieżącej gałęzi od 'base'.

  • --relativeWydaje się, że w niektórych przypadkach brakuje dokumentacji tej opcji , ale wydaje się, że i tak działa (od wersji 2.7.4).

Brent Bradburn
źródło
1

Możesz dodać nowego pilota i wyciągnąć z niego. Artykuł ze szczegółami.

$ cd <path-to-repoB>
$ git remote add repoA <git-URL-for-repoA>
$ git pull repoA
Der_Meister
źródło
1

Możesz po prostu tymczasowo usunąć (zmienić nazwę) główne repozytorium.

cd to/main/project
mv .git .git_
cd to/sub/project
git apply patchname
cd -
mv .git_ .git
ya.teck
źródło
-1

Myślę, że poddrzewo jest najlepszym rozwiązaniem Twojego problemu

Samouczek 1

Tuorial 2

Mauro
źródło