Last active
June 1, 2020 01:49
-
-
Save danielfbm/37b0ca88b745503557b2b3f16865d8c3 to your computer and use it in GitHub Desktop.
how to merge two local branches using git2go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"errors" | |
"log" | |
"github.com/libgit2/git2go" | |
) | |
func mergeBranches(repo *git.Repository, sourceBranchName string, destinationBranchName string) error { | |
// Assuming that these two branches are local already | |
sourceBranch, err := repo.LookupBranch(sourceBranchName, git.BranchLocal) | |
if err != nil { | |
log.Print("Failed lookup source branch " + sourceBranchName) | |
return err | |
} | |
defer sourceBranch.Free() | |
destinationBranch, err := repo.LookupBranch(destinationBranchName, git.BranchLocal) | |
if err != nil { | |
log.Print("Failed lookup destination branch " + destinationBranchName) | |
return err | |
} | |
defer destinationBranch.Free() | |
//Assuming we are already checkout as the destination branch | |
sourceAnnCommit, err := repo.AnnotatedCommitFromRef(sourceBranch.Reference) | |
if err != nil { | |
log.Print("Failed get annotated commit from source branch " + sourceBranchName) | |
return err | |
} | |
defer sourceAnnCommit.Free() | |
//Getting repo HEAD | |
head, err := repo.Head() | |
if err != nil { | |
log.Print("Failed get head ") | |
return err | |
} | |
// Do merge analysis | |
mergeHeads := make([]*git.AnnotatedCommit, 1) | |
mergeHeads[0] = sourceAnnCommit | |
analysis, something, err := repo.MergeAnalysis(mergeHeads) | |
// Branches are already merged? | |
if analysis&git.MergeAnalysisNone != 0 || analysis&git.MergeAnalysisUpToDate != 0 { | |
log.Print("Nothing to merge?") | |
return nil | |
} | |
// Should merge | |
if analysis&git.MergeAnalysisNormal == 0 { | |
log.Print("Some issue and should not merge?") | |
return errors.New("Merge analysis returned as not normal merge...") | |
} | |
//Options for merge | |
mergeOpts, _ := git.DefaultMergeOptions() | |
mergeOpts.FileFavor = git.MergeFileFavorNormal | |
mergeOpts.TreeFlags = git.MergeTreeFailOnConflict | |
//Options for checkout | |
checkoutOpts := &git.CheckoutOpts{ | |
Strategy: git.CheckoutSafe | git.CheckoutRecreateMissing | git.CheckoutUseTheirs, | |
} | |
//Merge action | |
if err = repo.Merge(mergeHeads, &mergeOpts, checkoutOpts); err != nil { | |
log.Print("Failed to merge heads") | |
return err | |
} | |
//Getting repo Index | |
index, err := repo.Index() | |
if err != nil { | |
log.Print("Failed to get repo index") | |
return err | |
} | |
defer index.Free() | |
//Checking for conflicts | |
if index.HasConflicts() { | |
return errors.New("Merge resulted in conflicts. Please solve the conflicts before merging.") | |
} | |
// Getting last commit from source | |
commit, err := repo.LookupCommit(sourceBranch.Target()) | |
if err != nil { | |
log.Print("Failed to get last commit from source branch") | |
return err | |
} | |
defer commit.Free() | |
//Getting signature | |
signature := commit.Author() | |
// Writting tree to index | |
treeId, err := index.WriteTree() | |
if err != nil { | |
log.Print("Failed to write tree") | |
return err | |
} | |
// Getting the created tree | |
tree, err := repo.LookupTree(treeId) | |
if err != nil { | |
log.Print("Failed to lookup tree after writting") | |
return err | |
} | |
defer tree.Free() | |
//Getting HEAD's commit | |
currentDestinationCommit, err := repo.LookupCommit(head.Target()) | |
if err != nil { | |
log.Print("Failed to get HEAD's commit") | |
return err | |
} | |
//Commit | |
_, err = repo.CreateCommit("HEAD", signature, signature, "Merged "+sourceBranchName+" into "+destinationBranchName, | |
tree, currentDestinationCommit, commit) | |
if err != nil { | |
log.Print("Failed to commit") | |
return err | |
} | |
err = repo.StateCleanup() | |
if err != nil { | |
log.Print("Error while cleaning up state") | |
return err | |
} | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment