Skip to content
This repository has been archived by the owner on Sep 11, 2020. It is now read-only.

Pushing a repo on master works, but using references/branches seems to fail #684

Closed
dbriesz opened this issue Dec 7, 2017 · 8 comments
Closed
Labels

Comments

@dbriesz
Copy link

dbriesz commented Dec 7, 2017

Steps to reproduce:
• Add a downstream remote (r.CreateRemote)

• Push https://github.com/src-d/go-git.git-> works

• Push https://github.com/src-d/go-git.git/fix/checkout-empty-repo -> results in "already up-to-date"

Example code:

    // Add a downstream remote
    _, err = r.CreateRemote(&config.RemoteConfig{
        Name: "downstream",
        URLs: []string{"https://github.com/src-d/go-git.git"},
    })
    if err != nil {
        switch err {
        case git.ErrRemoteNotFound:
            log.Fatal("remote not found")
        default:
            log.Println(err)
        }
    }

    // Push using default options
    upstreamReference := plumbing.ReferenceName("refs/remotes/fix/checkout-empty-repo")
    downstreamReference := plumbing.ReferenceName("refs/remotes/fix/checkout-empty-repo")
    referenceList := append([]config.RefSpec{},
        config.RefSpec(upstreamReference+":"+downstreamReference))

    log.Printf("Pushing to https://github.com/src-d/go-git.git ...\n")
    err = r.Push(&git.PushOptions{
        RemoteName: "downstream",
        RefSpecs:   referenceList,
    })
    if err != nil {
        log.Fatal(err)
    } 

• Push with refs/heads usage also fails

Example code:

    // Add a downstream remote
    _, err = r.CreateRemote(&config.RemoteConfig{
        Name: "downstream",
        URLs: []string{"https://github.com/src-d/go-git.git"},
    })
    if err != nil {
        switch err {
        case git.ErrRemoteNotFound:
            log.Fatal("remote not found")
        default:
            log.Println(err)
        }
    }

    // Push using default options
    upstreamReference := plumbing.ReferenceName("refs/heads/fix/checkout-empty-repo")
    downstreamReference := plumbing.ReferenceName("refs/heads/fix/checkout-empty-repo")
    referenceList := append([]config.RefSpec{},
        config.RefSpec(upstreamReference+":"+downstreamReference))

    log.Printf("Pushing to https://github.com/src-d/go-git.git ...\n")
    err = r.Push(&git.PushOptions{
        RemoteName: "downstream",
        RefSpecs:   referenceList,
    })
    if err != nil {
        log.Fatal(err)
    } 
@orirawlings
Copy link
Contributor

Hey @dbriesz,

If you get an "already up-to-date" it means that the reference on the remote already contains the commits you are trying to push. Unless you know for sure that there are changes locally on your fix/checkout-empty-repo that are not in the remote branch, this is expected behavior.

@dbriesz
Copy link
Author

dbriesz commented Dec 8, 2017

Hey @orirawlings,

Yes, I know for sure that local changes aren't in the remote branch since I'm trying to push a branch that I have locally to an empty remote branch

@orirawlings
Copy link
Contributor

Hey @dbriesz,

I did some more troubleshooting on this. I'm not able to reproduce, although perhaps the error message is a little confusing when the branch you're trying to push does not exist either locally or on the remote (i.e. already up-to-date).

I'm running this code based on the latest changes in go-git/master:

$ cat main.go
package main

import (
	"fmt"
	"os"

	"gopkg.in/src-d/go-git.v4"
	. "gopkg.in/src-d/go-git.v4/_examples"
	"gopkg.in/src-d/go-git.v4/config"
	"gopkg.in/src-d/go-git.v4/plumbing"
)

// Open an existing repository in a specific folder.
func main() {
	CheckArgs("<path>")
	path := os.Args[1]

	r, err := git.PlainOpen(path)
	CheckIfError(err)

	ds, err := r.Remote("downstream")
	if err == git.ErrRemoteNotFound {
		ds, err = r.CreateRemote(&config.RemoteConfig{
			Name: "downstream",
			URLs: []string{"git@github.com:orirawlings/go-git-issues.git"},
		})
	}
	CheckIfError(err)

	b := plumbing.ReferenceName("refs/heads/fix/newBranch")

	// Check if reference exists locally
	refs, err := r.References()
	CheckIfError(err)
	var foundLocal bool
	CheckIfError(refs.ForEach(func(ref *plumbing.Reference) error {
		if ref.Name() == b {
			fmt.Printf("reference exists locally:\n%s\n", ref)
			foundLocal = true
		}
		return nil
	}))
	if !foundLocal {
		fmt.Printf("reference %s does not exist locally\n", b)
	}

	// Check if reference exists on remote
	remoteRefs, err := ds.List(&git.ListOptions{})
	CheckIfError(err)
	var found bool
	for _, ref := range remoteRefs {
		if ref.Name() == b {
			fmt.Printf("reference already exists on remote:\n%s\n", ref)
			found = true
		}
	}
	if !found {
		fmt.Printf("reference %s does not exist on remote\n", b)
	}

	// Push reference to remote
	CheckIfError(r.Push(&git.PushOptions{
		RemoteName: "downstream",
		RefSpecs: []config.RefSpec{
			config.RefSpec(b + ":" + b),
		},
	}))
}
$ git clone git@github.com:orirawlings/go-git-issues.git
Cloning into 'go-git-issues'...
remote: Counting objects: 21, done.
remote: Total 21 (delta 0), reused 0 (delta 0), pack-reused 21
Receiving objects: 100% (21/21), done.
Resolving deltas: 100% (5/5), done.

When I try the push without the branch locally or on the remote:

$ go run main.go go-git-issues/
reference refs/heads/fix/newBranch does not exist locally
reference refs/heads/fix/newBranch does not exist on remote
error: already up-to-date
exit status 1

When I create the branch locally and reattempt, the push succeeds without error:

$ git -C go-git-issues/ branch fix/newBranch master
$ go run main.go go-git-issues/
reference exists locally:
453962b0637a10461f40e14545940de0439770b4 refs/heads/fix/newBranch
reference refs/heads/fix/newBranch does not exist on remote

When I reattempt after both the local and remote have the branch:

$ go run main.go go-git-issues/
reference exists locally:
453962b0637a10461f40e14545940de0439770b4 refs/heads/fix/newBranch
reference already exists on remote:
453962b0637a10461f40e14545940de0439770b4 refs/heads/fix/newBranch
error: already up-to-date
exit status 1

In the specific example you posted above @dbriesz, the branch in question does exist on that particular git repository:

$ git ls-remote https://github.com/src-d/go-git.git | grep refs/heads/fix/checkout-empty-repo
92eff6678c1dd01bed17e4ab7bdf93b53b3bdffb        refs/heads/fix/checkout-empty-repo

So the trouble you are having might just be the particulars of the local and remote repository states.

I think something that would be a potential improvement here for go-git would be a better error message when you try to push a reference that does not exist locally. The standard git tooling gives a much more clear error in this scenario:

$ git -C go-git-issues/ push downstream refs/heads/doesNotExist:refs/heads/doesNotExist
error: src refspec refs/heads/doesNotExist does not match any.
error: failed to push some refs to 'git@github.com:orirawlings/go-git-issues.git'

@dbriesz
Copy link
Author

dbriesz commented Dec 14, 2017

Thanks @orirawlings. I'm trying a similar solution on my end, but I'm unable to get this code to work:

remoteRefs, err := ds.List(&git.ListOptions{})

This results in the error

ds.List undefined (type *git.Remote has no field or method List)

Is there another way to get a list of references from the Remote?

@orirawlings
Copy link
Contributor

Sorry. I'm using a new feature in that example code that hasn't yet been published to the v4 branch. It is only available on go-git master.

@dbriesz
Copy link
Author

dbriesz commented Dec 19, 2017

Thanks - what is the proper way to use go-git master? I've tried go get -u github.com/src-d/go-git, but get an error that says package github.com/src-d/go-git ... expects import "gopkg.in/src-d/go-git.v4"

@orirawlings
Copy link
Contributor

If you've retrieved the code using go get -u gopkg.in/src-d/go-git.v4/... then you can update it to the master branch by doing something like the following:

$ git -C $GOPATH/gopkg.in/src-d/go-git.v4 remote add github git@github.com:src-d/go-git.git
$ git -C $GOPATH/gopkg.in/src-d/go-git.v4 fetch github
$ git -C $GOPATH/gopkg.in/src-d/go-git.v4 checkout github/master  

@dbriesz
Copy link
Author

dbriesz commented Dec 21, 2017

Thanks, that worked! I had been using http.NewBasicAuth() in order to provide a username and password when the endpoint.Protocol() was https, but I don't see that function in master. Is there a way I can still do that when using master? For example, when I was using v4, I did something like this:

case endpoint.Protocol() == "https":
		auth := http.NewBasicAuth(username, password)
		return auth

Also, as an unrelated question, when might master be the new released version of go-git?

Thanks for your help!

andrzejd-pl added a commit to andrzejd-pl/git-crawler that referenced this issue Nov 28, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants