为什么我不能从浅克隆中推送?
git clone --depth
命令选项显示
--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.
“为什么浅层克隆有此限制?”为什么它是仅补丁工作流程?
对于某些项目工作流程,我需要将单个分支的最新提交传递给编码器,然后让他们能够将其(快进)开发推送到主服务器。这部分是为了安全、IP 保护和存储库大小,部分是为了减少大型存储库给新手编码人员带来的混乱。是否有允许这样做的 git 工作流程?
更新:根据 Karl Bielefeldt 的回答,git checkout --orphan
应该是正确的答案。但仍然需要将该分支单独“克隆”给新用户,并能够有效地推送它。
手册页指出:
git checkout [-q] [-f] [-m] [[-b|-B|--orphan]
] [ ] --orphan 创建一个新的孤立分支,名为
,从
并切换到它。对这个新的第一次提交 分支将没有父母,它将成为新历史的根源 与所有其他分支和提交完全断开连接。
索引和工作树的调整就像您之前所做的那样 运行 git checkout
。这可以让你开始一个新的 记录一组类似于 的路径的历史记录 轻松运行 git commit -a 来进行根提交。
当您想要从提交发布树时,这可能很有用 而不暴露其完整历史。你可能想要这样做 发布当前树为的项目的开源分支 “干净”,但其完整历史包含专有或其他内容 受阻碍的代码位。
如果您想启动记录一组的断开连接历史记录 与
完全不同的路径,那么 您应该在创建后立即清除索引和工作树 通过从顶层运行 git rm -rf . 来创建孤立分支 工作树。之后您将准备好准备新文件, 通过从其他地方复制它们来重新填充工作树, 提取 tarball 等。
VonC 的 Junio 评论链接很有趣 我认为手册应该在这种情况下提供指导,并允许正确的命令[例如 clone
] 仅提取存储库的相关部分。显然,通过在历史记录底部添加一些链接提交和 SHA1 来锁定存储库匹配,可以增加推送成功的概率。
更新 Git 1.9.0:发行说明,2014 年 2 月 14 日。
“从浅克隆存储库中获取数据过去是被禁止的, 主要是因为所涉及的代码路径没有经过仔细审查 我们并没有费心支持这种用法。此版本尝试 允许对象从浅克隆存储库中传输出来 更受控制的方式(即接收器变成浅存储库 历史被截断)。”
这对于浅层克隆者来说是个好消息。 下一步 - 可能缩小克隆范围。
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
rungit checkout <start_point>
. This allows you to start a new
history that records a set of paths similar to<start_point>
by
easily runninggit 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 runninggit 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
作为 Junio C. Hamano(主要 Git 维护者)
2014 年更新:请参阅“Is git clone --深度 1(浅克隆)比它显示的更有用吗?”: Git 1.9 将解除限制!
2015 年更新:使用 Git 2.5+,您甚至可以获取单个提交。请参阅“从远程 git 存储库中提取特定提交”
原始答案(2011 年 8 月):
所以它在某些情况下可以工作,但不受支持:
如果我必须对此说些什么......
有关浅克隆更新过程的更多信息,请参阅“如何更新 git 浅克隆?”。
As Junio C. Hamano (main Git maintainer) puts it:
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):
So it could work in some case, but it is not supported:
If I have to say something on this...
For more on the shallow clone update process, see "How to update a git shallow clone?".
是的,它将修复作为补丁发送。
git format-patch
是专门为实现此目的而设计的。如果你想通过谷歌搜索更多细节,它被称为“看门人”工作流程。很难相信像您这样关注“安全和 IP 保护”的组织还没有使用类似的东西,其中一个人或一个小组负责在将“不受信任”的更改纳入真正的构建之前对其进行审查。根据您的评论,我现在对您的要求有了更好的了解。我建议创建一个孤儿分支(请参阅git checkout --orphan) ,从您希望开发人员开始的位置开始。仅将该分支克隆到这些开发人员可以访问的不同存储库,并让他们从该存储库正常克隆、推送和拉取。
然后,当您需要将他们的更改重新集成到官方受保护的存储库时,只需拉出他们的分支,使用 gitbranch 复制它,这样您就不会覆盖原始的孤立分支(如果您想重复)稍后的过程),然后将副本重新设置为原始分支点,然后正常合并或进行其他操作。历史记录看起来就像它们直接从您受保护的存储库中工作一样。
这比正常情况要复杂一些,但这就是额外隔离所付出的代价。
Yes, it's to send in fixes as patches.
git format-patch
is specially designed to enable this. It's called a "gatekeeper" workflow, if you want to google for more details. It's hard to believe an organization as concerned with "security and IP protection" as yours isn't already using something similar, where one person or a small group is responsible for vetting "untrusted" changes before they make it into the real build.Based on your comment, I now have a better idea of your requirements. What I would recommend is creating an orphan branch (see git checkout --orphan), from whichever point you want your devs to start. Clone only that branch to a different repository accessible to those devs, and let them clone, push, and pull normally from that repo.
Then when you need to reintegrate their changes to the official protected repository, just pull their branch, make a copy of it with
git branch
so you don't overwrite your original orphan (in case you want to repeat the process later), then rebase the copy onto your original branch point, and merge or whatever as normal. The history will look like they worked directly from your protected repo.It's a little bit more complicated than normal, but that's the price paid for the extra isolation.
我找到了使用 git 包的解决方法。
此解决方案将像“git Push”一样将完全相同的提交复制到其他存储库,并且不需要重新设置基准或导致更改提交 ID。
不幸的是,它需要对目标主机进行 shell 访问(例如 ssh)。
我将通过示例展示解决方案。
首先,我们需要获得一个浅克隆用于演示目的。
让我们从 https://github.com/skarnet/s6- 获取单个提交版本 v0.5.0.0 rc 作为浅克隆进入新存储库。
我将在示例中使用 shell 变量,而不是直接在命令中包含示例设置,因为这将允许您在将变量设置为适用于您的情况的不同值之后,将本文中的指令直接复制/粘贴到您的 shell 中。
因此,请随意使用不同的 URL 和版本来替换以下变量分配。
在我们的示例中,可以使用以下命令创建浅层克隆:
这将创建一个包含新克隆的“s6-src”(当使用上述变量值时)子目录。
现在我们的浅层克隆只包含一个提交,并且本地存储库中缺少其所有父历史记录,我们将这个单个提交捆绑到一个 git 捆绑文件中:
这将使用 shell 创建文件 v0.5.0.0.gbnd之前设置的变量。
现在您必须将此文件复制到您通常想要推送到的目标计算机。 (只有 git Push 拒绝从浅克隆推送,因此不起作用,至少不能使用较旧的 git 版本。)
在目标主机上,执行以下操作以创建一个新存储库作为子目录,其中包含与之前捆绑:
请注意,您应该将变量设置为与复制捆绑包的主机上相同的值。
另请注意,如果存储库已经存在,您可以省略“git init”。
就是这样!
然而,后者的说明仅适用于定期结帐。
也许您想将浅克隆包导入到“裸”存储库中。
在这种情况下,请执行以下操作:
I found a workaround using git bundles.
This solution will replicate the exact same commits to the other repository like "git push" would do, and will not require rebasing or result in a changed commit ID.
It requires shell-access (such as ssh) to the target host, unfortunately.
I will show the solution by example.
First we need to get a shallow clone for demonstration purposes.
Lets fetch the single commit release v0.5.0.0 from https://github.com/skarnet/s6-rc into a new repository as a shallow clone.
I will use shell variables in my examples rather than including the example settings directly within the commands, because this will allow you to copy/paste the instruction from this posting directly into your shell, after setting the variables to different values which apply to your situation.
Therefore, feel free to replace the following variable assigmnents by using a different URL and release.
In the case of our example, the shallow clone can be created with:
This will create a "s6-src" (when using the above variable values) subdirectory containing the new clone.
Now that we have our shallow clone containing only a single commit with all its parent history missing in the local repository, we bundle this single commit into a git bundle file:
This will create file v0.5.0.0.gbnd making use of the shell variables set before.
Now you have to copy this file to the target machine where you would normally like to push to. (Only that git push refuses to push from shallow clones and will therefore not work, at least not using older git versions.)
On the target host, do the following in order to create a new repository as a subdirectory, containing the same commit as bundled before:
Note that you should set the variables to the same values as you did on the host from which the bundle was copied.
Also note that you can omit the "git init" it the repository already exists.
That's it!
However, the latter instructions only apply for regular checkouts.
Maybe you want to import a shallow clone bundle into a "bare" repository.
In this case, do the following instead: