Como clonar repositório git com revisão / conjunto de alterações específicas?


393

Como posso clonar o repositório git com revisão específica, algo como normalmente faço no Mercurial:

hg clone -r 3 /path/to/repository

3
Não é específico para alterar conjuntos ou revisões, mas clonar o mais recente em um ramo específico pode ser tão eficaz ou seja git clone -b 10.1 https://github.com/MariaDB/server.git --depth=1 mariadb-server-src
MrMesees


Deseja que a história seja superficial, ou seja, contenha apenas a revisão 3 no seu exemplo ou também os pais?
sschuberth

Se o repositório em questão estiver sendo clonado de dentro de outro repositório e você desejar clonar esse repositório interno em um sha específico, os sub-módulos git farão exatamente isso de maneira auto-mágica.
precisa saber é o seguinte

Respostas:


203

ATUALIZAÇÃO 2 Desde o Git 2.5.0, o recurso descrito abaixo pode ser ativado no lado do servidor com variável de configuração uploadpack.allowReachableSHA1InWant, aqui a solicitação do recurso GitHub e o GitHub confirmam a ativação desse recurso . Observe que alguns servidores Git ativam essa opção por padrão, por exemplo, o Bitbucket Server a ativou desde a versão 5.5+ . Veja esta resposta no Stackexchange para um exemplo de como ativar a opção de configuração.

ATUALIZAÇÃO 1 Para versões Git, 1.7 < v < 2.5use git clone e git reset, conforme descrito na resposta de Vaibhav Bajpai

Se você não deseja buscar o repositório completo, provavelmente não deve usá-lo clone. Você sempre pode usar a busca para escolher a ramificação que deseja buscar. Eu não sou um especialista em hg, então não sei os detalhes, -rmas no git você pode fazer algo assim.

# 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
Eu não acho que git fetch origin <sha1>funciona; parece que você precisa passar uma referência nomeada, como uma marca ou nome de filial. Veja kerneltrap.org/mailarchive/git/2009/1/13/4707444
artur

48
@artur: Você não acha que funciona, ou você já tentou e não funciona?
CB Bailey

37
Com o git 1.4, descobri que era capaz de usar o git fetch origin <SHA1>para alternar para qualquer revisão que desejava, depois de buscar o mestre no controle remoto e fazer isso reset --hardpara instanciar a ramificação localmente. Não pude buscar diretamente as revisões individuais. Com o git 1.7, git fetch origin <SHA1>não funcionou, conforme relatado pelo @artur; você precisa usar git checkout <SHA1>seguido de a reset --hard.
Joe McMahon

6
A busca pelo SHA-1 funcionará apenas com os protocolos http e rsync. Vejo kerneltrap.org/mailarchive/git/2009/1/14/4716044/…
CharlesB

23
Esta resposta está desatualizada. Isso não funciona com o git 1.7 nem o git 1.8, nem com o protocolo https: // nem ssh. ("Não foi possível encontrar a ref remota df44398762393c67af487edeb0831ad9579df4aa" - não é uma ref, é uma confirmação.)
Paulo Ebermann

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

Para voltar novamente ao commit mais recente

$ git pull

13
Isso funciona apenas se o commit estiver na ramificação principal, caso contrário, irá atrapalhar a referência local. Por que o git reset e não o git checkout em primeiro lugar?
Joky

72
Esta não é uma boa opção para grandes repositórios, pois puxa tudo.
Incógnito

11
Esta solução deve estar no topo. Ninguém se importa que "não seja o ideal", é o que o OP pediu. Especificamente: "como clonar o repositório git com revisão específica"?
Florian Segginger 18/03/16

20
@FlorianSegginger Se estou procurando clonar uma revisão específica, provavelmente não quero clonar tudo, mas apenas essa revisão. Para mim, essa foi a pergunta. Esta solução responde a uma pergunta diferente: "Como vejo uma revisão específica no meu repo?". Buscar o repositório inteiro é exatamente o que muitas pessoas aqui querem evitar.
Renato

11
Não aborda a questão real IMHO, já que poder especificar uma revisão durante o clone também me permite usar o --depthque é muito importante para grandes repositórios. Esta solução requer puxar todos os objetos e redefinir para uma revisão anterior. Isso consome muito tempo e desperdiça largura de banda da rede.
void.pointer

54

A clonagem de um repositório git, apropriadamente, clona o repositório inteiro: não há como selecionar apenas uma revisão para clonar. No entanto, depois de executar git clone, você pode fazer o check-out de uma revisão específica fazendo isso checkout <rev>.


4
Não quero clonar apenas uma revisão. Eu só quero especificar o limite de clonagem. Em outras palavras, quero clonar tudo até a revisão especificada.
John

6
Você não pode fazer isso. git cloneagarra o repositório inteiro. Depois de obtê-lo, você poderá fazer o checkout de uma revisão específica.

4
Uma coisa a notar; O Git geralmente é bastante eficiente para armazenar histórico, por isso não é como se você economizasse uma quantidade enorme de espaço clonando apenas metade das revisões.
22610 Amber

Não se trata de "economizar espaço" - trata-se apenas de fazer uma revisão específica - como se uma nova mudança introduzisse um bug e, portanto, eu não quero essa nova mudança - você está dizendo que o Git não pode fazer isto? Isso não pode estar certo - por que ter controle de origem, se você não pode reverter para uma versão mais antiga?
precisa saber é o seguinte

11
"não existe uma maneira de selecionar apenas uma revisão para clonar" - sim, existe:git clone --single-branch ...
morxa 2/16/16

33

Para clonar apenas um único commit específico em uma ramificação ou marca específica, use:

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

Infelizmente, NAMEsó pode ser o nome do ramo ou o nome da marca (não confirma o SHA).

Omita a --depthbandeira para fazer o download de todo o histórico e faça check-out dessa ramificação ou tag:

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

Isso funciona com a versão recente do git (eu fiz isso com a versão 2.18.0).


mas não na versão mais antiga 2.17.1
RzR 27/06

4
Isso precisa de mais votos. Isso é muito melhor do que outras respostas desatualizadas.
Étienne

32

Se você quer buscar tudo, desde o início até um ponto específico, a resposta de Charles Bailey é perfeita. Se você deseja fazer o inverso e recuperar um subconjunto do histórico desde a data atual, você pode usar git clone --depth [N] onde N é o número de rotações do histórico que deseja. Contudo:

--profundidade

Crie um clone superficial com um histórico truncado para o número especificado de revisões. Um repositório superficial tem várias limitações (você não pode clonar ou buscar dele, nem empurrá-lo nem empurrá-lo), mas é adequado se você estiver interessado apenas no histórico recente de um grande projeto com um longo histórico e desejar envie correções como patches.


4
A versão mais recente do git melhorou os clones rasos, e você pode puxar e empurrar a partir dele.
precisa saber é o seguinte

26

Apenas para resumir as coisas (git v. 1.7.2.1):

  1. faça um regular git cloneonde você quer o repo (deixa tudo atualizado - eu sei, não o que é desejado, estamos chegando lá)
  2. git checkout <sha1 rev> da rev que você quer
  3. git reset --hard
  4. git checkout -b master

6
o que as etapas 3 e 4 fazem?
precisa saber é o seguinte

Passo 4 não funcionou para mim, mas até a etapa 3 fez o truque - Graças
Gene Bo

@ BrainSlugs83: O passo 4 cria um ramo local chamado mastere muda para ele.
precisa saber é

3
@phill: Por que o git reset --hard? Os documentos para isso dizem "Redefine o índice e a árvore de trabalho. Quaisquer alterações nos arquivos rastreados na árvore de trabalho desde que <commit> [cujo padrão é HEAD, que agora é <sha1 rev>] são descartadas". Mas neste momento não fizemos nenhuma alteração desde a clonagem, então qual é o objetivo? Trunca a ramificação atual em <sha1 rev>?
precisa saber é

19

TL; DR - Basta criar uma tag no repositório de origem contra a confirmação que você deseja clonar e usar a tag no comando buscar. Você pode excluir a tag do repositório original posteriormente para limpar.

Bem, em 2014 e parece que a resposta aceita por Charles Bailey a partir de 2010 está bem e verdadeiramente desatualizada agora e a maioria (todas?) Das outras respostas envolve clonagem, o que muitas pessoas esperam evitar.

A solução a seguir alcança o que o OP e muitos outros estão procurando, que é uma maneira de criar uma cópia de um repositório, incluindo histórico, mas apenas até um determinado commit.

Aqui estão os comandos que usei com o git versão 2.1.2 para clonar um repositório local (por exemplo, um repositório em outro diretório) até um certo ponto:

# 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

Esperamos que esta solução continue funcionando por mais alguns anos! :-)


2
Esta é uma boa idéia do que você é o proprietário do repo, não tenho certeza se ele funciona com repos públicas que você não manter
Suhaib

18

Você pode usar simplesmente git checkout <commit hash>

nesta sequência

bash git clone [URLTORepository] git checkout [commithash]

o hash de confirmação tem esta aparência "45ef55ac20ce2389c9180658fdba35f4a663d204"


como a anterior - por que fazer check-out depois de clonar. Depois de clonar, você tem todo o histórico no repositório local. Por que essa resposta tem muitos votos positivos?
Dmitry Perfilyev

2

O uso de 2 das respostas acima ( como clonar repositório git com revisão / conjunto de alterações específico? E como clonar repositório git com revisão / conjunto de alterações específico? ) Me ajudou a criar uma definição. Se você deseja clonar até um ponto, esse ponto deve ser uma marca / ramificação, não apenas um SHA ou o FETCH_HEAD fica confuso. Após o conjunto de busca git, se você usar um nome de filial ou marca, obterá uma resposta; se você simplesmente usar um SHA-1, não obterá resposta.
Aqui está o que eu fiz: - criar um clone completo do repositório completo, a partir da origem real

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

Em seguida, crie uma filial local, no ponto que for interessante

git checkout 2050c8829c67f04b0db81e6247bb589c950afb14
git checkout -b origin_point

Em seguida, crie meu novo repositório em branco, com minha cópia local como origem

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

Nesse ponto, eu recebi essa resposta. Notei isso porque se você usar um SHA-1 no lugar do ramo acima, nada acontece, então a resposta significa que funcionou

/ var / www / html / ui-hacking $ git fetch local_copy origin_point
remote: Contando objetos: 45493, concluído.
remote: Compactando objetos: 100% (15928/15928), concluído.
remoto: Total 45493 (delta 27508), reutilizado 45387 (delta 27463)
Objetos de recebimento: 100% (45493/45493), 53,64 MiB | 50,59 MiB / s, concluído.
Resolução de deltas: 100% (27508/27508), concluído.
De / var / www / html / ui
 * ponto de origem da ramificação -> FETCH_HEAD
 * [novo ramo] ponto de origem -> ponto de origem / origem

Agora, no meu caso, eu precisava colocar isso de volta no gitlab, como um novo repositório.

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

O que significava que eu poderia reconstruir meu repositório a partir do origin_point usando o git --git-dir=../ui/.git format-patch -k -1 --stdout <sha1> | git am -3 -kcherry pick remotamente e depois usar o git push originupload de todo o lote de volta para sua nova casa.

Espero que ajude alguém


Você pode explicar o que você quer dizer com "FETCH_HEAD fica confuso"? E como você git fetch local_copy origin_pointdifere do JamesGs git fetch origin refs/tags/tmptag?
precisa saber é o seguinte

O git fetch local_copy origin_pointdeixa em um estado com um reduced-repodiretório vazio , contendo apenas um .git. Há outra coisa que faltava para estas instruções ...
not2qubit

2

Minha versão foi uma combinação de respostas aceitas e mais votadas. Mas é um pouco diferente, porque todo mundo usa SHA1, mas ninguém diz como obtê-lo

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

agora você pode ver todas as filiais e confirmações

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

Finalmente, você conhece o SHA1 da confirmação desejada

git reset --hard <sha1>

1

Eu uso esse trecho com o GNU make para fechar qualquer tag de revisão, ramificação ou hash

foi testado na versão 2.17.1 do git

${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 (clone o repositório)

cd repository (navigate to the repository)

git fetch origin 2600f4f928773d79164964137d514b85400b09b2

git checkout FETCH_HEAD


2
por que buscar depois de clonar. Depois de clonar, você tem todo o histórico no repositório local. Por que essa resposta tem dois votos positivos?
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> 

você não pode obter uma revisão sem históricos se não estiver definido uploadpack.allowReachableSHA1InWant=trueno lado do servidor, enquanto pode criar uma tag para ela e clonar a tag especial.


-3

É simples. Você só precisa definir o upstream da ramificação atual

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

Isso é tudo


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

gitusa a palavra originem vez de popularmente conhecidorevision

A seguir, um trecho do manual $ git help clone

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

4
Não faço ideia por que você está recebendo votos negativos aqui; isto era exatamente o que eu esperava ver no meu caso de uso: Obter uma versão específica do kernel Linux de uma versão que eles não tiveram o bom senso de marcar como lançamento (parece ser um problema para o pessoal da RPi), sem baixando toda a história de vários gigabytes do Linux. Aliás, deu certo.
Fordi

11
--depth=1não é mencionado na resposta, então por que você diria que essa resposta funcionou se você adicionou mais itens que não foram mencionados aqui? Estou feliz que tenha funcionado para você, mas essa resposta é enganosa e não responde à pergunta, mesmo em parte. Daí os votos negativos.
Emil Styrke

5
@Fordi: Não. Ao usar esta resposta, você obtém exatamente a mesma árvore que obteria de uma baunilha git clone <url> <local_dir_name>, tente você mesmo. A única diferença é que o controle remoto (mostrado usando git remote) será chamado de sequência sha1 enigmática em vez do nome "origem" que é habitual. Em outras palavras, o <sha1-of-the-commit>mencionado nesta resposta não tem qualquer influência sobre quais revisões são buscadas no servidor ou qual filial será retirada.
Emil Styrke

6
@Fordi: Acabei de fazer git clone -o 896066ee1cf4d653057dac4e952f49c96ad16fa7 https://github.com/torvalds/linux.git linux --depth=1. Isso me dá uma revisão 8a28d674e não 896066ee como você e esta resposta afirma.
Emil Styrke

4
enfatizando que "origem" não tem nada a ver com "revisão" e esta resposta está completamente errada.
Eevee
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.