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


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».


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

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


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 -> Показать историю для выбора. Вы увидите список коммитов, которые влияли на выбранные строки:

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


Это сработало лучше, чем другие ответы для меня (используя 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, и это восходит к корневому коммиту. Это связано с наблюдением Макса Нанаси выше.


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-винах, потому что номера строк обычно «меняются» с течением времени.


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
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.