Завантажити журнал фіксації для певного рядка у файлі?


502

Чи є якийсь спосіб отримати git, щоб надати вам журнал фіксованих обчислень лише для комісій, які торкнулися певного рядка у файлі?

Начебто git blame, але git blameпокаже тобі ОСТАННІ зобов’язання, які торкнулися певної лінії.

Мені дуже хотілося б отримати аналогічний журнал не списку комітетів у будь-якій точці файлу, а лише комітетів, які торкалися певного рядка.


Відповіді:


631

Дивіться також 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)

2
'git log --topo-order --graph -u -L 155,155: git-web--browse.sh' - це призвело до фатальної помилки: 'недійсне ім'я об'єкта 155,155'. Версія Git: 1.8.3.2. Будь-які пропозиції?
BairDev

12
Оновіть до Git 1.8.4 або новішої версії.
Метт МакКлюр

4
що робити, якщо я хочу знати "історію того, що є рядком 155 у комісіїA" (замість рядка 155 в HEAD). Чи можу я просто використовувати git log commitA-hash -L 155,155:file-name?
Іда

@Flimm, я не маю сильних уподобань.
Метт МакКлур

це добре працює, за винятком випадків, коли файл переміщено / перейменовано ... здається, що --follow не любить поєднуватися з аргументами рядків рядків.
Майк Еллері

66

Ви можете отримати набір комітетів, використовуючи 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

5
Я не впевнений, що бачу, як це допомагає. Якщо текст вплинув, то рядок уже не той самий, тож пікакс покаже лише останню зміну. Тоді вам доведеться робити git log -S'the previous version of the line'і так далі, точно так само, як і в кінцевому підсумку git blame -L. І це буде набагато повільніше git blame, оскільки текст доводиться шукати скрізь, а не лише в даному місці.
Каскабель

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

3
чому це називається пікером ? :)
Ciprian Tomoiagă

43

Спробуйте скористатися командою нижче, реалізованою в 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


2
Я думаю --pretty=short, що ігнорується при використанні -L. Будь ласка, виправте
Вік Седублеєв

14

Надзвичайно простий спосіб зробити це за допомогою vim-втікача . Просто відкрийте файл in vim, виберіть рядок, який вам цікавий V, а потім введіть

:Glog

Тепер ви можете використовувати :cnextта :cprevбачити всі версії файлу, де цей рядок змінено. У будь-який момент введіть, :Gblameщоб побачити інформацію про ша, автора та дату.


13

Спрощення відповіді @ matt -

git blame -L14,15 -- <file_path>

Тут ви отримаєте провину за лінії 14 to 15.

Оскільки -Lопція розраховує Rangeяк парам, ми не можемо отримати Blameодин рядок за допомогою -Lпараметра " .

Довідково


10

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

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

Це вимагатиме, git blameщоб кожна змістовна редакція показала рядок $LINEфайлу $FILE:

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

Як завжди, винна показує номер перегляду на початку кожного рядка. Можна додати

| sort | uniq -c

щоб отримати узагальнені результати, щось на зразок переліку комітетів, які змінили цей рядок. (Не зовсім, якщо тільки код був переміщений навколо, це може показати те передайте ID двічі для різних змістів лінії. Для більш детального аналізу ви повинні були б зробити лаговий порівняння git blameрезультатів для суміжних фіксацій. Anyone? )


Знову я думаю, що це не працює, оскільки воно не відстежує попереднє розташування цього рядка. Тож якщо рядок було додано 2 комітки тому, ви
подивилися

6

Ось рішення, яке визначає псевдонім 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
}

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

Обмеженням цього рішення є те, що винна git повертає лише 1-й матч REGEX, тому, якщо існує декілька збігів, рекурсія може «перестрибнути», щоб перейти за іншим рядком. Не забудьте перевірити повний вивід історії, щоб виявити ці "стрибки", а потім виправити REGEX, щоб ігнорувати лінії паразитів.

Нарешті, ось альтернативна версія, яка запускає git show на кожній комісії, щоб отримати повну різницю:

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

2

Ви можете змішувати 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); }'

2

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

Звичайно, це може бути перетворено на сценарій або функцію.

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