我想這個問題的答案是git不是爲此而做的。 Git真的不喜歡「承諾的孩子」的想法,並且有一個很好的理由:它沒有很好的定義。因爲提交併不知道它的子節點,所以它是一個非常模糊的集合。你可能實際上沒有回購所有的分支,所以錯過了一些孩子。
Gits內部存儲結構也使得找到一個提交的子代是一個相當昂貴的操作,因爲您必須將所有頭的修訂圖移至相應的根或直到您看到所有提交的子對象想要知道關於。
git支持的唯一概念是一個提交包含另一個提交的想法。但是這個功能只支持很少的git命令(其中之一就是git branch
)。在git支持它的地方,它不支持任意提交,但只支持分支頭。
這一切都可能看起來像git的一個相當苛刻的限制,但實際上它證明你不需要提交的「子」,但通常只需要知道哪些分支包含特定的提交。
這都說:如果你真的想得到你的問題的答案,你將不得不編寫自己的腳本,找到它。最簡單的方法是從git rev-list --parents --reverse --all
的輸出開始。一行一行解析,你會構建一棵樹,併爲每個節點標記它是否是你正在尋找的提交的子代。一旦你遇到了他們,然後把這些財產帶到他們的孩子身上,你就可以做到這一點,等等。
一旦您的提交被標記爲包含所有提交,您將其添加到您的「解決方案列表」並將其所有子項標記爲已死 - 它們不能再包含任何第一次提交。這個屬性也將被傳遞給它的所有後代。
如果您不存儲任何不包含任何您請求的提交的樹的任何部分,則可以在此保存一些內存。
編輯亂砍一些Python代碼
#!/usr/bin/python -O
import os
import sys
if len(sys.argv) < 2:
print ("USAGE: {0} <list-of-revs>".format([sys.argv[0]]))
exit(1)
rev_list = os.popen('git rev-list --parents --reverse --all')
looking_for = os.popen('git rev-parse {0}'
.format(" ".join(sys.argv[1:]))).read().splitlines()
solutions = set()
commits = {}
for line in rev_list:
line = line.strip().split(" ")
commit = set()
sha = line[0]
for parent in line[1:]:
if not parent in commits:
continue
commit.update(commits[parent])
if parent in solutions:
commit.add("dead")
if sha in looking_for:
commit.add(sha)
if not "dead" in commit and commit.issuperset(looking_for):
solutions.add(sha)
# only keep commit if it's a child of looking_for
if len(commit) > 0:
commits[sha] = commit
print "\n".join(solutions)
我想不出一個簡單的(有效)的方式來做到這一點,短生成所有的列表的合併提交,每一個測試分別查看是否可以從那裏訪問所述提交中的每個提交。可以相對容易地編寫腳本,但它會*慢*。我認爲最近(即1.8+版本)的'git'在幾個地方增加了一個'--contains'選項,這可能會讓這個更容易一些。 – twalberg
B和C屬於不同的分支嗎? – ShadyKiller
@ShadyKiller:在具體的例子中,是的;一般來說,沒有。所有這三個人可能都在同一個分支(在這種情況下,答案只會是最新的提交)或不同的分支。地獄,可能會多於或少於三次提交;這是一個相對任意的數字。 –