Как я могу получить/перечислить/увидеть всех потомков коммита с помощью git (или gitk)?

Если вы используете gitk --all, вы можете увидеть все коммиты вашего репо из всех веток. Я хочу что-то подобное, кроме потомков данной фиксации.


person Pistos    schedule 11.12.2011    source источник
comment
Хотя первое предложение manojlds правильное, это не вся правда: можно было бы что-то запутать, чтобы проверить, есть ли у каждой ссылки данный коммит в его родословной, а затем отобразить историю, начиная с этих ссылок.   -  person Cascabel    schedule 11.12.2011
comment
возможный дубликат Получение списка всех дочерних элементов данного зафиксировать   -  person jthill    schedule 15.06.2014


Ответы (4)


Я думаю, это может сделать то, что вы хотите. Все коммиты во всех ветках, предком которых является A:

gitk --all --ancestry-path A..
person jsvnm    schedule 17.02.2012

Короче говоря:

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)

РЕДАКТИРОВАТЬ 17 11 2017 . Спасибо 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
person Izkata    schedule 08.05.2014
comment
Я пробовал возиться с вариациями этого, но, похоже, он не совсем показывает, чего я хочу [с gitk]. Например, предположим, что вы создали промежуточную дочернюю ветку, а оттуда создали 3 ветки-внука. Как можно было бы показать gitk только для этого семейства ветвей, а не для мастера или чего-то еще? - person Pistos; 13.05.2014
comment
@Pistos Итак, используя вышеизложенное, я получаю тот же вывод в gitk, что и log, когда я использую gitk --all master.. (в отличие от git log --all master~1... Итак, чтобы использовать ветку, отличную от master, попробуйте gitk --all branchname.. (включите две точки) - person Izkata; 14.05.2014
comment
@Pistos Теперь я также отмечаю, что мой комментарий оказался почти таким же, как ответ jsvnm, за исключением того, что я не совсем понимаю --ancestry-path и зачем это нужно - person Izkata; 14.05.2014
comment
Разве foo.. не означает foo..HEAD или что-то в этом роде? то есть это не зависит от вашей текущей ветки? то есть я хочу решение, которое не зависит от того, является ли текущая ветвь чем-то конкретным. - person Pistos; 14.05.2014
comment
@Pistos Да, но именно поэтому мы также используем --all. Если вы посмотрите на последний пример в моем ответе, несмотря на то, что HEAD находится в ветке a, ветки b и c также видны, потому что в настоящее время они являются дочерними ветвями master. - person Izkata; 14.05.2014
comment
Я пытаюсь сделать это с локальным репозиторием, и --all показывает слишком много, с фиксациями, которые не имеют ничего общего с одной фиксацией/веткой, от которой я пытаюсь получить потомков. Можете ли вы попробовать это со зрелым репо со многими (сотнями) коммитами и многими (20+) ветками? - person Pistos; 15.05.2014
comment
--all показывает вам все коммиты в репозитории, включая совершенно не связанные коммиты. - person STW; 17.11.2017
comment
@STW Да, и вопрос задан для всех потомков, поэтому --all необходимо включить их, а не только путь от ветки к HEAD. branch~1.. затем удаляет предков и неродственных потомков этих предков. - person Izkata; 17.11.2017
comment
@Izkata - branch~1.., похоже, исключает старые коммиты, но не отфильтровывает несвязанные коммиты. tpcg.io/K09v2Z - person STW; 17.11.2017
comment
@STW Ааа, независимое дерево. Я знал, что git может это сделать, но лично никогда не видел этого в дикой природе. - person Izkata; 17.11.2017
comment
Им не нужно быть независимыми, эта команда зависит от хронологии, а не от происхождения. - person STW; 18.11.2017

Коммит знает только о своем родителе (и, следовательно, полностью), но не имеет ни малейшего представления о своих дочерних элементах/потомках. Вы должны использовать обозначение типа A..B, чтобы найти его.

Например, если вы хотите найти коммиты в текущей ветке, начиная с данного коммита A, вы можете сделать что-то вроде этого:

git rev-list A..
person manojlds    schedule 11.12.2011
comment
gitk --all должно как-то работать. Кажется возможным, по крайней мере, закодировать его сначала gitk --all, а затем пропустить каждый коммит, который не имеет данного коммита в качестве родителя. - person Pistos; 11.12.2011

Я смог сделать это для всех веток, используя 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})
}

Если потомок имеет несколько родителей (например, из коммита слияния), он также покажет свое происхождение без полномочий root. Это то, чем я был доволен, поэтому я не стал выяснять, как от этого избавиться.

person Sean    schedule 24.12.2020