Получить журнал фиксации для определенной строки в файле?

Есть ли способ заставить git выдать вам журнал коммитов для коммитов, которые касались определенной строки в файле?

подобно git blame, но git blame покажет вам последний коммит, который коснулся конкретной строки.

Мне бы очень хотелось получить похожий журнал, а не список коммитов в любом месте файла, а только коммиты, которые коснулись конкретной строки.

12 ответов

Решение

Смотрите также Git: узнайте, какие коммиты когда-либо касались ряда строк.


Начиная с Git 1.8.4, git log имеет -L просматривать эволюцию ряда линий.

Например, предположим, вы смотрите на git blame выходной. Вот -L 150,+11 означает "только посмотрите на строки от 150 до 150+11":

$ git blame -L 150,+11 -- git-web--browse.sh
a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 150)            die "The browser $browser is not
a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 151)    fi
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 152) fi
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 153) 
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 154) case "$browser" in
81f42f11 git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:38 +0100 155) firefox|iceweasel|seamonkey|iceape)
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 156)    # Check version because firefox < 2.0 do
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 157)    vers=$(expr "$($browser_path -version)" 
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 158)    NEWTAB='-new-tab'
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 159)    test "$vers" -lt 2 && NEWTAB=''
a0685a4f git-web--browse.sh (Dmitry Potapov   2008-02-09 23:22:22 -0800 160)    "$browser_path" $NEWTAB "$@" &

И вы хотите узнать историю того, что сейчас линия 155.

Затем используйте git log, Вот, -L 155,155:git-web--browse.sh означает "проследить эволюцию строк от 155 до 155 в файле с именем git-web--browse.sh ".

$ git log --pretty=short -u -L 155,155:git-web--browse.sh
commit 81f42f11496b9117273939c98d270af273c8a463
Author: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>

    web--browse: support opera, seamonkey and elinks

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- a/git-web--browse.sh
+++ b/git-web--browse.sh
@@ -143,1 +143,1 @@
-firefox|iceweasel)
+firefox|iceweasel|seamonkey|iceape)

commit a180055a47c6793eaaba6289f623cff32644215b
Author: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>

    web--browse: coding style

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- a/git-web--browse.sh
+++ b/git-web--browse.sh
@@ -142,1 +142,1 @@
-    firefox|iceweasel)
+firefox|iceweasel)

commit 5884f1fe96b33d9666a78e660042b1e3e5f9f4d9
Author: Christian Couder <chriscool@tuxfamily.org>

    Rename 'git-help--browse.sh' to 'git-web--browse.sh'.

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- /dev/null
+++ b/git-web--browse.sh
@@ -0,0 +127,1 @@
+    firefox|iceweasel)

Вы можете получить набор коммитов с помощью кирки.

git log -S'the line from your file' -- path/to/your/file.txt

Это даст вам все коммиты, которые повлияли на этот текст в этом файле. Если файл был переименован в какой-то момент, вы можете добавить --follow-parent.

Если вы хотите проверять коммиты при каждом из этих правок, вы можете передать этот результат в git show:

git log ... | xargs -n 1 git show

Попробуйте использовать приведенную ниже команду, реализованную в Git 1.8.4.

git log --pretty=short -u -L <upperLimit>,<lowerLimit>:<path_to_filename>

Итак, в вашем случае upperLimit & lowerLimit это тронутый line_number

Упрощение ответа @ Мэтта -

git blame -L14,15 -- <file_path>

Здесь вы получите вину за строки 14 to 15,

поскольку -L вариант ожидает Range в качестве параметра мы не можем получить Blame для одной строки, используя -L вариант`.

Ссылка

Чрезвычайно простой способ сделать это - использовать vim-fugitive. Просто откройте файл в vim, выберите интересующую вас строку (и) Vзатем введите

:Glog

Теперь вы можете использовать :cnext а также :cprev чтобы увидеть все ревизии файла, в котором изменена эта строка. В любой момент введите :Gblame чтобы увидеть информацию о ша, авторе и дате.

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

Если вам повезло, что строка всегда имеет некоторую идентифицирующую характеристику, например, присваивание переменной, имя которой никогда не менялось, вы можете использовать выбор регулярного выражения для git blame -L, Например:

git blame -L '/variable_name *= */',+1

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

Вы могли бы взломать что-нибудь, я полагаю. Сейчас у меня нет времени писать код, но... что-то в этом роде. Бежать git blame -n -L $n,$n $file, Первое поле - это предыдущий коммит, а второе - номер строки в этом коммите, поскольку он мог измениться. Хватай их и беги git blame -n $n,$n $commit^ $fileто есть то же самое, что начиная с коммита до последнего изменения файла.

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

Редактировать: я встретил этот пост в списке рассылки с марта 2011 года сегодня, в котором упоминается, что tig а также git gui есть функция, которая поможет вам сделать это. Похоже, что функция была рассмотрена, но не закончена, для самого git.

Вот решение, которое определяет псевдоним git, так что вы сможете использовать его следующим образом:

git rblame -M -n -L '/REGEX/,+1' FILE

Пример вывода:

00000000 18 (Not Committed Yet 2013-08-19 13:04:52 +0000 728) fooREGEXbar
15227b97 18 (User1 2013-07-11 18:51:26 +0000 728) fooREGEX
1748695d 23 (User2 2013-03-19 21:09:09 +0000 741) REGEXbar

Вы можете определить псевдоним в вашем .gitconfig или просто запустить следующую команду

git config alias.rblame !sh -c 'while line=$(git blame "$@" $commit 2>/dev/null); do commit=${line:0:8}^; [ 00000000^ == $commit ] && commit=$(git rev-parse HEAD); echo $line; done' dumb_param

Это уродливая однострочная строка, так что вот неясная эквивалентная функция bash:

git-rblame () {
    local commit line
    while line=$(git blame "$@" $commit 2>/dev/null); do
        commit="${line:0:8}^"
        if [ "00000000^" == "$commit" ]; then
            commit=$(git rev-parse HEAD)
        fi
        echo $line
    done
}

Решение для кирки (git log --pickaxe-regex -S'REGEX ') даст вам только добавление / удаление строк, а не другие изменения строки, содержащей регулярное выражение.

Ограничением этого решения является то, что git blame возвращает только 1-е совпадение с REGEX, поэтому, если существует несколько совпадений, рекурсия может "перепрыгнуть", чтобы перейти к другой строке. Убедитесь, что проверили полный вывод истории, чтобы определить эти "скачки", а затем исправьте свой REGEX, чтобы игнорировать паразитные линии.

Наконец, вот альтернативная версия, которая запускает git show для каждого коммита, чтобы получить полный diff:

git config alias.rblameshow !sh -c 'while line=$(git blame "$@" $commit 2>/dev/null); do commit=${line:0:8}^; [ 00000000^ == $commit ] && commit=$(git rev-parse HEAD); git show $commit; done' dumb_param

Это позвонит git blame за каждую значимую ревизию, чтобы показать строку $LINE файла $FILE:

git log --format=format:%H $FILE | xargs -L 1 git blame $FILE -L $LINE,$LINE

Как обычно, обвинение показывает номер редакции в начале каждой строки. Вы можете добавить

| sort | uniq -c

чтобы получить агрегированные результаты, что-то вроде списка коммитов, которые изменили эту строку. (Не совсем, если бы только код был перемещен, это могло бы показать один и тот же идентификатор фиксации дважды для различного содержимого строки. Для более детального анализа вам нужно будет выполнить запаздывающее сравнение git blame результаты для смежных коммитов. Кто-нибудь?)

Простая и легкая команда git обвинять Начало и конец строки (735750)

L735,750 (Синтаксис)

git обвинять -L735,750 пациента.php (путь и имя файла)

В моем случае номер строки со временем сильно изменился. Я также был на git 1.8.3, которая не поддерживает регулярные выражения в "git blame -L". (RHEL7 все еще имеет 1.8.3)

myfile=haproxy.cfg
git rev-list HEAD -- $myfile | while read i
do
    git diff -U0 ${i}^ $i $myfile | sed "s/^/$i /"
done | grep "<sometext>"

Один лайнер:

myfile=<myfile> ; git rev-list HEAD -- $myfile | while read i; do     git diff -U0 ${i}^ $i $myfile | sed "s/^/$i /"; done | grep "<sometext>"

Это, конечно, можно превратить в скрипт или функцию.

Вы можете смешивать git blame а также git log Команды для получения сводки каждого коммита в команде git blame и добавления их. Что-то вроде следующего скрипта bash + awk. Он добавляет сводку коммита как встроенный комментарий к коду.

git blame FILE_NAME | awk -F" " \
'{
   commit = substr($0, 0, 8);
   if (!a[commit]) {
     query = "git log --oneline -n 1 " commit " --";
     (query | getline a[commit]);
   }
   print $0 "  // " substr(a[commit], 9);
 }'

В одной строке:

git blame FILE_NAME | awk -F" " '{ commit = substr($0, 0, 8); if (!a[commit]) { query = "git log --oneline -n 1 " commit " --"; (query | getline a[commit]); } print $0 "  // " substr(a[commit], 9); }'

Если положение строки (номер строки) остается неизменным на протяжении всей истории файла, это покажет вам содержимое строки при каждой фиксации:

git log --follow --pretty=format:"%h" -- 'path/to/file' | while read -r hash; do echo $hash && git show $hash:'path/to/file' | head -n 544 | tail -n1; done

+ Изменить 544 на номер строки и path/to/file к пути к файлу.

Другие вопросы по тегам