Есть ли способ узнать, из какой ветви происходит коммит, учитывая его хеш-значение SHA-1 ?
Бонусные баллы, если вы можете сказать мне, как сделать это, используя Ruby Grit.
Есть ли способ узнать, из какой ветви происходит коммит, учитывая его хеш-значение SHA-1 ?
Бонусные баллы, если вы можете сказать мне, как сделать это, используя Ruby Grit.
Ответы:
Хотя Дэв прав, что информация не хранится напрямую, это не значит, что вы никогда не узнаете. Вот несколько вещей, которые вы можете сделать.
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 на связанный вопрос услужливо развивает эту тему.
git describeдостаточно, поскольку (аннотированные) теги можно рассматривать как более значимые, чем ветви.
--no-ffопцию, чтобы убедиться, что всегда есть коммит слияния, так что вы всегда можете проследить путь данного коммита, когда он слился с master.
-aфлаг к первой команде, например,git branch -a --contains <commit>
-r.
merge --no-ffдля надежной записи названия ветви при слиянии. Но в остальном воспринимайте имена ветвей как временные короткие метки, а коммиты - как постоянные. "Какое короткое имя мы упоминали во время разработки?" не должно быть таким важным вопросом, как "что делает этот коммит?"
Эта простая команда работает как шарм:
git name-rev <SHA>
Например (где test-branch это имя ветки):
git name-rev 651ad3a
251ad3a remotes/origin/test-branch
Даже это работает для сложных сценариев, таких как:
origin/branchA/
/branchB
/commit<SHA1>
/commit<SHA2>
Здесь git name-rev commit<SHA2>возвращает branchB .
git name-rev --name-only <SHA>более полезным для получения только название ветви. Мой вопрос ... Может ли он вернуть более одной ветки при любых обстоятельствах?
Обновление декабря 2013 года:
git-what-branch(Скрипт Perl, см. Ниже), похоже, больше не поддерживается.git-when-mergedэто альтернатива, написанная на Python, которая работает очень хорошо для меня.
Он основан на « Найти коммит слияния, который включает определенный коммит ».
git when-merged [OPTIONS] COMMIT [BRANCH...]
Найти, когда коммит был объединен в одну или несколько веток.
Найти коммит слияния, который принесCOMMITв указанные ФИЛИАЛЫ.В частности, ищите самый старый коммит в истории первого родителя,
BRANCHкоторый содержит вCOMMITкачестве предка.
Оригинальный ответ сентябрь 2010:
Себастьян Душ только что дернулся (за 16 минут до этого ТАКОГО ответа):
git-what-branch : узнайте, на какой ветке находится коммит или как он попал в именованную ветку
Это сценарий Perl от Сета Робертсона, который кажется очень интересным:
СИНТАКСИС
git-what-branch [--allref] [--all] [--topo-order | --date-order ]
[--quiet] [--reference-branch=branchname] [--reference=reference]
<commit-hash/tag>...
ОБЗОР
Сообщите нам (по умолчанию) самый ранний причинный путь коммитов и слияний, чтобы запрошенный коммит попал в именованную ветвь. Если фиксация была сделана непосредственно в именованной ветви, это, очевидно, самый ранний путь.
Под самым ранним причинным путем мы подразумеваем путь, который объединяется в именованную ветвь как можно раньше, за время фиксации (если
--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, которая очень хорошо работает для меня.
Например, чтобы найти, что 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 log c0118fa..HEAD --ancestry-path --merges --oneline --color | tail -n 1
git merge -m"Any String Here"будет скрывать информацию об источнике и целевой ветви.
Merge: f6b70fa d58bdcb. Вы можете назвать свой коммит слияния как вы. У меня не будет дела
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
(кросспост из этого SO ответа )
хичар.анил покрытый большую часть этого в своем ответе.
Я просто добавляю флаг, который удалит теги из списка имен ревизий. Это дает нам:
git name-rev --name-only --exclude=tags/* $SHA
Опция бедного человека состоит в том, чтобы использовать инструмент tig1 on HEAD, искать коммит, а затем визуально следовать линии от этого коммита до тех пор, пока коммит слияния не будет виден. В сообщении о слиянии по умолчанию должно быть указано, в какую ветку и где происходит слияние :)
1 Tig - это основанный на ncurses интерфейс текстового режима для Git. Он функционирует в основном как браузер Git-репозитория, но он также может помочь в организации изменений для фиксации на уровне чанка и выступать в качестве пейджера для вывода различных команд Git.
В качестве эксперимента я создал хук после фиксации, который хранит информацию о текущей извлеченной ветви в метаданных фиксации. Я также немного изменил gitk, чтобы показать эту информацию.
Вы можете проверить это здесь: https://github.com/pajp/branch-info-commits
Я имею дело с той же проблемой ( Дженкинс многоотраслевой конвейер ) - иметь только информацию о коммите и пытаться найти имя ветки, откуда изначально пришел этот коммит. Он должен работать для удаленных филиалов, локальные копии недоступны.
Это то, с чем я работаю:
git rev-parse HEAD | xargs git name-rev
При желании вы можете обрезать вывод:
git rev-parse HEAD | xargs git name-rev | cut -d' ' -f2 | sed 's/remotes\/origin\///g'
Я думаю, что кто-то должен столкнуться с той же проблемой, что и не может найти ветку, хотя в действительности она существует в одной ветке.
Тебе лучше сначала все потянуть
git pull --all
Затем выполните поиск по ветке:
git name-rev <SHA>
или:
git branch --contains <SHA>
Если OP пытается определить историю , пройденную ветвью при создании определенного коммита («выяснить, из какой ветки происходит коммит, учитывая его значение хеш-функции SHA-1»), то без рефлога нет какого - либо записи в базе данных объектов Git, которые показывают, какая именованная ветвь была связана с какой историей коммитов.
(Я отправил это как ответ в ответ на комментарий.)
Надеюсь, этот скрипт иллюстрирует мою точку зрения:
rm -rf /tmp/r1 /tmp/r2; mkdir /tmp/r1; cd /tmp/r1
git init; git config user.name n; git config user.email e@x.io
git commit -m"empty" --allow-empty; git branch -m b1; git branch b2
git checkout b1; touch f1; git add f1; git commit -m"Add f1"
git checkout b2; touch f2; git add f2; git commit -m"Add f2"
git merge -m"merge branches" b1; git checkout b1; git merge b2
git clone /tmp/r1 /tmp/r2; cd /tmp/r2; git fetch origin b2:b2
set -x;
cd /tmp/r1; git log --oneline --graph --decorate; git reflog b1; git reflog b2;
cd /tmp/r2; git log --oneline --graph --decorate; git reflog b1; git reflog b2;
Вывод показывает отсутствие какого-либо способа узнать, поступил ли коммит с 'Add f1' из ветви b1 или b2 из удаленного клона / tmp / r2.
(Последние строки вывода здесь)
+ cd /tmp/r1
+ git log --oneline --graph --decorate
* f0c707d (HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: merge b2: Fast-forward
086c9ce b1@{1}: commit: Add f1
18feb84 b1@{2}: Branch: renamed refs/heads/master to refs/heads/b1
18feb84 b1@{3}: commit (initial): empty
+ git reflog b2
f0c707d b2@{0}: merge b1: Merge made by the 'recursive' strategy.
80c10e5 b2@{1}: commit: Add f2
18feb84 b2@{2}: branch: Created from b1
+ cd /tmp/r2
+ git log --oneline --graph --decorate
* f0c707d (HEAD, origin/b2, origin/b1, origin/HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: clone: from /tmp/r1
+ git reflog b2
f0c707d b2@{0}: fetch origin b2:b2: storing head
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 - которые показывают сводку коммитов слияния, которую (как я утверждал) можно перезаписать при создании слияния, возможно, запутав историю ветвлений слияния.
Используйте ниже, если вы заботитесь о статусах выхода из оболочки:
branch-current - название текущей ветвиbranch-names - чистые имена веток (по одному в строке)branch-name - Убедитесь, что только одна ветвь возвращается из branch-namesОбе branch-nameи branch-namesпринимают коммит в качестве аргумента, и по умолчанию, HEADесли ничего не дано.
branch-current = "symbolic-ref --short HEAD" # https://stackoverflow.com/a/19585361/5353461
branch-names = !"[ -z \"$1\" ] && git branch-current 2>/dev/null || git branch --format='%(refname:short)' --contains \"${1:-HEAD}\" #" # https://stackoverflow.com/a/19585361/5353461
branch-name = !"br=$(git branch-names \"$1\") && case \"$br\" in *$'\\n'*) printf \"Multiple branches:\\n%s\" \"$br\">&2; exit 1;; esac; echo \"$br\" #"
% git branch-name eae13ea
master
% echo $?
0
0.% git branch-name 4bc6188
Multiple branches:
attempt-extract
master%
% echo $?
1
1 .Из-за статуса выхода их можно безопасно строить. Например, чтобы получить удаленный доступ для извлечения:
remote-fetch = !"branch=$(git branch-name \"$1\") && git config branch.\"$branch\".remote || echo origin #"
Чтобы найти местное отделение:
grep -lR YOUR_COMMIT .git/refs/heads | sed 's/.git\/refs\/heads\///g'
Чтобы найти удаленную ветку:
grep -lR $commit .git/refs/remotes | sed 's/.git\/refs\/remotes\///g'