如何克隆具有特定修订/变更集的git存储库?


393

如何克隆具有特定修订版的git存储库,就像我通常在Mercurial中所做的那样:

hg clone -r 3 /path/to/repository

3
不是特定于变更集或修订版,而是在特定分支中克隆最新版本可能同样有效,即 git clone -b 10.1 https://github.com/MariaDB/server.git --depth=1 mariadb-server-src
MrMesees


您是否希望历史记录比较浅,例如您的示例中仅包含修订版3,还是父母?
sschuberth

如果要从另一个存储库中克隆有问题的存储库,并且您想在特定的sha处克隆该内部存储库,则git子模块会以一种自动魔术的方式完全做到这一点。
J0hnG4lt

Answers:


202

更新2Git 2.5.0起,可以使用配置变量在服务器端启用以下描述的功能uploadpack.allowReachableSHA1InWant,此处GitHub功能请求GitHub提交启用了此功能。请注意,某些Git服务器默认情况下会激活此选项,例如Bitbucket Server从5.5+版本开始启用了该选项。有关如何激活配置选项的示例,请参见Stackexchange上的答案

更新1对于Git版本,请1.7 < v < 2.5使用git clone和git reset,如Vaibhav Bajpai的答案中所述

如果您不想获取完整的存储库,则可能不应该使用clone。您始终可以仅使用fetch选择要提取的分支。我不是hg专家,所以我不知道的细节,-r但是在git中,您可以执行以下操作。

# 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
我认为没有用git fetch origin <sha1>;似乎您需要传递命名参考,例如标记或分支名称。参见kerneltrap.org/mailarchive/git/2009/1/13/4707444
artur 2011年

48
@artur:您认为它不起作用,或者您已经尝试过并且不起作用?
CB Bailey

37
在git 1.4中,我发现git fetch origin <SHA1>从远程获取master并完成reset --hard本地实例化实例后,可以使用切换到所需的任何修订版。我无法直接获取各个修订。git fetch origin <SHA1>@artur报告说,在git 1.7中,它不起作用;你需要使用git checkout <SHA1>后跟一个reset --hard
乔·麦克马洪

6
SHA-1提取仅适用于http和rsync协议。见kerneltrap.org/mailarchive/git/2009/1/14/4716044/...
CharlesB

23
这个答案已经过时了。这不适用于git 1.7或git 1.8,也不适用于https://或ssh协议。(“找不到远程参考df44398762393c67af487edeb0831ad9579df4aa” –它不是参考,这是一次提交。)
PaŭloEbermann 2014年

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

再次回到最近的提交

$ git pull

13
这仅在提交位于master分支中时才有效,否则将使本地引用混乱。为什么要首先重置git而不选择git checkout?
2015年

72
对于大型存储库,这不是一个好选择,因为它可以拉动所有内容。
隐身

1
该解决方案应该放在最前面。没人在乎它不是“最佳”,这是OP所要求的。具体来说:“如何克隆具有特定修订版的git存储库”?
Florian Segginger

20
@FlorianSegginger如果我要克隆特定的修订版,可能是我不想克隆所有内容,而只是克隆该修订版。对我来说,这是一个问题。此解决方案回答了一个不同的问题:“如何查看我的存储库中的特定修订版?”。正是整个这里的很多人都想避免获取整个仓库。
雷纳托

1
不能解决实际的问题恕我直言,因为能够在克隆期间指定修订版本还允许我使用--depth它,这对于大型存储库而言非常重要。此解决方案需要提取所有对象,然后将其重置为早期版本。这非常耗时并且浪费网络带宽。
void.pointer '18

54

克隆git存储库很合适,它会克隆整个存储库:没有一种方法只能选择一个修订版本进行克隆。但是,一旦执行git clone,您可以通过执行签出特定的修订版checkout <rev>


4
我不想克隆一个修订版。我只想指定克隆的限制。换句话说,我想克隆所有内容直到指定的版本。
约翰

6
你不能那样做。git clone获取整个存储库。有了它之后,就可以签出特定的修订版了。

4
需要注意的一件事;Git通常在存储历史记录方面非常有效,因此,好像您只克隆一半的修订版就不会节省大量空间一样。
琥珀

这不是“节省空间”,而是仅涉及特定的修订,例如新变更是否引入了错误,因此我不希望最新变更-您是说Git无法做到这个?那是不对的-如果您无法回滚到旧版本,为什么还要拥有源代码控制?
BrainSlugs83

1
“没有办法只选择一个版本来克隆”-是的,存在:git clone --single-branch ...
morxa

33

要在特定分支或标签上克隆单个特定提交,请使用:

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

不幸的是,NAME只能是分支名称或标记名称(不能提交SHA)。

省略该--depth标志以下载整个历史记录,然后检出该分支或标记:

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

这适用于最新版本的git(我使用version做到了2.18.0)。


但不适用于旧版2.17.1
RzR

4
这需要更多的支持。这比其他过时的答案要好得多。
艾蒂安

32

如果您是想从一开始就获取所有东西,则可以使用Charles Bailey的答案。如果要进行反向操作并检索从当前日期返回的历史记录的子集,则可以使用git clone --depth [N] N作为所需历史记录的转速。然而:

- 深度

创建一个浅表副本,其历史记录被截断为指定的修订版本。浅层存储库有很多限制(您不能从中克隆或获取,也不能从中推入或推入其中),但是如果您仅对具有悠久历史的大型项目的最新历史感兴趣,并且想要发送修补程序作为补丁。


4
较新版本的git改进了浅层克隆,您可以从中拉出和推动。
orion78fr

26

总结一下(git v。1.7.2.1):

  1. 定期git clone在需要回购的地方进行操作(获取所有最新信息-我知道,不是想要的东西,我们到了那里)
  2. git checkout <sha1 rev> 你想要的转速
  3. git reset --hard
  4. git checkout -b master

6
第3步和第4步做什么?
BrainSlugs83

第4步对我不起作用,但直到第3步都成功了-谢谢
Gene Bo

@ BrainSlugs83:步骤4创建一个名为的本地分支master并切换到该分支。
LarsH '16

3
@phill:为什么git reset --hard?该文档说:“重置索引和工作树。自<commit> [默认为HEAD,现在<sha1 rev>是HEAD以来,对工作树中跟踪文件的任何更改都将被丢弃。” 但是到目前为止,自克隆以来我们还没有进行任何更改,所以目的是什么?它会截断当前分支<sha1 rev>吗?
LarsH '16

19

TL; DR-只需在源存储库中针对要克隆的提交创建标签,然后在fetch命令中使用该标签。您可以稍后从原始存储库中删除标签以进行清理。

好吧,它的2014年,以及查尔斯·贝利(Charles Bailey)从2010年开始接受的答案,现在看来已经完全过时了,而其他大多数(所有?)答案都涉及克隆,这是许多人希望避免的。

以下解决方案实现了OP及其它许多人正在寻找的解决方案,这是一种创建存储库副本的方法,包括历史记录,但仅限于一定的提交。

这是我在git版本2.1.2中使用的命令,用于将本地存储库(即另一个目录中的存储库)克隆到特定点:

# 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

希望该解决方案可以继续工作几年!:-)


2
这是一个好主意,因为您是该回购协议的所有者,不确定它是否与您不维护的公共回购协议一起使用
Suhaib

18

您可以简单地使用 git checkout <commit hash>

按此顺序

bash git clone [URLTORepository] git checkout [commithash]

提交哈希看起来像这样“ 45ef55ac20ce2389c9180658fdba35f4a663d204”


像上一个一样-克隆后为何要签出。克隆后,您将在本地存储库中拥有整个历史记录。为什么这个答案投票过多?
德米特里·佩菲里耶夫

2

使用上述答案中的2个(如何克隆具有特定修订/更改集的git存储库?以及如何克隆具有特定修订/更改集的git存储库?)帮助我提出了一个明确的定义。如果要克隆到某个点,则该点必须是标记/分支,而不仅仅是SHA或FETCH_HEAD会引起混淆。遵循git fetch设置后,如果使用分支或标记名,则会得到响应,如果仅使用SHA-1,则不会响应。
这是我所做的:-从实际来源创建完整回购的完整工作克隆

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

然后在有趣的地方创建一个本地分支

git checkout 2050c8829c67f04b0db81e6247bb589c950afb14
git checkout -b origin_point

然后创建新的空白存储库,并将其本地副本作为源

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

那时我得到了这个回应。我注意到它是因为如果您使用SHA-1代替上面的分支,则什么也不会发生,因此响应意味着它有效

/ var / www / html / ui-hacking $ git fetch local_copy origin_point
remote:计数对象:45493,已完成。
远程:压缩对象:100%(15928/15928),已完成。
远程:总计45493(增量27508),已重用45387(增量27463)
接收物体:100%(45493/45493),53.64 MiB | 50.59 MiB / s,已完成。
解析增量:100%(27508/27508),已完成。
来自/ var / www / html / ui
 *分支origin_point-> FETCH_HEAD
 * [新分支] origin_point-> origin / origin_point

现在以我为例,然后我需要将其放回gitlab,作为一个新的仓库,所以我做了

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

这意味着我可以通过使用origin git --git-dir=../ui/.git format-patch -k -1 --stdout <sha1> | git am -3 -k来远程重建樱桃仓库,然后再将git push origin其全部上传回新家,从而从origin_point重建仓库。

希望可以帮助某人


您能否解释“ FETCH_HEAD混淆”的含义?您git fetch local_copy origin_point与JamesGs git fetch origin refs/tags/tmptag有何不同 ?
not2qubit

git fetch local_copy origin_point离开你的状态与空reduced-repo目录,只包含一个.git。这些指令还缺少其他内容...
not2qubit '17

2

我的版本是公认的和最受好评的答案的组合。但这有点不同,因为每个人都使用SHA1,但是没有人告诉您如何获取它

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

现在您可以看到所有分支和提交

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

最后,您知道所需提交的SHA1

git reset --hard <sha1>

1

我将此片段与GNU make一起使用以关闭任何修订标签,分支或哈希

它已在git 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 (克隆存储库)

cd repository (navigate to the repository)

git fetch origin 2600f4f928773d79164964137d514b85400b09b2

git checkout FETCH_HEAD


2
为什么克隆后要获取。克隆后,您将在本地存储库中拥有整个历史记录。为什么这个答案有两个投票?
madhairsilence '19

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> 

如果未uploadpack.allowReachableSHA1InWant=true在服务器端进行设置,则无法获得没有历史记录的修订,而您可以为其创建标签并克隆特殊标签。


-3

这很简单。您只需要为当前分支设置上游

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

就这样


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

git用这个词origin代替众所周知的词revision

以下是手册的摘录 $ git help clone

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

4
不知道为什么你在这里被低估;这正是我在用例中希望看到的:从一个他们没有良好标签意义的版本中获取特定版本的Linux内核(似乎是RPi人员的问题),而没有下载Linux的整个千兆字节历史记录。顺便说一句,它起到了治疗作用。
Fordi

1
--depth=1没有在答案中提及,所以如果您添加了此处未提及的更多内容,为什么还要说此答案有效呢?很高兴为您解决了这个问题,但是这个答案具有误导性,甚至无法部分回答问题。因此,反对票。
埃米尔·斯特尔克

5
@Fordi:不。使用此答案可以逐字逐句获得与从香草中得到的完全相同的树git clone <url> <local_dir_name>,只需亲自尝试即可。唯一的区别是,远程(使用git remote来显示)将被称为一些神秘的sha1序列,而不是通常的名称“ origin”。换句话说,在<sha1-of-the-commit>这个答复中提到有没有承载任何哪个版本是从分支将被检查出服务器或牵强。
Emil Styrke

6
@Fordi:我刚刚做了git clone -o 896066ee1cf4d653057dac4e952f49c96ad16fa7 https://github.com/torvalds/linux.git linux --depth=1。这给了我修改的余地,8a28d674不是 896066ee您和此答案所要求的。
Emil Styrke,2015年

4
强调“起源”与“修订”无关,这个答案是完全错误的。
伊芙
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.