Comment cloner le dépôt git avec une révision / un ensemble de modifications spécifique?

393

Comment puis-je cloner le dépôt git avec une révision spécifique, quelque chose comme je le fais habituellement dans Mercurial:

hg clone -r 3 /path/to/repository
John
la source
3
Non spécifique aux ensembles de modifications ou aux révisions, mais le clonage le plus récent dans une branche spécifique peut être aussi efficace, c'estgit clone -b 10.1 https://github.com/MariaDB/server.git --depth=1 mariadb-server-src
MrMesees
Copie possible de Télécharger une balise spécifique avec Git
SlightlyCuban
Voulez-vous que l'histoire soit superficielle, c'est-à-dire ne contienne que la révision 3 dans votre exemple, ou aussi ses parents?
sschuberth
Si le référentiel en question est cloné depuis l'intérieur d'un autre référentiel et que vous souhaitez cloner ce dépôt interne à un sha spécifique, les sous-modules git font exactement cela de manière automagique.
J0hnG4lt

Réponses:

203

MISE À JOUR 2 Depuis Git 2.5.0, la fonctionnalité décrite ci-dessous peut être activée côté serveur avec une variable de configuration uploadpack.allowReachableSHA1InWant, ici la demande de fonctionnalité GitHub et le commit GitHub activant cette fonctionnalité . Notez que certains serveurs Git activent cette option par défaut, par exemple Bitbucket Server l'a activée depuis la version 5.5+ . Voir cette réponse sur Stackexchange pour un exemple de comment activer l'option de configuration.

UPDATE 1 Pour les versions de Git, 1.7 < v < 2.5utilisez git clone et git reset, comme décrit dans la réponse de Vaibhav Bajpai

Si vous ne souhaitez pas récupérer le référentiel complet, vous ne devriez probablement pas utiliser clone. Vous pouvez toujours utiliser fetch pour choisir la branche que vous souhaitez récupérer. Je ne suis pas un expert en hg donc je ne connais pas les détails -rmais en git vous pouvez faire quelque chose comme ça.

# 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
la source
32
Je ne pense pas que cela git fetch origin <sha1>fonctionne; il semble que vous ayez besoin de passer une référence nommée telle qu'une balise ou un nom de branche. Voir kerneltrap.org/mailarchive/git/2009/1/13/4707444
artur
48
@artur: Vous ne pensez pas que cela fonctionne, ou vous l'avez essayé et cela ne fonctionne pas?
CB Bailey
37
Avec git 1.4, j'ai trouvé que j'étais capable d'utiliser le git fetch origin <SHA1>pour passer à n'importe quelle révision que je voulais après avoir récupéré le maître de la télécommande et fait l' reset --hardinstanciation réelle de la branche localement. Je n'ai pas pu récupérer directement les révisions individuelles. Avec git 1.7, git fetch origin <SHA1>n'a pas fonctionné, comme indiqué par @artur; vous devez utiliser git checkout <SHA1>suivi d'un reset --hard.
Joe McMahon
6
La récupération par SHA-1 ne fonctionnera qu'avec les protocoles http et rsync. Voir kerneltrap.org/mailarchive/git/2009/1/14/4716044/…
CharlesB
23
Cette réponse est dépassée. Cela ne fonctionne pas avec git 1.7 ni git 1.8, ni avec https: // ni le protocole ssh. ("Impossible de trouver la référence distante df44398762393c67af487edeb0831ad9579df4aa" - ce n'est pas une référence, c'est un commit.)
Paŭlo Ebermann
839
$ git clone $URL
$ cd $PROJECT_NAME
$ git reset --hard $SHA1

Pour revenir à nouveau au commit le plus récent

$ git pull
Vaibhav Bajpai
la source
13
Cela ne fonctionne que si le commit est dans la branche master, sinon il va gâcher la référence locale. Pourquoi git reset et pas git checkout en premier lieu?
Joky
72
Ce n'est pas une bonne option pour les grands dépôts, car cela tire tout.
Incognito
1
Cette solution devrait être au top. Personne ne se soucie du fait que ce n'est "pas optimal", c'est ce que le PO a demandé. Plus précisément: "comment cloner un dépôt git avec une révision spécifique"?
Florian Segginger
20
@FlorianSegginger Si je cherche à cloner une révision spécifique, c'est probablement que je ne veux pas tout cloner, mais juste cette révision. Pour moi, c'était la question posée. Cette solution répond à une question différente: "Comment afficher une révision spécifique dans mon référentiel?". Récupérer l'intégralité du dépôt est exactement ce que beaucoup de gens ici veulent éviter.
Renato
1
Ne répond pas à la question réelle à mon humble avis, car être en mesure de spécifier une révision pendant le clonage me permet également d'utiliser --depthce qui est très important pour les grands dépôts. Cette solution nécessite de retirer tous les objets, puis de réinitialiser une révision antérieure. Cela prend beaucoup de temps et gaspille de la bande passante réseau.
void.pointer
54

Le clonage d'un référentiel git, à juste titre, clone l'intégralité du référentiel: il n'y a pas moyen de sélectionner une seule révision à cloner. Cependant, une fois que vous avez effectué git clone, vous pouvez extraire une révision spécifique en faisant checkout <rev>.


la source
4
Je ne veux pas cloner une seule révision. Je veux juste spécifier la limite de clonage. En d'autres termes, je veux tout cloner jusqu'à la révision spécifiée.
John
6
Tu ne peux pas faire ça. git clonesaisit l'ensemble du référentiel. Une fois que vous l'avez, vous pouvez alors extraire une révision spécifique.
4
Une chose à noter; Git est généralement assez efficace pour stocker l'historique, donc ce n'est pas comme si vous économisiez d'énormes quantités d'espace en ne clonant que la moitié des révisions.
Amber
Il ne s'agit pas de "gagner de l'espace" - il s'agit uniquement de se mettre à jour pour une révision spécifique - comme si une nouvelle modification introduisait un bogue, et donc je ne veux pas de cette dernière modification - vous dites que Git ne peut pas faire cette? Cela ne peut pas être vrai - pourquoi avoir le contrôle des sources si vous ne pouvez pas revenir à une ancienne version?
BrainSlugs83
1
"il n'y a pas moyen de sélectionner une seule révision à cloner" - oui, il y a:git clone --single-branch ...
morxa
33

Pour cloner une seule validation spécifique sur une branche ou une balise particulière, utilisez:

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

Malheureusement, NAMEne peut être que le nom de la branche ou le nom de la balise (pas de validation SHA).

Omettez le --depthdrapeau pour télécharger l'historique complet, puis vérifiez cette branche ou cette balise:

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

Cela fonctionne avec la version récente de git (je l'ai fait avec la version 2.18.0).

Peter Kovac
la source
mais pas sur l'ancienne version 2.17.1
RzR
4
Cela nécessite plus de votes positifs. C'est bien mieux que d'autres réponses obsolètes.
Étienne
32

Si vous voulez dire que vous voulez tout récupérer du début à un point particulier, la réponse de Charles Bailey est parfaite. Si vous voulez faire l'inverse et récupérer un sous-ensemble de l'historique remontant à la date actuelle, vous pouvez utiliser git clone --depth [N] où N est le nombre de tours de l'historique que vous souhaitez. Toutefois:

--profondeur

Créez un clone superficiel avec un historique tronqué au nombre de révisions spécifié. Un référentiel superficiel a un certain nombre de limitations (vous ne pouvez pas le cloner ou le récupérer, ni le pousser ni le pénétrer), mais il est adéquat si vous n'êtes intéressé que par l'histoire récente d'un grand projet avec une longue histoire et que vous souhaitez envoyer des correctifs sous forme de correctifs.

Walter Mundt
la source
4
La nouvelle version de git a amélioré les clones peu profonds, et vous pouvez les tirer et les pousser.
orion78fr
26

Juste pour résumer les choses (git v. 1.7.2.1):

  1. faire un régulier git cloneoù vous voulez le repo (obtient tout à ce jour - je sais, pas ce que l'on veut, nous y arrivons)
  2. git checkout <sha1 rev> du régime que vous voulez
  3. git reset --hard
  4. git checkout -b master
phill
la source
6
que font les étapes 3 et 4?
BrainSlugs83
L'étape 4 n'a pas fonctionné pour moi, mais jusqu'à l'étape 3 a fait l'affaire - Merci
Gene Bo
@ BrainSlugs83: l'étape 4 crée une branche locale appelée masteret y bascule.
LarsH
3
@phill: Pourquoi le git reset --hard? Les documents pour cela disent "Réinitialise l'index et l'arborescence de travail. Toutes les modifications apportées aux fichiers suivis dans l'arborescence de travail depuis <commit> [qui par défaut est HEAD, qui est maintenant <sha1 rev>] sont ignorées." Mais à ce stade, nous n'avons apporté aucun changement depuis le clonage, alors quel est le but? Tronque-t-il la branche actuelle à <sha1 rev>?
LarsH
19

TL; DR - Créez simplement une balise dans le référentiel source par rapport à la validation que vous souhaitez cloner et utilisez la balise dans la commande fetch. Vous pouvez supprimer la balise du référentiel d'origine plus tard pour nettoyer.

Eh bien, c'est 2014 et il semble que la réponse acceptée par Charles Bailey de 2010 soit bel et bien dépassée à l'heure actuelle et la plupart (toutes?) Des autres réponses impliquent le clonage, que beaucoup de gens espèrent éviter.

La solution suivante atteint ce que l'OP et bien d'autres recherchent, ce qui est un moyen de créer une copie d'un référentiel, y compris l'historique, mais uniquement jusqu'à un certain commit.

Voici les commandes que j'ai utilisées avec git version 2.1.2 pour cloner un dépôt local (c'est-à-dire un référentiel dans un autre répertoire) jusqu'à un certain point:

# 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

Espérons que cette solution fonctionne encore quelques années! :-)

JamesG
la source
2
C'est une bonne idée que vous êtes le propriétaire du dépôt, je ne sais pas si cela fonctionne avec des dépôts publics que vous ne maintenez pas
Suhaib
18

Vous pouvez utiliser simplement git checkout <commit hash>

dans cette séquence

bash git clone [URLTORepository] git checkout [commithash]

le hachage de validation ressemble à ceci "45ef55ac20ce2389c9180658fdba35f4a663d204"

M.Othman
la source
comme le précédent - pourquoi commander après avoir cloné. Une fois que vous avez cloné, vous avez tout l'historique dans le référentiel local. Pourquoi cette réponse a-t-elle trop de votes positifs?
Dmitry Perfilyev
2

L'utilisation de 2 des réponses ci-dessus ( Comment cloner le référentiel git avec une révision / un ensemble de modifications spécifique? Et Comment cloner un référentiel git avec une révision / un ensemble de modifications spécifique? ) M'a aidé à trouver une définition. Si vous voulez cloner jusqu'à un point, alors ce point doit être une balise / branche et pas simplement un SHA ou le FETCH_HEAD se confond. Après le git fetch set, si vous utilisez un nom de branche ou de tag, vous obtenez une réponse, si vous utilisez simplement un SHA-1, vous n'obtenez pas de réponse.
Voici ce que j'ai fait: - créer un clone de travail complet du repo complet, à partir de l'origine réelle

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

Ensuite, créez une branche locale, au point qui est intéressant

git checkout 2050c8829c67f04b0db81e6247bb589c950afb14
git checkout -b origin_point

Ensuite, créez mon nouveau référentiel vierge, avec ma copie locale comme 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

À ce stade, j'ai obtenu cette réponse. Je le note parce que si vous utilisez un SHA-1 à la place de la branche ci-dessus, rien ne se passe, donc la réponse signifie que cela a fonctionné

/ var / www / html / ui-hacking $ git fetch local_copy origin_point
à distance: comptage d'objets: 45493, terminé.
à distance: compression des objets: 100% (15928/15928), fait.
à distance: Total 45493 (delta 27508), réutilisé 45387 (delta 27463)
Réception d'objets: 100% (45493/45493), 53,64 Mio | 50,59 Mio / s, fait.
Résolution des deltas: 100% (27508/27508), fait.
Depuis / var / www / html / ui
 * branche origin_point -> FETCH_HEAD
 * [nouvelle branche] point_origine -> point d'origine / origine

Maintenant, dans mon cas, je devais ensuite remettre cela sur gitlab, comme un nouveau repo, donc je l'ai fait

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

Ce qui signifiait que je pouvais reconstruire mon référentiel à partir du point d'origine en utilisant git --git-dir=../ui/.git format-patch -k -1 --stdout <sha1> | git am -3 -kpour sélectionner à distance puis utiliser git push originpour télécharger le lot dans sa nouvelle maison.

J'espère que cela aide quelqu'un

sibaz
la source
Pouvez-vous expliquer ce que vous voulez dire par "FETCH_HEAD devient confus"? Et en quoi git fetch local_copy origin_pointdiffère-t-on des JamesG git fetch origin refs/tags/tmptag?
not2qubit
Le git fetch local_copy origin_pointvous laisser dans un état avec un reduced-reporépertoire vide , contenant uniquement un .git. Il manque quelque chose à ces instructions ...
not2qubit
2

Ma version était une combinaison de réponses acceptées et les plus votées. Mais c'est un peu différent, parce que tout le monde utilise SHA1 mais personne ne vous dit comment l'obtenir

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

vous pouvez maintenant voir toutes les branches et les commits

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

Enfin, vous connaissez SHA1 du commit souhaité

git reset --hard <sha1>
Vladkras
la source
1

J'utilise cet extrait avec GNU make pour fermer toute balise de révision, branche ou hachage

il a été testé sur git version 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
la source
0

git clone https://github.com/ORGANIZATION/repository.git (cloner le référentiel)

cd repository (navigate to the repository)

git fetch origin 2600f4f928773d79164964137d514b85400b09b2

git checkout FETCH_HEAD

JeffDropsIT
la source
2
pourquoi aller chercher après avoir cloné. Une fois que vous avez cloné, vous avez tout l'historique dans le référentiel local. Pourquoi cette réponse a-t-elle deux votes positifs?
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> 

vous ne pouvez pas obtenir une révision sans historique si elle n'est pas définie uploadpack.allowReachableSHA1InWant=truecôté serveur, tandis que vous pouvez créer une balise pour celle-ci et cloner la balise spéciale à la place.

wongoo
la source
-3

C'est simple. Il vous suffit de définir l'amont pour la branche courante

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

C'est tout

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

gitutilise le mot originau lieu de populairement connurevision

Voici un extrait du manuel $ 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
la source
4
Je ne sais pas pourquoi vous obtenez un vote négatif ici; c'est exactement ce que j'espérais voir pour mon cas d'utilisation: obtenir une version particulière du noyau Linux à partir d'une version qu'ils n'avaient pas le bon sens de marquer comme une version (semble être un problème avec les gens RPi), sans télécharger toute l'histoire de plusieurs gigaoctets de Linux. Soit dit en passant, cela a fonctionné un régal.
Fordi
1
--depth=1n'est pas mentionné dans la réponse, alors pourquoi diriez-vous que cette réponse a fonctionné si vous avez ajouté plus de choses qui ne sont pas mentionnées ici? Je suis heureux que cela ait fonctionné pour vous, mais cette réponse est trompeuse et ne répond pas à la question même en partie. D'où les downvotes.
Emil Styrke
5
@Fordi: Non. En utilisant cette réponse textuellement, vous obtenez exactement le même arbre que vous obtiendriez d'une vanille git clone <url> <local_dir_name>, essayez-le par vous-même. La seule différence est que la télécommande (représentée en utilisant git remote) sera appelée une séquence cryptique sha1 au lieu du nom "origine" qui est habituel. En d'autres termes, les éléments <sha1-of-the-commit>mentionnés dans cette réponse n'ont aucune incidence sur les révisions extraites du serveur ou sur la branche à extraire.
Emil Styrke du
6
@Fordi: Je viens de le faire git clone -o 896066ee1cf4d653057dac4e952f49c96ad16fa7 https://github.com/torvalds/linux.git linux --depth=1. Cela me donne une révision 8a28d674et non pas 896066ee comme vous et cette réponse le prétend.
Emil Styrke du
4
soulignant que "l'origine" n'a rien à voir avec la "révision" et cette réponse est complètement fausse.
Évoli