How to clone git repository with specific revision/changeset?
Asked Answered
C

20

534

How can I clone git repository with specific revision, something like I usually do in Mercurial:

hg clone -r 3 /path/to/repository
Capybara answered 15/8, 2010 at 20:45 Comment(6)
Not specific to change-sets or revisions, but cloning the latest in a specific branch can be as effective i.e. git clone -b 10.1 https://github.com/MariaDB/server.git --depth=1 mariadb-server-srcMonteiro
Possible duplicate of Download a specific tag with GitJenny
Do you want the history to be shallow, i.e. only contain revision 3 in your example, or also it's parents?Craving
If the repository in question is being cloned from inside another repository and you want to clone that internal repo at a specific sha, then git submodules do exactly that in an automagical way.Schaefer
I'm sorry, but this entire thread proves how overly complicated git is. So much difficulty and confusion just to preform a simple basic task? I'll never understand how git became so popular.Uxorial
Best answer as of 2021 is the one by Peter Kovac: https://mcmap.net/q/13273/-how-to-clone-git-repository-with-specific-revision-changeset one single git clone command that downloads just that one commit.Scutari
U
321

UPDATE 2 Since Git 2.5.0 the feature described below can be enabled on server side with configuration variable uploadpack.allowReachableSHA1InWant, here the GitHub feature request and the GitHub commit enabling this feature. Note that some Git servers activate this option by default, e.g. Bitbucket Server enabled it since version 5.5+. See this answer on Stackexchange for a exmple of how to activate the configuration option.

UPDATE 1 For Git versions 1.7 < v < 2.5 use git clone and git reset, as described in Vaibhav Bajpai's answer

If you don't want to fetch the full repository then you probably shouldn't be using clone. You can always just use fetch to choose the branch that you want to fetch. I'm not an hg expert so I don't know the details of -r but in git you can do something like this.

# make a new blank repository in the current directory
git init

# add a remote
git remote add origin url://to/source/repository

# fetch a commit (or branch or tag) of interest
# Note: the full history up to this commit will be retrieved unless 
#       you limit it with '--depth=...' or '--shallow-since=...'
git fetch origin <sha1-of-commit-of-interest>

# reset this repository's master branch to the commit of interest
git reset --hard FETCH_HEAD
Unbar answered 15/8, 2010 at 22:40 Comment(25)
I don't think git fetch origin <sha1> works; it seems like you need to pass a named reference such as a tag or branch name. See kerneltrap.org/mailarchive/git/2009/1/13/4707444Brownout
@artur: You don't think it works, or you've tried it and it doesn't work?Unbar
With git 1.4, I found that I was able to use the git fetch origin <SHA1> to switch to any revision I wanted after I'd fetched the master from the remote and done the reset --hard to actual instantiate the branch locally. I was not able to fetch the individual revisions directly. With git 1.7, git fetch origin <SHA1> did not work, as reported by @artur; you need to use git checkout <SHA1> followed by a reset --hard.Atomism
How do I get the parameter to replace <sha1>?Toluol
@CharlesBailey yes, I have the same doubt as Danny, any answer? I have a project in bitbucket and I want to pull the content (I mean files and folders) of a specific commit.Resilient
@tirengarfio: I don't really understand. The question is about fetching a specific revision / changeset. You just use the id of the commit that you're interested it.Unbar
Fetching by SHA-1 will work only with http and rsync protocols. See kerneltrap.org/mailarchive/git/2009/1/14/4716044/…Trawler
Can someone explain the scary-sounding reset? If I want to just check if a bug was/wasn't in a particular revision, can I skip this resetting stuff? Like temporarily peeking at a previous revision.Quach
This answer is outdated. This doesn't work with git 1.7 nor git 1.8, neither with https:// nor ssh protocol. ("Couldn't find remote ref df44398762393c67af487edeb0831ad9579df4aa" – it isn't a ref, it is a commit.)Earthnut
@Trawler the kerneltrap links don't work anymore ... I guess you meant this message? marc.info/?l=git&m=123191657620781&w=2Earthnut
@PaŭloEbermann Indeed, complete thread at thread.gmane.org/gmane.comp.version-control.git/105475Trawler
@Trawler I would interpret that not as "will work with HTTP and rsync protocols", but "can't work with other protocols, but could be implemented with those two on the client side". With git 1.7.9.5 (on Ubuntu), it doesn't work with a https:// remote link either.Earthnut
Adding a --depth=1 flag to the fetch will not fetch the full commit history.Jodee
Downvoted: tried it and not working ( fatal: ambiguous argument 'FETCH_HEAD': unknown revision or path not in the working tree. ), the commit hash I given exists. Later seen the answer below, which is strongly easier and working. You may edit your answer to give @Vaibhav's answer too.Bogle
********P L E A S E********* Remove this as the accepted answer. This is out of date, and has not worked for several years (that is several years worth of git versions)Cioban
This does not work in 2.3.4. Specifically, the fetch completes, but the checkout complains that "<SHA1> is not a tree".Mcdougall
THis is no longer valid with current GIT versions. I downvoted because this is now a version specific function, and a server needs to allow SHAs to be checked out. otherwise it must be a tag/branchBitten
This worked for me despite all of these comments - weird. Version 2.14.3Bellwether
Answered like a true, logically thinking programmer +1Caught
2018-08-20 This works for me. Git version on server side: 2.12.2, Git version on client side 2.16.2. I'm using this solution with --depth=1 and am very happy! 2018-08-21 I updated the answer with details about how to enable this feature in Git repositories and the Git versions supporting this feature.Ligule
Looks like GitHub may have dropped support for this feature recently. I know use the GitHub v3 API to: 1) Create a ref that points to the commit 2) Checkout the ref using the same method detailed in this answer 3) Delete the ref blankenship.io/file/content-addressable-githubYingling
As a note: to fetch from GitHub you'll need to use git -c protocol.version=2 fetch origin <sha>.Olomouc
I just used this with github https and git client from ubuntu 18 and it worked fine. Did not specify protocols or anything specificSapp
Thanks, you have saved my day. I was getting an error ('reference is not a tree' error) while checking out a particular commit from an old repository. I used your answer as a workaround for directly checking out a commit from that repository, works super fine!!!Particulate
Still works with Git 2.30.2 and GitHub. git checkout gave an error similar to Himanshu'sArrestment
I
977
$ git clone $URL
$ cd $PROJECT_NAME
$ git reset --hard $SHA1

To again go back to the most recent commit

$ git pull

To save online (remote) the reverted commit, you must to push enforcing origin:

git push origin -f
Infrastructure answered 30/12, 2012 at 13:41 Comment(7)
This works only if the commit is in the master branch, if not it is gonna mess-up the local reference. Why git reset and not git checkout in the first place?Crayton
This is not a good option for large repos, as it pulls everything.Jodee
Isn't there a cd missing?Aptitude
@FlorianSegginger If I'm looking to clone a specific revision it's probably that I don't want to clone everything, but just that revision. To me that was the question asked. This solution answers a different question: "How do I view a specific revision in my repo?". Fetching the entire repo is exactly what a lot of people here wants to avoid.Diller
Doesn't address the actual question IMHO, since being able to specify a revision during clone also allows me to use --depth which is very important for large repos. This solution requires pulling all objects, and then resetting to an earlier revision. This is very time consuming and wasteful of network bandwidth.Brewis
But this clones whole repository which is useless,.Macula
git checkout is a cleaner way of doing this than mucking than with resettingGavriella
U
321

UPDATE 2 Since Git 2.5.0 the feature described below can be enabled on server side with configuration variable uploadpack.allowReachableSHA1InWant, here the GitHub feature request and the GitHub commit enabling this feature. Note that some Git servers activate this option by default, e.g. Bitbucket Server enabled it since version 5.5+. See this answer on Stackexchange for a exmple of how to activate the configuration option.

UPDATE 1 For Git versions 1.7 < v < 2.5 use git clone and git reset, as described in Vaibhav Bajpai's answer

If you don't want to fetch the full repository then you probably shouldn't be using clone. You can always just use fetch to choose the branch that you want to fetch. I'm not an hg expert so I don't know the details of -r but in git you can do something like this.

# make a new blank repository in the current directory
git init

# add a remote
git remote add origin url://to/source/repository

# fetch a commit (or branch or tag) of interest
# Note: the full history up to this commit will be retrieved unless 
#       you limit it with '--depth=...' or '--shallow-since=...'
git fetch origin <sha1-of-commit-of-interest>

# reset this repository's master branch to the commit of interest
git reset --hard FETCH_HEAD
Unbar answered 15/8, 2010 at 22:40 Comment(25)
I don't think git fetch origin <sha1> works; it seems like you need to pass a named reference such as a tag or branch name. See kerneltrap.org/mailarchive/git/2009/1/13/4707444Brownout
@artur: You don't think it works, or you've tried it and it doesn't work?Unbar
With git 1.4, I found that I was able to use the git fetch origin <SHA1> to switch to any revision I wanted after I'd fetched the master from the remote and done the reset --hard to actual instantiate the branch locally. I was not able to fetch the individual revisions directly. With git 1.7, git fetch origin <SHA1> did not work, as reported by @artur; you need to use git checkout <SHA1> followed by a reset --hard.Atomism
How do I get the parameter to replace <sha1>?Toluol
@CharlesBailey yes, I have the same doubt as Danny, any answer? I have a project in bitbucket and I want to pull the content (I mean files and folders) of a specific commit.Resilient
@tirengarfio: I don't really understand. The question is about fetching a specific revision / changeset. You just use the id of the commit that you're interested it.Unbar
Fetching by SHA-1 will work only with http and rsync protocols. See kerneltrap.org/mailarchive/git/2009/1/14/4716044/…Trawler
Can someone explain the scary-sounding reset? If I want to just check if a bug was/wasn't in a particular revision, can I skip this resetting stuff? Like temporarily peeking at a previous revision.Quach
This answer is outdated. This doesn't work with git 1.7 nor git 1.8, neither with https:// nor ssh protocol. ("Couldn't find remote ref df44398762393c67af487edeb0831ad9579df4aa" – it isn't a ref, it is a commit.)Earthnut
@Trawler the kerneltrap links don't work anymore ... I guess you meant this message? marc.info/?l=git&m=123191657620781&w=2Earthnut
@PaŭloEbermann Indeed, complete thread at thread.gmane.org/gmane.comp.version-control.git/105475Trawler
@Trawler I would interpret that not as "will work with HTTP and rsync protocols", but "can't work with other protocols, but could be implemented with those two on the client side". With git 1.7.9.5 (on Ubuntu), it doesn't work with a https:// remote link either.Earthnut
Adding a --depth=1 flag to the fetch will not fetch the full commit history.Jodee
Downvoted: tried it and not working ( fatal: ambiguous argument 'FETCH_HEAD': unknown revision or path not in the working tree. ), the commit hash I given exists. Later seen the answer below, which is strongly easier and working. You may edit your answer to give @Vaibhav's answer too.Bogle
********P L E A S E********* Remove this as the accepted answer. This is out of date, and has not worked for several years (that is several years worth of git versions)Cioban
This does not work in 2.3.4. Specifically, the fetch completes, but the checkout complains that "<SHA1> is not a tree".Mcdougall
THis is no longer valid with current GIT versions. I downvoted because this is now a version specific function, and a server needs to allow SHAs to be checked out. otherwise it must be a tag/branchBitten
This worked for me despite all of these comments - weird. Version 2.14.3Bellwether
Answered like a true, logically thinking programmer +1Caught
2018-08-20 This works for me. Git version on server side: 2.12.2, Git version on client side 2.16.2. I'm using this solution with --depth=1 and am very happy! 2018-08-21 I updated the answer with details about how to enable this feature in Git repositories and the Git versions supporting this feature.Ligule
Looks like GitHub may have dropped support for this feature recently. I know use the GitHub v3 API to: 1) Create a ref that points to the commit 2) Checkout the ref using the same method detailed in this answer 3) Delete the ref blankenship.io/file/content-addressable-githubYingling
As a note: to fetch from GitHub you'll need to use git -c protocol.version=2 fetch origin <sha>.Olomouc
I just used this with github https and git client from ubuntu 18 and it worked fine. Did not specify protocols or anything specificSapp
Thanks, you have saved my day. I was getting an error ('reference is not a tree' error) while checking out a particular commit from an old repository. I used your answer as a workaround for directly checking out a commit from that repository, works super fine!!!Particulate
Still works with Git 2.30.2 and GitHub. git checkout gave an error similar to Himanshu'sArrestment
D
152

To clone only one single specific commit on a particular branch or tag use:

git clone --depth=1 --branch NAME https://github.com/your/repo.git

Unfortunately, NAME can only be branch name or tag name (not commit SHA).

Omit the --depth flag to download the whole history and then checkout that branch or tag:

git clone --branch NAME https://github.com/your/repo.git

This works with recent version of git (I did it with version 2.18.0).

Divergency answered 9/8, 2018 at 16:16 Comment(9)
but not on older version 2.17.1Symbol
This needs more upvotes. This is much better than other outdated answers.Godmother
Am I interpreting this right: when you want to get a revision via a tag, you still have to use --branch, even though you don't have anything in mind related to any branch whatsoever?Kingcraft
@Kingcraft yes, the --branch option is used for both branches and tagsDivergency
Where do you specify the commit?Misdoing
@Misdoing Replace NAME with a tag or branch. Specific commits aren't supported, but you can use git checkout on an existing repo to revert to previous commitsArrestment
@Arrestment so it's impossible to clone a repository at a specific commit?Misdoing
@PeterKovac Using depth clones from the tip of the specified branch. Can you clone from a branch's initial commit? like git clone --depth 1 <url> which clones only the first commit, in chronological order?Mink
@Étienne NAME can be neither SHA nor a refspec (e.g. for Gerrit paths) so in general case better answer is git init; git fetch <remote> <revision>Victorious
A
59

Cloning a git repository, aptly, clones the entire repository: there isn't a way to select only one revision to clone. However, once you perform git clone, you can checkout a specific revision by doing checkout <rev>.

Agnail answered 15/8, 2010 at 20:49 Comment(7)
I don't want to clone only one revision. I just want to specify the limit of cloning. Other words, I want to clone everything up to the specified revision.Capybara
You can't do that. git clone grabs the whole repository. Once you have it, you can then checkout a specific revision.Agnail
One thing to note; Git is generally pretty efficient about storing history, so it's not as if you'd save massive amounts of space by only cloning half the revisions.Shane
It's not about "saving space" -- it's about only getting up to a specific revision -- like if a new change introduced a bug, and so I don't want that newest change -- you're saying Git can't do this? That can't be right -- why have source control at all if you can't roll back to an older version?Globular
@BrainSlugs83: You can use reset/branch/checkout after you cloned the history to go to an old version, and forget the newer ones.Earthnut
"there isn't a way to select only one revision to clone" - yes, there is: git clone --single-branch ...Anabolism
Didn't know it was this simple!Bathos
V
39

You can use simply git checkout <commit hash>

in this sequence

git clone [URLTORepository]
git checkout  [commithash]

commit hash looks like this 45ef55ac20ce2389c9180658fdba35f4a663d204.

Vane answered 3/8, 2013 at 21:35 Comment(2)
like previous one - why checkout after you clone. Once you clone , you have the entire history in the local repo. Why does this answer has too many upvotes?Jugurtha
@DmitryPerfilyev you seem to not get the point of the question: git checkout makes the revision current. If you simply clone, you are at the tip of the default (or specified) branch, which is often not what you wanted.Masakomasan
B
31

If you mean you want to fetch everything from the beginning up to a particular point, Charles Bailey's answer is perfect. If you want to do the reverse and retrieve a subset of the history going back from the current date, you can use git clone --depth [N] where N is the number of revs of history you want. However:

--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.

Bini answered 15/8, 2010 at 22:45 Comment(1)
Newer version of git have improved shallow clones, and you can pull and push from it.Aubergine
D
26

Just to sum things up (git v. 1.7.2.1):

  1. do a regular git clone where you want the repo (gets everything to date — I know, not what is wanted, we're getting there)
  2. git checkout <sha1 rev> of the rev you want
  3. git reset --hard
  4. git checkout -b master
Deckert answered 4/3, 2012 at 20:7 Comment(4)
what do steps 3 and 4 do?Globular
Step 4 didn't work for me, but up to step 3 did the trick - ThanksConceptualism
@BrainSlugs83: Step 4 creates a local branch called master and switches to it.Theophylline
@phill: Why the git reset --hard? The docs for that say "Resets the index and working tree. Any changes to tracked files in the working tree since <commit> [which defaults to HEAD, which is now <sha1 rev>] are discarded." But at this point we haven't made any changes since cloning, so what's the purpose? Does it truncate the current branch at <sha1 rev>?Theophylline
S
18

TL;DR - Just create a tag in the source repository against the commit you want to clone up to and use the tag in the fetch command. You can delete the tag from the original repo later to clean up.

Well, its 2014 and it looks like Charles Bailey's accepted answer from 2010 is well and truly outdated by now and most (all?) of the other answers involve cloning, which many people are hoping to avoid.

The following solution achieves what the OP and many others are looking for, which is a way to create a copy of a repository, including history, but only up to a certain commit.

Here are the commands I used with git version 2.1.2 to clone a local repo (ie. a repository in another directory) up to a certain point:

# in the source repository, create a tag against the commit you want to check out
git tag -m "Temporary tag" tmptag <sha1>

# create a new directory and change into that directory
cd somewhere_else;mkdir newdir;cd newdir

# ...and create a new repository
git init

# add the source repository as a remote (this can be a URL or a directory)
git remote add origin /path/to/original/repo

# fetch the tag, which will include the entire repo and history up to that point
git fetch origin refs/tags/tmptag

# reset the head of the repository
git reset --hard FETCH_HEAD

# you can now change back to the original repository and remove the temporary tag
cd original_repo
git tag -d tmptag

Hopefully this solution keeps working for a few more years! :-)

Spiritoso answered 18/11, 2014 at 23:56 Comment(1)
This is a good idea of you are the owner of the repo, not sure if it works with public repos that you don't maintainRaymer
S
15

No need to download the whole history, and no need to call git init:

git clone --depth=1 URL
git fetch --depth=1 origin SHA1
git checkout SHA1
git branch -D @{-1}  # if you want to tidy up the fetched branch

This has the disadvantage, to CB Baileys answer, that you will still download 1 unnecessary revision. But it's technically a git clone (which the OP wants), and it does not force you to download the whole history of some branch.

Subphylum answered 18/4, 2022 at 12:9 Comment(3)
this didn't work for me. if the SHA1 is older than the --depth, or in a different branch than the default, then it won't be fetched and so the checkout fails.Outgeneral
@Outgeneral It works in both of these cases with git 2.40.0. Can you prove the opposite?Subphylum
Gulp, I tested it better and it did work. I bet that I used the short hash but that doesn't work, I seemed to need the full SHA1 hash with no truncation, at least for the fetch command. fatal: Couldn't find remote ref faf2a5a6. So I upvoted your method, it's great.Outgeneral
S
6

I was able to accomplish this using the git clone --config option, which I learned from this answer: https://mcmap.net/q/13553/-why-does-quot-git-clone-quot-not-take-a-refspec

My scenario involves a sparse checkout in an Azure DevOps pipeline, where I need to clone a repo using a commit hash, not a branch name. The clone command doesn't accept a commit hash as a parameter. The workaround is to set a configuration variable (-c) containing a refspec, because that refspec can use a commit hash instead of a branch name:

git clone -c remote.origin.fetch=+<commit hash>:refs/remotes/origin/<commit hash> <repo_url> --no-checkout --progress --depth 1
git sparse-checkout init --cone
git sparse-checkout set <file list>
git checkout <commit hash>
Supporter answered 19/7, 2021 at 21:6 Comment(1)
Cool approach. This seems to be the converse of git clone --branch ... where this only accepts a SHA, but won't work with a branch name or tag. Just saving people like me from having to find that out by trial and error so you know what this is useful for.Coimbra
A
2

Using 2 of the above answers (How to clone git repository with specific revision/changeset? and How to clone git repository with specific revision/changeset?) Helped me to come up with a definative. If you want to clone up to a point, then that point has to be a tag/branch not simply an SHA or the FETCH_HEAD gets confused. Following the git fetch set, if you use a branch or tag name, you get a response, if you simply use an SHA-1 you get not response.
Here's what I did:- create a full working clone of the full repo, from the actual origin

cd <path to create repo>
git clone git@<our gitlab server>:ui-developers/ui.git 

Then create a local branch, at the point that's interesting

git checkout 2050c8829c67f04b0db81e6247bb589c950afb14
git checkout -b origin_point

Then create my new blank repo, with my local copy as its origin

cd <path to create repo>
mkdir reduced-repo
cd reduced-repo
git init
git remote add local_copy <path to create repo>/ui
git fetch local_copy origin_point

At that point I got this response. I note it because if you use a SHA-1 in place of the branch above, nothing happens, so the response, means it worked

/var/www/html/ui-hacking$ git fetch local_copy origin_point
remote: Counting objects: 45493, done.
remote: Compressing objects: 100% (15928/15928), done.
remote: Total 45493 (delta 27508), reused 45387 (delta 27463)
Receiving objects: 100% (45493/45493), 53.64 MiB | 50.59 MiB/s, done.
Resolving deltas: 100% (27508/27508), done.
From /var/www/html/ui
 * branch            origin_point -> FETCH_HEAD
 * [new branch]      origin_point -> origin/origin_point

Now in my case, I then needed to put that back onto gitlab, as a fresh repo so I did

git remote add origin git@<our gitlab server>:ui-developers/new-ui.git

Which meant I could rebuild my repo from the origin_point by using git --git-dir=../ui/.git format-patch -k -1 --stdout <sha1> | git am -3 -k to cherry pick remotely then use git push origin to upload the whole lot back to its new home.

Hope that helps someone

Antons answered 7/1, 2016 at 10:47 Comment(4)
Can you explain what you mean with "FETCH_HEAD gets confused"? And how does your git fetch local_copy origin_point differ from JamesGs git fetch origin refs/tags/tmptag?Syllogistic
The git fetch local_copy origin_point leave you in a state with an empty reduced-repo directory, only containing a .git. There is something else missing to these instructions...Syllogistic
short answer, they're the same. any branch or tag, is a ref, so refs/tags/<sometag> is equivalent to what I said. Can't remember what I meant by FETCH_HEAD, but sometimes tokens in git must be a ref (sometimes it can be a ref or sha). This is one of those times.Antons
Re the 2nd comment, your questions suggests a misunderstanding. Any git checkout, has 2 storage devices. The Repositories (which are 'always' fully synced using fetch), and The Context (which set of files, is currently reconstructed from the repositories). My objective was to sync Repositories, only up to a point. I did not want a Context. Hence I was just using git fetch. From those Repositories, I could get a context matching any sha or ref. What I was attempting was to clone a partial Repository copy (starting with origin_point), rather than the normal, full copy (full history).Antons
C
2
# clone special tag/branch without history
git clone --branch=<tag/branch> --depth=1 <repository>


# clone special revision with minimal histories
git clone --branch <branch> <repository> --shallow-since=yyyy-MM-ddTHH:mm:ss  # get the commit time
cd <dir>
git reset --hard <revision> 

you can't get a revision without histories if not set uploadpack.allowReachableSHA1InWant=true on server side, while you can create a tag for it and clone the special tag instead.

Carmelcarmela answered 14/4, 2020 at 9:42 Comment(0)
A
2

Full workflow for cloning a single branch, choosing a commit, then checking out that specific commit... This method requires git version 2.28.0 or higher to use the option --no-write-fetch-head, tested with version 2.35.3. (If you already know the full sha1 hash of the commit you want, please skip ahead to the second method available in the final code block)

#Create empty git repo
mkdir repo && cd repo && git init

#add remote, configure it to track <branch>
git remote add --no-tags -t <branch> -m <branch> origin <url>

#fetch objects from remote repo
git fetch --no-write-fetch-head

#examine commits and logs to decide which one we will use
git log --oneline origin

#Once you have found the commit of interest copy the abbreviated hash or save as variable
commit=<sha1>

#rename our default branch to match remote branch
git branch -m <branch>

#set branch head to desired commit
git branch <branch> $commit

#set remote branch as upstream for <branch>
git branch -u origin <branch>

#All done time to checkout
git checkout

To optionally truncate the history of the local branch execute :

git fetch --no-write-fetch-head --depth <n> ./ <branch>

To truncate the remote branch history you can execute the following, but keep in mind that if you truncate history to a commit newer than the commit you checked out git status will tell you that you have diverged from the remote by <n> commits

git fetch --no-write-fetch-head --depth <n>

If you don't need remote tracking and already know the the full commit hash :

mkdir repo && cd repo && git init
git remote add --no-tags origin <url>
git fetch --depth 1 --no-write-fetch-head origin <sha1>
#Set default local branch (master in this case) head to <sha1>
git branch master <sha1>
git checkout

What makes this method better in my opinion is that it truly fetches only a single commit. We also avoid creating a FETCH_HEAD or ORIG_HEAD leaving our .git directory squeaky clean. This also leaves the reflog clean (with a single entry) as opposed to having two entries due to a git reset --hard commit Without the need for remote tracking and using fetch --depth 1 it creates the smallest possible clone (shallow clone).

Aerology answered 5/3, 2022 at 17:28 Comment(3)
git fetch --depth=1 --no-write-fetch-head [email protected]:torvalds/linux.git 9154301a47b33bdc273d8254c407792524367558 error: unknown option `no-write-fetch-head'Oviduct
git version 2.17.1Oviduct
The option --no-write-fetch-head was added in version 2.28Aerology
C
1

My version was a combination of accepted and most upvoted answers. But it's a little bit different, because everyone uses SHA1 but nobody tells you how to get it

$ git init
$ git remote add <remote_url>
$ git fetch --all

now you can see all branches & commits

$ git branch -a
$ git log remotes/origin/master <-- or any other branch

Finally you know SHA1 of desired commit

git reset --hard <sha1>
Cigar answered 28/10, 2016 at 10:27 Comment(1)
You can use git ls-remote <repo> <pattern> to list remote refs (including the hash). pattern is the name of a reference or a shell glob. If you omit pattern all refs are listed. Can optionally use --tags or --heads as an additional filter.Aerology
S
1

I would suggest git clone --single-branch --branch NAME https://github.com/your/repo.git as explained below.

The following are given in other answers.

  1. Clone the entire repository, then git reset --hard $SHA1 to go to the specific commit given by that hash. (Vaibhav Bajpai)
  2. git clone --depth=1 --branch NAME https://github.com/your/repo.git to only get the latest commit in the specific branch and nothing else (no history, no other branches) (Peter Kovac)
  3. git clone --branch NAME https://github.com/your/repo.git to get all history (of the desired branch AND other branches) and point to the latest commit of the desired branch (Peter Kovac)

However, they do not appear to exactly match what the question is asking for, for the following reasons (corresponding to the 3 suggestions above):

  1. Clones the entire repository, not just the desired branch; for the hard reset to work, it assumes the desired commit is on the default/master branch.
  2. Only the latest commit in the desired branch is obtained. History of the desired branch is not obtained.
  3. The commit structure/history of the whole tree (including other branches) is obtained, which may be more than what the question requires.

I would suggest that git clone --single-branch --branch NAME https://github.com/your/repo.git provides the most matching answer, with just the whole single branch history obtained, and the HEAD pointer pointing to the latest commit (we see it as a straight line with git log --all --graph with HEAD pointing to the commit at the top/tip), whereas:

  • with git clone --depth=1 --branch NAME https://github.com/your/repo.git then git log --all --graph only shows the tip of the branch
  • with git clone --branch NAME https://github.com/your/repo.git then git log --all --graph shows the tree structure with the desired branch and other branches branching at various times from various other commits.

The above were all tested with git version 2.24.3 ; I've read that --single-branch was added in git version 1.7.10.

Single answered 1/5, 2023 at 4:45 Comment(0)
S
-1

I use this snippet with GNU make to close any revision tag, branch or hash

it was tested on git version 2.17.1

${dir}:
    mkdir -p ${@D}
    git clone --recursive --depth 1 --branch ${revison} ${url} ${@} \
 || git clone --recursive --branch ${revison} ${url} ${@} \
 || git clone ${url} ${@}
    cd ${@} && git reset --hard ${revison}
    ls $@
Symbol answered 27/6, 2019 at 18:28 Comment(0)
O
-1
mkdir linux-4.3.20151106
cd linux-4.3.20151106/
git init
git fetch [email protected]:torvalds/linux.git 9154301a47b33bdc273d8254c407792524367558

error: unknown option `no-write-fetch-head'        
usage: git fetch [<options>] [<repository> [<refspec>...]]   or: git fetch [<options>] <group>                                      
   or: git fetch --multiple [<options>] [(<repository> | <group>)...]   or: git fetch --all [<options>]       



 git --version
git version 2.17.1

export https_proxy=http://192.168.1.3:1080;export http_proxy=http://192.168.1.3:1080
add-apt-repository ppa:git-core/ppa
apt update
apt-get install --only-upgrade git

 git --version
git version 2.38.0


 git fetch [email protected]:torvalds/linux.git 9154301a47b33bdc273d8254c407792524367558 --no-write-fetch-head --depth=1 
remote: Enumerating objects: 54692, done.
remote: Counting objects: 100% (54692/54692), done.
remote: Compressing objects: 100% (50960/50960), done.
remote: Total 54692 (delta 3828), reused 29210 (delta 2966), pack-reused 0
Receiving objects: 100% (54692/54692), 147.35 MiB | 2.85 MiB/s, done.
Resolving deltas: 100% (3828/3828), done.
 


git branch master 9154301a47b33bdc273d8254c407792524367558


git checkout
 
Oviduct answered 4/10, 2022 at 8:9 Comment(0)
D
-2

git clone https://github.com/ORGANIZATION/repository.git (clone the repository)

cd repository (navigate to the repository)

git fetch origin 2600f4f928773d79164964137d514b85400b09b2

git checkout FETCH_HEAD

Dismiss answered 10/7, 2018 at 5:59 Comment(1)
why fetch after you clone. Once you clone , you have the entire history in the local repo. Why does this answer has two upvotes?Nevins
S
-2

For single files and when the commit number is known, one can use a wget onliner:

wget https://raw.githubusercontent.com/torvalds/linux/896066ee1cf4d653057dac4e952f49c96ad16fa7/README
Sociometry answered 15/8, 2021 at 19:12 Comment(1)
OP is asking for how to clone.Urticaceous
S
-7
git clone -o <sha1-of-the-commit> <repository-url> <local-dir-name>

git uses the word origin in stead of popularly known revision

Following is a snippet from the manual $ git help clone

--origin <name>, -o <name>
    Instead of using the remote name origin to keep track of the upstream repository, use <name>.
Sauls answered 6/6, 2015 at 8:2 Comment(11)
No idea why you're getting downvoted here; this was exactly what I was hoping to see for my use case: Getting a particular version of the Linux kernel from a version they did not have the good sense to tag as a release (seems to be a problem with the RPi people), without downloading the whole multi-gigabyte history of Linux. Incidentally, it worked a treat.Resale
@Resale The answerer has clearly misunderstood the meaning of "origin" completely. With or without the -o, you get the full 1.3G of Linux history (which is around twice the size of the actual working copy).Gog
Er. When I say, "it worked a treat", I mean it did what was on the tin. Combined with the nominal --depth=1 to limit the set of revisions I get, i got a 150M download, at the revision I requested. Is it not supposed to do that? Should I file a bug report?Resale
--depth=1 is not mentioned in the answer, so why would you say this answer worked if you added more things that aren't mentioned here? I'm happy it worked out for you, but this answer is misleading and doesn't answer the question even in part. Hence the downvotes.Gog
The question asked above was "How to clone git repository with specific revision/changeset?", which this answered correctly. The additional requirement was mine, as was the additional solution. I still don't understand why you think it's misleading. It's the only one that lets you select a revision at clone-time. Admittedly, this is only useful if you're looking to use --depth=1, but still, it's good information, despite the undeserved downvotes.Resale
I come from the svn school! Every commit is assigned a revision no. in svn; and hence my use of the word <revision> interchangably with <sha1-of-the-commit> and with <name> --- the one being used as a parameter for -o. --origin This was probably my first answer in SO! I am happy to see that my words resonate with a @Resale ; Thanks!Sauls
Downvotes are as equally admired, as are upvotes! Thanks for the explanation @EmilStyrke --- this does help me understand the common knowledge.Sauls
@Fordi: No. Using this answer verbatim gets you exactly the same tree as you'd get from a vanilla git clone <url> <local_dir_name>, just try it for yourself. The only difference is that the remote (shown using git remote) will be called some cryptic sha1 sequence instead of the name "origin" that is customary. In other words, the <sha1-of-the-commit> mentioned in this answer has no bearing whatsoever on which revisions are fetched from the server or which branch will be checked out.Gog
@Fordi: I just did git clone -o 896066ee1cf4d653057dac4e952f49c96ad16fa7 https://github.com/torvalds/linux.git linux --depth=1. This gives me revision 8a28d674 and not 896066ee as you and this answer claims.Gog
emphasizing that "origin" has nothing to do with "revision" and this answer is completely wrong.Fussy
Downvoted because it doesn't actually choose any revision. Very misleading and dangerous.Dania

© 2022 - 2024 — McMap. All rights reserved.