问题
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 tofalse
. 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 tofalse
.
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 allgit fetch
the one commit you want, by hash ID (create a branch name if you like, or let the oldFETCH_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