Как мне найти следующий коммит в git? (ребенок / дети реф.) - PullRequest
206 голосов
/ 15 февраля 2010

ref^ относится к коммиту до ref, как насчет получения коммита после ref?

Например, если я git checkout 12345 как мне проверить следующий коммит?

Спасибо.

PS Да, git - это дерево структуры указателя узла DAG. Как мне найти коммит после этого?

Ответы [ 14 ]

163 голосов
/ 26 марта 2012

Чтобы вывести список всех коммитов, начиная с текущего, а затем его потомка и т. Д. - в основном это стандартный git log, но в другом направлении используйте что-то вроде

git log --reverse --ancestry-path 894e8b4e93d8f3^..master

, где 894e8b4e93d8f3 - первый коммит, который вы хотите показать.

33 голосов
/ 15 февраля 2010

Создатель для Гудзона (теперь Дженкинс) Kohsuke Kawaguchi только что опубликовано (ноябрь 2013):
kohsuke / git-children-of :

С учетом коммита найдите непосредственных потомков этого коммита.

#!/bin/bash -e
# given a commit, find immediate children of that commit.
for arg in "$@"; do
  for commit in $(git rev-parse $arg^0); do
    for child in $(git log --format='%H %P' --all | grep -F " $commit" | cut -f1 -d' '); do
      git describe $child
    done
  done
done

Как показано этой цепочкой , в VCS на основе истории, представленной DAG (направленный ациклический граф) , не существует ни «одного родителя», ни «одного потомка».

        C1 -> C2 -> C3
      /               \
A -> B                  E -> F
      \               /
        D1 -> D2 ----/

Упорядочение коммитов осуществляется с помощью «топ-заказа» или «даты-заказа» (см. книга GitPro )

Но начиная с Git1.6.0 , вы можете перечислить дочерних элементов коммита.

git rev-list --children
git log --children

Примечание: для родительских коммитов возникает та же проблема с суффиксом ^ к параметру ревизии, означающему first parent этого объекта коммита. ^<n> означает <n>-го родителя (т. Е. rev^ эквивалентно rev^1).

Если вы находитесь на ветке foo и используете "git merge bar", тогда foo будет первым родителем.
I.e: Первый родитель - это ветвь, в которой вы были, когда вы сливались, а второй - коммит в ветке, в которую вы вошли.

18 голосов
/ 20 мая 2012

что я нашел, это

git rev-list --ancestry-path commit1..commit2

, где я устанавливаю commit1 в качестве текущего коммита и commit2 для текущего заголовка. Это возвращает мне список всех коммитов, которые строят путь между commit1 и commit2.

Последняя строка вывода является дочерним элементом commit1 (на пути к commit2).

8 голосов
/ 27 февраля 2012

Я знаю, что вы имеете в виду.Расстраивает наличие обильного синтаксиса для перехода к предыдущим коммитам, но нет перехода к следующим.В сложной истории проблема «что будет следующим коммитом» становится довольно сложной, но затем в сложном слиянии возникает такая же сложность и с «предыдущими» коммитами.В простом случае, внутри одной ветви с линейной историей (даже локально для некоторого ограниченного числа коммитов) было бы неплохо и имеет смысл идти вперед и назад.

Однако реальная проблема с этимв том, что на дочерние коммиты не ссылаются, это только список с обратной связью.Поиск дочернего коммита требует поиска, что не так уж и плохо, но, вероятно, не то, что git хочет включить в логику refspec.

В любом случае, я столкнулся с этим вопросом, потому что я просто хочу сделать шаг впередв истории один коммит за раз, делая тесты, и иногда вам приходится шагать вперед, а не назад.Что ж, подумав еще немного, я придумал это решение:

Выберите коммит вперед, где вы находитесь.Вероятно, это может быть глава филиала.Если вы находитесь на ветке ~ 10, то "git checkout branch ~ 9", затем "git checkout branch ~ 8", чтобы получить следующую после этого, затем "git checkout branch ~ 7" и так далее.

Уменьшение числа должно быть действительно простым в скрипте, если вам это нужно.Намного проще, чем разбирать git rev-list.

6 голосов
/ 19 сентября 2016

Два практических ответа:

Один ребенок

На основании @ ответа Майкла я взломал псевдоним child в своем .gitconfig.

Он работает как положено в случае по умолчанию, а также универсален.

# Get the child commit of the current commit.
# Use $1 instead of 'HEAD' if given. Use $2 instead of curent branch if given.
child = "!bash -c 'git log --format=%H --reverse --ancestry-path ${1:-HEAD}..${2:\"$(git rev-parse --abbrev-ref HEAD)\"} | head -1' -"

По умолчанию он задает дочерний элемент HEAD (если не указан другой аргумент commit-ish), следуя одному шагу предка к вершине текущей ветви (если в качестве второго аргумента не указан другой commit-ish).

Используйте %h вместо %H, если хотите получить форму короткого хэша.

Несколько детей

С отсоединенной ГОЛОВКОЙ (нет ветки) или чтобы получить всех детей независимо от ветвей:

# For the current (or specified) commit-ish, get the all children, print the first child 
children = "!bash -c 'c=${1:-HEAD}; set -- $(git rev-list --all --not \"$c\"^@ --children | grep $(git rev-parse \"$c\") ); shift; echo $1' -"

Измените $1 на $* для печати всех детей.

Вы также можете изменить --all на коммит, чтобы отображать только потомков, которые являются предками этого коммита, другими словами, отображать только потомков «в направлении» данного коммита. Это может помочь вам сузить вывод от многих детей до одного.

6 голосов
/ 02 декабря 2015

В случае, если вы не имеете в виду конкретную фиксацию «назначения», а вместо этого хотите видеть дочерние коммиты, которые могут быть в любой ветви, вы можете использовать эта команда:

git rev-list --children --all | grep ^${COMMIT}

Если вы хотите увидеть всех детей и внуков , вы должны использовать rev-list --children рекурсивно, например:

git rev-list --children --all | \
egrep ^\($(git rev-list --children --all | \
           grep ^${COMMIT} | \
           sed 's/ /|/g')\)

(Версия, которая дает только внукам, будет использовать более сложные sed и / или cut.)

Наконец, вы можете передать это в команду log --graph, чтобы увидеть древовидную структуру, например:

git log --graph --oneline --decorate \
\^${COMMIT}^@ \
$(git rev-list --children --all | \
  egrep ^\($(git rev-list --children --all | \
             grep ^${COMMIT} | \
             sed 's/ /|/g')\))

Примечание : все вышеприведенные команды предполагают, что вы установили переменную оболочки ${COMMIT} для некоторой ссылки (branch, tag, sha1) коммита, чьи дочерние элементы вам интересны.

6 голосов
/ 15 февраля 2010

Не существует уникального «следующего коммита». Поскольку история в Git - это DAG, а не строка, многие коммиты могут иметь общего родителя (ветви), а коммиты могут иметь более одного родителя (слияния).

Если вы имеете в виду конкретную ветвь, вы можете посмотреть в ее журнале и посмотреть, в каком коммите указана текущая ветвь в качестве его родителя.

4 голосов
/ 17 ноября 2015

Я пробовал много разных решений, и ни одно из них не помогло мне. Пришлось придумать свое.

найти следующий коммит

function n() {
    git log --reverse --pretty=%H master | grep -A 1 $(git rev-parse HEAD) | tail -n1 | xargs git checkout
}

найти предыдущий коммит

function p() {
    git checkout HEAD^1
}
4 голосов
/ 03 мая 2015

У меня есть этот псевдоним в ~/.gitconfig

first-child = "!f() { git log  --reverse --ancestry-path --pretty=%H $1..${2:-HEAD} | head -1; }; f"
2 голосов
/ 06 июня 2012

Мне удалось найти следующего ребенка следующим образом:

git log --reverse --children -n1 HEAD (where 'n' is the number of children to show)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...