Как я могу видеть, от какой ветки от нее разветвлялась ветка?
У моего репозитория git есть три ветки, devel
, stable
и customers/acme_patches
. Давно, stable
был разветвлен от devel
, и все исправления ошибок имеют место в stable
. Время от времени stable
снова объединяется в devel
. customers/acme_patches
- это ветвь с несколькими клиентскими патчами. Филиал не был объединен ни с одним из devel
и stable
.
Немного искусства ASCII, чтобы проиллюстрировать сценарий:
o---o---o customers/acme_patches?
/
o---o---1---o---o---o stable
/ \ \
o---o---o---2---o---o---o---o devel
\
o---o---o customers/acme_patches?
Теперь я задаюсь вопросом:
Какая ветвь была customers/acme_patches
разветвлена от - devel
или stable
? Я знаю только, что в прошлом он был раздвоен одним из них, но я не знаю, что. Например. он мог бы зафиксировать 1
или 2
на приведенной выше диаграмме.
Я играл с git log --oneline --graph
и gitk
, но поскольку customers/acme_patches
был разветвлен на несколько сотен комм. назад, трудно следовать за строками.
Может быть, быстрая команда (немного script тоже прекрасна), которая может каким-то образом выполнить коммиты в customers/acme_patches
назад, чтобы найти первый коммит с двумя дочерними элементами (точка fork), а затем определяет, было сделано в stable
или в devel
?
В лучшем случае я мог бы просто выполнить что-то вроде (извините приглашение, я на Windows):
C:\src> git fork-origin customers/acme_patches
stable
Ответы
Ответ 1
Ну, вероятно, нет идеального решения этого ответа. Я имею в виду, что эквивалент fork-origin
в git (насколько мне известно).
Поскольку ветвь stable
объединяется в devel
, ваш acme_patches
(от 1) находится на ветке devel
и stable
.
Что вы можете сделать:
git branch --contains $(git merge-base customers/acme_patches devel stable)
Если у вас стабильный, а не девелопмент, или девелопмент, а не стабильный, то вы знаете, откуда оно взялось.
Например, в случае 2 у вас будет
$ git branch --contains $(git merge-base customers/acme_patches devel stable)
customers/acme_patches
devel
в то время как в случае 1 у вас будет
$ git branch --contains $(git merge-base customers/acme_patches devel stable)
customers/acme_patches
devel
stable
Как сейчас, на обеих ветвях (из-за слияния от stable к dev)
Ответ 2
С git 1.9/2.0 (Q1 2014) вы можете использовать git merge-base --fork-point
для запроса лучшего общего предка в соответствии с Git.
Вы можете увидеть эту новую опцию:
А так как совершить ad8261d из John Keeping (johnkeeping
), git rebase
может использовать тот же самый новый параметр --fork-point
, который может пригодиться, если вам нужно переустановить ветвь типа customers/acme_patches
на devel
.
(Я не говорю, что это имело бы смысл в вашем конкретном сценарии)
Примечание: git 2.16 (Q1 2018) уточняет и улучшает документацию для "merge-base --fork-point
", так как было ясно, что она вычисляла, но не почему/зачем.
См. commit 6d1700b (09 ноября 2017 г.) Junio C Хамано (gitster
).
(слияние Junio C Hamano - gitster
- в совершить 022dd4a, 27 ноября 2017 г.)
merge-base --fork-point
doc: уточнить пример и режимы отказа
Иллюстрированная история, используемая для объяснения режима --fork-point
названный тремя ключевыми точками, фиксирует B3, B2 и B1 от самого старого до новейший, который трудно было прочитать.
Отнесите их к B0, B1, B2.
Также проиллюстрируйте историю после того, как была выполнена перезагрузка с использованием средства --fork-point
.
В тексте уже упоминается использование reflog, но описание не clear какую выгоду мы пытаемся получить с помощью reflog.
Уточните, что нужно найти коммиты, которые, как известно, находятся на кончике ветвь удаленного отслеживания.
Это, в свою очередь, требует от пользователей знать последствия базовых допущений, а именно, истечение записей reflog сделает невозможным определить, какие коммиты находились на кончике ветвей удаленного отслеживания, и мы терпим неудачу, когда сомневаемся (вместо того, чтобы давать случайные и неправильный результат без предупреждение).
Другим ограничением является то, что это не будет полезно, если вы не разветвлялись с кончика ветки удаленного слежения, а из середины.
Опишите их.
Итак документация теперь читает:
После работы с ветвью topic
, созданной с помощью git checkout -b
topic origin/master
, история ветки удаленного отслеживания origin/master
возможно, был переделан и перестроен, что привело к история этой формы:
o---B2
/
---o---o---B1--o---o---o---B (origin/master)
\
B0
\
D0---D1---D (topic)
где origin/master
используется для указания на значения B0, B1, B2 и теперь это точки в B, и ваша ветвь topic
была запущена поверх нее назад когда origin/master
был в B0, и вы построили три коммитов: D0, D1, и D, поверх нее.
Представьте, что теперь вы хотите переустановить работу, которую вы сделали в topic
, поверх обновленного origin/master
.
В таком случае git merge-base origin/master topic
вернет родительский элемент B0 на приведенном выше рисунке, но B0^..D
не является диапазоном вы обязуетесь переигрывать поверх B (он включает B0, который это не то, что вы написали; это битва, другая сторона отбрасывается, когда он переместил наконечник от B0 до B1).
git merge-base --fork-point origin/master topic
призван помочь в этом случае.
Требуется не только B, но также B0, B1 и B2 (т.е. старые подсказки ветвей удаленного отслеживания, о которых знает ваш репозиторий reflog), чтобы увидеть, на каком основании была создана ваша ветка темы, и находит B0, что позволяет вам воспроизводить только коммиты по вашей теме, за исключением коммитов другой стороны позже отбрасываются.
Следовательно
$ fork_point=$(git merge-base --fork-point origin/master topic)
найдет B0 и
$ git rebase --onto origin/master $fork_point topic
воспроизведет D0, D1 и D поверх B, чтобы создать новую историю этого форма:
o---B2
/
---o---o---B1--o---o---o---B (origin/master)
\ \
B0 D0'--D1'--D' (topic - updated)
\
D0---D1---D (topic - old)
Предостережение заключается в том, что старые записи reflog в вашем репозитории могут быть expired by git gc
.
Если B0 больше не отображается в рефлоге ветки удаленного слежения origin/master
, режим --fork-point
, очевидно, не может найти его и не удастся, избегая случайного и бесполезного результата (например, родительский элемент B0, как и ту же команду без опции --fork-point
).
Кроме того, ветвь удаленного отслеживания использует режим --fork-point
с тем должна быть ваша тема, раздвоенная с ее наконечника.
Если вы разветвлялись от более старой фиксации, чем кончик, этот режим не нашел бы точку fork (представьте себе, что в приведенной выше истории ошибок B0 не существует, origin/master
началось с B1, переместилось на B2, а затем B, и вы раздвоены ваша тема в origin/master^
, когда origin/master
был B1; форма история будет такой же, как и выше, без B0, а родительская B1 - это то, что git merge-base origin/master topic
правильно находит, но режим --fork-point
не будет, поскольку он не является одним из который раньше был на вершине origin/master
).
Ответ 3
Ну, git merge-base customers/acme_patches stable
должен показать общий предок этих двух ветвей.
Вы можете попробовать, например, gitk --left-right customers/acme_patches...stable
(отметьте три точки!). Это покажет все коммиты, которые находятся в этих ветвях, а не в базе слияния. Использование --left-right
будет отмечать каждую фиксацию стрелкой влево или вправо в соответствии с той ветвью, в которой они находятся в левой стрелке, если они находятся в клиенте /acme _patches и стрелке вправо, если они находятся в стабильном состоянии.
Возможно, добавление --date-order
, которое я нашел, иногда помогает понять результат.
(Этот синтаксис можно использовать с git log --graph
, а не gitk
, но imho - это случай, когда визуальный графический дисплей является большим улучшением).
Ответ 4
Не уверен, что он охватывает все случаи, но здесь функции, которые я придумал:
git_branch_contains() {
local b=$1
local c=$2
IFS_=$IFS
IFS=$'\n'
local branches=($(git branch --contains "$c" | sed -E 's/^(\*| ) //'))
IFS=$IFS_
for b2 in "${branches[@]:+${branches[@]}}"; do
if [ "$b2" = "$b" ]; then
return 0
fi
done
return 1
}
git_upstream_branch() {
local b=$1
local c1=$(git merge-base --fork-point master "$b") || local c1=
local c2=$(git merge-base --fork-point dev "$b") || local c2=
if ! [ "$c1" ]; then
echo dev
return
fi
if ! [ "$c2" ]; then
echo master
return
fi
local fp
if git merge-base --is-ancestor "$c1" "$c2"; then
fp=$c2
else
fp=$c1
fi
if git_branch_contains master "$fp" && ! git_branch_contains dev "$fp"; then
echo master
else
echo dev
fi
}
И здесь script для их проверки (git-upstream-branch-test.sh
):
#!/usr/bin/env bash
set -eu
. git-upstream-branch.sh
git_commit() {
if ! [ "${commit_i:-}" ]; then
commit_i=0
fi
(( commit_i++ )) || true
echo "$commit_i" > "$commit_i"
git add "$commit_i"
git commit -qm "c$commit_i"
}
git_merge() {
if ! [ "${merge_i:-}" ]; then
merge_i=0
fi
(( merge_i++ )) || true
git merge -m "$merge_i" $1
}
A_TOPOLOGY=${1:-}
mkdir git-upstream-branch-test-repo
cd git-upstream-branch-test-repo
git init -q
if [ "$A_TOPOLOGY" = 10 ]; then
git_commit
git_commit
git checkout -qb dev
git_commit
git_commit
git checkout -q master
git_commit
git_commit
c=$(git rev-parse HEAD)
git_commit
git_commit
git checkout -q dev
git checkout -qb t1
git_commit
git_commit
git checkout -q dev
git_commit
git_commit
git rebase --onto "$c" dev t1
elif [ "$A_TOPOLOGY" = 11 ]; then
git_commit
git_commit
git checkout -qb dev
git_commit
git_commit
git checkout -q master
git_commit
git_commit
git checkout -q dev
c=$(git rev-parse HEAD)
git_commit
git_commit
git checkout -q master
git checkout -qb t1
git_commit
git_commit
git checkout -q master
git_commit
git_commit
git rebase --onto "$c" master t1
else
git_commit
git_commit
git checkout -qb dev
git_commit
git_commit
git checkout -q master
git_commit
git_commit
if [ "$A_TOPOLOGY" = 4 ] || [ "$A_TOPOLOGY" = 5 ] || [ "$A_TOPOLOGY" = 6 ]; then
git_merge dev
git_commit
git_commit
git checkout -q dev
git_commit
git_commit
git checkout -q master
elif [ "$A_TOPOLOGY" = 7 ] || [ "$A_TOPOLOGY" = 8 ] || [ "$A_TOPOLOGY" = 9 ]; then
git checkout -q dev
git_merge master
git_commit
git_commit
git checkout -q master
git_commit
git_commit
fi
git checkout -qb t1
git_commit
git_commit
git checkout -q master
git_commit
git_commit
if [ "$A_TOPOLOGY" = 2 ] || [ "$A_TOPOLOGY" = 5 ] || [ "$A_TOPOLOGY" = 8 ]; then
git_merge dev
elif [ "$A_TOPOLOGY" = 3 ] || [ "$A_TOPOLOGY" = 6 ] || [ "$A_TOPOLOGY" = 9 ]; then
git checkout -q dev
git_merge master
fi
fi
git --no-pager log --oneline --graph --decorate --all
git_upstream_branch t1
Используйте его так,
$ rm -rf git-upstream-branch-test-repo && ./git-upstream-branch-test.sh NUMBER
Где NUMBER - это число от 1 до 11, чтобы указать, какой случай (топология) проверить.