Ссылка на ребенка коммита в Git - PullRequest
35 голосов
/ 19 ноября 2009

Если вы хотите переместить HEAD к родителю текущего HEAD, это просто:

git reset --hard HEAD^

Но есть ли простой способ сделать прямо противоположное этой операции, то есть установить головку в качестве первого дочернего коммита текущей головы?

Сейчас я использую gitk в качестве обходного пути (alt-tab, up-arrow, alt-tab, middle-click), но я бы хотел более элегантное решение, которое также можно использовать, когда gitk недоступен .

Ответы [ 10 ]

16 голосов
/ 19 ноября 2009

Скорее всего, не самое быстрое решение, но оно делает то, что мне нужно:

#!/bin/bash

REV=$1

if [[ -z "$REV" ]]; then
    echo "Usage: git-get-child  []"
    exit
fi

HASH=$(git rev-parse $REV)

NUM=$2

if [[ -z "$NUM" ]]; then
    NUM=1
fi

git rev-list --all --parents | grep " $HASH" | sed -n "${NUM}s/\([^ ]*\) .*$/\\1/p"

git rev-list --all --parents делает именно то, что мне нужно: он перебирает все достижимые коммиты и печатает следующую строку для каждого:

SHA1_commit SHA1_parent1 SHA1_parent2 и т. Д.

Пробел в выражении grep гарантирует, что будут найдены только те строки, где рассматриваемый SHA1 является родителем. Затем мы получаем n-ю строку для n-го ребенка и получаем SHA1 этого ребенка.

12 голосов
/ 18 марта 2011

Метод выше с использованием git rev-list --all учитывает все доступные коммиты, которые могут быть много и часто не нужны. Если интересующие дочерние коммиты доступны из некоторой ветви, число коммитов, которые должен обработать скрипт, интересующий дочерние коммиты, может быть уменьшено:

branches=$(git branch --contains $commit| grep -v '[*] ('| sed -e 's+^..++')

определит набор ветвей, предком которых является $ commit. С современным git, по крайней мере, версии 2.21+, это должно делать то же самое без необходимости sed (не проверено):

branches=$(git branch --format='%(refname:short)' --contains $commit| grep -v '[*] (')

Используя этот набор, git rev-list --parents ^$commit $branches должен привести именно к набору всех родительско-дочерних отношений между $ commit и всеми заголовками ветвей, предком которых он является.

4 голосов
/ 10 января 2014

Основываясь частично на ответе Пола Уогланда и частично на его источнике , я использую следующее:

git log --ancestry-path --format=%H ${commit}..master | tail -1

Я обнаружил, что ответ Пола дал мне неправильный вывод для старых коммитов (возможно, из-за слияния?), Где основным отличием является флаг --ancestry-path.

3 голосов
/ 18 сентября 2016

Чтобы просто переместить HEAD (как и просили - это не обновляет индекс или рабочее дерево), используйте:

git reset --soft $(git child)

Вам потребуется использовать конфигурацию, указанную ниже.

Объяснение

Основываясь на ответе @ Майкла , я взломал псевдоним 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 на $*, чтобы напечатать все дочерние элементы

3 голосов
/ 19 ноября 2009

Вы можете использовать gitk ..., поскольку может быть более одного ребенка, вероятно, нет простого способа, как HEAD^.

Если вы хотите отменить всю операцию, вы также можете использовать reflog. Используйте git reflog, чтобы найти указатель вашего коммита, который вы можете использовать для команды reset. Смотри здесь .

2 голосов
/ 20 января 2013

На основании ответа, данного в Как мне найти следующий коммит в git? , у меня есть другое решение, которое работает для меня.

Предполагая, что вы хотите найти следующую ревизию в "основной" ветке, вы можете сделать:

git log --reverse ${commit}..master | sed 's/commit //; q'

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

2 голосов
/ 19 ноября 2009

Это зависит от того, что вы спрашиваете. Может существовать бесконечное число дочерних элементов текущей главы в бесконечном количестве ветвей, некоторые локальные, некоторые удаленные, и многие из них были перебазированы и находятся в вашем хранилище, но не являются частью истории, которую вы собираетесь опубликовать. 1001 *

Для простого случая, если вы только что сделали сброс на HEAD^, вы можете вернуть ребенка, которого только что выбросили, как HEAD@{1}.

1 голос
/ 22 ноября 2013

Вы можете использовать сущность создателя для Гудзона (теперь Дженкинс) Кохсуке Кавагути (ноябрь 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

Поместите этот скрипт в папку, на которую ссылается ваш $PATH, и просто введите:

git children-of <a-commit>
0 голосов
/ 03 апреля 2015

Этот пост (http://www.jayway.com/2015/03/30/using-git-commits-to-drive-a-live-coding-session/#comment-282667) показывает аккуратный способ, если вы делаете это, если вы можете создать четко определенный тег в конце стека фиксации. По существу git config --global alias.next '!git checkout `git rev-list HEAD..demo-end | tail -1`' где "demo-end" - последний тег.

0 голосов
/ 19 ноября 2009

Строго невозможно дать хороший ответ - поскольку git распространяется, большинство дочерних элементов коммита, о котором вы спрашиваете, могут находиться в репозиториях, которых у вас нет на вашем локальном компьютере! Это, конечно, глупый ответ, но есть над чем подумать. Git редко реализует операции, которые он не может выполнить правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...