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

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

Как и git blame, но git blame покажет вам последнее коммит, касающееся определенной строки.

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

Ответ 1

Смотрите также 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 "[email protected]" &

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

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

$ git log --pretty=short -u -L 155,155:git-web--browse.sh
commit 81f42f11496b9117273939c98d270af273c8a463
Author: Giuseppe Bilotta <[email protected]>

    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 <[email protected]>

    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 <[email protected]>

    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)

Ответ 2

Вы можете получить набор коммитов, используя pick-ax.

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

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

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

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

Ответ 3

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

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

Итак, в вашем случае upperLimit & lowerLimit - это line_number

Дополнительная информация - https://www.techpurohit.com/list-some-useful-git-commands

Ответ 4

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

:Glog

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

Ответ 5

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

Если вам повезло, что линия всегда имеет некоторую идентифицирующую характеристику, например. присвоение переменной, имя которой никогда не менялось, вы могли бы использовать выбор регулярного выражения для 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.

Ответ 6

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

git blame -L14,15 -- <file_path>

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

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

Ссылка

Ответ 7

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

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

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

| sort | uniq -c

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

Ответ 8

Вот решение, которое определяет псевдоним 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 "[email protected]" $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 "[email protected]" $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 виноват только возвращает 1-е соответствие REGEX, поэтому, если существует несколько совпадений, рекурсия может "прыгать" на следующую строку. Обязательно проверьте полный вывод истории, чтобы определить эти "прыжки", а затем исправьте REGEX, чтобы игнорировать линии паразитов.

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

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

Ответ 9

В моем случае число строк со временем сильно изменилось. Я также был на git 1.8.3, который не поддерживает регулярное выражение в git вине -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>"

Oneliner:

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

Конечно, это можно сделать в script или в функции.

Ответ 10

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

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); }'