Дізнавшись, з якої гілки походить Git


649

Чи є спосіб дізнатись, з якої гілки береться команда, враховуючи хеш-значення SHA-1 ?

Бонусні бали, якщо ви можете сказати мені, як це досягти, використовуючи Ruby Grit.


4
Різні методи нижче прагматичні, корисно, працюючи шляху , виводити на ймовірний відповідь, але давайте звернемо увагу , що в мерзотник сам питання непорозуміння, які вчиняють не з гілок. Гілки приходять і йдуть, вони рухаються, лише коміти представляють реальну історію репо. Знову ж таки, це не спосіб сказати, що нижче рішення погані. Просто знайте, що жоден з них не дає цілком надійної відповіді, що неможливо отримати за допомогою дизайну в git. (Простий випадок видаляється гілками: я гілка, я здійснюю двічі, я зливаюсь в іншу гілку, я
видаляю

1
У мене є випадок, коли я чітко витягаю з мітки клони глибиною 1 міл. Це дешево, легко і ефективно ... і до цього часу робив все, що я хотів красиво. Тепер, коли я хотів би дізнатися, на якій гілці розміщено тег, я хотів, принаймні, для цієї деталі. Не завжди можна їхати додому,
Пол Ходжес

Відповіді:


864

Хоча Дав вірно вважає, що інформація не зберігається безпосередньо, це не означає, що ви ніколи не можете їх дізнатися. Ось кілька речей, які ви можете зробити.

Знайдіть гілки, на яких здійснюється комісія

git branch -a --contains <commit>

Це розповість вам про всі гілки, які в своїй історії дали ці зобов'язання. Очевидно, це менш корисно, якщо коміти вже об'єднані.

Шукайте відходи

Якщо ви працюєте в сховищі, в якому було здійснено фіксацію, ви можете шукати рефлоги в рядку для цього коміту. Reflogs старше 90 днів обрізається git-gc, тому якщо комітка занадто стара, ви її не знайдете. Однак це можна зробити:

git reflog show --all | grep a871742

знайти фіксацію a871742. Зауважте, що ОБОВ'ЯЗКОВО слід використовувати скорочені 7 перших цифр комітів. Вихід повинен бути приблизно таким:

a871742 refs/heads/completion@{0}: commit (amend): mpc-completion: total rewrite

що вказує на те, що зобов’язання було здійснено на філії "завершення". Вихід за замовчуванням показує скорочені хеші фіксації, тож не шукайте повний хеш, інакше ви нічого не знайдете.

git reflog showнасправді є лише псевдонімом git log -g --abbrev-commit --pretty=oneline, тому, якщо ви хочете поспілкуватися з вихідним форматом, щоб зробити різні речі доступними для грепування, це ваш вихідний пункт!

Якщо ви не працюєте в сховищі, де було здійснено фіксацію, найкраще, що ви можете зробити в цьому випадку - вивчити відкладені файли та виявити, коли комісія вперше була введена у ваше сховище; з будь-якою удачею ви здобули гілку, на яку вона була віддана. Це трохи складніше, тому що ви не можете одночасно ходити і по дереву фіксів, і по відкладенню. Ви хочете проаналізувати вихід рефлогу, вивчаючи кожен хеш, щоб побачити, чи містить він потрібну фіксацію чи ні.

Знайдіть наступну комісію злиття

Це залежить від робочого процесу, але при хороших робочих процесах здійснюються комісії в галузях розвитку, які потім об'єднуються. Ви можете зробити це:

git log --merges <commit>..

побачити об'єднання комітетів, які дають фіксацію як предка. (Якщо фіксація була об'єднана лише один раз, першою повинна бути злиття, яку ви шукаєте; в іншому випадку, вам, мабуть, доведеться вивчити декілька.

Якщо ви хочете мати можливість розраховувати на це, ви можете скористатися --no-ffопцією, git mergeщоб змусити створення об'єднань фіксації навіть у випадку швидкого переходу. (Не надто прагніть, однак, це може стати запаморочливим при надмірному використанні.) Відповідь VonC на відповідне запитання корисно висвітлює цю тему.


5
+1. Цілком відсутність інформації щодо конкретного питання змушує задуматися, чи це насправді проблема? Гілки можна змінити, перейменувати або видалити в будь-який час. Може бути git describeдостатньо, тому що (анотовані) теги можуть розглядатися як більш значущі, ніж гілки.
VonC

9
Я точно погоджуюся - гілки мають бути легкими та гнучкими. Якщо ви прийняли робочий процес, у якому ця інформація стає важливою, ви можете використовувати --no-ffпараметр, щоб переконатися, що завжди існує об'єднання об'єднань, так що ви завжди можете простежити шлях даного комітету під час його злиття до головного.
Каскабель

32
FYI, якщо ви хочете знайти комісії, які існують лише на пульті дистанційного керування, додайте -aпрапор до першої команди, наприкладgit branch -a --contains <commit>
Jonathan Day

8
@JonathanDay: Ні, це знайде коміти на будь-якій гілці. Якщо ви хочете лише на пульті дистанційного керування, використовуйте -r.
Каскабель

7
@SimonTewsi Як я вже говорив, якщо це справді проблема, використовуйте merge --no-ffдля надійного запису назви гілки при злитті. Але в іншому випадку розгляньте назви філій як тимчасові короткі мітки, а описи виконайте як постійні. "Яке коротке ім'я ми посилалися на це під час розробки?" насправді не повинно бути настільки важливим питанням, як "що робить це зобов'язання?"
Каскабель

154

Ця проста команда працює як шарм:

git name-rev <SHA>

Наприклад (де тест-гілка - це назва гілки):

git name-rev 651ad3a
251ad3a remotes/origin/test-branch

Навіть це працює для складних сценаріїв, таких як:

origin/branchA/
              /branchB
                      /commit<SHA1>
                                   /commit<SHA2>

Тут git name-rev commit<SHA2>повертається відділенняB .


3
Ти врятував мені день. Це ідеальне рішення.
Тако

7
І на це ідеальне рішення знадобилося лише 8 років. Дякую!
S1J0

6
Мені git name-rev --name-only <SHA>було корисніше отримати лише ім'я гілки. Моє запитання ... Чи може за будь-яких обставин повернути більше однієї гілки?
Дін Кейтон

1
Це має бути найкращою відповіддю.
JCollier

1
Дякую @JCollier за добрі слова.
khichar.anil

47

Оновлення грудня 2013 року:

sschuberth коментарі

git-what-branch(Сценарій Perl, див. Нижче), схоже, більше не підтримується. git-when-mergedце альтернатива, написана на Python, яка працює для мене дуже добре.

Він заснований на " Знайти комісію злиття, яка включає конкретну комісію ".

git when-merged [OPTIONS] COMMIT [BRANCH...]

Знайдіть, коли комісія була об'єднана в одну або кілька гілок.
Знайдіть комісію злиття, внесену COMMITдо вказаних BRANCH (ив).

Зокрема, шукайте найдавніший вчинок з історії первинних батьків, 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
   [...]

Ця програма не враховує наслідків вибору вишні, що цікавить, лише операції з об'єднання.


4
git-what-branchсхоже, не підтримується більше. git-kada-spared - це альтернатива, написана на Python, яка працює для мене дуже добре.
sschuberth

@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 log c0118fa..HEAD --ancestry-path --merges --oneline --color | tail -n 1

4
Це було єдине рішення, яке дало мені бажаний результат. Я спробував решту.
крафтер

Зауважте, це працює лише в тому випадку, якщо зведення комісій злиття містять імена гілок, які використовуються в злиттях, що зазвичай вони роблять за замовчуванням. Однак git merge -m"Any String Here"буде затьмарювати вихідну та цільову інформацію про галузь.
qneill

@qneill: Ні, злиття завжди є інформація про приєднуються філіях: Merge: f6b70fa d58bdcb. Ви можете назвати свою комісію злиття, як і ви. Я не матиму справи
Євген Конков

1
@EugenKonkov, як тільки гілки пройшли злиття, історія про те, з якого шляху у графіку вони прийшли, залишається в рефлозі, але не в базі даних об’єктів git. Я опублікував відповідь, намагаючись пояснити, що я говорю
qneill

Версія UPD працює для мене, проста команда, яка знаходить оригінальний
фіксатор

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

(перехресний відповідь з цієї відповіді ТАК )


6

khichar.anil висвітлював більшість цього у своїй відповіді.

Я просто додаю прапор, який видалить теги зі списку імен редакції. Це дає нам:

git name-rev --name-only --exclude=tags/* $SHA

Щось, здається, бракує у другому реченні.
Пітер Мортенсен

Я оновив опис. Thx для зворотного зв'язку.
фіат

4

Варіант бідної людини - використовувати інструмент tig1 увімкнено HEAD, здійснити пошук фіксації, а потім візуально дотримуватися рядка з цього комікату, поки не буде показано об'єднання об'єднань. Повідомлення злиття за замовчуванням повинно вказувати, до якої гілки об'єднується куди :)

1 Tig - це інтерфейс текстового режиму для Git на основі ncurses. Він функціонує, головним чином, як браузер репозиторію Git, але також може допомогти в постановці змін для фіксації на рівні фрагментів і виступати в якості пейджера для виводу з різних команд Git.


3

В якості експерименту я зробив гачок після фіксації, який зберігає інформацію про поточно перевірену гілку у метаданих фіксації. Я також трохи змінив gitk, щоб показати цю інформацію.

Перевірити це можна тут: https://github.com/pajp/branch-info-commissions


1
Але якщо ви хочете додати метадані, чому б не використовувати git note, а не возитися із заголовками комітетів? Див stackoverflow.com/questions/5212957 / ... , stackoverflow.com/questions/7298749 / ... або stackoverflow.com/questions/7101158 / ...
VonC

Якщо чесно, я не знав, що ноти про git існували, коли писав це. Так, використання git нот для досягнення того ж самого, мабуть, краща ідея.
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'

0

Я думаю, що хтось повинен зіткнутися з тією ж проблемою, яка не може дізнатися галузь, хоча вона насправді існує в одній галузі.

Ви краще перетягніть все спочатку:

git pull --all

Потім виконайте пошук філії:

git name-rev <SHA>

або:

git branch --contains <SHA>

0

Якщо ОП намагається визначити історію, яку проходила гілка, коли було створено певний комітет ("з'ясуйте, з якої гілки комісія походить з огляду на її хеш-значення 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команди для обох випадків?
Євген Конков

Зрозуміло, що 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якщо не вказано жодне.


Псевдоніми, корисні для сценаріїв

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
  • Вихід - STDOUT
  • Значення виходу - 0.

Здійснити доступ з декількох відділень

% git branch-name 4bc6188
Multiple branches:
attempt-extract
master%
% echo $?
1
  • Вихід - STDERR
  • Значення виходу - 1.

Через стан виходу їх можна безпечно надбудовувати. Наприклад, щоб отримати пульт дистанційного використання для отримання:

remote-fetch = !"branch=$(git branch-name \"$1\") && git config branch.\"$branch\".remote || echo origin #"

-1

Щоб знайти місцеве відділення:

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'

1
деякі пояснення ваших прикладів будуть чудовими
Євген Конков

-4

Крім пошуку по всьому дереву, поки ви не знайдете відповідний хеш, ні.


7
Я не хочу цього робити, тому що строго кажучи, це правда, що git не зберігає цю інформацію назавжди, але це дуже часто можливо дізнатися. Дивіться мою відповідь.
Каскабель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.