I want to checkout a specific version of a specific file from a remote git repo, without downloading other unnecessary files or history.
Given a $URL
in the format .git
, and a $REVISION
which should accept a branch name, a tag name, or a short or long commit hash, I have this solution:
git clone --depth 1 --no-checkout $URL .
git fetch origin $REVISION
git checkout FETCH_HEAD -- foo.txt
but it does not work on short commit hashes. The fetch step fails with fatal: couldn't find remote ref
, but works with the full-length hash. Is there a general solution that also works on short hashes?
The solution here, using git show
, does not work because it assumes that the revision already exists locally.
I want to checkout a specific version of a specific file from a remote git repo, without downloading other unnecessary files or history.
Given a $URL
in the format https://github.com/foo/bar.git
, and a $REVISION
which should accept a branch name, a tag name, or a short or long commit hash, I have this solution:
git clone --depth 1 --no-checkout $URL .
git fetch origin $REVISION
git checkout FETCH_HEAD -- foo.txt
but it does not work on short commit hashes. The fetch step fails with fatal: couldn't find remote ref
, but works with the full-length hash. Is there a general solution that also works on short hashes?
The solution here, using git show
, does not work because it assumes that the revision already exists locally.
- Is it ok for a Github specific solution? – Schwern Commented Jan 22 at 0:57
- Ideally it should work for any git server, but if that's not possible, a Github specific solution might be helpful to someone – em_ly Commented Jan 22 at 3:59
1 Answer
Reset to default 3Expanding a short commit hash to its full hash requires already having that commit locally (on the system doing the expansion) as otherwise the hashes aren't known at all. Since you're only trying to git fetch
it just now, that means Git can't expand it to a full hash locally – and unfortunately, it also cannot ask the server to expand it, either, as the protocol requires full-length hashes or refs.
So you will have to fetch all commits first, or otherwise discover the full hash and specify that.
Instead of a shallow clone, I would suggest cloning with --filter=tree:0
or blob:none
(filtered clone) so that all commit objects will be available locally even though their contents are not. This will allow Git to locally expand the short commit IDs and will even make it automatically fetch the necessary individual objects when you try to checkout
them.
Non-GitHub hosted repositories need both capabilities enabled manually (on the server side, i.e. the repository that you're cloning from):
git config uploadpack.allowFilter true
git config uploadpack.allowReachableSHA1InWant true