Допустим, у меня есть следующий локальный репозиторий с деревом коммитов:
master --> a
\
\
develop c --> d
\
\
feature f --> g --> h
master
это мое это последний код стабильного релиза , develop
это мое это «следующий» код релиза , и feature
это новая функция готовится кdevelop
.
То, что я хочу делать в моем удаленном репо с использованием хуков, - feature
это отказ от толчков, если commit не f
является прямым потомком develop
HEAD. т.е. фиксации дерево выглядит так, потому что функция была git rebase
на d
.
master --> a
\
\
develop c --> d
\
\
feature f --> g --> h
Так возможно ли:
- Определить родительскую ветвь
feature
? - Определите коммит в родительской ветви, которая
f
является потомком?
Оттуда я бы проверил, что такое HEAD родительской ветви, и посмотрел, соответствует ли f
предшественник родительской ветви HEAD, чтобы определить, нужно ли перебазировать эту функцию.
Ответы:
Предполагая, что удаленный репозиторий имеет копию ветви разработки (ваше первоначальное описание описывает ее в локальном репозитории, но похоже, что она также существует в удаленном), вы должны быть в состоянии достичь того, что я думаю, что вы хотите, но подход немного отличается от того, что вы предполагали.
История Git основана на DAG коммитов. Ветви (и вообще «ссылки») - это просто временные метки, которые указывают на конкретные коммиты в постоянно растущей DAG коммитов. Таким образом, отношения между ветвями могут меняться со временем, но отношения между фиксациями не изменяются.
Похоже на
baz
основе (старой версии)bar
? Но что если мы удалимbar
?Теперь, похоже,
baz
основано наfoo
. Но происхождениеbaz
не изменилось, мы просто удалили метку (и получившийся висячий коммит). А что если мы добавим новый ярлык на4
?Теперь, похоже,
baz
основано наquux
. И все же родословная не изменилась, изменились только ярлыки.Если, однако, мы спрашиваем «является ли коммит
6
потомком коммита3
?» (предполагая , что3
и6
полный SHA-1 совершают имена), то ответ будет «да», то лиbar
иquux
метки присутствуют или нет.Таким образом, вы можете задать такие вопросы, как «является ли проталкиваемый коммит потомком текущего кончика ветви разработки ?», Но вы не можете с уверенностью спросить «какова родительская ветвь проталкиваемого коммита?».
Наиболее надежный вопрос, который, кажется, приближается к тому, что вы хотите:
Который может быть реализован как:
Это покроет то, что вы хотите ограничить, но, возможно, не все.
Для справки, вот расширенный пример истории:
Приведенный выше код может быть использован для отклонения
H
иS
при приемеH'
,J
,K
илиN
, но он также будет приниматьL
иP
(они включают слияние, но они не сливаются кончиком разработки ).Чтобы также отклонить
L
иP
, вы можете изменить вопрос и спроситьисточник
develop > release > feature
, я вернулась бы к развитию, и это требует знания родителей. Решение моей проблемы было stackoverflow.com/a/56673640/2366390Перефразирование
Другой способ сформулировать вопрос: «Какой ближайший коммит находится в ветке, отличной от текущей, и какая это ветка?»
Решение
Вы можете найти это с небольшим количеством волшебства командной строки
С awk :
Вот как это работает:
И результат
Запуск вышеуказанного кода на
Даст вам,
develop
если вы запустите его от H иmaster
если вы запустите его от I.Код доступен как суть
источник
cannot handle more than 25 refs
ack
это не доступно на Mac (кто-то предложил заменитьack
наgrep
)git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'
git show-branch | sed "s/].*//" | grep "\*" | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed "s/^.*\[//"
parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"
работает для меняВы также можете попробовать:
источник
git log --graph --decorate --simplify-by-decoration
где--graph
не обязательно.git log --graph --decorate --simplify-by-decoration --oneline
мерзавец родитель
Вы можете просто запустить команду
git parent
чтобы найти родителя ветви, если вы добавите ответ @Joe Chrysler в качестве псевдонима git . Это упростит использование.
Откройте файл gitconfig, расположенный в
"~/.gitconfig"
любом текстовом редакторе. (Для Linux). А для Windows путь ".gitconfig" обычно находится по адресуc:\users\your-user\.gitconfig
Добавьте следующую команду псевдонимов в файл:
Сохраните и выйдите из редактора.
Запустите команду
git parent
Это оно!
источник
cannot handle more than 25 refs
исключения.У меня есть решение вашей общей проблемы (определите,
feature
происходит ли оно от кончикаdevelop
), но оно не работает с использованием описанного вами метода.Вы можете использовать,
git branch --contains
чтобы перечислить все ветви, произошедшие от кончикаdevelop
, а затем использовать,grep
чтобы убедиться, чтоfeature
среди них есть.Если он находится среди них, он выводит
" feature"
на стандартный вывод и имеет код возврата 0. В противном случае он ничего не печатает и имеет код возврата 1.источник
<branch>
, где я выполнил:git checkout -b <branch-2>
от ... ЭТО ответ! Нет необходимости в grep, правда.git branch --contains <branch>
Это работает хорошо для меня.
Вежливые ответы от: @droidbot и @Jistanidiot
источник
*
не является подходящим регулярным выражением для перехода к grep. Следует использоватьgrep -F '*'
илиgrep '\*'
вместо. Хорошее решение в противном случае.Поскольку ни один из ответов выше не работал в нашем хранилище, я хочу поделиться своим собственным способом, используя последние слияния в
git log
:Поместите его в скрипт с именем
git-last-merges
, который также принимает имя ветви в качестве аргумента (вместо текущей ветви), а также другиеgit log
аргументыИсходя из результатов, мы можем вручную определить родительскую ветвь (и) на основе собственных соглашений о ветвлении и количества слияний от каждой ветви.
РЕДАКТИРОВАТЬ: Если вы
git rebase
часто используете дочерние ветви (и слияния часто переадресовываются, так что не слишком много коммитов слияния), этот ответ не будет работать хорошо, поэтому я написал скрипт для подсчета коммитов вперед (обычный и слияния) и за коммитами (не должно быть никаких слияний в родительской ветке) во всех ветках по сравнению с текущей веткой. Просто запустите этот скрипт и дайте мне знать, работает у вас или нетисточник
rebase
часто используете (и слиянияfast-forward
редактируются часто). Я отредактирую свой ответ, если найду лучшее решение.git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 1 | cut -d ' ' -f 8
Решение
Решение, основанное на,
git show-branch
мне не совсем помогло (см. Ниже), поэтому я объединил его с решением, основанным наgit log
и в конечном итоге с этим:Ограничения и предостережения
log
командеmaster
иdevelop
результаты ( в основном) в<SHA> Initial commit
Результаты
Несмотря на существование локальной ветви (например,
origin/topic
присутствует только с момента фиксацииO
была извлечена непосредственно его SHA), скрипт должен напечатать следующее:G
,H
,I
(филиалhotfix
) →master
M
,N
,O
(филиалfeature/a
) →develop
S
,T
,U
(филиалfeature/c
) →develop
P
,Q
,R
(филиалfeature/b
) →feature/a
J
,K
,L
(филиалdevelop
) →<sha> Initial commit
*B
,D
,E
,F
(филиалmaster
) →<sha> Initial commit
* - или
master
еслиdevelop
коммиты были на вершине HEAD мастера (~ мастер мог бы быстро развиваться)Почему у меня не работает шоу-ветка
Решение на основе
git show-branch
оказалось ненадежным для меня в следующих ситуациях:grep '\*' \
на `grep '!' \ - и это только начало всех неприятностейmaster
иdevelop
приводитdevelop
и `` соответственноmaster
ветви (hotfix/
ветви) заканчиваютсяdevelop
как родитель, так как их ближайшийmaster
родительский филиал был отмечен!
вместо*
по причине.источник
"!git log --decorate --simplify-by-decoration --oneline | grep -v '(HEAD' | head -n1 | sed 's/.* (\\(.*\\)) .*/\\1/' | sed 's/\\(.*\\), .*/\\1/' | sed 's/origin\\///'"
Помните, что, как описано в «Git: Поиск ветви, из которой получен коммит» , вы не можете легко определить ветку, в которой был сделан этот коммит (ветви могут быть переименованы, перемещены, удалены ...), даже если
git branch --contains <commit>
это начало.git branch --contains <commit>
не перечислитеfeature
ветку и списокdevelop
ветвей,/refs/heads/develop
Если идентификаторы двух коммитов совпадают, вы можете идти (это будет означать, что
feature
ветвь имеет свое происхождение в HEAD ofdevelop
).источник
Магия командной строки JoeChrysler может быть упрощена. Вот логика Джо - для краткости я ввел параметр, названный
cur_branch
вместо подстановки команд`git rev-parse --abbrev-ref HEAD`
в обеих версиях; это можно инициализировать так:Тогда вот трубка Джо:
Мы можем выполнить то же самое, что и все пять из этих отдельных фильтров команд, в относительно простой
awk
команде:Это ломается так:
разделить строку на поля в
]
,^
,~
и[
персонажах.Найти строки, которые содержат звездочку
... но не текущее имя ветки
Когда вы найдете такую строку, напечатайте ее второе поле (то есть часть между первым и вторым вхождением наших символов разделителя полей). Для простых имен ветвей это будет именно то, что находится в скобках; для ссылок с относительными переходами это будет просто имя без модификатора. Таким образом, наш набор разделителей полей обрабатывает назначение обеих
sed
команд.Тогда выходите немедленно. Это означает, что он обрабатывает только первую совпадающую строку, поэтому нам не нужно передавать данные через него
head -n 1
.источник
Вот реализация Power Mark для решения Марка Рида:
источник
Я не говорю, что это хороший способ решить эту проблему, однако, похоже, это работает для меня.
git branch --contains $(cat .git/ORIG_HEAD)
Проблема в том, что cat'ing файл заглядывает во внутреннюю работу git, так что это не обязательно совместимо вперед (или обратно).источник
Кроссплатформенная реализация с Ant
источник
@Mark Reed: Вы должны добавить, что строка коммита должна содержать не только звездочку, но и начинаться со звездочки! В противном случае сообщения о фиксации, содержащие звездочку, также включаются в соответствующие строки. Так и должно быть:
git show-branch -a | awk -F'[]^~[]' '/^\*/ && !/'"$current_branch"'/ {print $2;exit}'
или длинная версия:
источник
Достигает того же конца, что и ответ Марка Рида, но использует гораздо более безопасный подход, который не ведет себя неправильно в ряде сценариев:
-
не*
*
источник
Любой, кто хочет сделать это в наши дни - приложение Atlassian SourceTree показывает вам наглядное представление о том, как ваши ветви связаны друг с другом, то есть, где они начались и где они в настоящее время находятся в порядке фиксации (например, HEAD или 4 коммитов и т. Д.) ,
источник
Если вы используете Source Tree, посмотрите на детали вашего коммита> Parents>, тогда вы увидите подчеркнутые номера коммитов (ссылки)
источник
Альтернатива:
git rev-list master | grep "$(git rev-list HEAD)" | head -1
Получите последний коммит, который является моей веткой и
master
(или любой веткой, которую вы хотите указать)источник
Это не сработало для меня, когда я сделал что-то подобное
develop > release-v1.0.0 > feature-foo
, все пошло бы назад, чтобы развиться, заметьте, что произошел ребазинг, не уверен, что это усугубляет мою проблему ...Следующий код дал мне правильный коммит
источник