Git2go - 拉&&合并
Git2go - pull && merge
我正在尝试实施一些可以给我 git pull
或 git fetch && git merge
结果的东西。我得到了这个部分工作,但我遇到的问题是在 运行 以下代码之后, 当前回购认为有本地更改要提交。
据我所知,我相信我可能没有从正确的 HEAD 创建带注释的提交,或者我需要进行另一次提交? (我不确定)。
我的代码看起来像这样,但我卡住了:
func (repo *Repo) Pull() error {
// Get remote
remote, err := repo.Remotes.Lookup("origin")
if err != nil {
remote, err = repo.Remotes.Create("origin", repo.Path())
if err != nil {
return err
}
}
// Get the branch
branch, err := repo.Branch()
if err != nil {
return err
}
// Get the name
branchName, err := branch.Name()
if err != nil {
return err
}
if err := remote.Fetch([]string{}, &git.FetchOptions{}, ""); err != nil {
return err
}
// Merge
remoteRef, err := repo.References.Lookup("refs/remotes/origin/" + branchName)
if err != nil {
return err
}
mergeRemoteHead, err := repo.AnnotatedCommitFromRef(remoteRef)
if err != nil {
return err
}
mergeHeads := make([]*git.AnnotatedCommit, 1)
mergeHeads[0] = mergeRemoteHead
if err = repo.Merge(mergeHeads, nil, nil); err != nil {
return err
}
return nil
}
在 运行 之后,我得到了来自远程合并的更改并更新了工作目录,但它告诉我需要提交。
我想我和 的 OP 有类似的问题。
这就是 libgit2 的 git_merge 函数的记录方式:
Any changes are staged for commit and any conflicts are written to the index. Callers should inspect the repository's index after this completes, resolve any conflicts and prepare a commit.
所以你必须添加代码来检查 index has conflicts. If there are none, you may commit 什么是上演的。否则,您可能希望提示用户解决冲突。
使用上面 sschuberth
的回答中的输入,我能够将这个函数的工作版本放在一起,我想我会分享突破。正如所指出的,libgit2 中的 repo.Merge()
函数(在本例中为 Git2go)几乎没有 git pull
做的那么多。让我一步一步来解释(我的立场是正确的):
正如 here 所解释的那样,git pull
实际上做了一个 git fetch
,然后是一个 git merge
,这就是我们要做的:
找到遥控器以从中检索更改
remote, err := repo.Remotes.Lookup("origin")
if err != nil {
return err
}
从远程获取更改
if err := remote.Fetch([]string{}, nil, ""); err != nil {
return err
}
获取对应的远程引用
remoteBranch, err := repo.References.Lookup("refs/remotes/origin/branch_name")
if err != nil {
return err
}
您现在已经从远程获得了更改,但您需要让 Git 告诉您如何进一步处理它们。所以,做一个合并分析。
执行合并分析
annotatedCommit, err := repo.AnnotatedCommitFromRef(remoteBranch)
if err != nil {
return err
}
// Do the merge analysis
mergeHeads := make([]*git.AnnotatedCommit, 1)
mergeHeads[0] = annotatedCommit
analysis, _, err := repo.MergeAnalysis(mergeHeads)
if err != nil {
return err
}
现在,您需要检查 analysis
的值以查看它指向哪个 status value 并相应地进行合并。
测试返回值
一定要在二进制级别进行测试,所以要使用按位运算符。例如:
if analysis & git.MergeAnalysisUpToDate != 0 {
return nil
}
这里无事可做(对我而言)。一切都是最新的。
else if analysis & git.MergeAnalysisNormal != 0 {
// Just merge changes
if err := repo.Merge([]*git.AnnotatedCommit{annotatedCommit}, nil, nil); err != nil {
return err
}
// Check for conflicts
index, err := repo.Index()
if err != nil {
return err
}
if index.HasConflicts() {
return errors.New("Conflicts encountered. Please resolve them.")
}
// Make the merge commit
sig, err := repo.DefaultSignature()
if err != nil {
return err
}
// Get Write Tree
treeId, err := index.WriteTree()
if err != nil {
return err
}
tree, err := repo.LookupTree(treeId)
if err != nil {
return err
}
localCommit, err := repo.LookupCommit(head.Target())
if err != nil {
return err
}
remoteCommit, err := repo.LookupCommit(remoteBranchID)
if err != nil {
return err
}
repo.CreateCommit("HEAD", sig, sig, "", tree, localCommit, remoteCommit)
// Clean up
repo.StateCleanup()
}
简而言之,上面的代码块只是执行合并并测试冲突。如果遇到任何冲突,请处理它们(可能会提示用户)。这将导致未提交的更改,因此请务必在之后创建提交。
else if analysis & git.MergeAnalysisFastForward != 0 {
// Fast-forward changes
// Get remote tree
remoteTree, err := repo.LookupTree(remoteBranchID)
if err != nil {
return err
}
// Checkout
if err := repo.CheckoutTree(remoteTree, nil); err != nil {
return err
}
branchRef, err := repo.References.Lookup("refs/heads/branch_name")
if err != nil {
return err
}
// Point branch to the object
branchRef.SetTarget(remoteBranchID, "")
if _, err := head.SetTarget(remoteBranchID, ""); err != nil {
return err
}
}
在上面的代码中,没有任何要合并的东西。您只需要将更改从远程重播到您的本地并更新 HEAD 指向的位置。
以上对我来说已经足够了。我希望该方法也能对您有所帮助。在 this gist
上找到完整的函数
我正在尝试实施一些可以给我 git pull
或 git fetch && git merge
结果的东西。我得到了这个部分工作,但我遇到的问题是在 运行 以下代码之后, 当前回购认为有本地更改要提交。
据我所知,我相信我可能没有从正确的 HEAD 创建带注释的提交,或者我需要进行另一次提交? (我不确定)。
我的代码看起来像这样,但我卡住了:
func (repo *Repo) Pull() error {
// Get remote
remote, err := repo.Remotes.Lookup("origin")
if err != nil {
remote, err = repo.Remotes.Create("origin", repo.Path())
if err != nil {
return err
}
}
// Get the branch
branch, err := repo.Branch()
if err != nil {
return err
}
// Get the name
branchName, err := branch.Name()
if err != nil {
return err
}
if err := remote.Fetch([]string{}, &git.FetchOptions{}, ""); err != nil {
return err
}
// Merge
remoteRef, err := repo.References.Lookup("refs/remotes/origin/" + branchName)
if err != nil {
return err
}
mergeRemoteHead, err := repo.AnnotatedCommitFromRef(remoteRef)
if err != nil {
return err
}
mergeHeads := make([]*git.AnnotatedCommit, 1)
mergeHeads[0] = mergeRemoteHead
if err = repo.Merge(mergeHeads, nil, nil); err != nil {
return err
}
return nil
}
在 运行 之后,我得到了来自远程合并的更改并更新了工作目录,但它告诉我需要提交。
我想我和
这就是 libgit2 的 git_merge 函数的记录方式:
Any changes are staged for commit and any conflicts are written to the index. Callers should inspect the repository's index after this completes, resolve any conflicts and prepare a commit.
所以你必须添加代码来检查 index has conflicts. If there are none, you may commit 什么是上演的。否则,您可能希望提示用户解决冲突。
使用上面 sschuberth
的回答中的输入,我能够将这个函数的工作版本放在一起,我想我会分享突破。正如所指出的,libgit2 中的 repo.Merge()
函数(在本例中为 Git2go)几乎没有 git pull
做的那么多。让我一步一步来解释(我的立场是正确的):
正如 here 所解释的那样,git pull
实际上做了一个 git fetch
,然后是一个 git merge
,这就是我们要做的:
找到遥控器以从中检索更改
remote, err := repo.Remotes.Lookup("origin")
if err != nil {
return err
}
从远程获取更改
if err := remote.Fetch([]string{}, nil, ""); err != nil {
return err
}
获取对应的远程引用
remoteBranch, err := repo.References.Lookup("refs/remotes/origin/branch_name")
if err != nil {
return err
}
您现在已经从远程获得了更改,但您需要让 Git 告诉您如何进一步处理它们。所以,做一个合并分析。
执行合并分析
annotatedCommit, err := repo.AnnotatedCommitFromRef(remoteBranch)
if err != nil {
return err
}
// Do the merge analysis
mergeHeads := make([]*git.AnnotatedCommit, 1)
mergeHeads[0] = annotatedCommit
analysis, _, err := repo.MergeAnalysis(mergeHeads)
if err != nil {
return err
}
现在,您需要检查 analysis
的值以查看它指向哪个 status value 并相应地进行合并。
测试返回值
一定要在二进制级别进行测试,所以要使用按位运算符。例如:
if analysis & git.MergeAnalysisUpToDate != 0 {
return nil
}
这里无事可做(对我而言)。一切都是最新的。
else if analysis & git.MergeAnalysisNormal != 0 {
// Just merge changes
if err := repo.Merge([]*git.AnnotatedCommit{annotatedCommit}, nil, nil); err != nil {
return err
}
// Check for conflicts
index, err := repo.Index()
if err != nil {
return err
}
if index.HasConflicts() {
return errors.New("Conflicts encountered. Please resolve them.")
}
// Make the merge commit
sig, err := repo.DefaultSignature()
if err != nil {
return err
}
// Get Write Tree
treeId, err := index.WriteTree()
if err != nil {
return err
}
tree, err := repo.LookupTree(treeId)
if err != nil {
return err
}
localCommit, err := repo.LookupCommit(head.Target())
if err != nil {
return err
}
remoteCommit, err := repo.LookupCommit(remoteBranchID)
if err != nil {
return err
}
repo.CreateCommit("HEAD", sig, sig, "", tree, localCommit, remoteCommit)
// Clean up
repo.StateCleanup()
}
简而言之,上面的代码块只是执行合并并测试冲突。如果遇到任何冲突,请处理它们(可能会提示用户)。这将导致未提交的更改,因此请务必在之后创建提交。
else if analysis & git.MergeAnalysisFastForward != 0 {
// Fast-forward changes
// Get remote tree
remoteTree, err := repo.LookupTree(remoteBranchID)
if err != nil {
return err
}
// Checkout
if err := repo.CheckoutTree(remoteTree, nil); err != nil {
return err
}
branchRef, err := repo.References.Lookup("refs/heads/branch_name")
if err != nil {
return err
}
// Point branch to the object
branchRef.SetTarget(remoteBranchID, "")
if _, err := head.SetTarget(remoteBranchID, ""); err != nil {
return err
}
}
在上面的代码中,没有任何要合并的东西。您只需要将更改从远程重播到您的本地并更新 HEAD 指向的位置。
以上对我来说已经足够了。我希望该方法也能对您有所帮助。在 this gist
上找到完整的函数