Как я могу получить / просмотреть / увидеть всех потомков коммита с помощью git (или gitk)?
Если вы используете gitk --all
, вы можете увидеть все коммиты вашего репо из всех веток. Я хочу что-то подобное, кроме только потомков данного коммита.
4 ответа
Я думаю, что это может сделать то, что вы хотите. Все коммиты во всех ветвях, которые имеют A в качестве предка:
gitk --all --ancestry-path A..
Короче:
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
будет включен в этот вывод. Начиная с копии вышеупомянутого репозитория, вот что будет выводить моя последняя команда:
$ 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
Коммит знает только о своем родителе (и, следовательно, полностью), но не имеет представления о своих потомках / потомках. Вы должны использовать нотацию типа A..B, чтобы найти ее.
Например, если вы хотите найти коммиты в текущей ветке начиная с данного коммита A, вы можете сделать что-то вроде этого:
git rev-list A..
Я смог сделать это для всех веток, используя 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})
}
Если потомок имеет несколько родителей (т. е. из коммита слияния), он также покажет своего некорневого предка. Это то, чем я был доволен, поэтому я не стал выяснять, как от этого избавиться.