为什么我不能从浅克隆推? [英] Why can't I push from a shallow clone?

查看:39
本文介绍了为什么我不能从浅克隆推?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

git clone --depth 命令选项说

--depth 创建一个浅克隆,其历史记录被截断为指定数量的修订.浅层存储库有许多限制(你不能从它克隆或获取,也不能从它推入或推入),但如果你只对历史悠久的大型项目的近期历史感兴趣,那就足够了,并希望将修复程序作为补丁发送.

为什么浅克隆有这个限制?为什么它是一个只有补丁的工作流程?

对于某些项目工作流,我只需要将来自单个分支的最新提交传递给编码器,然后让他们能够push他们的(快进)开发到主服务器.这部分是为了安全、IP 保护和 repo 大小,部分是为了减少大型 repo 会给天真的编码员带来的混乱.是否有允许这样做的 git 工作流程?

<小时>

更新:根据 Karl Bielefeldt 的回答,git checkout --orphan 应该是正确的答案.但是仍然需要将该分支单独克隆"给新用户,并能够有效地推送它.

手册页指出:

<块引用>

git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>] --orphan

创建一个新的孤立分支,命名为 ,从 并切换到它.对这个新的第一次提交分支将没有父母,它将成为新历史的根源与所有其他分支和提交完全断开.

索引和工作树被调整,就像你以前一样运行 git checkout .这允许您开始一个新的记录一组类似于 的路径的历史记录轻松运行 git commit -a 进行根提交.

当你想从提交中发布树时,这很有用没有暴露其完整的历史.你可能想这样做发布一个项目的开源分支,其当前树是干净",但其完整历史包含专有或其他受累的代码.

如果要开始记录一组断开连接的历史记录与 中的路径完全不同的路径,则您应该在创建后立即清除索引和工作树通过从顶层运行 git rm -rf .工作树.之后,您将准备好准备新文件,通过从其他地方复制它们来重新填充工作树,提取压缩包等

VonC 指向 Junio 评论的链接很有趣.我认为手册应该在这种情况下提供指导,并允许正确的命令[例如clone --options] 只提取 repo 的相关部分.显然,push 成功的概率是通过在历史记录底部添加一些链接提交和 SHA1 来锁定 repo 匹配的.

<小时>

更新 Git 1.9.0:2014 年 2 月 14 日发行说明.

"以前禁止从浅克隆存储库中获取数据,主要是因为所涉及的代码路径没有经过仔细审查我们没有费心支持这种用法.此版本尝试允许对象从浅克隆的存储库中转移出更可控的方式(即接收器变成一个浅层存储库具有截断的历史记录)."

这对浅层克隆人来说是个好消息.下一个 - 可能是窄克隆.

解决方案

作为 Junio C. Hamano(主要 Git 维护者)把它:

<块引用>

规则是不是或多或少像:

<块引用>

如果您的浅存储库的历史扩展不够长,并且另一个存储库在您截断的历史记录之前分叉,则您无法计算共同祖先,也无法推出.

2014 年更新:参见git clone --depth 1(浅层克隆)是否比它看起来更有用?":Git 1.9 将取消该限制!

更新 2015:使用 Git 2.5+,您甚至可以获取单个提交.请参阅从远程 git 存储库中提取特定提交"

<小时>

原始答案(2011 年 8 月):

<块引用>

其实想想,比cannotcompute"强多了共同".

历史可能是这样的:

 R---R---R/--R---R---X---X---S---S---S

<块引用>

其中 S 是您在浅层存储库中的提交,R 是接收推送的存储库中存在的提交.
因为你的历史很浅,所以两个存储库都没有 'X' 这是为了保持接收者存储库的历史完整而需要存在的提交;接受者一开始并不肤浅,我们也不想让它变得肤浅.

如果您前一段时间进行了浅薄的克隆,在另一方进行时没有与另一方沟通就工作,AND如果另一方的进度包括倒带&重建历史,你会看到类似的拓扑结构.
上图中最左边的 'S' 可能是当你用深度 1 进行浅层克隆时的分支的尖端,从那时起,远端可能已经丢弃了最上面的三个提交并重建了它的历史记录通向最右边的R".
在这种情况下,推送到遥控器的 HEAD 将失败.

<小时>

所以它可以在某些情况下工作,但不受支持:

如果我必须要说些什么...

<块引用>
  • 我认为不支持"是提供足够好的信息的简洁方式,但它只适用于聪明人.

  • 并不是每个人都聪明;有些人自己尝试一下,发现该操作似乎对他们有限的试验次数有效,并得出结论,它在大多数情况下都有效.
    他们祝贺自己说大部分时间",而不是总是".
    即使他们已被警告,当他们看到它不起作用时也会感到不安.

<小时>

有关浅克隆更新过程的更多信息,请参阅如何更新 git 浅克隆?".>

The git clone --depth command option says

--depth <depth> 
Create a shallow clone with a history truncated to the specified number of revisions. 
A shallow repository has a number of limitations 
(you cannot clone or fetch from it, nor push from nor into it),
 but is adequate if you are only interested in the recent history of a large project with a long history,
 and would want to send in fixes as patches. 

Why do shallow clones have this limitation? Why is it a patches only workflow?

For some project workflows I need to pass just the latest commit from a single branch to a coder, and then have them be able to push their (fast forward) developments to the main server. This partly for security, IP protection and repo size, and partly to reduce the confusion that a big repo would bring to a naive coder. Is there a git workflow that allows this?


Update: Based on Karl Bielefeldt's answer the git checkout --orphan should be the right answer. But one still needs to 'clone' that branch alone to the new user, and be able to push it effectively.

The man page states:

git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>] --orphan

Create a new orphan branch, named <new_branch>, started from <start_point> and switch to it. The first commit made on this new branch will have no parents and it will be the root of a new history totally disconnected from all the other branches and commits.

The index and the working tree are adjusted as if you had previously run git checkout <start_point>. This allows you to start a new history that records a set of paths similar to <start_point> by easily running git commit -a to make the root commit.

This can be useful when you want to publish the tree from a commit without exposing its full history. You might want to do this to publish an open source branch of a project whose current tree is "clean", but whose full history contains proprietary or otherwise encumbered bits of code.

If you want to start a disconnected history that records a set of paths that is totally different from the one of <start_point>, then you should clear the index and the working tree right after creating the orphan branch by running git rm -rf . from the top level of the working tree. Afterwards you will be ready to prepare your new files, repopulating the working tree, by copying them from elsewhere, extracting a tarball, etc.

VonC's link to Junio's comments is interesting. I think the manual should provide the guidance in this case, and allow the right command [e.g. clone <branch> --options] to extract just the relevant part of the repo. Obviously the probability of push success is increased by having a few linked commits and SHA1s at the bottom of the history that will lock down the repo matching.


Update Git 1.9.0 : release notes 14 Feb '14.

"Fetching from a shallowly-cloned repository used to be forbidden, primarily because the codepaths involved were not carefully vetted and we did not bother supporting such usage. This release attempts to allow object transfer out of a shallowly-cloned repository in a more controlled way (i.e. the receiver becomes a shallow repository with a truncated history)."

This is good news for the shallow cloners. Next - Narrow clones possibly.

解决方案

As Junio C. Hamano (main Git maintainer) puts it:

Isn't the rule more or less like:

If your shallow repository's history does not extend long enough and the other repository forked before your truncated history, wyou cannot compute the common ancestor and you cannot push out.

Update 2014: see "Is git clone --depth 1 (shallow clone) more useful than it makes out?": that limitation will be lifted with Git 1.9!

Update 2015: with Git 2.5+, you will even be able to fetch a single commit. See "Pull a specific commit from a remote git repository"


Original answer (August 2011):

Actually, come to think of it, it is a lot stronger than "cannot compute the common".

The history may look like this:

          R---R---R
         /
  --R---R---X---X---S---S---S

where S are the commits you have in your shallow repository, and R are the commits that exist in the repository that receives your push.
Because your history is shallow, neither repository has 'X' that are the commits that need to exist in order to keep the history of recipient repository complete; the recipient is not shallow to begin with, and we do not want to make it shallow.

If you cloned shallowly some time ago, worked without communicating with the other side while the other side progressed, AND if the other side's progress included a rewind & rebuild of the history, you would see a similar topology.
The leftmost 'S' in the above picture might have been the tip of the branch when you shallowly cloned with depth 1, and since then the remote end may have discarded topmost three commits and have rebuilt its history that leads to the rightmost 'R'.
In such a case pushing to the remote's HEAD will fail.


So it could work in some case, but it is not supported:

If I have to say something on this...

  • I think "is not supported" is a succinct way to give good enough information, but it would only work for intelligent people.

  • Not everybody is intelligent; some try it out themselves, see that the operation seems to work for their limited number of trials, and would conclude it would work most of the time.
    And they congratulate their own intelligence for saying "most of the time", not "always".
    And they get upset when they see it does not work, even though they have been warned.


For more on the shallow clone update process, see "How to update a git shallow clone?".

这篇关于为什么我不能从浅克隆推?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆