Git clone --single-branch does not work for sha / commit ids?

谁说我不能喝 提交于 2019-12-24 10:48:43

问题


This works:

 git clone --branch='master' \
    --single-branch \
    git@bitbucket.org:teros/datavana.git 

but this doesn't:

commit='fda0b49f81d0b67ad8a1413eca129498b9eb61db'

git clone --branch="$commit" \
    --single-branch  \
    git@bitbucket.org:teros/datavana.git 

the error I get is:

Cloning into 'datavana'...
Warning: Permanently added the RSA host key for IP address 'xx.xxx.93.1' to the list of known hosts.
warning: Could not find remote branch fda0b49f81d0b67ad8a1413eca129498b9eb61db to clone.
fatal: Remote branch fda0b49f81d0b67ad8a1413eca129498b9eb61db not found in upstream origin

I know for sure that the git commit id is in the remote - so is there some reason this won't work? Is there a way to clone a single commit (instead of by branch name)?


回答1:


This was intentional, to allow some control over what could be fetched from repos, especially in setups where a single object db serves multiple repos.

You can enable fetching any arbitrary sha by setting uploadpack.allowanysha1inwant in the upstream repo, after which you'll be able to fetch arbitrary sha's from it by giving the full hash, but git clone isn't set up for arbitrary refspecs, you'll have to e.g.

git init .
git remote add origin git@bitbucket.org:teros/datavana.git
git fetch origin fda0b49f81d0b67ad8a1413eca129498b9eb61db:refs/heads/newbranch

where the init and remote add are basically everything extra the clone does for you anyway.

I don't know whether anything but Git itself supports this.




回答2:


At a technical level, it doesn't work because the SHA is not a branch or tag name. As documented on the git clone page (https://git-scm.com/docs/git-clone) the --branch option takes a branch name or a tag name, not an arbitrary expression that resolves to any old commit.

But that's different from most commands that want you to specify a commit.... so why?

The motivation for this is kinda-sorta-security; the idea is a commit that's rewritten out of the remote's refs' history cannot be accessed by someone who knows its SHA even if it hasn't been physically deleted.

More complex rules (like taking any expression but having the server verify that the resulting commit is reachable) could accomplish that too... but they're more complicated, and at least as of now that's not something the git devs have felt the need to support.




回答3:


As Mark Adelsberger said, this is a pseudo-security1 feature. However, it's not actually limited to clone's --single-branch / --branch options. It also applies to git fetch.

There is a configuration knob you can set in a repository to enable things. In fact, there are two of them, both listed in the git config documentation:

uploadpack.allowReachableSHA1InWant

      Allow upload-pack to accept a fetch request that asks for an object that is reachable from any ref tip. However, note that calculating object reachability is computationally expensive. Defaults to false. Even if this is false, a client may be able to steal objects via the techniques described in the "SECURITY" section of the gitnamespaces[7] man page; it’s best to keep private data in a separate repository.

uploadpack.allowAnySHA1InWant

      Allow upload-pack to accept a fetch request that asks for any object at all. Defaults to false.

Since these both default tofalse, your standard Git server won't let you do what you want. If you have access to the server itself, though, you can configure one (or both but that's redundant) to true. Once you do that, you can:

  • git clone --depth 1 any branch at all
  • git fetch the one commit you want, by hash ID (create a branch name if you like, or let the old FETCH_HEAD compatibility stuff remember the hash ID)
  • check out the one commit you want (now HEAD holds the hash ID as a detached HEAD)

and then optionally delete the one branch you cloned shallowly. (You still have a shallow repository, which you can't really deepen properly since you don't know which branch name(s) to key off of from your origin. But no doubt the reason you're doing all this is to get just the one commit.)

(Or, see jthill's answer: git init, etc., then fetch.)

Consider also / instead, using git archive to make a non-Git-repo archive out of the (single) commit you want.


1Pseudo-security: because it superficially resembles security, but may not actually be secure. See Pseudo-.



来源:https://stackoverflow.com/questions/57316783/git-clone-single-branch-does-not-work-for-sha-commit-ids

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!