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")
}
}
There were several issues:
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.
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
}