【发布时间】:2012-01-17 16:46:58
【问题描述】:
如果您使用gitk --all,您可以从所有分支查看您的 repo 的所有提交。我想要类似的东西,除了给定提交的后代。
【问题讨论】:
-
虽然 manojlds 的第一句话是正确的,但这并不是全部事实:可以将检查每个 ref 是否在其祖先中具有给定提交,然后显示从那些参考。
标签: git parent commit gitk descendant
如果您使用gitk --all,您可以从所有分支查看您的 repo 的所有提交。我想要类似的东西,除了给定提交的后代。
【问题讨论】:
标签: git parent commit gitk descendant
我能够使用 bash/git 为所有分支执行此操作。
这列出了后代提交(和给定的根):
git_list_all_descendant_hashes() {
COMMIT=$1
if [[ ${#COMMIT} -lt 40 ]]; then # short commit hash, need full hash
COMMIT=`git rev-parse ${COMMIT}`
fi
declare -A ALL_HASHES
while IFS= read -r string; do
IFS=' ' read -r -a array <<< $string
key=${array[0]}
value=${array[@]:1}
ALL_HASHES[${key}]=$value
done <<< $(git rev-list --children --all)
declare -A HASHES # subset of ALL_HASHES that are descendants
HASHES[${COMMIT}]=1
added_hashes=1
while [[ ${added_hashes} -gt 0 ]]; do
added_hashes=0
# this loop is inefficient, as it will iterate over all collected hashes each time a hash is found to have new children
for hash in ${!HASHES[@]}; do
for child_hash in ${ALL_HASHES[${hash}]}; do
if [[ ! -v HASHES[$child_hash] ]]; then
added_hashes=1
HASHES[${child_hash}]=1
fi
done
done
done
for hash in ${!HASHES[@]}; do
echo ${hash}
done
}
你可以调用它:
git_descendants() {
# the --short flag is a hack that'll return an error code if no argument is given, but git_list_all_descendant_hashes actually needs to turn it into a full hash
COMMIT=`git rev-parse --short $1 2>/dev/null || git rev-parse HEAD`
git log --graph --oneline --decorate ^${COMMIT}^@ $(git_list_all_descendant_hashes ${COMMIT})
}
如果后代有多个父母(即来自合并提交),它也会显示其非根祖先。这是我很满意的事情,所以我没有费心去想如何摆脱它。
【讨论】:
简而言之:
git log --all BRANCH~1..
详细示例:这是我刚刚创建的存储库的完整树:
$ git log --graph --oneline --decorate --all
* e3972be (HEAD, a) a-6
* 2707d79 a-5
* cdea9a7 a-4
| * 65b716e (c) c-5
| * ebe2a0e c-4
|/
| * 2ed9abe (b) b-4
|/
* ace558e (master) 3
* 20db61f 2
* 3923af1 1
除了--all,还有一点很明显:master -> HEAD:
$ git log --graph --oneline --decorate master..
* e3972be (HEAD, a) a-6
* 2707d79 a-5
* cdea9a7 a-4
所以我尝试将它们组合起来,它几乎得到了我们想要的:
$ git log --graph --oneline --decorate --all master..
* e3972be (HEAD, a) a-6
* 2707d79 a-5
* cdea9a7 a-4
* 65b716e (c) c-5
* ebe2a0e c-4
* 2ed9abe (b) b-4
但不幸的是,这并没有显示分支之间的关系,因为我们询问的分支被省略了。所以我们必须使用来自master 父级的日志,如下所示:
$ git log --graph --oneline --decorate --all master~1..
* e3972be (HEAD, a) a-6
* 2707d79 a-5
* cdea9a7 a-4
| * 65b716e (c) c-5
| * ebe2a0e c-4
|/
| * 2ed9abe (b) b-4
|/
* ace558e (master) 3
哒哒! (我不知道这在过去是否根本不起作用,但以防万一:我使用的是 git 版本 1.7.1)
编辑 2017-11-17 - 感谢 STW 实际展示了这个问题:独立树会搞砸这个。完全独立于master 的提交将包含在此输出中。从上述 repo 的副本开始,这是我最后一个命令的输出:
$ git checkout --orphan z
Switched to a new branch 'z'
$ git commit --allow-empty -m'z-1'
[z (root-commit) bc0c0bb] z-1
$ git commit --allow-empty -m'z-2'
[z 1183713] z-2
$ git log --graph --oneline --decorate --all master~1..
* 1183713 (HEAD -> z) z-2
* bc0c0bb z-1
* 6069f73 (a) a-6
* 654d106 a-5
* a218c59 a-4
| * 338432a (c) c-5
| * 2115318 c-4
|/
| * 43a34dc (b) b-4
|/
* ce05471 (master) 3
z 分支是作为孤儿创建的,与 master 没有共同的历史记录,因此 z-1 和 z-2 应该被排除但没有。这就是--ancestry-path 的用途,我现在明白了。包括它将排除分支z:
$ git log --graph --oneline --decorate --all --ancestry-path master~1..
* 6069f73 (a) a-6
* 654d106 a-5
* a218c59 a-4
| * 338432a (c) c-5
| * 2115318 c-4
|/
| * 43a34dc (b) b-4
|/
* ce05471 (master) 3
为了完整起见,即使已经有了--ancestry-path,当前的最佳答案也没有正确显示分支关系,因为它排除了master 本身的提交:
$ git log --graph --oneline --decorate --all --ancestry-path master..
* 6069f73 (a) a-6
* 654d106 a-5
* a218c59 a-4
* 338432a (c) c-5
* 2115318 c-4
* 43a34dc (b) b-4
【讨论】:
log 时,我在gitk 中得到与log 相同的输出(而不是git log --all master~1.. - 所以,使用除大师,试试gitk --all branchname..(包括两个点)
--ancestry-path 以及为什么有必要
foo.. 不是指foo..HEAD 之类的吗?也就是说,这不取决于您当前的分支吗?即我想要一个不依赖于当前分支的解决方案。
--all 的原因。如果您查看我回答中的最后一个示例,尽管HEAD 位于分支a,但分支b 和c 也是可见的,因为它们当前是master 的子分支
我认为这可能会满足您的需求。以 A 为祖先的所有分支中的所有提交:
gitk --all --ancestry-path A..
【讨论】:
提交只知道它的父级(因此一直向上),但不知道它的子级/后代。您必须使用 A..B 之类的符号才能找到它。
例如,如果您想在当前分支中查找自给定提交 A 以来的提交,您可以执行以下操作:
git rev-list A..
【讨论】:
gitk --all 必须以某种方式工作。似乎至少可以先将其编码为gitk --all,然后省略每个没有将给定提交作为其父提交的提交。