240 votes

Récupérer un commit spécifique d'un dépôt Git distant

Existe-t-il un moyen de récupérer un seul commit spécifique d'un repo Git distant sans le cloner sur mon PC ? La structure du repo distant est absolument identique à celle du mien et donc il n'y aura pas de conflits mais je n'ai aucune idée de comment faire et je ne veux pas cloner cet énorme dépôt.

Je suis novice en matière de git, y a-t-il un moyen ?

1 votes

Votre repo existant est-il déjà un clone du repo distant, ou est-il complètement différent ?

0 votes

Eh bien, le dépôt est le noyau source de Linux, et c'est à peu près la même chose.

0 votes

Alors, c'est un clone ou pas ?

140voto

VonC Points 414372

Depuis la version 2.5+ de Git (Q2 2015), il est possible de récupérer un seul commit (sans cloner le repo complet).

Voir commettre 68ee628 par Fredrik Medley ( moroten ) , 21 mai 2015.
(fusionné par Junio C Hamano -- gitster -- sur commettre a9d3493 , 01 Jun 2015)

Vous avez maintenant une nouvelle configuration (du côté du serveur)

uploadpack.allowReachableSHA1InWant

Autoriser upload-pack pour accepter une requête de récupération qui demande un objet qui est atteignable à partir de n'importe quelle pointe de référence. Cependant, notez que le calcul de l'accessibilité des objets est coûteux en temps de calcul.
La valeur par défaut est false .

Si vous combinez cette configuration côté serveur avec un clone peu profond ( git fetch --depth=1 ), vous pouvez demander un seul commit (voir t/t5516-fetch-push.sh :

git fetch --depth=1 ../testrepo/.git <full-length SHA1>

Vous pouvez utiliser le git cat-file pour voir si le commit a été récupéré :

git cat-file commit <full-length SHA1>

" git upload-pack "qui sert " git fetch "On peut demander à ce que les les commits qui ne sont pas à l'extrémité d'une référence, tant qu'ils sont accessibles depuis une ref, avec uploadpack.allowReachableSHA1InWant variable de configuration.

Comme l'a noté matt sur les commentaires :

Notez que le SHA doit être le SHA complet non abrégé, sinon Git dira qu'il n'a pas pu trouver le commit.


La documentation complète est la suivante :

upload-pack : permet éventuellement de récupérer les sha1 accessibles

Avec uploadpack.allowReachableSHA1InWant option de configuration définie du côté du serveur, " git fetch "peut faire une demande avec une ligne "want" qui nomme un objet qui n'a pas été annoncé (susceptible d'avoir été obtenu hors bande ou à partir d'un pointeur de sous-module).
Seuls les objets accessibles depuis les extrémités de la branche, c'est-à-dire l'union des branches annoncées et des branches cachées par des transfer.hideRefs seront traitées.
Notez qu'il y a un coût associé au fait de devoir revenir en arrière dans l'historique pour vérifier l'accessibilité.

Cette fonctionnalité peut être utilisée pour obtenir le contenu d'un certain commit, pour lequel le sha1 est connu, sans avoir besoin de cloner le dépôt entier entier, surtout si une recherche peu profonde est utilisée. .

Les cas utiles sont par exemple

  • les dépôts contenant des fichiers volumineux dans l'historique,
  • Récupérer uniquement les données nécessaires à la vérification d'un sous-module,
  • lorsque l'on partage un sha1 sans dire à quelle branche exacte il appartient et dans Gerrit, si l'on pense en termes de commits au lieu de numéros de changement.
    (L'affaire Gerrit a déjà été résolue grâce à allowTipSHA1InWant car chaque changement Gerrit a une référence).

Git 2.6 (Q3 2015) améliorera ce modèle.
Voir commettre 2bc31d1 , commettre cc118a6 (28 juillet 2015) par Jeff King ( peff ) .
(fusionné par Junio C Hamano -- gitster -- sur commettre 824a0be , 19 août 2015)

refs : soutien négatif transfer.hideRefs

Si vous masquez une hiérarchie de refs à l'aide de l'option transfer.hideRefs il n'y a aucun moyen de remplacer cette configuration par la suite pour le "démasquer".
Ce patch implémente un masquage "négatif" qui fait que les correspondances sont immédiatement marquées comme non masquées, même si une autre correspondance les masquerait.
Nous prenons soin d'appliquer les correspondances dans l'ordre inverse de celui dans lequel elles nous sont fournies par la machinerie de la configuration, car cela permet à l'habituel "dernier gagnant" de la configuration de fonctionner (et les entrées dans .git/config par exemple, aura la priorité sur /etc/gitconfig ).

Donc vous pouvez maintenant le faire :

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

pour cacher refs/secret dans tous les dépôts, sauf pour un bit public dans un repo spécifique.


Git 2.7 (Nov/Déc 2015) apportera encore des améliorations :

Voir commettre 948bfa2 , commettre 00b293e (05 Nov 2015), commettre 78a766a , commettre 92cab49 , commettre 92cab49 , commettre 92cab49 (03 Nov 2015), commettre 00b293e , commettre 00b293e (05 Nov 2015), et commettre 92cab49 , commettre 92cab49 , commettre 92cab49 , commettre 92cab49 (03 Nov 2015) par Lukas Fleischer ( lfos ) .
Aidé par : Eric Sunshine ( sunshineco ) .
(fusionné par Jeff King peff -- sur commettre dbba85e , 20 Nov 2015)

config.txt : documenter la sémantique de hideRefs avec des espaces de noms

Pour l'instant, il n'y a pas de définition claire de la manière dont les transfer.hideRefs devrait se comporter lorsqu'un espace de nom est défini.
Expliquez que hideRefs Les préfixes correspondent aux noms dépouillés dans ce cas. C'est ainsi que hideRefs Les modèles sont actuellement traités dans le paquet de réception.

hideRefs : ajout d'un support pour la correspondance des refs complètes

En plus de faire correspondre les réfs dépouillées, on peut maintenant ajouter des hideRefs les motifs contre lesquels la référence complète (non dépouillée) est comparée.
Pour distinguer les correspondances dépouillées des correspondances complètes, ces nouveaux motifs doivent être préfixés par un accent circonflexe ( ^ ).

D'où la nouvelle documentation :

transfer.hideRefs:

Si un espace de noms est utilisé, le préfixe de l'espace de noms est supprimé de chaque référence avant qu'elle ne soit comparée à l'espace de noms de l'UE. transfer.hiderefs modèles.
Par exemple, si refs/heads/master est spécifié dans transfer.hideRefs et l'espace de nom actuel est foo alors refs/namespaces/foo/refs/heads/master est omis des annonces mais refs/heads/master et refs/namespaces/bar/refs/heads/master sont toujours annoncées comme des lignes dites "avoir" des lignes.
Afin de faire correspondre les refs avant de les dépouiller, ajoutez une balise ^ devant le nom de l'arbitre. Si vous combinez ! et ^ , ! doit être spécifié en premier.


R.. mentionne dans les commentaires la configuration uploadpack.allowAnySHA1InWant qui permet upload-pack d'accepter un fetch qui demande un objet quelconque. (La valeur par défaut est false ).

Voir commit f8edeaa (Nov. 2016, Git v2.11.1) par David "novalis" Turner ( novalis ) :

upload-pack : permet éventuellement de récupérer n'importe quel sha1

Il semble un peu stupide de faire une vérification de l'accessibilité dans le cas où nous l'utilisateur d'accéder à absolument tout dans le référentiel.

De plus, c'est osé dans un système distribué -- peut-être qu'un serveur annonce une référence, mais qu'un autre a depuis été poussé vers cette référence, et peut-être que les deux requêtes HTTP finissent par être dirigées vers ces différents différents.

5 votes

Pouvez-vous donner un exemple plus complet sur la façon de créer un clone de repo avec ce seul commit ? J'ai essayé mais j'ai échoué.. Merci !

0 votes

@LarsBilke avez-vous la bonne version pour le repo Git ? serveur ? Si le serveur n'a pas le uploadpack.allowReachableSHA1InWant activé, tout clone à commande unique échouerait.

1 votes

Je veux pousser vers GitHub. Peut-être qu'ils ne le permettent pas.

110voto

CharlesB Points 27070

Vous ne clonez qu'une seule fois, donc si vous avez déjà un clone du dépôt distant, le fait de tirer à partir de celui-ci ne téléchargera pas tout à nouveau. Il suffit d'indiquer la branche que vous voulez extraire, ou de récupérer les changements et de vérifier le commit que vous voulez.

La récupération à partir d'un nouveau dépôt est très économique en bande passante, car il ne téléchargera que les modifications que vous n'avez pas. Pensez en termes de Git qui fait la bonne chose, avec une charge minimale.

Git stocke tout dans .git dossier. Un commit ne peut pas être récupéré et stocké isolément, il a besoin de tous ses ancêtres. Ils sont interrelié .


Pour réduire la taille du téléchargement, vous pouvez cependant demander à git de ne récupérer que les objets liés à une branche ou un commit spécifique :

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

Ceci ne téléchargera que les commits contenus dans la branche distante. branch (et seulement ceux qui vous manquent) et le stocker dans origin/branch . Vous pouvez ensuite fusionner ou passer à la caisse.

Vous pouvez également spécifier uniquement un commit SHA1 :

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

Ceci téléchargera seulement le commit du SHA-1 96de5297df870 spécifié (et ses ancêtres qui vous manquent), et le stockera dans une branche distante (inexistante). origin/foo-commit .

0 votes

Je souhaite éviter cela parce que je travaille sur les sources du noyau Linux, et j'aime visiter différents dépôts et fusionner les commits que j'aime qui améliorent certains composants que j'aime et donc je ne peux pas cloner chaque dépôt distant :( ils sont de taille énorme

3 votes

On dirait que vous faites une confusion sur ce que signifie clone. Lorsque vous récupérez les modifications d'un repo distant, vous ne le clonez pas, vous obtenez simplement les commits dans votre historique. Ensuite, vous choisissez quel commit vous voulez extraire, ou le fusionner dans votre historique.

2 votes

Il télécharge toujours beaucoup de données (430mb) avec git fetch. Le commit requis est juste de quelques kbs. Il n'y a pas vraiment de commande spéciale pour faire cela ? Et que se passe-t-il si je veux supprimer le repo 'git fetched' ? Où est-il stocké ?

78voto

Flow Points 8018

Vous pouvez simplement récupérer un seul commit d'un repo distant avec

git fetch <repo> <commit>

où,

  • <repo> peut être un nom de dépôt distant (ex. origin ) ou même l'URL d'un dépôt distant (par ex. https://git.foo.com/myrepo.git )
  • <commit> peut être le commit SHA1

par exemple

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

après avoir récupéré le commit (et les ancêtres manquants) vous pouvez simplement le vérifier avec

git checkout FETCH_HEAD

Notez que cela vous amènera à l'état de "tête détachée".

12 votes

Quand j'essaie de fetch une révision spécifique comme vous le faites ici, git échoue avec le code d'erreur 1 et aucune sortie. Est-ce que c'était quelque chose qui fonctionnait dans les versions précédentes ? (Je suis la v2.0.2.)

2 votes

Edit : Cela fonctionne si j'ai déjà le commit en question en local, comme si j'ai déjà fait un commit complet. fetch mais dans ce cas, je ne suis pas sûr de l'utilité.

3 votes

En effet, cela ne semble plus fonctionner pour moi non plus avec git 2.0.2 :(

66voto

Piu Sharma Points 19

J'ai fait un pull sur mon dépôt git :

git pull --rebase <repo> <branch>

J'ai permis à git de récupérer tout le code de la branche, puis j'ai fait un reset sur le commit qui m'intéressait.

git reset --hard <commit-hash>

J'espère que cela vous aidera.

1 votes

Aucune des réponses n'a fonctionné, mais celle-ci m'a sauvé la vie ! Merci beaucoup !

1 votes

La réinitialisation --dure a fonctionné pour moi après le clonage ! Merci.

5 votes

-1 : Les commandes "destructives" comme git reset --hard lorsqu'ils sont partagés en solutions généralisées, peuvent conduire les gens dans des pièges où ils perdent des données (ou, dans ce cas, dans un état où récupérer leurs données n'est pas trivial).

21voto

Sérgio Points 854

Vous pouvez simplement récupérer le dépôt distant avec :

git fetch <repo>

où,

  • <repo> peut être un nom de dépôt distant (ex. origin ) ou même l'URL d'un dépôt distant (par ex. https://git.foo.com/myrepo.git )

par exemple :

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

après avoir récupéré les dépôts, vous pouvez fusionner les commits que vous voulez (puisque la question est de récupérer un commit, au lieu de fusionner vous pouvez utiliser cherry-pick pour choisir juste un commit) :

git merge <commit>
  • <commit> peut être le commit SHA1

par exemple :

git cherry-pick 0a071603d87e0b89738599c160583a19a6d95545

ou

git merge 0a071603d87e0b89738599c160583a19a6d95545

si c'est le dernier commit que vous voulez fusionner, vous pouvez aussi utiliser la variable FETCH_HEAD :

git cherry-pick (or merge) FETCH_HEAD

0 votes

Cela nécessite la configuration d'un compte Git sur une machine. Cela ne fonctionne pas sous un compte de test. Avez-vous quelque chose qui fonctionne sous un compte de test ?

0 votes

Qu'est-ce que tu veux dire ? Tu ne peux pas faire un git fetch ?

0 votes

Ummm donc la commande serait git config set uploadpack.allowReachableSHA1InWant ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X