Jak sklonować repozytorium git za pomocą określonej wersji / zestawu zmian?

393

Jak mogę sklonować repozytorium git z określoną wersją, jak zwykle w Mercurial:

hg clone -r 3 /path/to/repository
Jan
źródło
3
Niespecyficzne dla zestawów zmian lub poprawek, ale klonowanie najpóźniej w konkretnej gałęzi może być równie skuteczne, tj. git clone -b 10.1 https://github.com/MariaDB/server.git --depth=1 mariadb-server-src
MrMesees,
Możliwy duplikat Pobierz konkretny tag za pomocą Git
SlightlyCuban
Czy chcesz, aby historia była płytka, tj. Zawiera tylko wersję 3 w twoim przykładzie, czy też jej rodziców?
sschuberth
Jeśli dane repozytorium jest klonowane z innego repozytorium i chcesz sklonować to wewnętrzne repozytorium w określonym sha, wówczas podmoduły git robią to dokładnie w sposób automatyczny.
J0hnG4lt

Odpowiedzi:

202

AKTUALIZACJA 2 Od wersji Git 2.5.0 opisaną poniżej funkcję można włączyć po stronie serwera za pomocą zmiennej konfiguracyjnej uploadpack.allowReachableSHA1InWant, tutaj żądanie funkcji GitHub i zatwierdzenie GitHub włączające tę funkcję . Pamiętaj, że niektóre serwery Git domyślnie aktywują tę opcję, np. Serwer Bitbucket włączył ją od wersji 5.5+ . Zobacz tę odpowiedź na Stackexchange aby dowiedzieć się, jak aktywować opcję konfiguracji.

AKTUALIZACJA 1 W przypadku wersji Git 1.7 < v < 2.5użyj klonowania git i resetowania git, jak opisano w Vaibhav Bajpai

Jeśli nie chcesz pobrać pełnego repozytorium, prawdopodobnie nie powinieneś go używać clone. Zawsze możesz po prostu użyć opcji Pobierz, aby wybrać gałąź, którą chcesz pobrać. Nie jestem ekspertem od hg, więc nie znam szczegółów, -rale w git możesz zrobić coś takiego.

# make a new blank repository in the current directory
git init

# add a remote
git remote add origin url://to/source/repository

# fetch a commit (or branch or tag) of interest
# Note: the full history up to this commit will be retrieved unless 
#       you limit it with '--depth=...' or '--shallow-since=...'
git fetch origin <sha1-of-commit-of-interest>

# reset this repository's master branch to the commit of interest
git reset --hard FETCH_HEAD
CB Bailey
źródło
32
Nie sądzę, że git fetch origin <sha1>działa; wygląda na to, że musisz przekazać nazwane odwołanie, takie jak tag lub nazwa oddziału. Zobacz kerneltrap.org/mailarchive/git/2009/1/13/4707444
artur
48
@artur: Nie sądzisz, że to działa, czy próbujesz i nie działa?
CB Bailey,
37
W przypadku gita 1.4 okazało się, że mogłem użyć tej opcji, git fetch origin <SHA1>aby przełączyć się na dowolną wersję, którą chciałem po tym, jak ściągnąłem mistrza ze zdalnego i wykonałem reset --hardlokalną instancję w celu rzeczywistego utworzenia gałęzi. Nie mogłem pobrać poszczególnych wersji bezpośrednio. Z git 1.7 git fetch origin <SHA1>nie działało, jak donosi @artur; musisz użyć, git checkout <SHA1>a następnie reset --hard.
Joe McMahon,
6
Pobieranie przez SHA-1 działa tylko z protokołami http i rsync. Zobacz kerneltrap.org/mailarchive/git/2009/1/14/4716044/…
CharlesB
23
Ta odpowiedź jest nieaktualna. Nie działa to z git 1.7 ani git 1.8, ani z protokołem https: // ani ssh. („Nie można znaleźć zdalnego ref df44398762393c67af487edeb0831ad9579df4aa” - to nie jest ref, to jest zatwierdzenie.)
Paŭlo Ebermann
838
$ git clone $URL
$ cd $PROJECT_NAME
$ git reset --hard $SHA1

Aby ponownie wrócić do ostatniego zatwierdzenia

$ git pull
Vaibhav Bajpai
źródło
13
Działa to tylko wtedy, gdy zatwierdzenie znajduje się w gałęzi master, jeśli nie, zepsuje lokalne odwołanie. Dlaczego git zresetował, a nie kasę?
Joky
72
Nie jest to dobra opcja dla dużych repozytoriów, ponieważ wyciąga wszystko.
Incognito,
1
To rozwiązanie powinno być na górze. Nikt nie dba o to, że nie jest „optymalny”, o to prosił PO. W szczególności: „jak sklonować repozytorium git z określoną wersją”?
Florian Segginger,
20
@FlorianSegginger Jeśli chcę sklonować określoną wersję, prawdopodobnie nie chcę klonować wszystkiego, ale tylko tę wersję. Dla mnie to było pytanie. To rozwiązanie odpowiada na inne pytanie: „Jak wyświetlić konkretną wersję mojego repozytorium?”. Pobieranie całego repo jest dokładnie tym, czego wielu ludzi chce uniknąć.
Renato,
1
Nie odnosi się do rzeczywistego pytania IMHO, ponieważ możliwość określenia wersji podczas klonowania pozwala mi również na używanie, --depthco jest bardzo ważne w przypadku dużych repozytoriów. To rozwiązanie wymaga wyciągnięcia wszystkich obiektów, a następnie zresetowania do wcześniejszej wersji. Jest to bardzo czasochłonne i marnuje przepustowość sieci.
void.pointer
54

Klonowanie repozytorium git trafnie klonuje całe repozytorium: nie ma sposobu, aby wybrać tylko jedną wersję do sklonowania. Jednak po wykonaniu możesz sprawdzić git clonekonkretną wersję, wykonując tę ​​czynność checkout <rev>.


źródło
4
Nie chcę klonować tylko jednej wersji. Chcę tylko określić limit klonowania. Innymi słowy, chcę sklonować wszystko do określonej wersji.
Jan
6
Nie możesz tego zrobić. git clonepobiera całe repozytorium. Gdy już go masz, możesz następnie pobrać konkretną wersję.
4
Należy zwrócić uwagę na jedną rzecz; Git jest ogólnie dość skuteczny w przechowywaniu historii, więc nie jest tak, jakbyś zaoszczędził ogromne ilości miejsca, klonując tylko połowę wersji.
Amber
Tu nie chodzi o „oszczędzanie miejsca” - chodzi tylko o to, aby dostać się do konkretnej wersji - tak jakby nowa zmiana wprowadziła błąd, więc nie chcę tej najnowszej zmiany - mówisz, że Git nie może tego zrobić to? To nie może być prawda - po co w ogóle mieć kontrolę nad źródłem, jeśli nie możesz przywrócić starszej wersji?
BrainSlugs83
1
„nie ma sposobu, aby wybrać tylko jedną wersję do sklonowania” - tak, jest:git clone --single-branch ...
morxa
33

Aby sklonować tylko jeden konkretny zatwierdzenie dla określonej gałęzi lub tagu użyj:

git clone --depth=1 --branch NAME https://github.com/your/repo.git

Niestety NAMEmoże to być tylko nazwa oddziału lub nazwa znacznika (nie zatwierdzaj SHA).

Pomiń --depthflagę, aby pobrać całą historię, a następnie sprawdź tę gałąź lub tag:

git clone --branch NAME https://github.com/your/repo.git

Działa to z najnowszą wersją git (zrobiłem to z wersją 2.18.0).

Peter Kovac
źródło
ale nie w starszej wersji 2.17.1
RzR
4
To wymaga więcej pozytywnych opinii. Jest to znacznie lepsze niż w przypadku innych nieaktualnych odpowiedzi.
Étienne
32

Jeśli masz na myśli, że chcesz pobrać wszystko od początku do określonego punktu, odpowiedź Charlesa Baileya jest idealna. Jeśli chcesz zrobić odwrotną stronę i odzyskać podzbiór historii cofający się od bieżącej daty, możesz użyć git clone --depth [N] gdzie N to liczba obrotów historii, którą chcesz. Jednak:

--głębokość

Utwórz płytki klon z historią obciętą do określonej liczby wersji. Płytkie repozytorium ma wiele ograniczeń (nie można go klonować ani pobierać z niego, ani wypychać z niego ani do niego), ale jest wystarczające, jeśli interesuje Cię tylko najnowsza historia dużego projektu z długą historią i chciałbyś wysyłaj poprawki jako łatki.

Walter Mundt
źródło
4
Nowsza wersja git ma ulepszone płytkie klony i możesz z niego wyciągać i pchać.
orion78 z
26

Podsumowując (git v. 1.7.2.1):

  1. rób regularne git clonetam, gdzie chcesz repo (dostaje wszystko na bieżąco - wiem, nie to, co jest potrzebne, my się tam dostaniemy)
  2. git checkout <sha1 rev> pożądanej prędkości
  3. git reset --hard
  4. git checkout -b master
Phill
źródło
6
co robią kroki 3 i 4?
BrainSlugs83
Krok 4 nie działał dla mnie, ale do kroku 3 udało się - Dzięki
Gene Bo
@ BrainSlugs83: Krok 4 tworzy lokalną gałąź o nazwie masteri przełącza się na nią.
LarsH
3
@phill: Dlaczego git reset --hard? Dokumenty tego mówią: „Resetuje indeks i działające drzewo. Wszelkie zmiany w śledzonych plikach w działającym drzewie od czasu <commit> [domyślna wartość HEAD, która jest teraz <sha1 rev>] są odrzucane”. Ale w tym momencie nie dokonaliśmy żadnych zmian od klonowania, więc jaki jest cel? Czy to obcina obecną gałąź <sha1 rev>?
LarsH
19

TL; DR - po prostu utwórz znacznik w repozytorium źródłowym dla zatwierdzenia, do którego chcesz sklonować, i użyj znacznika w poleceniu fetch. Możesz usunąć tag z oryginalnego repozytorium później, aby go wyczyścić.

No cóż, jego 2014 rok i wygląda na to, że zaakceptowana przez Charlesa Baileya odpowiedź z 2010 roku jest już naprawdę i naprawdę nieaktualna, a większość (wszystkich?) Innych odpowiedzi dotyczy klonowania, którego wiele osób chce uniknąć.

Poniższe rozwiązanie osiąga to, czego szuka OP i wielu innych, co jest sposobem na utworzenie kopii repozytorium, w tym historii, ale tylko do pewnego zatwierdzenia.

Oto polecenia, których użyłem z git w wersji 2.1.2, aby sklonować lokalne repozytorium (tj. Repozytorium w innym katalogu) do pewnego momentu:

# in the source repository, create a tag against the commit you want to check out
git tag -m "Temporary tag" tmptag <sha1>

# create a new directory and change into that directory
cd somewhere_else;mkdir newdir;cd newdir

# ...and create a new repository
git init

# add the source repository as a remote (this can be a URL or a directory)
git remote add origin /path/to/original/repo

# fetch the tag, which will include the entire repo and history up to that point
git fetch origin refs/tags/tmptag

# reset the head of the repository
git reset --hard FETCH_HEAD

# you can now change back to the original repository and remove the temporary tag
cd original_repo
git tag -d tmptag

Mam nadzieję, że to rozwiązanie będzie działać jeszcze przez kilka lat! :-)

JamesG
źródło
2
To dobry pomysł, że jesteś właścicielem repozytorium, nie jestem pewien, czy działa on z repozytoriami publicznymi, których nie zarządzasz
Suhaib
18

Możesz użyć po prostu git checkout <commit hash>

w tej sekwencji

bash git clone [URLTORepository] git checkout [commithash]

zatwierdzenie skrótu wygląda tak: „45ef55ac20ce2389c9180658fdba35f4a663d204”

Człowiek ćma
źródło
jak poprzedni - po co kasować po sklonowaniu. Po sklonowaniu masz całą historię w lokalnym repozytorium. Dlaczego ta odpowiedź ma zbyt wiele głosów pozytywnych?
Dmitrij Perfilyjew
2

Korzystanie z 2 powyższych odpowiedzi ( Jak sklonować repozytorium git z konkretną wersją / zmianą? I Jak sklonować repozytorium git z określoną zmianą / zmianą? ) Pomogło mi wymyślić definicję. Jeśli chcesz sklonować do pewnego momentu, to musi to być znacznik / gałąź, a nie tylko SHA, w przeciwnym razie FETCH_HEAD się myli. Zgodnie z zestawem pobierania git, jeśli użyjesz nazwy gałęzi lub tagu, otrzymasz odpowiedź, jeśli po prostu użyjesz SHA-1, nie otrzymasz odpowiedzi.
Oto co zrobiłem: - stwórz w pełni działający klon pełnego repozytorium, z faktycznego pochodzenia

cd <path to create repo>
git clone git@<our gitlab server>:ui-developers/ui.git 

Następnie utwórz lokalny oddział w interesującym punkcie

git checkout 2050c8829c67f04b0db81e6247bb589c950afb14
git checkout -b origin_point

Następnie utwórz moje nowe puste repozytorium, z oryginalną kopią lokalną

cd <path to create repo>
mkdir reduced-repo
cd reduced-repo
git init
git remote add local_copy <path to create repo>/ui
git fetch local_copy origin_point

W tym momencie otrzymałem tę odpowiedź. Zwracam na to uwagę, ponieważ jeśli użyjesz SHA-1 zamiast gałęzi powyżej, nic się nie dzieje, więc odpowiedź oznacza, że ​​zadziałało

/ var / www / html / ui-hacking $ git fetch plik_lokalny punkt_początkowy
pilot: Zliczanie obiektów: 45493, gotowe.
zdalne: Kompresowanie obiektów: 100% (15928/15928), gotowe.
zdalne: Razem 45493 (delta 27508), ponownie wykorzystane 45387 (delta 27463)
Otrzymywanie przedmiotów: 100% (45493/45493), 53,64 MiB | 50,59 MiB / s, gotowe.
Rozwiązywanie delt: 100% (27508/27508), gotowe.
Z / var / www / html / ui
 * gałąź origin_point -> FETCH_HEAD
 * [nowa gałąź] origin_point -> origin / origin_point

Teraz w moim przypadku musiałem odłożyć to z powrotem na gitlab, jako świeże repo, więc zrobiłem to

git remote add origin git@<our gitlab server>:ui-developers/new-ui.git

Co oznaczało, że mogłem odbudować moje repozytorium z punktu początkowego za pomocą git --git-dir=../ui/.git format-patch -k -1 --stdout <sha1> | git am -3 -kzdalnego wybierania, a następnie użyć git push origindo przesłania całej partii z powrotem do jej nowego domu.

Mam nadzieję, że komuś pomoże

Sibaz
źródło
Czy możesz wyjaśnić, co masz na myśli mówiąc „FETCH_HEAD się myli”? A czym git fetch local_copy origin_pointróżni się twój od JamesGs git fetch origin refs/tags/tmptag?
not2qubit
git fetch local_copy origin_pointZostawiają cię w stanie pustym reduced-repokatalogu, zawierająca tylko .git. Tych instrukcji brakuje jeszcze coś ...
not2qubit
2

Moja wersja była kombinacją zaakceptowanych i najbardziej pozytywnych odpowiedzi. Ale jest trochę inaczej, ponieważ wszyscy używają SHA1, ale nikt nie mówi ci, jak go zdobyć

$ git init
$ git remote add <remote_url>
$ git fetch --all

teraz możesz zobaczyć wszystkie oddziały i zobowiązania

$ git branch -a
$ git log remotes/origin/master <-- or any other branch

Wreszcie znasz SHA1 pożądanego zatwierdzenia

git reset --hard <sha1>
Vladkras
źródło
1

Używam tego fragmentu kodu z GNU make do zamykania dowolnego tagu zmiany, gałęzi lub skrótu

został przetestowany na git w wersji 2.17.1

${dir}:
    mkdir -p ${@D}
    git clone --recursive --depth 1 --branch ${revison} ${url} ${@} \
 || git clone --recursive --branch ${revison} ${url} ${@} \
 || git clone ${url} ${@}
    cd ${@} && git reset --hard ${revison}
    ls $@




RzR
źródło
0

git clone https://github.com/ORGANIZATION/repository.git (klonowanie repozytorium)

cd repository (navigate to the repository)

git fetch origin 2600f4f928773d79164964137d514b85400b09b2

git checkout FETCH_HEAD

JeffDropsIT
źródło
2
po co ściągać po sklonowaniu. Po sklonowaniu masz całą historię w lokalnym repozytorium. Dlaczego ta odpowiedź ma dwa pozytywne głosy?
madhairsilence
0
# clone special tag/branch without history
git clone  --branch=<tag/branch> --depth=1 <repository>


# clone special revision with minimal histories
git clone --branch <branch> <repository> --shallow-since=yyyy-MM-ddTHH:mm:ss  # get the commit time
cd <dir>
git reset --hard <revision> 

nie można uzyskać wersji bez historii, jeśli nie jest ustawiona uploadpack.allowReachableSHA1InWant=truepo stronie serwera, można natomiast utworzyć dla niej znacznik i sklonować znacznik specjalny.

wongoo
źródło
-3

To proste. Musisz tylko ustawić upstream dla bieżącego oddziału

$ git clone repo
$ git checkout -b newbranch
$ git branch --set-upstream-to=origin/branch newbranch
$ git pull

To wszystko

NEOJPK
źródło
-4
git clone -o <sha1-of-the-commit> <repository-url> <local-dir-name>

gitużywa tego słowa originzamiast powszechnie znanegorevision

Poniżej znajduje się fragment instrukcji $ git help clone

--origin <name>, -o <name>
    Instead of using the remote name origin to keep track of the upstream repository, use <name>.
hell_ical_vortex
źródło
4
Nie mam pojęcia, dlaczego jesteś tak uprzywilejowany; właśnie tego chciałem zobaczyć w moim przypadku użycia: Pobieranie konkretnej wersji jądra Linux z wersji, której nie mieli rozsądku oznaczyć jako wydania (wydaje się, że jest to problem dla ludzi RPi), bez pobierając całą historię Linuksa z wieloma gigabajtami. Nawiasem mówiąc, zadziałało.
Fordi
1
--depth=1nie jest wymieniony w odpowiedzi, więc dlaczego miałbyś powiedzieć, że ta odpowiedź zadziałała, jeśli dodałeś więcej rzeczy, które nie zostały tutaj wymienione? Cieszę się, że ci się udało, ale ta odpowiedź jest myląca i nawet częściowo nie odpowiada na pytanie. Stąd opinie negatywne.
Emil Styrke,
5
@Fordi: Nie. Używając tej odpowiedzi dosłownie otrzymujesz dokładnie to samo drzewo, które otrzymujesz od wanilii git clone <url> <local_dir_name>, po prostu spróbuj sam. Jedyną różnicą jest to, że zdalny (pokazany za pomocą git remote) będzie nazywany jakąś tajemniczą sekwencją sha1 zamiast zwyczajowej nazwy „origin”. Innymi słowy, <sha1-of-the-commit>wspomniana w tej odpowiedzi nie ma żadnego wpływu na to, które wersje są pobierane z serwera lub który oddział zostanie sprawdzony.
Emil Styrke
6
@Fordi: Właśnie to zrobiłem git clone -o 896066ee1cf4d653057dac4e952f49c96ad16fa7 https://github.com/torvalds/linux.git linux --depth=1. To daje mi rewizję, 8a28d674a nie, 896066ee jak twierdzisz i ta odpowiedź.
Emil Styrke
4
podkreślając, że „pochodzenie” nie ma nic wspólnego z „rewizją”, a ta odpowiedź jest całkowicie błędna.
Eevee