Come clonare repository git con revisione / changeset specifici?


393

Come posso clonare il repository git con una revisione specifica, come faccio di solito in Mercurial:

hg clone -r 3 /path/to/repository

3
Non specifico per i set di modifiche o le revisioni, ma la clonazione delle ultime in un ramo specifico può essere altrettanto efficace, ad esempio git clone -b 10.1 https://github.com/MariaDB/server.git --depth=1 mariadb-server-src
MrMesees,


Vuoi che la storia sia superficiale, cioè contenga solo la revisione 3 nel tuo esempio o anche i suoi genitori?
sschuberth

Se il repository in questione viene clonato dall'interno di un altro repository e si desidera clonare quel repository interno in uno sha specifico, allora i sottomoduli git lo fanno esattamente in modo automagico.
J0hnG4lt

Risposte:


203

AGGIORNAMENTO 2 Da Git 2.5.0 la funzione descritta di seguito può essere abilitata sul lato server con una variabile di configurazione uploadpack.allowReachableSHA1InWant, qui la richiesta della funzione GitHub e il commit GitHub abilitano questa funzione . Si noti che alcuni server Git attivano questa opzione per impostazione predefinita, ad esempio Bitbucket Server l'ha abilitata dalla versione 5.5+ . Vedi questa risposta su Stackexchange per un esempio di come attivare l'opzione di configurazione.

AGGIORNAMENTO 1 Per le versioni Git 1.7 < v < 2.5utilizzare git clone e git reset, come descritto nella risposta di Vaibhav Bajpai

Se non vuoi recuperare l'intero repository, probabilmente non dovresti utilizzarlo clone. Puoi sempre usare il recupero per scegliere il ramo che vuoi recuperare. Non sono un esperto di hg, quindi non conosco i dettagli -rma in git puoi fare qualcosa del genere.

# 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

32
Non penso git fetch origin <sha1>funzioni; sembra che sia necessario passare un riferimento denominato come un tag o il nome del ramo. Vedi kerneltrap.org/mailarchive/git/2009/1/13/4707444
artur

48
@artur: Non pensi che funzioni o l'hai provato e non funziona?
CB Bailey,

37
Con git 1.4, ho scoperto che ero in grado di usare il git fetch origin <SHA1>per passare a qualsiasi revisione volessi dopo aver recuperato il master dal telecomando e aver fatto l' reset --hardistanza effettiva del ramo localmente. Non sono stato in grado di recuperare direttamente le singole revisioni. Con git 1.7, git fetch origin <SHA1>non ha funzionato, come riportato da @artur; è necessario utilizzare git checkout <SHA1>seguito da a reset --hard.
Joe McMahon,

6
Il recupero da SHA-1 funzionerà solo con i protocolli http e rsync. Vedi kerneltrap.org/mailarchive/git/2009/1/14/4716044/…
CharlesB

23
Questa risposta è obsoleta. Questo non funziona con git 1.7 né git 1.8, né con il protocollo https: // né ssh. ("Impossibile trovare il riferimento remoto df44398762393c67af487edeb0831ad9579df4aa" - non è un riferimento, è un commit.)
Paŭlo Ebermann

839
$ git clone $URL
$ cd $PROJECT_NAME
$ git reset --hard $SHA1

Per tornare nuovamente al commit più recente

$ git pull

13
Funziona solo se il commit si trova nel ramo master, in caso contrario rovinerà il riferimento locale. Perché git reset e non git checkout in primo luogo?
Joky,

72
Questa non è una buona opzione per repository di grandi dimensioni, in quanto estrae tutto.
Incognito,

1
Questa soluzione dovrebbe essere al top. A nessuno importa che "non sia ottimale", è ciò che l'OP ha richiesto. In particolare: "come posso clonare repository git con una revisione specifica"?
Florian Segginger,

20
@FlorianSegginger Se sto cercando di clonare una revisione specifica è probabilmente che non voglio clonare tutto, ma solo quella revisione. Per me questa era la domanda. Questa soluzione risponde a una domanda diversa: "Come posso visualizzare una revisione specifica nel mio repository?". Recuperare l'intero repository è esattamente ciò che molte persone qui vogliono evitare.
Renato

1
Non affronta la vera domanda IMHO, dato che essere in grado di specificare una revisione durante il clone mi consente anche di utilizzare, il --depthche è molto importante per repository di grandi dimensioni. Questa soluzione richiede il pull di tutti gli oggetti e il ripristino di una versione precedente. Ciò richiede molto tempo e spreca la larghezza di banda della rete.
void.pointer

54

Clonare un repository git, giustamente, clona l'intero repository: non esiste un modo per selezionare una sola revisione da clonare. Tuttavia, una volta eseguito git clone, puoi fare il checkout di una revisione specifica facendo checkout <rev>.


4
Non voglio clonare solo una revisione. Voglio solo specificare il limite di clonazione. In altre parole, voglio clonare tutto fino alla revisione specificata.
Giovanni,

6
Non puoi farlo. git cloneprende l'intero repository. Una volta che lo hai, puoi quindi verificare una revisione specifica.

4
Una cosa da notare; Git è generalmente abbastanza efficiente nel memorizzare la cronologia, quindi non è come se risparmiassi enormi quantità di spazio clonando solo metà delle revisioni.
Ambra

Non si tratta di "risparmiare spazio" - si tratta solo di passare a una revisione specifica - come se una nuova modifica introducesse un bug, e quindi non voglio quella più recente - stai dicendo che Git non può fare Questo? Non può essere giusto: perché avere il controllo del codice sorgente se non è possibile tornare a una versione precedente?
BrainSlugs83,

1
"non esiste un modo per selezionare una sola revisione da clonare" - sì, c'è:git clone --single-branch ...
morxa

33

Per clonare solo un singolo commit specifico su un determinato ramo o tag utilizzare:

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

Sfortunatamente, NAMEpuò essere solo il nome del ramo o il nome del tag (non commettere SHA).

Ometti la --depthbandiera per scaricare l'intera cronologia e quindi controlla quel ramo o tag:

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

Funziona con la versione recente di git (l'ho fatto con la versione 2.18.0).


ma non nella versione precedente 2.17.1
RzR

4
Ciò richiede più voti. Questo è molto meglio di altre risposte obsolete.
Étienne

32

Se vuoi dire che vuoi recuperare tutto dall'inizio fino a un determinato punto, la risposta di Charles Bailey è perfetta. Se vuoi fare il contrario e recuperare un sottoinsieme della cronologia che risale alla data corrente, puoi usare git clone --depth [N] dove N è il numero di giri della cronologia che desideri. Però:

--profondità

Crea un clone superficiale con una cronologia troncata al numero specificato di revisioni. Un repository superficiale presenta una serie di limitazioni (non è possibile clonare o recuperare da esso, né spingere da né all'interno di esso), ma è adeguato se si è interessati solo alla storia recente di un grande progetto con una lunga storia e si desidera invia correzioni come patch.


4
La versione più recente di git ha migliorato i cloni superficiali e puoi estrarre e spingere da esso.
orion78,

26

Riassumendo (git v. 1.7.2.1):

  1. fare un regolare git clonedove si desidera il repository (ottiene tutto aggiornato - lo so, non quello che si desidera, ci stiamo arrivando)
  2. git checkout <sha1 rev> del rev che vuoi
  3. git reset --hard
  4. git checkout -b master

6
cosa fanno i passaggi 3 e 4?
BrainSlugs83,

Il passaggio 4 non ha funzionato per me, ma fino al passaggio 3 ha funzionato - Grazie
Gene Bo,

@ BrainSlugs83: il passaggio 4 crea un ramo locale chiamato mastere passa ad esso.
LarsH,

3
@phill: Perché il git reset --hard? I documenti per questo dicono "Reimposta l'indice e l'albero di lavoro. Qualsiasi modifica ai file tracciati nell'albero di lavoro da <commit> [che per impostazione predefinita è HEAD, che ora è <sha1 rev>] viene scartata." Ma a questo punto non abbiamo apportato modifiche dalla clonazione, quindi qual è lo scopo? Tronca l'attuale ramo in <sha1 rev>?
LarsH,

19

TL; DR: basta creare un tag nel repository di origine rispetto al commit a cui si desidera clonare e utilizzare il tag nel comando fetch. È possibile eliminare il tag dal repository originale in un secondo momento per ripulire.

Bene, è il 2014 e sembra che la risposta accettata da Charles Bailey dal 2010 sia ormai superata e veramente obsoleta e la maggior parte (tutte?) Delle altre risposte riguardano la clonazione, che molte persone sperano di evitare.

La seguente soluzione realizza ciò che l'OP e molti altri stanno cercando, che è un modo per creare una copia di un repository, inclusa la cronologia, ma solo fino a un certo commit.

Ecco i comandi che ho usato con git versione 2.1.2 per clonare un repository locale (cioè un repository in un'altra directory) fino a un certo punto:

# 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

Spero che questa soluzione continui a funzionare per qualche altro anno! :-)


2
Questa è una buona idea di te che sei il proprietario del repository, non sono sicuro che funzioni con repository pubblici che non
gestisci

18

Puoi usare semplicemente git checkout <commit hash>

in questa sequenza

bash git clone [URLTORepository] git checkout [commithash]

commit hash si presenta così "45ef55ac20ce2389c9180658fdba35f4a663d204"


come il precedente - perché effettuare il checkout dopo aver clonato. Una volta clonato, hai l'intera cronologia nel repository locale. Perché questa risposta ha troppi voti?
Dmitry Perfilyev,

2

L'uso di 2 delle risposte sopra ( Come clonare il repository git con revisione / changeset specifici? E Come clonare il repository git con revisioni / changeset specifici? ) Mi ha aiutato a trovare un definitivo. Se vuoi clonare fino a un certo punto, quel punto deve essere un tag / ramo non semplicemente un SHA o FETCH_HEAD viene confuso. Seguendo il set di recupero git, se si utilizza un nome di ramo o tag, si ottiene una risposta, se si utilizza semplicemente un SHA-1 non si ottiene risposta.
Ecco cosa ho fatto: - creare un clone di lavoro completo del repository completo, dall'origine effettiva

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

Quindi crea un ramo locale, nel punto che è interessante

git checkout 2050c8829c67f04b0db81e6247bb589c950afb14
git checkout -b origin_point

Quindi crea il mio nuovo repository vuoto, con la mia copia locale come origine

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

A quel punto ho avuto questa risposta. Lo noto perché se si utilizza un SHA-1 al posto del ramo sopra, non accade nulla, quindi la risposta, significa che ha funzionato

/ var / www / html / ui-hacking $ git recupera local_copy origin_point
telecomando: conteggio degli oggetti: 45493, fatto.
remoto: compressione degli oggetti: 100% (15928/15928), fatto.
remoto: totale 45493 (delta 27508), riutilizzato 45387 (delta 27463)
Ricezione di oggetti: 100% (45493/45493), 53,64 MiB | 50,59 MiB / s, fatto.
Delta di risoluzione: 100% (27508/27508), fatto.
Da / var / www / html / ui
 * branch origin_point -> FETCH_HEAD
 * [nuovo ramo] punto_origine -> punto origine / origine

Ora nel mio caso, ho dovuto quindi rimetterlo su gitlab, come nuovo repository, così ho fatto

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

Il che significava che avrei potuto ricostruire il mio repository dal punto_origine utilizzando git --git-dir=../ui/.git format-patch -k -1 --stdout <sha1> | git am -3 -ka cherry pick in remoto, quindi utilizzare git push originper caricare l'intero lotto nella sua nuova home.

Spero che aiuti qualcuno


Puoi spiegare cosa intendi con "FETCH_HEAD viene confuso"? E in cosa git fetch local_copy origin_pointdifferisce da JamesGs git fetch origin refs/tags/tmptag?
not2qubit

La git fetch local_copy origin_pointsi lascia in uno stato con un vuoto reduced-repodi directory, che contengano una .git. C'è qualcos'altro che manca in queste istruzioni ...
not2qubit

2

La mia versione era una combinazione di risposte accettate e più votate. Ma è un po 'diverso, perché tutti usano SHA1 ma nessuno ti dice come ottenerlo

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

ora puoi vedere tutte le filiali e gli commit

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

Finalmente conosci SHA1 del commit desiderato

git reset --hard <sha1>

1

Uso questo frammento con GNU make per chiudere tag di revisione, branch o hash

è stato testato su git versione 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 $@





0

git clone https://github.com/ORGANIZATION/repository.git (clona il repository)

cd repository (navigate to the repository)

git fetch origin 2600f4f928773d79164964137d514b85400b09b2

git checkout FETCH_HEAD


2
perché recuperare dopo aver clonato. Una volta clonato, hai l'intera cronologia nel repository locale. Perché questa risposta ha due voti?
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> 

non è possibile ottenere una revisione senza cronologia se non impostato uploadpack.allowReachableSHA1InWant=truesul lato server, mentre è possibile creare un tag per esso e clonare invece il tag speciale.


-3

È semplice. Devi solo impostare l'upstream per il ramo corrente

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

È tutto


-4
git clone -o <sha1-of-the-commit> <repository-url> <local-dir-name>

gitusa la parola original posto di popolarmente conosciutarevision

Di seguito è riportato un frammento del manuale $ git help clone

--origin <name>, -o <name>
    Instead of using the remote name origin to keep track of the upstream repository, use <name>.

4
Non ho idea del perché vieni sottoposto a downvoting qui; questo era esattamente quello che speravo di vedere per il mio caso d'uso: ottenere una versione particolare del kernel Linux da una versione non aveva il buon senso di etichettarlo come una versione (sembra essere un problema con le persone RPi), senza scaricando l'intera storia multi-gigabyte di Linux. Per inciso, ha funzionato a meraviglia.
Fordi,

1
--depth=1non è menzionato nella risposta, quindi perché dovresti dire che questa risposta ha funzionato se hai aggiunto più cose che non sono menzionate qui? Sono felice che abbia funzionato per te, ma questa risposta è fuorviante e non risponde alla domanda nemmeno in parte. Da qui i voti negativi.
Emil Styrke,

5
@Fordi: No. Usando questa risposta alla lettera si ottiene esattamente lo stesso albero che si otterrebbe da una vaniglia git clone <url> <local_dir_name>, provalo tu stesso. L'unica differenza è che il telecomando (mostrato usando git remote) verrà chiamato una sequenza criptica di sha1 invece del nome "origine" che è consuetudine. In altre parole, il <sha1-of-the-commit>menzionato in questa risposta non ha alcuna influenza su quali revisioni vengono recuperate dal server o su quale ramo verrà verificato.
Emil Styrke,

6
@Fordi: l'ho appena fatto git clone -o 896066ee1cf4d653057dac4e952f49c96ad16fa7 https://github.com/torvalds/linux.git linux --depth=1. Questo mi dà una revisione 8a28d674e non 896066ee come te e questa risposta afferma.
Emil Styrke,

4
sottolineando che "origine" non ha nulla a che fare con "revisione" e questa risposta è completamente sbagliata.
Eevee,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.