Знайдіть гілку Git, що містить зміни до даного файлу


88

У мене 57 місцевих відділень. Я знаю, що змінив певний файл в одному з них, але не впевнений, який саме. Чи є якась команда, яку я можу запустити, щоб знайти, які гілки містять зміни до певного файлу?

Відповіді:


87

Знайти всі гілки, що містять зміну на FILENAME (навіть якщо до (незаписаної) точки гілки)

FILENAME="<filename>"
git log --all --format=%H $FILENAME | while read f; do git branch --contains $f; done | sort -u

Перевірити вручну:

gitk --all --date-order -- $FILENAME

Знайти всі зміни до FILENAME, не об’єднані для обробки:

git for-each-ref --format="%(refname:short)" refs/heads | grep -v master | while read br; do git cherry master $br | while read x h; do if [ "`git log -n 1 --format=%H $h -- $FILENAME`" = "$h" ]; then echo $br; fi; done; done | sort -u

Чи потрібно щось замінювати в цій команді, крім FILENAME? Він повертає всі 57 назв гілок.
Дастін,

@Dustin: Якщо всі 57 гілок містять це ім'я файлу, то всі 57 гілок містять зміни, що включають це ім'я файлу. Гілки починаються з найстарішої версії, доступної для цієї гілки, навіть якщо ця редакція існувала до того, як ви створили гілку (гілка в деяких сенсах створюється заднім числом). Я думаю, вам потрібно краще визначити свою проблему. Чи знаєте ви, в чому полягає зміна? Не могли б ви використати git log -Schange …або git log --grep LOGMESSAGE …(із… що представляє решту команди, про яку я згадав).
Сет Робертсон,

2
@Dustin: Іншим варіантом є використання, gitk --all -- filenameяке графічно покаже всі зміни до цього файлу. Якщо ви можете ідентифікувати спірний коміт, тоді ви можете використовувати, git branch --containsщоб побачити, до яких гілок коміт мігрував. Якщо ви хочете побачити, на якій гілці спочатку був створений відповідний коміт, тоді google git-what-branch, але майте на увазі, що швидкі злиття можуть закрити цю інформацію.
Сет Робертсон,

@Seth: Я не міг згадати повідомлення про фіксацію або точну зміну коду. Я просто маю загальне уявлення. Проблема полягає в тому, що він ще не об’єднаний з master, тому для використання gitk мені все одно доведеться перевіряти кожну гілку, щоб знайти те, що я шукаю. Було б непогано, якби я міг сказати: "git, покажи мені гілки, які внесли зміни до FILENAME з моменту його відгалуження"
Дастін,

1
Ви можете написати перший рядок ефективнішеgit log --all --format='--contains %H' "$file" | xargs git branch
Кодіро

52

Все, що тобі потрібно, це

git log --all -- path/to/file/filename

Якщо ви хочете дізнатися гілку відразу, ви також можете використовувати:

git log --all --format=%5 -- path/to/file/filename | xargs -I{} -n 1 echo {} found in && git branch --contains {}

Крім того, якщо у вас були якісь перейменування, ви можете включити --followдля команди журналу Git.


15
Це покаже коміти, але він запитав, яке відділення. Додайте --sourceтуди, і ви золоті.
Карл Білефельдт,

Дякую, але я не думаю, що відображаються всі гілки для кожного коміту. Але це допомогло б.
Адам Димітрук,

1
Правда, але в цьому конкретному випадку він шукав лише одного.
Карл Білефельдт,

До речі, шлях до asp.net повинен бути у такому форматі, як AppName / Controllers / XController.cs
Алі

8

Схоже, це все ще проблема без відповідного рішення. У мене недостатньо кредитів, щоб коментувати, тож ось мій невеликий внесок.

Перше рішення Сета Робертсона начебто спрацювало для мене, але дало мені лише місцеві гілки, серед яких багато помилкових спрацьовувань, ймовірно через злиття зі стабільної гілки.

Друге рішення Адама Димітрука для мене взагалі не працювало. Для початку, що таке --format =% 5? Це не розпізнано git, я не міг нічого про це знайти і не міг змусити його працювати з іншими параметрами формату.

Але його перше рішення у поєднанні з варіантом --source та простим grep виявилось корисним:

git log --all --source -- <filename> | grep -o "refs/.*" | sort -u

Це дає мені ряд віддалених тегів та гілок та одну локальну гілку, де я вніс останні зміни у файл. Не впевнений, наскільки це повно.

ОНОВИТИ відповідно до запиту @nealmcb, сортуючи гілки за останньою зміною:

По-перше, ви можете змінити grep на "refs / heads /.*", що надасть вам лише місцеві відділення. Якщо є лише кілька гілок, ви можете вивчити останні коміти кожного з них так:

git log -1 <branch> -- <filename>

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

git log --all --source -- <filename> | grep -o "refs/heads/.*" | sort -u | xargs -I '{}' git log -1 --format=%aI%x20%S '{}' -- <filename> | sort -r

Це призведе до такого виводу:

2020-05-07T15:10:59+02:00 refs/heads/branch1
2020-05-05T16:11:52+02:00 refs/heads/branch3
2020-03-27T11:45:48+00:00 refs/heads/branch2

Чудово - дякую. А як щодо сортування за останньою зміною?
nealmcb

1

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

#!/bin/bash

file=$1
base=${2:-master}

b=$(tput bold) # Pretty print
n=$(tput sgr0)

echo "Searching for branches with changes to $file related to the $base branch"

# We look through all the local branches using plumbing
for branch in $(git for-each-ref --format='%(refname:short)' refs/heads/); do
  # We're establishing a shared ancestor between base and branch, to only find forward changes.  
  merge_base=$(git merge-base $base $branch)
  # Check if there are any changes in a given path.
  changes=$(git diff $merge_base..$branch --stat -- $file)

  if [[ ! -z $changes ]]; then
    echo "Branch: ${b}$branch${n} | Merge Base: $merge_base"
    # Show change statistics pretty formatted
    git diff $merge_base..$branch --stat -- $file
  fi
done

Якщо ви помістите його в PATH як git-find-changes(з дозволами на виконання) - тоді ви можете зателефонувати йому за допомогоюgit find-changes /path

Приклад виводу для git find-changes app/models/

Branch: update_callbacks | Merge base: db07d23b5d9600d88ba0864aca8fe79aad14e55b
 app/models/api/callback_config.rb | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)
Branch: repackaging | Merge base: 76578b9b7ee373fbe541a9e39cf93cf5ff150c73
 app/models/order.rb                 | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

Дуже цікавий сценарій. Прихильний. Це шоу-зміни чи пошук-зміни?
VonC

@VonC спасибі, виправлене використання, слід знаходити скрізь
Марцін Рачковський,

0

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

for branch in $(git for-each-ref --format="%(refname:short)" refs/heads); do
    git checkout $branch && git grep SOMETHING
done

1
Тому що, якщо ви знаєте, яку зміну ви можете використовуватиgit log -S
Сет Робертсон,

Яку оболонку ви припускаєте? Баш?
Пітер Мортенсен,

Ніяких башизмів, які повинні працювати на POSIX. Я не впевнений, що for-each-refвсе ще поважає цей shortпрапор. Тим не менш, ігноруйте мою відповідь; інші відповіді кращі.
whiteinge
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.