src-d / go-git

Project has been moved to: https://github.com/go-git/go-git
https://github.com/go-git/go-git
Apache License 2.0
4.91k stars 542 forks source link

Git clone shallow depth=1 --branch=TAG: `error: reference not found` for given Tag as branch #1277

Closed marcellodesales closed 4 years ago

marcellodesales commented 4 years ago

The git shallow is something we are looking at to solve clones of a single revision requested by Tag. The way to implement it is to use the shallow clones of a particular revision (branch, tag or SHA). The first test with git shows the single revision, cloned to dir /tmp/protobuf2, gives the expected result, while the one with go-git is failing with error: reference not found...

Regular Git Shallow

$ git clone --depth=1 https://github.com/protocolbuffers/protobuf --branch v3.10.0  /tmp/protobuf2
Cloning into '/tmp/protobuf2'...
remote: Enumerating objects: 2415, done.
remote: Counting objects: 100% (2415/2415), done.
remote: Compressing objects: 100% (1769/1769), done.
remote: Total 2415 (delta 941), reused 1200 (delta 524), pack-reused 0
Receiving objects: 100% (2415/2415), 5.08 MiB | 1.20 MiB/s, done.
Resolving deltas: 100% (941/941), done.
Note: switching to '6d4e7fd7966c989e38024a8ea693db83758944f1'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false
$ git --no-pager lol
* 6d4e7fd (grafted, HEAD, tag: v3.10.0) Merge pull request #6721 from protocolbuffers/rafi-kamal-patch-1

go-git returns error: reference not found when refs/tag or ref/heads is not provided

func main() {
        // Clone the given repository to the given directory
    CheckArgs("<url>", "<directory>")
    url := os.Args[1]
    directory := os.Args[2]
    revision := os.Args[3]

    // Clone the given repository to the given directory
    Info("git clone --depth=1 %s --branch %s %s", url, revision, directory)

    r, err := git.PlainClone(directory, false, &git.CloneOptions{
        URL:               url,
        Depth: 1,
        ReferenceName: plumbing.ReferenceName(revision),
    })```

* Execution failed with the following

```console
$ go run go-git-cloner.go https://github.com/protocolbuffers/protobuf $(pwd)/protobuf v3.10.0
git clone --depth=1 https://github.com/protocolbuffers/protobuf --branch v3.10.0 /tmp/protobuf
error: reference not found
exit status 1

How to get ReferenceName for either a Branch, Tag, or SHA?

marcellodesales commented 4 years ago

Could get this for tag or branch, but I found out there are some limitations for SHA...

solution

func main() {
    CheckArgs("<url>", "<directory>", "<revision>", "type")
    url := os.Args[1]
    directory := os.Args[2]
    revision := os.Args[3]
    cloneType := os.Args[4]

    var repo *git.Repository
    var err error

    if cloneType == "branch" {
        Info("git clone --depth=1 %s --branch %s %s", url, revision, directory)
        repo, err = git.PlainClone(directory, false, &git.CloneOptions{
            URL:               url,
            Depth: 1,
            // Branch       ReferenceName: plumbing.ReferenceName("refs/heads/" + revision),
            ReferenceName: plumbing.NewBranchReferenceName(revision),
        })

    } else if cloneType == "tag" {
        Info("git clone --depth=1 %s --tag %s %s", url, revision, directory)
        repo, err = git.PlainClone(directory, false, &git.CloneOptions{
            URL:               url,
            Depth: 1,
            // Branch       ReferenceName: plumbing.ReferenceName("refs/heads/" + revision),
            ReferenceName: plumbing.NewTagReferenceName(revision),
        })
    }

    // Verify if any error occurred
    CheckIfError(err)

    // ... retrieving the branch being pointed by HEAD
    ref, err := repo.Head()
    CheckIfError(err)

    // ... retrieving the commit object
    commit, err := repo.CommitObject(ref.Hash())
    CheckIfError(err)

    fmt.Println(commit)
}