我正在研究一个项目,其中我的项目集成了git
。为了整合目的,我使用了go-git
库。我的问题是如何以编程方式找到两个分支的共同祖先?我想实现这个功能。看起来像go-git
和其他去库不提供这样的功能。如何以编程方式查找两个分支的共同祖先
1
A
回答
0
下面是使用go-git
模仿的git merge-base --all
package main
import (
"fmt"
"os"
"gopkg.in/src-d/go-git.v4"
. "gopkg.in/src-d/go-git.v4/_examples"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/object"
"gopkg.in/src-d/go-git.v4/plumbing/storer"
)
// store h in set, s, handling nil s if necessary. Return new set.
func store(s map[plumbing.Hash]bool, h plumbing.Hash) map[plumbing.Hash]bool {
if s == nil {
s = make(map[plumbing.Hash]bool)
}
s[h] = true
return s
}
// mergeBase finds best common ancestors between two commits to use in a
// three-way merge. One common ancestor is better than another common ancestor
// if the latter is an ancestor of the former. A common ancestor that does not
// have any better common ancestor is a best common ancestor, i.e. a merge base.
// Note that there can be more than one merge base for a pair of commits.
func mergeBase(s storer.EncodedObjectStorer, a, b plumbing.Hash) ([]plumbing.Hash, error) {
commitA, err := object.GetCommit(s, a)
if err != nil {
return nil, err
}
commitB, err := object.GetCommit(s, b)
if err != nil {
return nil, err
}
// Mapping of direct descendants of each commit we visit
desc := make(map[plumbing.Hash]map[plumbing.Hash]bool)
// Set of commits reachable from a
reachableFromA := make(map[plumbing.Hash]bool)
// Walk commits reachable from A
err = object.NewCommitPreorderIter(commitA, nil, nil).ForEach(func(c *object.Commit) error {
reachableFromA[c.Hash] = true
for _, h := range c.ParentHashes {
desc[h] = store(desc[h], c.Hash)
}
return nil
})
if err != nil {
return nil, err
}
// Set of common commits between a and b
common := make(map[plumbing.Hash]bool)
// Walk commits reachable from B
err = object.NewCommitPreorderIter(commitB, nil, nil).ForEach(func(c *object.Commit) error {
if reachableFromA[c.Hash] {
common[c.Hash] = true
}
for _, h := range c.ParentHashes {
desc[h] = store(desc[h], c.Hash)
}
return nil
})
if err != nil {
return nil, err
}
best := make(map[plumbing.Hash]bool)
// Trim down the set of common commits to only those that are best
for h := range common {
best[h] = true
for child := range desc[h] {
if common[child] {
// there is a descendant to h that is common to both a and b. h is not in best.
delete(best, h)
break
}
}
}
var result []plumbing.Hash
for h := range best {
result = append(result, h)
}
return result, nil
}
// Open an existing repository in a specific folder.
func main() {
CheckArgs("<path> <commitA> <commitB>")
path := os.Args[1]
a := plumbing.NewHash(os.Args[2])
b := plumbing.NewHash(os.Args[3])
r, err := git.PlainOpen(path)
CheckIfError(err)
bases, err := mergeBase(r.Storer, a, b)
CheckIfError(err)
for _, b := range bases {
fmt.Println(b)
}
}
+0
谢谢@orirawlings –
1
你可以使用命令的结果:
git merge-base branch1 branch2
+0
我想在golang中实现这个命令。 –
+0
也许看看https://github.com/libgit2/git2go – Philippe
相关问题
- 1. 查找两个Git分支的最新共同祖先
- 2. 没有共同祖先的分支
- 3. 如何查找二叉树中节点的第一个共同祖先?
- 4. python最低共同祖先
- 5. 我如何找到共同的祖先来rebase?
- 6. 如何找到一棵树的最低共同祖先?
- 7. 如何以编程方式查找javac.exe?
- 8. 如何查找类型类的祖先?
- 9. 在neo4j中查找最低共同祖先(LCA)
- 10. 使用.NET反射找到一个共同的祖先类
- 11. iPhone以编程方式查找ios支持的图像格式
- 12. 如何以编程方式查找EJB的JNDI查找名称?
- 13. 以编程方式删除TFS分支
- 14. EXTSJS:treepanel以编程方式移动分支
- 15. 分支合并到主干不共享祖先
- 16. 如何检查一个分支是否是Git中的另一个分支的祖先
- 17. 如何以编程方式查找加载的共享库的版本?
- 18. 从一组xpath中找到共同的祖先?
- 19. 如何以编程方式查找文件的编码?
- 20. 查找XML节点集的最低公共祖先
- 21. 有没有更好的方法找到最低的共同祖先?
- 22. 以编程方式查找设备是否支持GPS?
- 23. 如何在git merge中强制共同的祖先?
- 24. Linq to Sql - 查找祖先的分层查询
- 25. 随着Mercurial,你如何记录与跨分支祖先的分支?
- 26. 以编程方式查找地区
- 27. 以编程方式查找GridView行
- 28. 如何以编程方式在黑莓上查找方向?
- 29. Google Datastore祖先查询每个祖先每秒写一个
- 30. 如何以编程方式区分两种不同的苹果手表?
行为小程序https://github.com/src-d/ go-git/issues/679 – orirawlings