Виноват - предыдущие коммиты?

391

Можно ли увидеть, кто редактировал конкретную строку перед коммитом, о котором сообщалось git blame, например историю коммитов для данной строки?

Например, я запускаю следующее (в превосходном uncrustifyпроекте):

$ git blame -L10,+1 src/options.cpp
^fe25b6d (Ben Gardner 2009-10-17 13:13:55 -0500 10) #include "prototypes.h"

Как я могу узнать, кто редактировал эту строку перед коммитом fe25b6d? И кто его редактировал перед этим коммитом?

Седате Чужой
источник
7
если причина, по которой вы ищете предыдущие коммиты - это изменения пробелов, используйте эту -wопцию. Существует также -Mдля перемещенного / скопированного кода
brita_
Чтобы найти все коммиты, которые включают данное слово, см. Мой сценарий ниже
VonC
Вот полезный скрипт для добавления этой функциональности на github greasyfork.org/en/scripts/…
Аарон Хоффман
3
Не уверен, как выглядел github, когда @AaronHoffman опубликовал сообщение, но его легко обвинить - и получить вину за предыдущие версии - сейчас в github .
Ерф

Ответы:

389
git blame -L 10,+1 fe25b6d^ -- src/options.cpp

Вы можете указать ревизию для git blame, чтобы оглянуться назад, начиная с (вместо значения по умолчанию HEAD); fe25b6d^является родителем fe25b6d.

янтарный
источник
107
Можете ли вы получить полную историю без повторного ввода команды несколько раз с разными хэшами?
Андерс Зоммарин
13
Я не верю, что в Git есть встроенный способ получить все обвинения, которые касались номера строки (что имеет смысл, поскольку данная строка может не иметь постоянного номера строки в истории файла из-за вставок и удалений). линий).
Янтарная
17
@Amber: Уверен, что вы правы в том, что эта функция не существует, но кажется, что она может быть реализована наивно, просто делая то, что сделал бы человек: обвините его один раз, возьмите сообщенную информацию, обвините, что , и так далее.
Каскабель
15
git gui позволяет легко проверить историю строки, так как версии кликабельны.
Цитракс
5
@shadyabhi --обычно используется в качестве разделителя в аргументах командной строки - в случае с Git он обычно используется для отделения таких вещей, как хеши коммитов, от списка имен файлов.
Январь
192

Вы можете использовать git log -L для просмотра эволюции ряда линий.

Например :

git log -L 15,23:filename.txt

означает «проследить эволюцию строк с 15 по 23 в файле с именем filename.txt».

Navneet
источник
12
Это твердый ответ, и он отвечает на вопрос Андерса Зоммарина выше о том, как увидеть изменения в определенных строках с течением времени.
bigtex777
4
К вашему сведению: git log -L <start>, <end>: <file> требует Git 1.8.4+, см .: git-scm.com/docs/git-log#git-log--Lltstartgtltendgtltfilegt для параметров синтаксиса
Neon
30

Амбер ответ правильный, но я нашел его неясным; Синтаксис:

git blame {commit_id} -- {path/to/file}

Примечание: --используется для отделения дерева sha1 от относительных путей к файлам. 1

Например:

git blame master -- index.html

Полная благодарность Амбер за знание всех вещей! :)

ThorSummoner
источник
1
Я согласен с твоими чувствами. Система комментариев, однако, слишком ограничена, чтобы представлять всю информацию четко. Я добавил содержание этого ответа в комментарии; Тем не менее, я настаиваю на том, чтобы оставить этот ответ для легкого доступа.
ThorSummoner
1
Это должен быть отдельный пост или редактирование. Мне нравится это как отдельный ответ.
Flimm
27

Вы можете проверить:

git gui blame <filename>

Дает вам хорошее графическое отображение изменений, таких как "git blame", но с кликабельными ссылками на строку, чтобы перейти к более ранним коммитам. Наведите указатель мыши на ссылки, чтобы получить всплывающее окно с подробной информацией о коммите. Не мои кредиты ... нашел это здесь:

http://zsoltfabok.com/blog/2012/02/git-blame-line-history/

git guiграфический интерфейс Tcl / Tc для git Без каких-либо других параметров он запускает довольно простое, но полезное графическое приложение для фиксации файлов, фрагментов или даже отдельных строк и других подобных команд, таких как изменение, возврат, нажатие ... Это часть пакета git stock. На окнах это включено в установщик. На Debian - я не знаю о других * nix системах - он должен быть установлен отдельно:

apt-get install git-gui

Из документов:

https://git-scm.com/docs/git-gui

ОПИСАНИЕ

Графический пользовательский интерфейс на основе Tcl / Tk для Git. git gui фокусируется на том, чтобы позволить пользователям вносить изменения в свой репозиторий, внося новые коммиты, внося изменения в существующие, создавая ветви, выполняя локальные слияния и извлекая / отправляя в удаленные репозитории.

В отличие от gitk, git gui фокусируется на генерации коммитов и аннотациях отдельных файлов и не отображает историю проекта. Однако он предоставляет действия меню для запуска сеанса gitk из git gui.

Известно, что git gui работает на всех популярных системах UNIX, Mac OS X и Windows (как под Cygwin, так и под MSYS). Насколько это возможно, соблюдаются правила, специфичные для ОС, что делает git gui довольно нативным интерфейсом для пользователей.

КОМАНДЫ

вина

Запустите средство просмотра вины для указанного файла в данной версии (или в рабочем каталоге, если он не указан).

браузер

Запустите древовидный браузер, показывающий все файлы в указанном коммите. Файлы, выбранные через браузер, открываются в программе просмотра виновных.

citool

Запустите git gui и сделайте ровно один коммит перед выходом и возвращением в оболочку. Интерфейс ограничен только совершением действий, что немного сокращает время запуска приложения и упрощает меню.

версия

Показать текущую версию git gui.

Хольгер Бонке
источник
Это не работает для меня. Я могу нажать на изменение в данной строке, но это просто меняет представление для этого коммита, и текущая строка теперь отображается как this: но как мне увидеть предыдущую версию строки и когда она была добавлена?
BeeOnRope
Это единственный известный мне случай использования git gui
cambuncsive
17

Основываясь на предыдущем ответе, эта однострочная команда bash должна дать вам то, что вы ищете. Он отображает историю мерзавца за конкретную строку определенного файла за последние 5 ревизий:

LINE=10 FILE=src/options.cpp REVS=5; for commit in $(git rev-list -n $REVS HEAD $FILE); do git blame -n -L$LINE,+1 $commit -- $FILE; done

В выходных данных этой команды вы можете увидеть, как меняется содержимое строки или даже может отображаться номер строки для конкретного коммита.

Это часто указывает на то, что строка была добавлена ​​впервые, после этой конкретной фиксации. Это также может указывать на то, что строка была перемещена из другой части файла.

Уилл Шеппард
источник
5
Обратите внимание, что это последние ревизии $ REVS, в которых изменился $ FILE, а не последние ревизии $ REVS, в которых изменилась $ LINE.
Макс Нанаси
Какой ответ вы имеете в виду?
Flimm
Я не помню больше. Возможно, я мог бы лучше рассчитать свой ответ на будущее.
Уилл Шеппард
11

Уникальным решением этой проблемы является использование git log:

git log -p -M --follow --stat - путь / к / вашему / файлу

Как объяснил Андре здесь

Манна
источник
1
Я создал псевдоним, чтобы использовать это: git config --global alias.changes 'log -p -M --follow --stat --'и тогда я могу просто напечататьgit changes path/to/your/file
Tizio Fittizio
Это, безусловно, лучший ответ и именно то, что я искал. Просто и элегантно.
maesk
10

Если вы используете JetBrains Idea IDE (и его производные), вы можете выбрать несколько строк, щелкнуть правой кнопкой мыши контекстное меню, затем Git -> Показать историю для выбора. Вы увидите список коммитов, которые влияли на выбранные строки:

введите описание изображения здесь

warvariuc
источник
Это сработало лучше, чем другие ответы для меня (используя IntelliJ). Потребовалось время, чтобы загрузить все ревизии, но ожидание того стоило.
Стив Чемберс
2

Начиная с Git 2.23 вы можете использовать git blame --ignore-rev

Для примера, приведенного в вопросе, это будет:

git blame -L10,+1 src/options.cpp --ignore-rev fe25b6d

(однако это вопрос с подвохом, потому что fe25b6d - первая ревизия файла!)

Майкл Плакингс
источник
1

Основываясь на ответе Уилла Шепарда, его вывод будет включать дубликаты строк для коммитов, в которых не было изменений, поэтому вы можете отфильтровать их следующим образом (используя этот ответ )

LINE=1 FILE=a; for commit in $(git rev-list HEAD $FILE); do git blame -n -L$LINE,+1 $commit -- $FILE; done | sed '$!N; /^\(.*\)\n\1$/!P; D'

Обратите внимание, что я удалил аргумент REVS, и это восходит к корневому коммиту. Это связано с наблюдением Макса Нанаси выше.

DavidN
источник
1

Основываясь на ответе DavidN, и я хочу следовать переименованному файлу:

LINE=8 FILE=Info.plist; for commit in $(git log --format='%h%%' --name-only --follow -- $FILE | xargs echo | perl -pe 's/\%\s/,/g'); do hash=$(echo $commit | cut -f1 -d ','); fileMayRenamed=$(echo $commit | cut -f2 -d ','); git blame -n -L$LINE,+1 $hash -- $fileMayRenamed; done | sed '$!N; /^\(.*\)\n\1$/!P; D'

ref: красиво отобразить историю переименования файлов в git log

Билл Чан
источник
0

Я использую этот маленький скрипт bash, чтобы посмотреть историю обвинений.

Первый параметр: файл для просмотра

Последующие параметры: передано, чтобы свалить вину

#!/bin/bash
f=$1
shift
{ git log --pretty=format:%H -- "$f"; echo; } | {
  while read hash; do
    echo "--- $hash"
    git blame $@ $hash -- "$f" | sed 's/^/  /'
  done
}

Вы можете указать параметры-вина, такие как -L 70, + 10, но лучше использовать поиск по регулярным выражениям в git-винах, потому что номера строк обычно «меняются» с течением времени.

stangls
источник
0

Основывается на stangls «ы ответ , я ставлю этот сценарий в моей PATH (даже на Windows) , как мерзавца-БХ:

Это позволяет мне искать все коммиты, в которых было задействовано слово:

git bh path/to/myfile myWord

Автор сценария:

#!/bin/bash
f=$1
shift
csha=""
{ git log --pretty=format:%H -- "$f"; echo; } | {
  while read hash; do
    res=$(git blame -L"/$1/",+1 $hash -- "$f" 2>/dev/null | sed 's/^/  /')
    sha=${res%% (*}
    if [[ "${res}" != "" && "${csha}" != "${sha}" ]]; then
      echo "--- ${hash}"
      echo "${res}"
      csha="${sha}"
    fi
  done
}
VonC
источник