确定git commit的实际分支名称

时间:2018-08-24 16:02:43

标签: python-3.x git gitpython

enter image description here

这是一个简单的git存储库。我已经用数字标记了提交,以便于参考。存储库具有以下分支:

  • master:13次提交(1,2,3,4,5,6,7,8,9,10,11,12,13)
  • new_branch:8次提交(1,2,3,4,5,6,14,15)
  • test_branch:3次提交(1,2,3)
  • yet_another_branch:14次提交(1,2,3,4,5,6,7,8,9,10,11,12,16,17)

提交5,6属于拉取请求,因此带有5,6的蓝色部分不是分支。

请注意,提交1,2被视为所有分支的一部分,但我想将所有黑色的提交视为主分支的一部分。同样,对于“测试分支”,我只考虑将提交3作为分支的一部分。

from git import Repo

git_url = "https://github.com/unimamun/test-repo.git"
repo_dir = "/mnt/hdd/aam/J2_Repos/test-repo/test-repo"

repo = Repo.clone_from(git_url, repo_dir)

# get all commits by branches    
def get_commits(repo, ref_name):
    commits = []
    for commit in repo.iter_commits(rev=ref_name):
        commits.append(commit)
    return commits

print('\nCommits in Branches:')
for ref in repo.references:
    print(ref.name,': ', str(len(get_commits(repo, ref.name))))


print('\nCommits in master:')
commits = list(repo.iter_commits('master'))
commits.reverse()
i = 0
for commit in commits:
    i += 1
    print(i,': ', commit.hexsha)

    # to see parents of the commit 
    #print('Parents: ',commit.parents)

从上面的代码中,我得到以下输出:

Commits in Branches:
master :  13
origin/HEAD :  13
origin/master :  13
origin/new_branch :  8
origin/test-branch :  3
origin/yet_another_branch :  14

Commits in master:
1 :  694df9fee2f9c03a33979725e76a484bce1738a0
2 :  c0fe1b76131b7fcb103f171fd93d85cda17b756c
3 :  0199ad335f65d52a2895a678a19e209e1e16a1a7
4 :  dd0903259b0aadbf2d8fb00e566eee014264f7c0
5 :  7ed55c51e2527f47bc6344cd960ff5beb90cc65d
6 :  d10f19c85fbc1c27b7719a2dc64989255697181d
7 :  c41bdfaeae1f801776420ce161ca2555dffc5aad
8 :  56b5d6e1831a477c79e0fd336acc96ca266d5dea
9 :  6305a72d4e257ebe74b10ca538906f1eceb091bf
10 :  4c5d1ebe5f2f8168ee8bf4a969855821d04caf09
11 :  362bc52be00af3fb917196cf27a8ddc0bb8fd4ba
12 :  5a70a46394eb08b4b48f9eb05798048ca7269a9d
13 :  f4a8bdd318b2678191d06616a55df26416a28363

我想要以下输出。这样,图中的每个黑点都将打印“ master”,非黑色提交将被打印到其他分支名称(在这种情况下,绿色提交3将被打印测试分支)

Commits in master:
1 :  694df9fee2f9c03a33979725e76a484bce1738a0 master
2 :  c0fe1b76131b7fcb103f171fd93d85cda17b756c master
3 :  0199ad335f65d52a2895a678a19e209e1e16a1a7 test-branch
4 :  dd0903259b0aadbf2d8fb00e566eee014264f7c0 master
5 :  7ed55c51e2527f47bc6344cd960ff5beb90cc65d master
6 :  d10f19c85fbc1c27b7719a2dc64989255697181d master
7 :  c41bdfaeae1f801776420ce161ca2555dffc5aad master
8 :  56b5d6e1831a477c79e0fd336acc96ca266d5dea master
9 :  6305a72d4e257ebe74b10ca538906f1eceb091bf master
10 :  4c5d1ebe5f2f8168ee8bf4a969855821d04caf09 master
11 :  362bc52be00af3fb917196cf27a8ddc0bb8fd4ba master
12 :  5a70a46394eb08b4b48f9eb05798048ca7269a9d master
13 :  f4a8bdd318b2678191d06616a55df26416a28363 master

我需要从提交1到13进行迭代,并一路确定哪个提交属于哪个分支。非常感谢。

2 个答案:

答案 0 :(得分:1)

您注意到:

  

commit 1,2被视为所有分支的一部分

也就是说,任何给定分支的可达提交集(从分支尖端的commit开始并通过有向非循环图的提交进行反向确定)始终包括提交1和2。

  

但是我想将所有黑色提交视为主[分支]的一部分

在这种情况下,请先查找所有提交的图形。您可能知道,图定义为 G =(V,E),其中 V 是所有顶点的集合,而 E 是所有边缘的集合。 Git在提交中将顶点和边缘数据存储在一起:提交的标识是其哈希ID,而其边缘(实际上是向外的弧,因为这是一个有向图)实际上是其父提交哈希ID。

接下来,使用您希望指定为“最重要”分支的名称(即master)来查找其提示提交的哈希ID。将此提交分配给主集。从该提交开始,遍历图的可到达部分,将每个提交添加到master中的提交集中。

现在,对于每个剩余的分支(以某种顺序,在许多情况下此顺序将决定您的结果,因此您可能希望使用拓扑排序)从分支的顶端开始,遍历图的可到达部分:

  • 对于已经分配给某个分支的任何提交,请忽略它-由于定义将其所有前任分配给某个分支,因此您可以立即停止在图形上移动。
  • 您在此遍历期间到达的提交集就是您希望声明“属于”此分支的提交集。

有多种方法可以实现此目的,包括遍历通过集减确定的子图:只需从原始 G 中减去每个分支的子图。

如果更方便-很有可能,因为您不必找到 G -您可以从另一个方向进行:从master开始并找到可实现的提交不在最初为空的某个集合中。将每个提交添加到集合中,同时将其列为“主”。然后遍历其余分支:如果提交已在集合中到目前为止已声明,则该分支会声明它。用这种方式工作的问题是,在选择较小的分支(feature-X)之前,您可能会选择一个包含其他分支(develop)包含的所有提交的分支(develop)。 :没有完整的图形就无法进行拓扑排序。

针对所有分支提示完成此操作后,现在将每个“从分支提示到达”提交分配给单个分支(而不是像Git那样,将其分配给每个 可以从中访问的分支。

请注意,Git图中可能存在无法通过任何分支提示访问的提交(例如,可以通过标签访问但不能从分支访问)。如果您深入研究Git的内部结构,则可以找到仅从 reflog 条目可以访问的提交,或者甚至是完全无法访问的,只能通过遍历整个对象键值数据库才能发现的提交。后者本质上是git gc的工作:遍历数据库以查找所有对象,然后执行标记清除垃圾收集操作(与Lisp一样),保留可访问对象并丢弃不可访问对象。

答案 1 :(得分:1)

您可能想尝试使用“ --first-parent”选项:

git log --oneline --first-parent master

从数学上来说,这是一个图,它使在合并点处,任何分支都不应该比另一个分支更“重要”。但是事实上,问题总是会出现,并且当执行“合并”操作时,实际上是将一个外部分支“引入”到当前分支中。因此,当前分支被称为提交对象中的第一个分支。

如果在大型项目(例如linux内核)的master分支上尝试此操作,则主要会落在合并点上,而分支上只有几个直接更改集。

如果这正是您想了解的,则可以另外指定“ --no-merges”以明确排除合并点。

git --oneline --first-parent --no-merges master

例如,这将从图形中排除点 4 7

最后,要将搜索限制为仅属于特定分支且不从主分支继承的提交,请使用“ ..”运算符:

git log master..yourbranch

…仅显示“ yourbranch”可访问的提交,而“ master”无法访问。