Як я можу визначити, чи є один вчинок нащадком іншого?


146

Що стосується Git, як я можу зрозуміти, чи є один вчинок у моїй гілці нащадком іншого?


2
Те ж питання задають зворотне: stackoverflow.com/questions/18345157 / ...
Кріс Cleeland

11
Чи можете ви змінити прийняту відповідь? Більшість любить --is-ancestorрішення.
Роберт Сімер

Відповіді:


51

Якщо ви хочете перевірити це програмно (наприклад, у скрипті), ви можете перевірити, чи git merge-base A Bдорівнює він git rev-parse --verify A(тоді A досягається з B), чи він є git rev-parse --verify B(тоді B є доступний від A). git rev-parseтут потрібно, щоб перетворити з імені комісії на фіксацію SHA-1 / ID ідентифікатора.

Використовувати, git rev-listяк у відповіді VonC , також є можливість.

Редагувати: в сучасному Git існує чітка підтримка цього запиту у вигляді git merge-base --is-ancestor.


Якщо один з коммітов ви питаєте це гілка наконечник , то git branch --contains <commit>чи git branch --merged <commit>може бути краще непрограммной рішенням.


1
Можливо, найшвидший спосіб був би до цього git checkout -b quickcheck <more-recent-commit-ID>і тоді git branch --contains <older-commit-ID>(а потім git branch -D quickcheckпозбутися тимчасової гілки).
clee

2
Два можливі підходи, обидва вони набагато гірші, ніж той, який у відповіді @ MattR.
jwg

6
@jwg: відповідь MattR краща, але ця відповідь (і, мабуть, її прийнято) передує git 1.8.0 і git merge-base --is-ancestorдо 2 років.
Якуб Нарбський

@ JakubNarębski Досить справедливо, вибачте.
jwg

2
У великому сховищі (2 мільйони комітів ) я порівняв швидкість git branch --contains <commit>і git merge-base --is-ancestor ...: 3m40s проти 0,14s
hagello

259

З Git 1.8.0 це підтримується як варіант merge-base:

git merge-base --is-ancestor <maybe-ancestor-commit> <descendant-commit>

Із чоловічої сторінки:

--є-предком

Перевірте, чи перший є предком другого, і вийдіть зі статусом 0, якщо це правда, або зі статусом 1, якщо ні. Про помилки сигналізує ненульовий стан, який не дорівнює 1.

Наприклад:

git merge-base --is-ancestor origin/master master; echo $?

4
Приємно! Ось сценарій оболонки, який описує цю відповідь у щось із реалістичним для людини результатом: gist.github.com/simonwhitaker/6354592
Simon Whitaker

1
Іншими словами: git merge-base THING --is-ancestor OF_THING && echo yes || echo noнапр .:git merge-base my-feature-branch --is-ancestor master && echo yes || echo no
user1735594

2
@smarber git merge-base --is-ancestor -- commit commitпрацює з хешами на моїй стороні з git2.1.4 (Debian / Devuan 7.10 jessie) та 1.9.1 (Ubuntu 14.04 надійний), які зараз досить давні. Це працює навіть для хрипів Debian, якщо ви це робите sudo apt-get install git/wheezy-backports.
Тіно

15

Цей вид операцій спирається на поняття про діапазон доопрацювань, детально описаний у запитанні SO: " Різниця в 'git log origin / master' vs 'git log origin / master ..' ".

git rev-list повинні бути в змозі піти назад від комітету, аж до іншого, якщо це можливо.

Тому я б спробував:

git rev-list --boundary 85e54e2408..0815fcf18a
0815fcf18a19441c1c26fc3495c4047cf59a06b9
8a1658147a460a0230fb1990f0bc61130ab624b2
-85e54e240836e6efb46978e4a1780f0b45516b20

(Межі коміксів мають префікс -)

Якщо відображається остання фіксація збігається з першою git rev-listкомандою в команді, то вона є доступною для другого коміту.

Якщо перша фіксація недосяжна з другою, git rev-listнічого не повертайте.

git rev-list --boundary A..B

закінчив би A, якщо Aце буде доступний з B.
Це те саме, що:

git rev-list --boundary B --not A

з Bбільш позитивної посиланням , і Aв негативному значенні завдання .
Він починається з Bта повертається назад по графіку, поки не стикається з переглядом, до якого можна дістатися A.
Я б заперечував, що якщо Aвін безпосередньо доступний B, він зіткнеться (і відобразиться через --boundaryопцію) Aсам.


Це звучить як досить поширений випадок, що я дивуюсь, що git ще не опублікував "порцелянової" команди, яка робить саме це.
Лоуренс І. Сіден

1
@lsiden: правда. Побічна примітка: не забувайте, що для того, щоб перевірити щось програмно , ви не повинні використовувати порцелянову команду (як у stackoverflow.com/questions/6976473/… ), а сантехнічні команди (як показано на stackoverflow.com/questions / 3878624 /… )
VonC

О, чоловіче, схоже, я повинен повернутися назад і попрацювати над своїми рукописними котлетами Shell!
Лоуренс І. Сіден

1
питання: чому -85e54e2...в фрагменті є мінус? також можливий помилковий
помилковий помилок

1
@sdaau -означає, що це кордон. Я відредагував відповідь, щоб зробити це зрозумілішим, а також оновити посилання на doc та виправити помилку на друк цієї п'ятирічної відповіді.
VonC

11

Іншим способом було б використання git logі grep.

git log --pretty=format:%H abc123 | grep def456

Це дасть один рядок виводу, якщо команда def456 є родоначальником чини abc123, або немає іншого виводу.

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


Я очікував, що це рішення буде повільним, але насправді досить швидким, навіть для проекту з 20-ти кілометровими зобов’язаннями
Ренато Заннон

2
замість цього --prettyя використовую --oneline: git log --oneline ce2ee3d | grep ec219ccчудово працює
gens

3

https://stackoverflow.com/a/13526591/895245 згадує про це, щоб зробити його більш людяним:

git-is-ancestor() (
  if git merge-base --is-ancestor "$1" "$2"; then
      echo 'ancestor'
  elif git merge-base --is-ancestor "$2" "$1"; then
      echo 'descendant'
  else
      echo 'unrelated'
  fi
)
alias giia='git-is-ancestor'

це повернеться "не пов'язано", якщо обидва параметри вказують на один і той же
mik

1

git show-branch -sha1 commit-sha1

Де:

  • branch-sha1: sha1 у вашій гілці, яку ви хочете перевірити
  • commit-sha1: sha1 зобов’язання, яке ви хочете перевірити

0

Якщо ви використовуєте git merge-base --is-ancestor , обов'язково використовуйте Git 2.28 (Q3 2020)

З Git 2.28 (Q3 2020) кілька полів у " struct commit", які не завжди повинні бути присутніми, були переміщені для здійснення плит.

Див. Зробити c752ad0 , здійснити c49c82a , зробити 4844812 , зробити 6da43d9 (17 червня 2020 р.) Від Абхішека Кумара ( abhishekkumar2718) .
(Об'єднав Хуніо С Хамано - gitster- у комітеті d80bea4 , 06 липня 2020 р.)

commit-graph: представити commit_graph_data_slab

Підписаний: Абхішек Кумар

Структурна комісія використовується в багатьох контекстах. Однак члени generationі graph_posвикористовуються лише для операцій, пов’язаних з графіками, а також інакше витрачають пам'ять.

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

Оскільки до них часто звертаються разом, давайте введемо структуру commit_graph_dataта перемістимо їх на commit_graph_dataплиту.

Хоча загальний тестовий набір працює так само швидко, як master(серія: 26m48s master,: 27m34s, швидше на 2,87%), деякі команди, якgit merge-base --is-ancestor були уповільнені на 40%, як виявив Szeder Gábor .
Після мінімізації доступу до комутаційних плит уповільнення зберігається, але наближається до 20%.

Деррік Столі вважає, що уповільнення пов'язане з алгоритмом, що лежить в основі, а не повільністю доступу до комутаційної панелі, і ми будемо слідувати в наступній серії.


-1

На основі відповіді itub, якщо вам потрібно зробити це для всіх тегів у сховищі:

for i in `git tag` ; do echo -ne $i "\t" ; git log --pretty=format:%H $i | (grep <commit to find> || echo ""); done
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.