deleting local branch in go-git: branch not found - go

I'm trying to delete a local branch using go-git, but getting an error branch not found when I run
branch := "refs/heads/template/test"
err = repo.DeleteBranch(branch)
or
err = repo.DeleteBranch(plumbing.ReferenceName(branch))
Using just the name of the branch (template/test) doesn't work either. The branch is included in the list of branches. This
refs, err := repo.Branches()
err = refs.ForEach(func(ref *plumbing.Reference) error {
fmt.Println(ref)
return nil
})
provides the following output:
f2d93bb67ced13936dbbbbfb44502abd42e7df13 refs/heads/global
df46ab083f17051afd6ca20e3ea4bfe01aedbb37 refs/heads/template/test
141f45305380aa0dc9f6802512ea76c5d48a87a1 refs/heads/template/test2
How can I delete it?
Update:
I checked the function DeleteBranch, it looks like this:
// DeleteBranch delete a Branch from the repository and delete the config
func (r *Repository) DeleteBranch(name string) error {
cfg, err := r.Storer.Config()
if err != nil {
return err
}
if _, ok := cfg.Branches[name]; !ok {
return ErrBranchNotFound
}
delete(cfg.Branches, name)
return r.Storer.SetConfig(cfg)
}
then I created cfg := repo.Storer.Config() and checked what cfg.Branches contains. Surprisingly, this map has only the following element: &{global origin refs/heads/global 0xc0007fbf80}. So other branches can't be deleted because they are not found in this config.

I know that this question is quite old but the naming here tripped me up as well so I thought I'd provide an answer.
Thanks to #Hephaestus and the post linked to, I was able to sort out the correct approach. If you're trying to delete a local branch (e.g. git branch -d foo) it looks like you're meant to use repo.Storer.RemoveReference.
In my case I already have a slice of (short) branch names:
for _, branchName := range branches {
ref := plumbing.NewBranchReferenceName(branchName)
err = repo.Storer.RemoveReference(ref)
if err != nil {
return "", err
}
}

Related

go-git checkout failing with reference not found

I'm just starting to use the go-git library and so far it looks very promising.
However, I'm trying to do a basic checkout of an existing branch and it is failing with "reference not found".
I have a simple repository, with several branches but one is "main" and another is "testoffmain".
Cloning, pulling and fetching the github repo work without issues.
Getting a hash for the branch seems to work fine as well:
repo, err := git.PlainOpen(localGitRepo)
w, err := repo.Worktree()
// Clone, Fetch, Pull all work, when I'm on the main branch
headRef, err := repo.Head()
newHashRef := plumbing.NewHashReference("refs/heads/testoffmain", headRef.Hash())
hashRef := plumbing.NewHash(newHashRef.String())
fmt.Printf("HashRef: %s", hashRef.String()) // Successfully displays the hash
// Returns a valid hash
revision := "origin/testoffmain"
revHash, err := repo.ResolveRevision(plumbing.Revision(revision))
fmt.Printf("HashRef: %s\n", revHash.String())
// Checkout fails with "reference not found"
referenceName := plumbing.ReferenceName("refs/heads/testoffmain")
err = w.Checkout(&git.CheckoutOptions{
Branch: referenceName,
Force: true})
if err != nil {
fmt.Printf("%s: Checkout: Cound not open local repository, Error: %s\n", project.LocalRepo, err)
return err
}
I've search around, and oddly can't find this simple usecase, so I'm assuming I'm doing something basic wrong.
I'm using github.com/go-git/go-git/v5 v5.5.2
I've tried a variety of options in
referenceName := plumbing.ReferenceName("refs/heads/testoffmain")
referenceName := plumbing.ReferenceName("testoffmain")
referenceName := plumbing.ReferenceName("origin/testoffmain")
referenceName := plumbing.ReferenceName("refs/origin/testoffmain")
referenceName := plumbing.ReferenceName("refs/remotes/origin/testoffmain")
referenceName := plumbing.ReferenceName("refs/remotes/testoffmain")
As I test, I tried copying .git/refs/remote/origin/testoffmain to .git/refs/head/testoffmain and I can the checkout to work, but then other issues occur.
You can list the referenceNames as below:
refs, _ := r.References()
refs.ForEach(func(ref *plumbing.Reference) error {
if ref.Type() == plumbing.HashReference {
fmt.Println(ref)
}
return nil
})
See official link.
And then we can use it for checkout:
w, err := r.Worktree()
if err != nil {
fmt.Println(err)
}
err = w.Checkout(&git.CheckoutOptions{
Branch: plumbing.ReferenceName("refs/remotes/origin/" + branchName),
})
if err != nil {
fmt.Println(err, branchName)
}
where branchName is the name of the git branch you want to switch

Golang - get list of git remote branches without cloning the repo

I want a list of all the remote branches for a git repo.
Now, this git repo can be private / public. I have the access to the token to access the repo.
I am using this particular SDK : https://pkg.go.dev/github.com/go-git/go-git/v5
One way to do this is ..
r, cloneErr := git.PlainClone(projectRoot, false, cloneOptions)
remote, err := r.Remote("origin")
if err != nil {
panic(err)
}
refList, err := remote.List(&git.ListOptions{})
if err != nil {
panic(err)
}
refPrefix := "refs/heads/"
for _, ref := range refList {
refName := ref.Name().String()
if !strings.HasPrefix(refName, refPrefix) {
continue
}
branchName := refName[len(refPrefix):]
fmt.Println(branchName)
}
But, this involves cloning the repo first.
How can I get the list without cloning the repo ?
Thanks in advence !

is there a way to verify if a git sha belongs to a git branch with go-github client?

would like to use go GitHub client to get result like
git branch -r origin/<branch> --contains <sha>
is there a way to verify if a git sha belongs to a git branch with go-github client?
I don't seem to be able to find an API endpoint that would specifically answer whether the SHA belongs to the branch or not, so you would have to iterate over commit within the branch. Something like:
func main() {
ctx := context.Background()
sts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: "<token>"},
)
tc := oauth2.NewClient(ctx, sts)
client := github.NewClient(tc)
repoOwner := "<owner>"
repoName := "<repo>"
branchToSearch := "<branch>"
shaToFind := "<sha>"
resultsPerPage := 25
listOptions := github.ListOptions{PerPage: resultsPerPage}
for {
rc, resp, err := client.Repositories.ListCommits(ctx,
repoOwner,
repoName,
&github.CommitsListOptions{
SHA: branchToSearch,
ListOptions: listOptions,
},
)
if err != nil {
log.Panic(err)
}
for _, c := range rc {
if *c.SHA == shaToFind {
log.Printf("FOUND commit \"%s\" in the branch \"%s\"\n", shaToFind, branchToSearch)
return
}
}
if resp.NextPage == 0 {
break
}
listOptions.Page = resp.NextPage
}
log.Printf("NOT FOUND commit \"%s\" in the branch \"%s\"\n", shaToFind, branchToSearch)
}

How to use key pair generated by openpgp in go

I'm trying to generate keypair with openpgp lib and when I want to test it by encrypting a test string, it returns the following error openpgp: invalid argument: cannot encrypt because no candidate hash functions are compiled in. (Wanted RIPEMD160 in this case.). However it works when I pass a public key exported from gpg.
Also I'm wondering how to encrypt the private key like gpg --generate-key does?
func main() {
var e *openpgp.Entity
var pubKey *bytes.Buffer
e, _ = openpgp.NewEntity("testUser", "test", "test#test.test", nil)
for _, id := range e.Identities {
err := id.SelfSignature.SignUserId(id.UserId.Id, e.PrimaryKey, e.PrivateKey, nil)
if err != nil {
fmt.Println(err)
return
}
}
buf := new(bytes.Buffer)
w, err := armor.Encode(buf, openpgp.PublicKeyType, nil)
if err != nil {
fmt.Println(err)
return
}
e.Serialize(w)
w.Close()
pubKey = buf
// Encrypting test with public key
entity, err := openpgp.ReadArmoredKeyRing(pubKey)
if err != nil {
fmt.Println(err)
return
}
buf = new(bytes.Buffer)
encoderWriter, err := armor.Encode(buf, "PGP MESSAGE", make(map[string]string))
if err != nil {
fmt.Println(err)
return
}
encryptorWriter, err := openpgp.Encrypt(encoderWriter, entity, nil, nil, nil)
if err != nil {
fmt.Println(err)
return
}
encryptorWriter.Write([]byte("hello world"))
encryptorWriter.Close()
encoderWriter.Close()
fmt.Println(buf.String())
}
I had the exact same error.
TL; DR
It seems that it's an abandoned bug of the golang.org/x/crypto/openpgp package.
golang.org/x/crypto/openpgp package is frozen and deprecated. (= wontfix)
Use a patched fork package instead.
github.com/ProtonMail/go-crypto package # GitHub
TS; DR
Since the official "golang.org/x/crypto/openpgp" package was frozen and deprecated, as long as we use the "golang.org/x/crypto/openpgp" package, it seems that the only current workaround is to either;
Downgrade the Go version and the package, then blank import "_ golang.org/x/crypto/ripemd160" as #mh-cbon mentioned.
Patch the rejected PR on your own. (Rejected due to the freezing of x/crypto/openpgp package)
Patch: https://github.com/golang/crypto/pull/128/files
PR: Use correct default hashes and default ciphers when no preferences given
But I had to implement an OpenPGP key pair generator on Go 1.16.6. Don't ask why...
So, my current alternative was to use the forked package. Which was one of the abounding forks that the Go team mentioned as a sample.
github.com/ProtonMail/go-crypto package # GitHub
go get github.com/ProtonMail/go-crypto
Remove golang.org/x/crypto/openpgp from go.mod
Replace all the "golang.org/x/crypto/openpgp" to "github.com/ProtonMail/go-crypto/openpgp" in the source code.
go mod tidy
References
"x/crypto/openpgp: mark as frozen and deprecated" | Issue #44226 | go | golang # GitHub
"x/crypto/openpgp: new entities cannot be encrypted to by default" | Issue #37646 | go | golang # GitHub
"x/crypto/openpgp: new entities cannot be encrypted to by default" | Issue #12153 | go | golang # GitHub

Golang - why is string slice element not included in exec cat unless I sort it

I have a slightly funky issue in golang. Essentially I have a slice of strings which represent file paths. I then run a cat against those filepaths to combine the files before sorting, deduping, etc.
here is the section of code (where 'applicableReductions' is the string slice):
applicableReductions := []string{}
for _, fqFromListName := range fqFromListNames {
filePath := GetFilePath()
//BROKE CODE GOES HERE
}
applicableReductions = append(applicableReductions, filePath)
fileOut, err := os.Create(toListWriteTmpFilePath)
if err != nil {
return err
}
cat := exec.Command("cat", applicableReductions...)
catStdOut, err := cat.StdoutPipe()
if err != nil {
return err
}
go func(cat *exec.Cmd) error {
if err := cat.Start(); err != nil {
return fmt.Errorf("File reduction error (cat) : %s", err)
}
return nil
}(cat)
// Init Writer & write file
writer := bufio.NewWriter(fileOut)
defer writer.Flush()
_, err = io.Copy(writer, catStdOut)
if err != nil {
return err
}
if err = cat.Wait(); err != nil {
return err
}
fDiff.StandardiseData(fileOut, toListUpdateFolderPath, list.Name)
The above works fine. The problem comes when I try to append a new ele to the array. I have a seperate function which creates a new file from db content which is then added to the applicableReductions slice.
func RetrieveDomainsFromDB(collection *Collection, listName, outputPath string) error {
domains, err := domainReviews.GetDomainsForList(listName)
if err != nil {
return err
}
if len(domains) < 1 {
return ErrNoDomainReviewsForList
}
fh, err := os.OpenFile(outputPath, os.O_RDWR, 0774)
if err != nil {
fh, err = os.Create(outputPath)
if err != nil {
return err
}
}
defer fh.Close()
_, err = fh.WriteString(strings.Join(domains, "\n"))
if err != nil {
return err
}
return nil
}
If I call the above function and append the filePath to the applicableReduction slice, it is in there but doesnt get called by cat.
To clarify, when I put the following where it says BROKE CODE GOES HERE:
if dbSource {
err = r.RetrieveDomainsFromDB(collection, ToListName, filePath)
if err != nil {
return err
continue
}
}
The filepath can be seen when doing fmt.Println(applicableReductions) but the content of the files contents are not seen in the cat output file.
I thought perhaps a delay in the file being written so i tried adding a time.wait, tis didnt help. However the solution I found was to sort the slice, e.g this code above the call to exec cat solves the problem but I dont know why:
sort.Strings(applicableReductions)
I have confirmed all files present on both successful and unsucessful runs the only difference is without the sort, the content of the final appended file is missing
An explanation from a go-pro out there would be very much appreciated, let me know if you need more info, debug - happy to oblige to understand
UPDATE
It has been suggested that this is the same issue as here: Golang append an item to a slice, I think I understand the issue there and I'm not saying this isnt the same but I cannot see the same thing happenning - the slice in question is not touched from outside the main function (e.g. no editing of the slice in RetrieveDomainsFromDB function), I create the slice before a loop, append to it within a loop and then use it after the loop - Ive added an example at the top to show how the slice is built - please could someone clarify where this slice is being copied if this is the case
UPDATE AND CLOSE
Please close question - the issue was unrelated to the use of a string slice. Turns out that I was reading from the final output file before bufio-writer had been flushed (at end of function before defer flush kicked in on function return)
I think the sorting was just re-arranging the problem so I didnt notice it persisted or possibly giving some time for the buffer to flush. Either way sorted now with a manual call to flush.
Thanks for all help provided

Resources