Czy jest możliwe wybranie zatwierdzenia z innego repozytorium git?


724

Pracuję z repozytorium git, które wymaga zatwierdzenia z innego repozytorium git, które nie wie nic o pierwszym.

Zazwyczaj wybrałbym cherry przy użyciu HEAD@{x}w dzienniku reflog, ale ponieważ .gitnic nie wie o tym wpisie reflog (inny katalog fizyczny), w jaki sposób mogę to wybrać, czy mogę?

Używam git-svn. Moja pierwsza gałąź korzysta git-svnz trunkrepozytorium Subversion, a kolejna gałąź korzysta git-svnz gałęzi Subversion.


2
Oto powód, dla którego Ben Lee otworzył nagrodę za to pytanie: „Przyznam nagrodę za właściwą odpowiedź, a raczej za zaakceptowaną odpowiedź. Muszę tylko czekać 24 [godziny], aby to zrobić”. Nie rozumiem jednak, która z nich ma być „właściwą odpowiedzią” i dlaczego zaakceptowana odpowiedź nie jest „właściwa”.

1
Nie jest jasne, jaka jest istota problemu. W jaki sposób powiązane są te różne transakcje repo? Czy jeden jest widelcem drugiego? Czy są to tak naprawdę dwa zupełnie odrębne i niepowiązane ze sobą projekty?

@Ciastko, zaakceptowana odpowiedź jest dobra i wyraźnie pomogła OP, więc powinna zostać zaakceptowana. Przez „właściwy” naprawdę po prostu miałem na myśli „odpowiedni dla mnie” (i sądząc po komentarzach, odpowiedni również dla kilku innych osób). Po prostu pomyślałem, że ta, którą dałem nagrodę, zasługuje na tyle samo przedstawicieli, co zaakceptowana odpowiedź.
Ben Lee

Odpowiedzi:


554

Musisz dodać drugie repozytorium jako zdalne, a następnie pobrać jego zmiany. Stamtąd zobaczysz zatwierdzenie i możesz go wybrać.

Tak:

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

Teraz masz wszystkie informacje do zrobienia git cherry-pick.

Więcej informacji na temat pracy z pilotami tutaj: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes


1
Co jeśli używam git-svn? moja pierwsza gałąź używa git-svn pnia, a następna używa git-svn na gałęzi (dzięki za szybką odpowiedź)
gitcoder182

1
podczas pierwszego klonowania repozytorium Subversion upewnij się, że klonujesz całe repozytorium, a nie tylko pień. Upewnij się także, że korzystasz z --stdlayoutopcji git-svn, jeśli używasz standardowego układu trunk / branch / tags w Subversion. Wtedy gałąź Subversion będzie zwykłą zdalną gałęzią git.
wilhelmtell,

33
Jeśli używasz Github, możesz pobrać łatkę, dodając .patch do adresu URL zatwierdzenia, a następnie stosując go git am < d821j8djd2dj812.patch. Poza GH podobne koncepcje można zrealizować zgodnie z alternatywną odpowiedzią poniżej.
radicand

2
@radicand, która odpowiedź poniżej jest „alternatywna”? Link do niego

7
Szczegółowe kroki, aby wybrać Cherry z innego repozytorium: coderwall.com/p/sgpksw/git-cherry-pick-from-another-repository
T. Kim Nguyen

854

Jak podano, odpowiedzią jest użycie poprawki formatu, ale ponieważ pytanie brzmiało, jak wybrać z innego folderu, oto fragment kodu, aby to zrobić:

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

(wyjaśnienie od @cong ma )

git format-patchPolecenie tworzy łatkę z some_other_repojest określone przez jej zatwierdzanie SHA ( -1w odniesieniu do pojedynczej popełnienia sam). Ta poprawka jest przesyłana potokowo git am, która lokalnie stosuje łatkę ( -3oznacza próbę scalenia trójstronnego, jeśli łatka nie zastosuje się czysto). Mam nadzieję, że to wyjaśnia.


18
Jest to na miejscu, ale byłoby wspaniale, gdyby ktokolwiek mógł to rozwinąć - podział dokładnie tego, co się dzieje (szczególnie z tymi flagami) byłby niezwykle przydatny.
Nick F

45
@NickF, git format-patchpolecenie tworzy łatkę z some_other_repozatwierdzenia określonego przez jego SHA (tylko -1dla jednego zatwierdzenia). Ta poprawka jest przesyłana potokowo git am, która lokalnie stosuje łatkę ( -3oznacza próbę scalenia trójstronnego, jeśli łatka nie zastosuje się czysto). Mam nadzieję, że to wyjaśnia.
Cong Ma

3
error: patch failed: somefile.cs: 85 error: somefile.cs: patch nie dotyczy Czy ręcznie edytowałeś łatkę? Nie dotyczy to obiektów blob zarejestrowanych w jego indeksie. Nie można wrócić do łączenia trójstronnego. Łata nie powiodła się w 0001 Dodano części GUI. Kopia nieudanej poprawki znajduje się w: <some_other_repo> /.git/rebase-apply/patch Po rozwiązaniu tego problemu uruchom polecenie „git am --continue”. Jeśli wolisz pominąć tę łatkę, uruchom zamiast tego polecenie „git am --skip”. Aby przywrócić oryginalną gałąź i zatrzymać łatanie, uruchom polecenie „git am --abort”.
Tom

8
@Tom spróbuj użyć --ignore-whitespace. Pełne polecenie: 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 Ponieważ jest to o wiele prostsze. Dodanie pilota i pobranie powoduje wprowadzenie wszystkich zmian w repozytorium. Ten wiersz poleceń jest działaniem jednorazowym.
Jonathon Reinhart

151

Oto przykład zdalnej fetch-merge.

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

Następnie możesz:

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

lub możesz nawet scalić cały oddział

git merge projectB/master

54
git merge projectB/master Jest bardzo, bardzo źle , ponieważ nie starasz zmiany z jednego commit (jak cherry-pick by), jesteś w rzeczywistości scalanie wszystkich zmian wprojectB/masterktóre nie są zawarte w swoimmasteroddziale.

4
Przypuszczałem, że taki był pierwotny zamiar plakatu. W przeciwnym razie tak, nie jest to dla nich odpowiednia opcja.
Brian

5
Działa to doskonale, gdy oba repozytoria są ze sobą powiązane.
Ronny Ager-Wick

1
Utworzyłem kopię z repozytorium git (tylko dla „zabawy” bez zerwania oryginalnego repozytorium) i aby być na bieżąco z jego źródłem, odpowiedź od Briana jest dokładnie tym, czego potrzebowałem, więc Cupcake, ja muszę powiedzieć, że to nie „zły”, ale inny przypadek użycia. Ale miło z twojej strony, że
zwróciłeś

6
IMO to musi być przyjęte rozwiązanie. Ponadto, jeśli chcesz usunąć pilota po zakończeniu wybierania z niego, użyj git remote rm projectB. Służy również git tag -d tag-namedo usuwania tagów pobranych ze zdalnego repozytorium. Zdalne zatwierdzenia nie będą już widoczne w twojej historii, a przycinanie ostatecznie je usunie z pamięci.
ADTC

130

Możesz to zrobić, ale wymaga to dwóch kroków. Oto jak:

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

Zastąp <remote-git-url>adres URL lub ścieżkę do repozytorium, z którego chcesz wybrać Cherry Cherry.

Zamień <branch>na nazwę gałęzi lub tagu, którą chcesz wybrać ze zdalnego repozytorium.

Możesz zastąpić FETCH_HEADgit SHA z oddziału.

Zaktualizowano: zmodyfikowano na podstawie opinii @ pkalinow.


8
Działa z nazwą oddziału, ale nie z SHA. Jeśli chcesz cherry-pick commit oznaczona jego hash, użyj zamiast tego: git fetch <repo-url> <branch> && git cherry-pick <sha>.
pkalinow

Dzięki. Właśnie tego potrzebowałem, aby wstawić wiele commits z jednego repozytorium do drugiego, które stworzyłem w tym celu.
wojciii

Właśnie tego potrzebowałem przy wielu niestandardowych implementacjach naszego kodu dla różnych klientów (z których każdy ma swoje własne repozytoria / forki). Potrzebowaliśmy sposobu, aby uzyskać określone commity do naszej bazy / pnia. DZIĘKI!
RedSands

To powinna być zaakceptowana odpowiedź na jednorazowy wybór wiśni w repozytorium. Używam go cały czas, gdy wybieram między repozytoriami, które są już lokalne, zdalny adres URL jest wtedy tylko ścieżką lokalnego systemu plików.
Amedee Van Gasse

61

Oto kroki, aby dodać zdalny, pobrać gałęzie i wybrać zatwierdzenie

# Cloning our fork
$ git clone git@github.com: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

Źródło: https://coderwall.com/p/sgpksw


17

Zobacz Jak utworzyć i zastosować łatkę za pomocą Git . (Na podstawie sformułowania twojego pytania założyłem, że to inne repozytorium jest dla zupełnie innej bazy kodu. Jeśli jest to repozytorium dla tej samej bazy kodu, powinieneś dodać je jako zdalne, jak sugeruje @CharlesB. Nawet jeśli jest to dla innej podstawa kodu, myślę, że nadal możesz dodać go jako zdalny, ale możesz nie chcieć umieścić całej gałęzi w swoim repozytorium ...)


11

Możesz to zrobić w jednym wierszu w następujący sposób. Mam nadzieję, że znajdujesz się w repozytorium git, które wymaga zmiany, którą wybrałeś, i sprawdziłeś poprawność gałęzi.

git fetch ssh://git@stash.mycompany.com:7999/repo_to_get_it_from.git branchToPickFrom && git cherry-pick 02a197e9533
# 

git fetch [adres URL oddziału] [Oddział do pobrania z] i & git cherry-pick [identyfikator zatwierdzenia]


1
Pozdrawiam, nie potrzebowałem tej ssh://części, tylko dlahttps://
Leo


1

Zakładając, że Ajest to repozytorium, z którego chcesz wybrać wiśnia, i Bto jest to, do którego chcesz wybrać wiśnia, możesz to zrobić, dodając </path/to/repo/A/>/.git/objectsdo </path/to/repo/B>/.git/objects/info/alternates. Utwórz te alternatespliki, jeśli nie istnieją.

To sprawi, że repo B uzyska dostęp do wszystkich obiektów git z repozytorium A i sprawi, że wybranie dla ciebie będzie działać.


0

Moja sytuacja była taka, że ​​mam nagie repozytorium, do którego drużyna naciska, i klon tego siedzącego tuż obok. Ten zestaw linii w Makefile działa dla mnie poprawnie:

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

Utrzymując aktualność mistrza samego repozytorium, jesteśmy w stanie wybrać proponowaną zmianę opublikowaną w samym repo. Mamy również (bardziej skomplikowany) sposób wybrania wielu przegródek do skonsolidowanego przeglądu i testowania.

Jeśli „nic nie wie” oznacza, że ​​„nie można używać jako pilota”, to nie pomaga, ale to pytanie SO pojawiło się, gdy szukałem go w Google, aby wymyślić ten przepływ pracy, więc pomyślałem, że wrócę.


-n oznacza brak zatwierdzenia według git docs i bardzo ważne jest, aby zobaczyć zmiany przed dokonaniem zatwierdzenia
canbax

0

Jeśli chcesz wybrać wiele zatwierdzeń dla danego pliku, aż dojdziesz do danego zatwierdzenia, użyj następujących.

# 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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.