その質問に対する答えは、git はこのために作られたものではないということだと思います。Git は「コミットの子」という考えを本当に好まないのですが、それには十分な理由があります。それはあまり明確に定義されていないからです。コミットはその子について知らないため、非常にあいまいなセットです。実際にはレポにすべてのブランチがあるとは限らないため、一部の子が欠落している可能性があります。
また、Gits の内部ストレージ構造により、コミットの子を見つけるのはかなりコストのかかる操作になります。すべてのヘッドのリビジョン グラフを、対応するルートまで、または知りたい子を持つすべてのコミットが表示されるまでたどらなければならないからです。
git がサポートするこの種の唯一の概念は、1 つのコミットが別のコミットを含むという考えです。しかし、この機能は非常に少数の git コマンドでしかサポートされていません (git branch
そのうちの 1 つです)。また、git がサポートしている場合でも、任意のコミットではサポートされていませんが、ブランチ ヘッドのみがサポートされています。
これはすべて git のかなり厳しい制限のように思えるかもしれませんが、実際には、コミットの「子」は必要なく、通常は特定のコミットが含まれるブランチを知るだけでよいことがわかります。
つまり、質問に対する回答を本当に取得したい場合は、それを見つける独自のスクリプトを作成する必要があります。これを行う最も簡単な方法は、 の出力から始めることですgit rev-list --parents --reverse --all
。その行ごとに解析してツリーを作成し、各ノードについて、探しているコミットの子であるかどうかをマークします。これを行うには、コミットに出会ったらコミット自体をマークし、そのプロパティをすべての子に継承します。
すべてのコミットを含むとマークされたコミットを作成したら、それを「ソリューション リスト」に追加し、そのすべての子をデッドとしてマークします。最初のコミットを含めることはできません。このプロパティは、そのすべての子孫にも渡されます。
要求したコミットを含まないツリーの部分を保存しない場合は、ここでメモリを少し節約できます。
editいくつかの 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)