Различные методы ниже прагматичны, полезно, работая пути , выводить на вероятный ответ, но давайте обратим внимание , что в мерзавец сам вопрос недоразумение, совершающие не из ветвей. Филиалы приходят и уходят, они движутся, только коммиты представляют реальную историю репо. Опять же, это не способ сказать, что решения ниже плохие. Просто знайте, что ни один из них не дает полностью достоверного ответа, который недоступен в git. (Простой случай - удаленные ветки: я разветвляюсь, дважды фиксирую, объединяюсь с другой веткой, удаляю первую ветку. Откуда берется коммит?
RomainValeri
1
У меня есть случай, когда я явно извлекаю мелкий клон глубиной 1 из тега. Это дешево, легко и эффективно ... и до сих пор делал все, что хотел красиво. Теперь, когда я хотел бы знать, на какой ветви был тег, я думаю, по крайней мере, для этой детали. Вы не можете всегда идти домой, лол
Пол Ходжес
Ответы:
865
Хотя Дэв прав, что информация не хранится напрямую, это не значит, что вы никогда не узнаете. Вот несколько вещей, которые вы можете сделать.
Найти ветки, на которых зафиксирован коммит
git branch -a --contains <commit>
Это расскажет вам все ветви, которые имеют данный коммит в своей истории. Очевидно, что это менее полезно, если коммит уже был объединен.
Поиск по журналам
Если вы работаете в репозитории, в котором была сделана фиксация, вы можете найти в журналах регистрации строку для этой фиксации. Рефлоги старше 90 дней удаляются git-gc, поэтому если коммит слишком старый, вы его не найдете. Тем не менее, вы можете сделать это:
git reflog show --all | grep a871742
найти коммит a871742. Обратите внимание, что вы ДОЛЖНЫ использовать abbreviatd 7 первых цифр коммита. Вывод должен быть примерно таким:
a871742 refs/heads/completion@{0}: commit (amend): mpc-completion: total rewrite
с указанием того, что коммит был сделан по ветке "Завершение". Вывод по умолчанию показывает сокращенные хеши коммитов, поэтому не ищите полный хеш, иначе вы ничего не найдете.
git reflog show на самом деле просто псевдоним для git log -g --abbrev-commit --pretty=oneline , так что если вы хотите поиграть с форматом вывода, чтобы сделать разные вещи доступными для grep, это ваша отправная точка!
Если вы не работаете в репозитории, в котором была сделана фиксация, лучшее, что вы можете сделать в этом случае, - это изучить reflogs и выяснить, когда коммит был впервые представлен в вашем репозитории; если повезет, вы взяли ветвь, которой он был посвящен. Это немного сложнее, потому что вы не можете одновременно обходить как дерево коммитов, так и флаги. Вы хотели бы проанализировать выходные данные reflog, исследуя каждый хеш, чтобы увидеть, содержит ли он желаемый коммит или нет.
Найти последующий коммит слияния
Это зависит от рабочего процесса, но с хорошими рабочими процессами в ветки разработки вносятся коммиты, которые затем объединяются. Вы можете сделать это:
git log --merges <commit>..
видеть коммиты слияния, которые имеют данный коммит в качестве предка. (Если коммит был объединен только один раз, первым должно быть слияние, за которым вы следите; в противном случае, я полагаю, вам придется изучить несколько из них.) Сообщение коммита слияния должно содержать имя ветви, которая была объединена.
Если вы хотите иметь возможность рассчитывать на это, вы можете использовать --no-ffопцию git mergeдля принудительного создания коммитов слияния даже в случае ускоренной перемотки вперед. (Однако не слишком рвитесь. Это может стать запутывающим, если его чрезмерно использовать.) Ответ VonC на связанный вопрос услужливо развивает эту тему.
+1. Само отсутствие информации по этой конкретной проблеме заставляет задуматься, действительно ли это проблема? Филиалы могут быть изменены, переименованы или удалены в любое время. Может быть git describeдостаточно, поскольку (аннотированные) теги можно рассматривать как более значимые, чем ветви.
VonC
9
Я определенно согласен - ветки должны быть легкими и гибкими. Если вы принимаете рабочий процесс, в котором эта информация становится важной, вы можете использовать --no-ffопцию, чтобы убедиться, что всегда есть коммит слияния, так что вы всегда можете проследить путь данного коммита, когда он слился с master.
Каскабель
32
К вашему сведению, если вы хотите найти коммиты, которые существуют только на удаленном компьютере, добавьте -aфлаг к первой команде, например,git branch -a --contains <commit>
Jonathan Day
8
@JonathanDay: нет, это найдет коммиты в любой ветке. Если вы хотите только один на пульте, используйте -r.
Каскабель
7
@SimonTewsi Как я уже сказал, если это действительно проблема, используйте merge --no-ffдля надежной записи названия ветви при слиянии. Но в остальном воспринимайте имена ветвей как временные короткие метки, а коммиты - как постоянные. "Какое короткое имя мы упоминали во время разработки?" не должно быть таким важным вопросом, как "что делает этот коммит?"
И это идеальное решение заняло всего 8 лет. Спасибо!
S1J0
6
Я нашел git name-rev --name-only <SHA>более полезным для получения только название ветви. Мой вопрос ... Может ли он вернуть более одной ветки при любых обстоятельствах?
git-what-branch(Скрипт Perl, см. Ниже), похоже, больше не поддерживается.
git-when-mergedэто альтернатива, написанная на Python, которая работает очень хорошо для меня.
Сообщите нам (по умолчанию) самый ранний причинный путь коммитов и слияний, чтобы запрошенный коммит попал в именованную ветвь. Если фиксация была сделана непосредственно в именованной ветви, это, очевидно, самый ранний путь.
Под самым ранним причинным путем мы подразумеваем путь, который объединяется в именованную ветвь как можно раньше, за время фиксации (если --topo-orderне указано иное).
ПРЕДСТАВЛЕНИЕ
Если во многих ветвях (например, сотнях) содержится фиксация, системе может потребоваться много времени (для определенного коммита в дереве Linux потребовалось 8 секунд, чтобы исследовать ветку, но было более 200 ветвей-кандидатов), чтобы отследить путь каждому коммиту.
Выбор конкретного--reference-branch --reference tag для изучения будет в сотни раз быстрее (если у вас есть сотни веток-кандидатов).
ПРИМЕРЫ
# git-what-branch --all 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4
1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4 first merged onto master using the following minimal temporal path:
v2.6.12-rc3-450-g1f9c381 merged up at v2.6.12-rc3-590-gbfd4bda (Thu May 5 08:59:37 2005)
v2.6.12-rc3-590-gbfd4bda merged up at v2.6.12-rc3-461-g84e48b6 (Tue May 3 18:27:24 2005)
v2.6.12-rc3-461-g84e48b6 is on master
v2.6.12-rc3-461-g84e48b6 is on v2.6.12-n
[...]
Эта программа не учитывает эффекты выбора вишни коммитов, только операции слияния.
git-what-branchкажется, больше не поддерживается. git-when-merged - это альтернатива, написанная на Python, которая очень хорошо работает для меня.
Щуберт
@sschuberth спасибо за это обновление. Я включил ваш комментарий в ответ для большей наглядности.
VonC
37
Например, чтобы найти, что c0118faкоммит произошел от redesign_interactions:
* ccfd449 (HEAD -> develop) Require to return undef if no digits found
* 93dd5ff Merge pull request #4 from KES777/clean_api
|\
| * 39d82d1 Fix tc0118faests for debugging debugger internals
| * ed67179 Move &push_frame out of core
| * 2fd84b5 Do not lose info about call point
| * 3ab09a2 Improve debugger output: Show info about emitted events
| * a435005 Merge branch 'redesign_interactions' into clean_api
| |\
| | * a06cc29 Code comments
| | * d5d6266 Remove copy/paste code
| | * c0118fa Allow command to choose how continue interaction
| | * 19cb534 Emit &interact event
Вы должны запустить:
git log c0118fa..HEAD --ancestry-path --merges
И прокрутите вниз, чтобы найти последний коммит слияния . Который:
commit a435005445a6752dfe788b8d994e155b3cd9778f
Merge: 0953cac a06cc29
Author: Eugen Konkov
Date: Sat Oct 1 00:54:18 2016 +0300
Merge branch 'redesign_interactions' into clean_api
Это было единственное решение, которое дало мне желаемый результат. Я попробовал остальное.
создатель
Обратите внимание, что это работает, только если сводки фиксации слияния содержат имена ветвей, используемые в слияниях, что по умолчанию они обычно делают. Однако git merge -m"Any String Here"будет скрывать информацию об источнике и целевой ветви.
Qneill
@qneill: Нет, слияние всегда есть информация о присоединяемых филиалах: Merge: f6b70fa d58bdcb. Вы можете назвать свой коммит слияния как вы. У меня не будет дела
Евгений Коньков
1
@EugenKonkov после того, как ветви прошли слияние, история о том, какой путь в графе, с которого они пришли, остается в reflog, но не в базе данных объектов git. Я опубликовал ответ, пытаясь объяснить, что я говорю
qneill
У меня работает версия UPD, простая команда, которая находит исходный коммит
vpalmu
9
git branch --contains <ref>это самая очевидная «фарфоровая» команда для этого. Если вы хотите сделать что-то похожее только с помощью «сантехнических» команд:
COMMIT=$(git rev-parse <ref>) # expands hash if needed
for BRANCH in $(git for-each-ref --format "%(refname)" refs/heads); do
if $(git rev-list $BRANCH | fgrep -q $COMMIT); then
echo $BRANCH
fi
done
Кажется, чего-то не хватает во втором предложении.
Питер Мортенсен
Я обновил описание. Спасибо за отзыв.
Phyatt
4
Опция бедного человека состоит в том, чтобы использовать инструмент tig1 on HEAD, искать коммит, а затем визуально следовать линии от этого коммита до тех пор, пока коммит слияния не будет виден. В сообщении о слиянии по умолчанию должно быть указано, в какую ветку и где происходит слияние :)
1 Tig - это основанный на ncurses интерфейс текстового режима для Git. Он функционирует в основном как браузер Git-репозитория, но он также может помочь в организации изменений для фиксации на уровне чанка и выступать в качестве пейджера для вывода различных команд Git.
В качестве эксперимента я создал хук после фиксации, который хранит информацию о текущей извлеченной ветви в метаданных фиксации. Я также немного изменил gitk, чтобы показать эту информацию.
Честно говоря, я не знал, что git заметки существовали, когда я писал это. Да, использование git notes для достижения того же самого - вероятно, лучшая идея.
Pajp
3
Я имею дело с той же проблемой ( Дженкинс многоотраслевой конвейер ) - иметь только информацию о коммите и пытаться найти имя ветки, откуда изначально пришел этот коммит. Он должен работать для удаленных филиалов, локальные копии недоступны.
Это то, с чем я работаю:
git rev-parse HEAD | xargs git name-rev
При желании вы можете обрезать вывод:
git rev-parse HEAD | xargs git name-rev | cut -d' ' -f2 | sed 's/remotes\/origin\///g'
Если OP пытается определить историю , пройденную ветвью при создании определенного коммита («выяснить, из какой ветки происходит коммит, учитывая его значение хеш-функции SHA-1»), то без рефлога нет какого - либо записи в базе данных объектов Git, которые показывают, какая именованная ветвь была связана с какой историей коммитов.
(Я отправил это как ответ в ответ на комментарий.)
Надеюсь, этот скрипт иллюстрирует мою точку зрения:
И каков выход для git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1 и git log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1команды в обоих случаях?
Евгений Коньков
SHA, конечно, меняются каждый раз, когда запускаются команды, чтобы изменить их, я использовал HEAD ^ 1 и HEAD ^ 2 при новом запуске. Команды и вывод: $ git log HEAD^1..HEAD --ancestry-path --merges --oneline --color | tail -n 1что дает376142d merge branches и $ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1какие выходы 376142d merge branches - которые показывают сводку коммитов слияния, которую (как я утверждал) можно перезаписать при создании слияния, возможно, запутав историю ветвлений слияния.
qneill
0
TL; DR:
Используйте ниже, если вы заботитесь о статусах выхода из оболочки:
branch-current - название текущей ветви
branch-names - чистые имена веток (по одному в строке)
branch-name - Убедитесь, что только одна ветвь возвращается из branch-names
Обе branch-nameи branch-namesпринимают коммит в качестве аргумента, и по умолчанию, HEADесли ничего не дано.
На самом деле я не хочу отрицать это, потому что, строго говоря, это правда, что git не хранит эту информацию постоянно, но, тем не менее, очень часто ее можно найти. Смотри мой ответ.
Ответы:
Хотя Дэв прав, что информация не хранится напрямую, это не значит, что вы никогда не узнаете. Вот несколько вещей, которые вы можете сделать.
Найти ветки, на которых зафиксирован коммит
Это расскажет вам все ветви, которые имеют данный коммит в своей истории. Очевидно, что это менее полезно, если коммит уже был объединен.
Поиск по журналам
Если вы работаете в репозитории, в котором была сделана фиксация, вы можете найти в журналах регистрации строку для этой фиксации. Рефлоги старше 90 дней удаляются git-gc, поэтому если коммит слишком старый, вы его не найдете. Тем не менее, вы можете сделать это:
найти коммит a871742. Обратите внимание, что вы ДОЛЖНЫ использовать abbreviatd 7 первых цифр коммита. Вывод должен быть примерно таким:
с указанием того, что коммит был сделан по ветке "Завершение". Вывод по умолчанию показывает сокращенные хеши коммитов, поэтому не ищите полный хеш, иначе вы ничего не найдете.
git reflog show
на самом деле просто псевдоним дляgit log -g --abbrev-commit --pretty=oneline
, так что если вы хотите поиграть с форматом вывода, чтобы сделать разные вещи доступными для grep, это ваша отправная точка!Если вы не работаете в репозитории, в котором была сделана фиксация, лучшее, что вы можете сделать в этом случае, - это изучить reflogs и выяснить, когда коммит был впервые представлен в вашем репозитории; если повезет, вы взяли ветвь, которой он был посвящен. Это немного сложнее, потому что вы не можете одновременно обходить как дерево коммитов, так и флаги. Вы хотели бы проанализировать выходные данные reflog, исследуя каждый хеш, чтобы увидеть, содержит ли он желаемый коммит или нет.
Найти последующий коммит слияния
Это зависит от рабочего процесса, но с хорошими рабочими процессами в ветки разработки вносятся коммиты, которые затем объединяются. Вы можете сделать это:
видеть коммиты слияния, которые имеют данный коммит в качестве предка. (Если коммит был объединен только один раз, первым должно быть слияние, за которым вы следите; в противном случае, я полагаю, вам придется изучить несколько из них.) Сообщение коммита слияния должно содержать имя ветви, которая была объединена.
Если вы хотите иметь возможность рассчитывать на это, вы можете использовать
--no-ff
опциюgit merge
для принудительного создания коммитов слияния даже в случае ускоренной перемотки вперед. (Однако не слишком рвитесь. Это может стать запутывающим, если его чрезмерно использовать.) Ответ VonC на связанный вопрос услужливо развивает эту тему.источник
git describe
достаточно, поскольку (аннотированные) теги можно рассматривать как более значимые, чем ветви.--no-ff
опцию, чтобы убедиться, что всегда есть коммит слияния, так что вы всегда можете проследить путь данного коммита, когда он слился с master.-a
флаг к первой команде, например,git branch -a --contains <commit>
-r
.merge --no-ff
для надежной записи названия ветви при слиянии. Но в остальном воспринимайте имена ветвей как временные короткие метки, а коммиты - как постоянные. "Какое короткое имя мы упоминали во время разработки?" не должно быть таким важным вопросом, как "что делает этот коммит?"Эта простая команда работает как шарм:
git name-rev <SHA>
Например (где test-branch это имя ветки):
Даже это работает для сложных сценариев, таких как:
Здесь
git name-rev commit<SHA2>
возвращает branchB .источник
git name-rev --name-only <SHA>
более полезным для получения только название ветви. Мой вопрос ... Может ли он вернуть более одной ветки при любых обстоятельствах?Обновление декабря 2013 года:
sschuberth комментарии
Он основан на « Найти коммит слияния, который включает определенный коммит ».
Оригинальный ответ сентябрь 2010:
Себастьян Душ только что дернулся (за 16 минут до этого ТАКОГО ответа):
Это сценарий Perl от Сета Робертсона, который кажется очень интересным:
источник
git-what-branch
кажется, больше не поддерживается. git-when-merged - это альтернатива, написанная на Python, которая очень хорошо работает для меня.Например, чтобы найти, что
c0118fa
коммит произошел отredesign_interactions
:Вы должны запустить:
И прокрутите вниз, чтобы найти последний коммит слияния . Который:
Обновить
Или только одна команда:
источник
git merge -m"Any String Here"
будет скрывать информацию об источнике и целевой ветви.Merge: f6b70fa d58bdcb
. Вы можете назвать свой коммит слияния как вы. У меня не будет делаgit branch --contains <ref>
это самая очевидная «фарфоровая» команда для этого. Если вы хотите сделать что-то похожее только с помощью «сантехнических» команд:(кросспост из этого SO ответа )
источник
хичар.анил покрытый большую часть этого в своем ответе.
Я просто добавляю флаг, который удалит теги из списка имен ревизий. Это дает нам:
источник
Опция бедного человека состоит в том, чтобы использовать инструмент
tig
1 onHEAD
, искать коммит, а затем визуально следовать линии от этого коммита до тех пор, пока коммит слияния не будет виден. В сообщении о слиянии по умолчанию должно быть указано, в какую ветку и где происходит слияние :)источник
В качестве эксперимента я создал хук после фиксации, который хранит информацию о текущей извлеченной ветви в метаданных фиксации. Я также немного изменил gitk, чтобы показать эту информацию.
Вы можете проверить это здесь: https://github.com/pajp/branch-info-commits
источник
Я имею дело с той же проблемой ( Дженкинс многоотраслевой конвейер ) - иметь только информацию о коммите и пытаться найти имя ветки, откуда изначально пришел этот коммит. Он должен работать для удаленных филиалов, локальные копии недоступны.
Это то, с чем я работаю:
При желании вы можете обрезать вывод:
источник
Я думаю, что кто-то должен столкнуться с той же проблемой, что и не может найти ветку, хотя в действительности она существует в одной ветке.
Тебе лучше сначала все потянуть
Затем выполните поиск по ветке:
или:
источник
Если OP пытается определить историю , пройденную ветвью при создании определенного коммита («выяснить, из какой ветки происходит коммит, учитывая его значение хеш-функции SHA-1»), то без рефлога нет какого - либо записи в базе данных объектов Git, которые показывают, какая именованная ветвь была связана с какой историей коммитов.
(Я отправил это как ответ в ответ на комментарий.)
Надеюсь, этот скрипт иллюстрирует мою точку зрения:
Вывод показывает отсутствие какого-либо способа узнать, поступил ли коммит с 'Add f1' из ветви b1 или b2 из удаленного клона / tmp / r2.
(Последние строки вывода здесь)
источник
git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1
иgit log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1
команды в обоих случаях?$ git log HEAD^1..HEAD --ancestry-path --merges --oneline --color | tail -n 1
что дает376142d merge branches
и$ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1
какие выходы376142d merge branches
- которые показывают сводку коммитов слияния, которую (как я утверждал) можно перезаписать при создании слияния, возможно, запутав историю ветвлений слияния.TL; DR:
Используйте ниже, если вы заботитесь о статусах выхода из оболочки:
branch-current
- название текущей ветвиbranch-names
- чистые имена веток (по одному в строке)branch-name
- Убедитесь, что только одна ветвь возвращается изbranch-names
Обе
branch-name
иbranch-names
принимают коммит в качестве аргумента, и по умолчанию,HEAD
если ничего не дано.Псевдонимы, полезные в сценариях
Коммит доступен только из одной ветки
0
.Фиксация достижима из нескольких веток
1
.Из-за статуса выхода их можно безопасно строить. Например, чтобы получить удаленный доступ для извлечения:
источник
Чтобы найти местное отделение:
Чтобы найти удаленную ветку:
источник
Помимо поиска по всему дереву, пока вы не найдете соответствующий хеш, нет.
источник