Ссылка на дочерний элемент фиксации в Git
Если вы хотите переместить HEAD
в родительский элемент текущего HEAD
, это легко:
git reset --hard HEAD^
Но существует ли какой-либо простой способ сделать точную противоположность этой операции, то есть установить головку в текущую головку с первым потомком?
В настоящее время я использую gitk в качестве обходного пути (alt-tab, стрелка вверх, alt-tab, средний щелчок), но мне хотелось бы более элегантное решение, которое также можно использовать, когда gitk недоступен.
Ответы
Ответ 1
Очень вероятно не самое быстрое решение, но оно делает то, что мне нужно:
#!/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.
Ответ 2
Приведенный выше метод с использованием 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 и всеми git rev-list --parents ^$commit $branches
предком которых он является.
Ответ 3
Отчасти на основе Пол Вагленд ответ и частично на его источник, я используя следующее:
git log --ancestry-path --format=%H ${commit}..master | tail -1
Я обнаружил, что ответ Павла дал мне неправильный результат для более старых коммитов (возможно, из-за слияния?), где основное различие - это флаг --ancestry-path
.
Ответ 4
Вы можете использовать gitk
... так как может быть более одного ребенка, вероятно, нет простого способа, как HEAD^
.
Если вы хотите отменить всю операцию, вы также можете использовать reflog. Используйте git reflog
, чтобы найти указатель Commits, который вы можете использовать для команды reset
. См. здесь.
Ответ 5
Чтобы просто переместить HEAD (как задано - это не обновляет индекс или рабочее дерево), используйте:
git reset --soft $(git child)
Вам нужно будет использовать конфигурацию, указанную ниже.
Объяснение
Основываясь на @Michael answer, я взломал псевдоним 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
на $*
, чтобы напечатать все дочерние элементы
Ответ 6
Это зависит от того, что вы просите. В бесконечном числе ветвей может быть бесконечное число дочерних элементов, несколько локальных, некоторых удаленных и многие из которых были переустановлены и находятся в вашем репозитории, но не являются частью истории, которую вы собираетесь опубликовать.
Для простого случая, если вы только что сделали reset до HEAD^
, вы можете вернуть ребенка, который вы просто выбросили, как [email protected]{1}
.
Ответ 7
Основываясь на ответе, приведенном в Как найти следующую фиксацию в git?, у меня есть другое решение, которое работает для меня.
Предполагая, что вы хотите найти следующую ревизию в ветке "master", вы можете сделать:
git log --reverse ${commit}..master | sed 's/commit //; q'
Это также предполагает, что есть одна следующая ревизия, но в любом случае это предположение принято вопросом.
Ответ 8
Вы можете использовать сущность создателя для Хадсона (теперь Дженкинс) Kohsuke Kawaguchi (ноябрь 2013):
kohsuke / git-children-of
:
Учитывая фиксацию, найдите немедленных дочерних элементов этой фиксации.
#!/bin/bash -e
# given a commit, find immediate children of that commit.
for arg in "[email protected]"; 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
Поместите этот script в папку, на которую ссылается ваш $PATH
, и просто введите:
git children-of <a-commit>
Ответ 9
Невозможно дать хороший ответ - поскольку распределяется git, большинство дочерних элементов комманды, о которых вы спрашиваете, могут быть в репозиториях, которые у вас нет на вашей локальной машине! Это, конечно, глупый ответ, но о чем подумать. git редко реализует операции, которые он не может реализовать правильно.
Ответ 10
Этот пост (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" - последний тег.