Pobierz określone zatwierdzenie ze zdalnego repozytorium Git


189

Czy istnieje sposób na pobranie tylko jednego konkretnego zatwierdzenia ze zdalnego repozytorium Git bez klonowania go na moim komputerze? Struktura zdalnego repo jest absolutnie taka sama jak moja, a zatem nie będzie żadnych konfliktów, ale nie mam pojęcia, jak to zrobić i nie chcę klonować tego ogromnego repozytorium.

Jestem nowy na git, czy jest jakiś sposób?


1
Czy twoje istniejące repozytorium jest już klonem zdalnego, czy może jest zupełnie inne?
CharlesB

Repozytorium jest źródłem jądra Linuksa i jest prawie takie samo
Varun Chitre

więc czy to klon, czy nie?
CharlesB

1
Nie dokładnie. Rozważ to: Niech zdalne repo będzie na czele D, a moje na czele A, a za nim B, C, D popełnia. Chciałbym połączyć zatwierdzenie B z jednego repozytorium i C z drugiego, a D z innego, ponieważ zobowiązania B, C, D w tych repozytoriach są różne z ich własnymi specjalnościami
Varun Chitre

1
@VarunChitre, czy możesz zaakceptować inną odpowiedź od VonC?
CharlesB,

Odpowiedzi:


109

Począwszy od Gita w wersji 2.5+ (Q2 2015), pobieranie pojedynczego zatwierdzenia (bez klonowania pełnego repozytorium) jest faktycznie możliwe.

Zobacz commit 68ee628, autor: Fredrik Medley ( moroten) , 21 maja 2015 r.
(Scalony przez Junio ​​C Hamano - gitster- w commit a9d3493 , 01 czerwca 2015)

Masz teraz nową konfigurację (po stronie serwera)

uploadpack.allowReachableSHA1InWant

Pozwól, upload-packaby zaakceptować żądanie pobierania, które prosi o obiekt, który jest osiągalny z dowolnej wskazówki. Należy jednak pamiętać, że obliczanie osiągalności obiektów jest drogie obliczeniowo.
Domyślnie to false.

Jeśli połączysz tę konfigurację po stronie serwera z płytkim klonowaniem ( git fetch --depth=1), możesz poprosić o pojedynczy zatwierdzenie (patrz t/t5516-fetch-push.sh:

git fetch --depth=1 ../testrepo/.git $SHA1

Możesz użyć git cat-filepolecenia, aby zobaczyć, że zatwierdzenie zostało pobrane:

git cat-file commit $SHA1

Polecenie „ git upload-pack”, które służy ” git fetchmoże służyć do zatwierdzania zatwierdzeń, które nie znajdują się na końcu żadnego odwołania, o ile są one dostępne z polecenia, przy uploadpack.allowReachableSHA1InWant zmiennej konfiguracyjnej.


Pełna dokumentacja to:

upload-pack: opcjonalnie zezwól na pobieranie osiągalnego sha1

Po uploadpack.allowReachableSHA1InWantustawieniu opcji konfiguracyjnej po stronie serwera „ git fetch” może wysłać zapytanie za pomocą wiersza „want”, który nazywa obiekt, który nie był reklamowany (prawdopodobnie został pozyskany poza pasmem lub ze wskaźnika submodułu). Przetwarzane będą
tylko obiekty osiągalne z wierzchołków gałęzi, tj. Połączenie reklamowanych gałęzi i ukrytych gałęzi transfer.hideRefs.
Pamiętaj, że wiąże się to z koniecznością przeglądania historii w celu sprawdzenia osiągalności.

Tej funkcji można użyć przy uzyskiwaniu zawartości określonego zatwierdzenia, dla którego znany jest sha1, bez potrzeby klonowania całego repozytorium, szczególnie jeśli używane jest płytkie pobieranie .

Przydatnymi przypadkami są np

  • repozytoria zawierające duże pliki w historii,
  • pobieranie tylko potrzebnych danych do kasy podmodułowej,
  • dzieląc sha1 bez informowania, do której dokładnie gałęzi należy, i w Gerrit, jeśli myślisz w kategoriach zatwierdzeń zamiast zmiany liczb.
    (Sprawa Gerrit została już rozwiązana, allowTipSHA1InWantponieważ każda zmiana Gerrit ma ref.)

Git 2.6 (III kwartał 2015) ulepszy ten model.
Zobacz zatwierdzenie 2bc31d1 , zatwierdzenie cc118a6 (28 lipca 2015 r.) Autor: Jeff King ( peff) .
(Połączone przez Junio ​​C Hamano - gitster- w commit 824a0be , 19 sierpnia 2015)

refs: wsparcie negatywne transfer.hideRefs

Jeśli ukryjesz hierarchię referencji za pomocą transfer.hideRefsconfig, nie ma możliwości późniejszego zastąpienia tej konfiguracji, aby ją „odkryć”.
Ta łatka implementuje „negatywne” ukrywanie, które powoduje, że mecze są natychmiast oznaczane jako ukryte, nawet jeśli inne dopasowanie je ukryje.
Dbamy o stosowanie dopasowań w odwrotnej kolejności od sposobu, w jaki są one dostarczane do nas przez maszynę konfiguracyjną, ponieważ pozwala to naszej zwykłej pracy na „ostatnią wygrywa” konfigurację (a wpisy w .git/config, na przykład, zostaną zastąpione /etc/gitconfig).

Możesz teraz zrobić:

git config --system transfer.hideRefs refs/secret
git config transfer.hideRefs '!refs/secret/not-so-secret'

aby ukryć się refs/secretwe wszystkich repozytoriach, z wyjątkiem jednego publicznego bitu w jednym konkretnym repozytorium.


Git 2.7 (listopad / grudzień 2015) poprawi się ponownie:

Zobacz zatwierdzenie 948bfa2 , zatwierdzenie 00b293e (05 listopada 2015), zatwierdzenie 78a766a , zatwierdzenie 92cab49 , zatwierdzenie 92cab49 , zatwierdzenie 92cab49 (03 listopada 2015), zatwierdzenie 00b293e , zatwierdzenie 00b293e (05 listopada 2015) i zatwierdzenie 92cab49 , zatwierdzenie 92cab49 , zatwierdzenie 92cab49 , commit 92cab49 (03 listopada 2015) autor: Lukas Fleischer ( lfos) .
Pomógł: Eric Sunshine ( sunshineco) .
(Scalony przez Jeff King - peff- in commit dbba85e , 20 listopada 2015)

config.txt: udokumentuj semantykę za hideRefspomocą przestrzeni nazw

W tej chwili nie ma jasnej definicji tego, jak transfer.hideRefspowinno się zachowywać po ustawieniu przestrzeni nazw.
Wyjaśnij, że hideRefsw tym przypadku przedrostki pasują do pozbawionych nazw. W ten sposób hideRefswzorce są obecnie obsługiwane w pakiecie odbiorczym.

hideRefs: dodaj obsługę pasujących pełnych referencji

Oprócz pasujących hideRefsreferencji w paski można teraz dodawać wzory, z którymi dopasowywana jest pełna referencja (bez pasów).
Aby rozróżnić dopasowania rozłożone i pełne, te nowe wzorce muszą być poprzedzone znakiem circumflex ( ^).

Stąd nowa dokumentacja :

transfer.hideRefs:

Jeśli używana jest przestrzeń nazw, prefiks przestrzeni nazw jest usuwany z każdego odwołania przed dopasowaniem do transfer.hiderefswzorców.
Na przykład, jeśli refs/heads/masterjest określony w transfer.hideRefsa obecna przestrzeń nazw foo, a następnie refs/namespaces/foo/refs/heads/master został pominięty z reklam, ale refs/heads/masteri refs/namespaces/bar/refs/heads/masternadal są reklamowane jako tzw „mieć” linii.
Aby dopasować ^referencje przed usunięciem, dodaj przed nazwą referencji. Jeśli połączysz !i ^, !musisz najpierw określić.


R .. wspomina w komentarzach o konfiguracji uploadpack.allowAnySHA1InWant, która pozwala upload-packzaakceptować fetchżądanie, które w ogóle prosi o dowolny obiekt. (Domyślnie false).

Zobacz commit f8edeaa (listopad 2016, Git v2.11.1) autorstwa Davida „novalis” Turnera ( novalis) :

upload-pack: opcjonalnie zezwól na pobieranie dowolnego sha1

Trochę głupio wydaje się sprawdzanie osiągalności w przypadku, gdy ufamy, że użytkownik uzyska dostęp do absolutnie wszystkiego w repozytorium.

Co więcej, jest to dość ryzykowne w systemie rozproszonym - być może jeden serwer reklamuje ref, ale od tego czasu inny został zmuszony do tego ref, a być może dwa żądania HTTP są skierowane do tych różnych serwerów.


4
Czy możesz podać bardziej kompletny przykład, w jaki sposób utworzyć klon repo za pomocą tylko jednego zatwierdzenia? Próbowałem, ale nie udało się .. Dzięki!
Lars Bilke,

1
Chcę naciskać na GitHub. Może nie pozwalają na to.
Lars Bilke,

2
@ LarsBilke mówimy o klonowaniu lub ciągnięciu tutaj, a nie wypychaniu. Jestem pewien, że GitHub nie ma jeszcze Git 2.5 po stronie serwera.
VCC,

2
Teraz jeszcze lepiej, nie ma uploadpack.allowAnySHA1InWantkary obliczeniowej osiągalności (i wektora DoS).
R .. GitHub ZATRZYMAJ LÓD

1
Dzięki! Zabawne jest dla mnie to, że opisują to jako „ufaj użytkownikowi w dostępie”, a nie „ufaj autorom repozytorium, aby nie forsowali przypadkowych bzdur, których nie zamierzają upubliczniać”.
R .. GitHub PRZESTAŃ POMÓC LODOWI

97

Klonujesz tylko raz, więc jeśli masz już klon zdalnego repozytorium, wyciągnięcie go z niego nie spowoduje ponownego pobrania wszystkiego. Po prostu wskaż gałąź, którą chcesz pobrać, lub pobierz zmiany i sprawdź, czy chcesz zatwierdzić.

Pobieranie z nowego repozytorium jest bardzo duże tanie pod względem przepustowości, ponieważ pobiera tylko te zmiany, których nie masz. Zastanów się, czy Git robi właściwe rzeczy przy minimalnym obciążeniu.

Git przechowuje wszystko w .gitfolderze. Zatwierdzenie nie może zostać pobrane i zapisane w izolacji, potrzebuje wszystkich swoich przodków. Są ze sobą powiązane .


Aby zmniejszyć rozmiar pobierania, możesz jednak poprosić git o pobranie tylko obiektów powiązanych z określoną gałęzią lub zatwierdzenie:

git fetch origin refs/heads/branch:refs/remotes/origin/branch

Spowoduje to pobranie tylko zatwierdzeń zawartych w zdalnym oddziale branch (i tylko tych, za którymi tęsknisz) i zapisanie ichorigin/branch . Następnie możesz scalić lub pobrać.

Możesz także określić tylko zatwierdzenie SHA1:

git fetch origin 96de5297df870:refs/remotes/origin/foo-commit

Spowoduje to pobranie tylko zatwierdzenia określonego SHA-1 96de5297df870 (i jego brakujących przodków) i zapisanie go jako (nieistniejącej) gałęzi zdalnej origin/foo-commit.


3
Wygląda na to, że wprowadzasz zamieszanie w to, co oznacza klon. Gdy pobierasz zmiany ze zdalnego repozytorium, nie klonujesz go, po prostu zapisujesz zmiany w swojej historii. Następnie wybierz, które zatwierdzenie chcesz sprawdzić, lub scal je ze swoją historią
CharlesB

1
Nadal pobiera dużo danych (430 MB) dzięki git fetch. Wymagane zatwierdzenie to zaledwie kilka KB. Nie ma specjalnego polecenia, aby to zrobić naprawdę? A jeśli chcę usunąć repozytorium „git fetched”? gdzie jest przechowywany?
Varun Chitre

9
To jest raczej nieaktualne. Mamy zarówno możliwość wykonania płytkiego klonu , jak i pobrania pojedynczego zatwierdzenia . Płytkie klony mogą teraz pchać i pobierać normalnie, bez konieczności poznawania pełnej historii projektu, więc nie jest już prawdą stwierdzenie, że zatwierdzenie nie może istnieć samodzielnie bez jego przodków. To, co mówisz o pobieraniu po pierwszym klonie, jest bardzo prawdziwe, ale mamy jeszcze tańsze opcje.
Theodore Murdock,

6
Ostatnie polecenie (przy użyciu zatwierdzenia SHA1) nie działa dla mnie. Polecenie po cichu robi przez chwilę „coś”, a następnie kończy działanie bez wiadomości lub widocznego efektu ubocznego.
HRJ,

1
@HRJ Tak, ja też to spotkałem na Ubuntu 16.04 z Git 2.7.4-0ubuntu1.3. Jednak w przypadku korzystania 2.16.2-0ppa1~ubuntu16.04.1z git-core PPA działa to tak, jak powinno. Brzmi jak naprawiony błąd. Nie można znaleźć odniesienia do tego za pomocą szybkiego wyszukiwania. Jeśli ktoś może mi w tym wskazać, chciałbym przywrócić tę poprawkę.
gertvdijk

62

Wykonałem repozytorium git:

git pull --rebase <repo> <branch>

Pozwalając gitowi pobrać cały kod dla gałęzi, a potem poszedłem zresetować interesujący mnie zatwierdzenie.

git reset --hard <commit-hash>

Mam nadzieję że to pomoże.


1
Żadna z odpowiedzi nie zadziałała, ale ta uratowała mi życie! Wielkie dzięki!
michaeltintiuc

Reset --hard zadziałał dla mnie po klonowaniu! Dzięki.
Nick-ACNB,

3
-1: polecenia „destrukcyjne”, takie jak git reset --hard, gdy są udostępniane w uogólnionych rozwiązaniach, mogą prowadzić ludzi do pułapek, w których tracą dane (lub, w tym przypadku: w stanie, w którym odzyskanie danych nie jest łatwe).
yaauie

54

Możesz po prostu pobrać pojedyncze zatwierdzenie zdalnego repo za pomocą

git fetch <repo> <commit>

gdzie,

  • <repo>może być nazwą zdalnego repozytorium (np. origin) lub nawet zdalnym adresem URL repozytorium (np. https://git.foo.com/myrepo.git)
  • <commit> może być zatwierdzeniem SHA1

na przykład

git fetch https://git.foo.com/myrepo.git 0a071603d87e0b89738599c160583a19a6d95545

po pobraniu zatwierdzenia (i brakujących przodków) możesz po prostu to sprawdzić

git checkout FETCH_HEAD

Pamiętaj, że spowoduje to przejście w stan „odłączonej głowy”.


10
Gdy próbuję fetchuzyskać określoną wersję, tak jak ty, git kończy się niepowodzeniem z kodem błędu 1 i brakiem danych wyjściowych. Czy było to coś, co działało w poprzednich wersjach? (Jestem v2.0.2.)
Jack O'Connor

2
Edycja: Działa, jeśli mam już lokalnie zatwierdzone, tak jak gdybym już wykonał pełny fetch, ale w tym przypadku nie jestem pewien, do czego służy.
Jack O'Connor,

2
Rzeczywiście, wydaje mi się, że nie działa to już w przypadku git 2.0.2. :(
Flow

2
git checkout FETCH_HEADpomaga
lzl124631x

1
Ta metoda nie działa z płytkim pobieraniem (np. --depth=1)!
kingmakerking

16

Możesz po prostu pobrać zdalne repozytorium za pomocą:

git fetch <repo>

gdzie,

  • <repo>może być nazwą zdalnego repozytorium (np. origin) lub nawet zdalnym adresem URL repozytorium (np. https://git.foo.com/myrepo.git)

na przykład:

git fetch https://git.foo.com/myrepo.git 

po pobraniu repozytoriów możesz scalić wybrane zatwierdzenia (ponieważ pytanie dotyczy odzyskania jednego zatwierdzenia, zamiast scalenia możesz użyć wybrania wiśniowego, aby wybrać tylko jedno zatwierdzenie):

git merge <commit>
  • <commit> może być zatwierdzeniem SHA1

na przykład:

git cherry-pick 0a071603d87e0b89738599c160583a19a6d95545

lub

git merge 0a071603d87e0b89738599c160583a19a6d95545

jeśli jest to ostatnie zatwierdzenie, które chcesz scalić, możesz również użyć zmiennej FETCH_HEAD:

git cherry-pick (or merge) FETCH_HEAD

Wymaga to konfiguracji konta Git na komputerze. Nie działa na koncie testowym. Czy masz coś, co działa na koncie testowym?
jww

co masz na myśli ? nie możesz zrobić Git Fetch?
Sérgio

Ummm, więc polecenie będzie git config set uploadpack.allowReachableSHA1InWant ?
Alexander Mills

2

Działa to najlepiej:

git fetch origin specific_commit
git checkout -b temp FETCH_HEAD

nazwij „temp” cokolwiek chcesz… gałąź ta może być jednak osierocona


Wyraźnie NIE ze starszymi wersjami gita, takimi jak 1.8.x
sorin

1

Wreszcie znalazłem sposób na sklonowanie konkretnego zatwierdzenia za pomocą git cherry-pick . Zakładając, że nie masz lokalnego repozytorium i pobierasz określone zmiany ze zdalnego,

1) utwórz puste repozytorium w lokalnych i git init

2) „ url-of-repositorygit remote add origin

3) początek pobierania git [nie przeniesie twoich plików do lokalnego obszaru roboczego, chyba że się scalisz]

4) git cherry-pick " Enter-long-commit-hash-that-you-need

Gotowe. W ten sposób będziesz mieć tylko pliki z tego konkretnego zatwierdzenia w twoim lokalnym.

Enter-long-commit-hash:

Możesz to uzyskać za pomocą -> git log --pretty = oneline



0

Jeśli żądane zatwierdzenie znajduje się w żądaniach ściągania zdalnego repozytorium, możesz uzyskać je według jego identyfikatora:

# Add the remote repo path, let's call it 'upstream':
git remote add upstream https://github.com/repo/project.git

# checkout the pull ID, for example ID '60':
git fetch upstream pull/60/head && git checkout FETCH_HEAD
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.