0

I'm currently struggling to get go-git working with private repositories on GitHub. Although working with the git command line works as expected (git push origin), the code snippet below does not work. The last log command returns the following result:

 Error during push     error=repository not found

The repository itself does exist, otherwise the push from the command line would not work. First, I thought, that it might be related that the remote repository is empty. But even if that's not the case, I've got the same error. The credentials are valid, I've double-checked them.

So, there must be something I am missing. But since I am new to Go, my expertise is too low for this to be figured out.

package git

import (
    "io/ioutil"
    "path/filepath"
    "time"

    "github.com/apex/log"
    "github.com/go-git/go-git/v5"
    "github.com/go-git/go-git/v5/config"
    "github.com/go-git/go-git/v5/plumbing/object"
    "github.com/go-git/go-git/v5/plumbing/transport/http"
    "github.com/spf13/viper"
)

const gitDataDirectory = "./data/"
const defaultRemoteName = "origin"

// Commit creates a commit in the current repository
func Commit() {
    repo, err := git.PlainOpen(gitDataDirectory)

    if err != nil {
        // Repository does not exist yet, create it
        log.Info("The Git repository does not exist yet and will be created.")

        repo, err = git.PlainInit(gitDataDirectory, false)
    }

    if err != nil {
        log.Warn("The data folder could not be converted into a Git repository. Therefore, the versioning does not work as expected.")
        return
    }

    w, _ := repo.Worktree()


    log.Info("Committing new changes...")
    w.Add(".gitignore")
    w.Add("info.json")
    w.Commit("test", &git.CommitOptions{
        Author: &object.Signature{
            Name:  "test",
            Email: "test@localhost",
            When:  time.Now(),
        },
    })

    _, err = repo.Remote(defaultRemoteName)
    if err != nil {
        log.Info("Creating new Git remote named " + defaultRemoteName)
        _, err = repo.CreateRemote(&config.RemoteConfig{
            Name: defaultRemoteName,
            URLs: []string{"https://github.com/jlnostr/blub.git"},
        })

        if err != nil {
            log.WithError(err).Warn("Error creating remote")
        }
    }

    auth := &http.BasicAuth{
        Username: "jlnostr",
        Password: "[git_basic_auth_token]",
    }
    log.Info("Pushing changes to remote")
    err = repo.Push(&git.PushOptions{
        RemoteName: defaultRemoteName,
        Auth:       auth,
    })

    if err != nil {
        log.WithError(err).Warn("Error during push")
    }
}

nachtjasmin
  • 386
  • 4
  • 13

2 Answers2

2

There were several issues:

  1. The GitHub token only had access to public repositories, but I've tried to push to a private repository. Using the repo permissions (instead of just repo:public) helped.

  2. The repo was not yet "really" initialized. Pulling before pushing helped in this case, as @peakle mentioned.

So, below is a complete working example for initializing a private repository with go-git v5.

package git

import (
    "io/ioutil"
    "path/filepath"
    "time"

    "github.com/go-git/go-git/v5"
    "github.com/go-git/go-git/v5/config"
    "github.com/go-git/go-git/v5/plumbing/object"
    "github.com/go-git/go-git/v5/plumbing/transport/http"
)

const gitDataDirectory = "./data/"
const defaultRemoteName = "origin"

var auth = &http.BasicAuth{
    Username: "<username>",
    Password: "<git_basic_auth_token>",
}

func createCommitOptions() *git.CommitOptions {
    return &git.CommitOptions{
        Author: &object.Signature{
            Name:  "Rick Astley",
            Email: "never.gonna.give.you.up@localhost",
            When:  time.Now(),
        },
    }
}

// Commit creates a commit in the current repository
func Commit() {
    err := initializeGitRepository()
    if err != nil {
        // logging: The folder could not be converted into a Git repository.
        return
    }

    // Open after initialization
    repo, _ := git.PlainOpen(gitDataDirectory)
    w, _ := repo.Worktree()

    status, _ := w.Status()
    if status.IsClean() {
        return
    }

    // Committing new changes
    w.Add("<your_file>.txt")
    w.Commit("test", createCommitOptions())

    // Pushing to remote
    err = repo.Push(&git.PushOptions{
        RemoteName: defaultRemoteName,
        Auth:       auth,
    })
}

func initializeGitRepository() error {
    _, err := git.PlainOpen(gitDataDirectory)
    if err == nil {
        return nil
    }

    // The Git repository does not exist yet and will be created.

    repo, err := git.PlainInit(gitDataDirectory, false)

    if err != nil {
        return err
    }

    // Writing default .gitignore with "media/" as first line
    filename := filepath.Join(gitDataDirectory, ".gitignore")
    err = ioutil.WriteFile(filename, []byte("media/"), 0644)

    if err != nil {
        return err
    }

    w, _ := repo.Worktree()
    w.Add(".gitignore")
    w.Commit("Initial commit", createCommitOptions())

    return initializeRemote()
}

func initializeRemote() error {
    repo, err := git.PlainOpen(gitDataDirectory)
    if err != nil {
        return err
    }

    _, err = repo.Remote(defaultRemoteName)
    if err == nil {
        // Repo already exists, skipping
        return nil
    }

    w, err := repo.Worktree()
    if err != nil {
        return err
    }

    refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*")

    // Creating default remote
    _, err = repo.CreateRemote(&config.RemoteConfig{
        Name:  defaultRemoteName,
        URLs:  []string{"https://github.com/<user>/<repo>.git"},
        Fetch: []config.RefSpec{refspec},
    })

    if err != nil {
        // TODO
    }

    // Pulling from remote
    w.Pull(&git.PullOptions{
        RemoteName: defaultRemoteName,
        Auth:       auth,
    })

    return err
}
nachtjasmin
  • 386
  • 4
  • 13
0

i tried your code few times with minimal changes like below and it work fine on case when repo also clonned and git inited, commit message to approve: https://github.com/peakle/iptables-http-services/commit/56eba2fcc4fac790ad573942ab1b926ddadf0875

i can't reproduce your problem but maybe it can help you with git error that occurred on your case: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/error-repository-not-found , i think you have typo on repo name or something similar to cases described in link above.

and additional for future enhancements to your codebase , i have problems on case when git not yet inited, i add some code and TODO block with recommendations maybe it can help you in future :)

package main

import (
    "fmt"
    _ "io/ioutil"
    "os"
    _ "path/filepath"
    "time"

    "github.com/apex/log"
    "github.com/go-git/go-git/v5"
    "github.com/go-git/go-git/v5/config"
    "github.com/go-git/go-git/v5/plumbing/object"
    "github.com/go-git/go-git/v5/plumbing/transport/http"
)

const gitDataDirectory = "/Users/peakle/projects/tests/iptables-http-services"
const defaultRemoteName = "origin"

func main() {
    filename := "kek.txt"
    file, _ := os.Create(fmt.Sprintf("%s/%s", gitDataDirectory, filename))
    _, _ = file.Write([]byte("test string2"))
    Commit(filename)
}

// Commit creates a commit in the current repository
func Commit(filename string) {
    var isNewInit bool
    repo, err := git.PlainOpen(gitDataDirectory)

    if err != nil {
        // Repository does not exist yet, create it
        log.Info("The Git repository does not exist yet and will be created.")

        repo, err = git.PlainInit(gitDataDirectory, false)
        isNewInit = true
    }

    if err != nil {
        log.Warn("The data folder could not be converted into a Git repository. Therefore, the versioning does not work as expected.")
        return
    }

    w, _ := repo.Worktree()

    log.Info("Committing new changes...")
    if isNewInit {
        err = w.AddGlob("*")
        if err != nil {
            fmt.Println(err)
        }

        //TODO if its new git init, need to add `git pull` command  with remote branch
    } else {
        _, _ = w.Add(filename)
    }

    _, _ = w.Commit("test", &git.CommitOptions{
        Author: &object.Signature{
            Name:  "peakle",
            Email: "test@mail.com",
            When:  time.Now(),
        },
    })

    _, err = repo.Remote(defaultRemoteName)
    if err != nil {
        log.Info("Creating new Git remote named " + defaultRemoteName)
        _, err = repo.CreateRemote(&config.RemoteConfig{
            Name: defaultRemoteName,
            URLs: []string{"https://github.com/Peakle/iptables-http-services.git"},
        })

        if err != nil {
            log.WithError(err).Warn("Error creating remote")
        }
    }

    auth := &http.BasicAuth{
        Username: "peakle",
        Password: "authtoken",
    }

    log.Info("Pushing changes to remote")
    err = repo.Push(&git.PushOptions{
        RemoteName: defaultRemoteName,
        Auth:       auth,
    })

    if err != nil {
        log.WithError(err).Warn("Error during push")
    }
}
peakle
  • 149
  • 5