Як я можу "звинуватити" вилучений рядок?


506

git blameчудово підходить для модифікованих та доданих рядків, але як я можу знайти, коли рядок, що існував у певній попередній комісії, був врешті видалений. Я думаю bisect, але я сподівався на щось корисніше.

(Перш ніж запитати: у цьому випадку я щойно робив git log -pі шукав рядок коду, і (а) якийсь ідіот щойно видалив життєвий рядок у попередньому комітеті та (б) я був ідіот.)


4
Там в період спостереження з відповіддю роз'яснюють , що git log -S<string> /path/to/fileхоче -cабо , -ccа також показати абсорбцію при злитті (конфлікти)
CFI

3
Це повинно бути -cі --cc. @Steen: Правильно, дякую за вказівку! Дурний нагляд. Бажаю, я міг би відредагувати коментар. Додавання нового, потім видалення мого, потім ви видаляєте своє, занадто громіздке, мабуть :)
cfi

4
Я хотів git blameби мати можливість відображати видалені рядки (з, можливо, перекресленим чи червоним текстом) разом із редакцією, в якій вони були видалені.
Крейг МакКуїн

Це важко було б написати? Я не знаю багато про внутрішні організації Git.
Мальволіо

Відповіді:


636

Якщо ви знаєте вміст рядка, це ідеальний варіант використання для:

git log -S <string> path/to/file

який показує, що ви вводите чи видаляєте екземпляр цього рядка. Є також те, -G<regex>що робить те ж саме з регулярними виразами! Щоб отримати додаткову інформацію, перегляньте man git-logта знайдіть варіанти -Gта -Sпараметри, або пікнік (дружня назва цих функцій).

Цей -Sваріант насправді згадується в заголовку сторінки сторінки git-blame, в розділі опису, де він дає приклад використання git log -S....


Блискуче ... просто те, що мені було потрібно в цій роботі з перенесення, я працюю над +1
jkp

37
Після використання Git протягом 1 року, він все ще мене дивує, коли Git завжди має десь команду / опцію для вирішення майже будь-якого сценарію використання, який у мене є. Дякую за те, що поділився цим, саме це мені зараз потрібно!
Паскаль Бурк

22
Цей метод працював для мене раніше, але якраз зараз я побачив випадок, коли він не знайшов коміту, де рядок було видалено. Виявилося, що відповідний рядок було видалено під час об'єднання - чи це пояснить бід? ( git blame --reverseМетод знайшов це.)
antinome

9
@antinome Щоб показати об'єкти злиття, додатково використовуйте цю -cопцію.
юнзен

2
Я зробив ctrl + f на "-s" на сторінці і нічого не знайшов. Де на сторінці ви це бачите ?? Я використовую мерзотник 1.8.5.2
temporary_user_name

134

Я думаю, що ти насправді хочеш

git blame --reverse START..END filename

На сторінці сторінки :

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

З git blame reverse, ви можете знайти останню фіксацію, у якій з'явився рядок. Ви все ще повинні отримати фіксацію, яка з'явиться після.

Ви можете використовувати наступну команду, щоб показати зворотний журнал git. Перше відображення відображатиметься в останній раз, коли цей рядок з’являється, а наступне виконання - коли воно буде змінено або видалено

git log --reverse --ancestry-path COMMIT^..master

14
Якщо з гілки є кілька об'єднань, де рядок було додано до гілки, де відсутня лінія (або будь-який інший випадок, коли в рядку є декілька шляхів від START до END), git blame --reverseбуде показано ревізію до злиття, яке було хронологічно останнє, а не перегляд до початкового злиття, коли було прийнято рішення не брати лінію. Чи є спосіб знайти найпершу редакцію, де лінія припинила існувати, а не останню?
rakslice

2
@rakslice, для цього можна використовувати вину - reverse - first-parent, це трохи краще.
max630

17

Просто для завершення відповіді Каскабеля :

git log --full-history -S <string> path/to/file

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


9

git blame - реверс може наблизитись до того, де видалено рядок. Але це насправді не вказує на версію, де рядок видалено. Він вказує на останню редакцію, де рядок був присутній . Тоді, якщо наступна редакція - це звичайна фіксація, вам пощастить, і ви отримали виправлення. OTOH, якщо наступна редакція є об'єднанням , то все може трохи розізлитись.

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

https://github.com/eantoranz/difflame


0

Для змін, прихованих у комісіях злиття

Об'єднання об'єднань автоматично приховують їх зміни від виходу журналу Git. І пікакс, і зворотна кримінальна зміна не знайшли змін. Тому рядок, який я хотів, був доданий і пізніше видалений, і я хотів знайти злиття, яке його видалило. Історія файлів git log -p -- path/fileлише показала, що він додається. Ось найкращий спосіб, який я знайшов:

git log -p -U9999 -- path/file

Шукайте зміни, а потім шукайте "^ здійснити" назад - перша "^ фіксація" - це фіксація, де в останньому файлі був цей рядок. Друга "^ фіксація" - це після її зникнення. Другим комітом може бути той, який його видалив. Ціль -U9999призначена для відображення всього вмісту файлу (після кожної зміни файлу), припускаючи, що ваші файли мають максимум 9999 рядків.

Знаходить будь-які пов'язані злиття за допомогою грубої сили (різниться кожен можливий злиття з його першим батьком, проти тонн комітетів)

git log --merges --pretty=format:"git diff %h^...%h | grep target_text" HEAD ^$(git merge-base A B) | sh -v 2>&1 | less

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

Покажіть дерево Git із цими двома комітами (і багато складної історії Git вилучено):

git log --graph --oneline A B ^$(git merge-base A B) (A - це перший перше місце, B - друге вище)

Показати історію A та історію B мінус історію як A, так і B.

Альтернативна версія (схоже, показує шлях більш лінійно, а не звичайне дерево історії Git - однак я віддаю перевагу звичайному дереву історії git):

git log --graph --oneline A...B

Три, а не дві крапки - три крапки означає "r1 r2 - not $ (git merge-base - всі r1 r2). Це безліч комітетів, які доступні або з одного з r1 (ліва сторона), або r2 (праворуч стороні), але не з обох ". - джерело: "людина gitrevision"

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