Ambil log komit untuk baris tertentu dalam file?

503

Apakah ada cara untuk membuat git memberi Anda log komit hanya untuk komit yang menyentuh baris tertentu dalam file?

Suka git blame, tetapi git blameakan menunjukkan Anda komit TERAKHIR yang menyentuh garis tertentu.

Saya benar-benar ingin mendapatkan log serupa, bukan daftar commit di mana saja dalam file, tetapi hanya commit yang menyentuh baris tertentu.

Jrochkind
sumber
2
Lihat juga: Git menyalahkan - melakukan sebelumnya
joeytwiddle

Jawaban:

632

Lihat juga Git: temukan komit yang pernah menyentuh serangkaian garis .


Sejak Git 1.8.4 , git logharus -Lmelihat evolusi berbagai garis.

Sebagai contoh, misalkan Anda melihat git blameoutput. Di sini -L 150,+11berarti "hanya melihat garis 150 hingga 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 "$@" &

Dan Anda ingin tahu sejarah garis 155 sekarang.

Lalu, gunakan git log. Di sini, -L 155,155:git-web--browse.shberarti "melacak evolusi baris 155 hingga 155 dalam file bernama 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)
Matt McClure
sumber
2
'git log --topo-order --graph -u -L 155.155: git-web--browse.sh' - ini telah memberikan kesalahan fatal: 'nama objek tidak valid 155.155'. Versi Git: 1.8.3.2. Ada saran?
BairDev
12
Tingkatkan ke Git 1.8.4 atau lebih baru.
Matt McClure
4
bagaimana jika saya ingin tahu "sejarah apa baris 155 di commitA" (bukan baris 155 di HEAD). Bisakah saya menggunakan git log commitA-hash -L 155,155:file-name?
Ida
@ Flimm, saya tidak punya preferensi yang kuat.
Matt McClure
ini berfungsi dengan baik, kecuali jika file telah dipindahkan / diganti namanya ... tampaknya --follow tidak suka digabungkan dengan argumen rentang garis.
Mike Ellery
67

Anda bisa mendapatkan satu set komit dengan menggunakan kapak.

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

Ini akan memberi Anda semua komit yang mempengaruhi teks dalam file itu. Jika file diubah namanya di beberapa titik, Anda dapat menambahkan --follow-parent.

Jika Anda ingin memeriksa komit di masing-masing suntingan ini, Anda dapat mengirimkan hasilnya ke git show:

git log ... | xargs -n 1 git show
Adam Dymitruk
sumber
5
Saya tidak yakin saya melihat bagaimana ini membantu. Jika teks terpengaruh, maka barisnya tidak sama lagi, jadi beliung hanya akan menunjukkan kepada Anda perubahan terbaru. Anda kemudian harus melakukan git log -S'the previous version of the line'dan seterusnya, persis seperti Anda akhirnya akan melakukannya git blame -L. Dan itu akan jauh lebih lambat daripada git blame, karena harus mencari teks di mana-mana, tidak hanya di tempat tertentu.
Cascabel
Anda dapat menggunakan regex di sana untuk membuatnya lebih menerima. Saat ini tidak ada cara untuk "menavigasi melalui tambalan" kembali ke masa tanpa beberapa skrip rumit. Saya berharap bahwa gitk akan mendapatkan fungsionalitas ini dalam tampilan tambalan di masa mendatang.
Adam Dymitruk
3
mengapa ini disebut kapak ? :)
Ciprian Tomoiagă
43

Coba gunakan perintah di bawah ini diimplementasikan dalam Git 1.8.4.

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

Jadi, dalam kasus Anda upperLimit& lowerLimitadalah tersentuhline_number

Info lebih lanjut - https://www.techpurohit.com/list-some-useful-git-commands

jitendrapurohit
sumber
2
Saya pikir --pretty=shortdiabaikan ketika menggunakan -L. Harap perbaiki
Vic Seedoubleyew
14

Cara yang sangat mudah untuk melakukan ini adalah dengan menggunakan pelarian-vim . Cukup buka file dalam vim, pilih baris yang ingin Anda gunakan V, lalu masukkan

:Glog

Sekarang Anda dapat menggunakan :cnextdan :cprevuntuk melihat semua revisi file di mana baris itu diubah. Kapan saja, masukkan :Gblameuntuk melihat info sha, penulis, dan tanggal.

Cory Klein
sumber
13

Menyederhanakan jawaban @ matt -

git blame -L14,15 -- <file_path>

Di sini Anda akan disalahkan untuk sebuah dialog 14 to 15.

Karena -Lopsi mengharapkan Rangesebagai param kita tidak bisa mendapatkan Blameuntuk satu baris menggunakan -Lopsi` .

Referensi

Swap
sumber
10

Saya tidak percaya ada sesuatu yang built-in untuk ini. Itu dibuat rumit oleh kenyataan bahwa jarang satu baris berubah beberapa kali tanpa sisa file berubah secara substansial juga, jadi Anda akan cenderung berakhir dengan nomor baris banyak berubah.

Jika Anda cukup beruntung bahwa baris selalu memiliki beberapa karakteristik pengidentifikasian, misalnya tugas untuk variabel yang namanya tidak pernah berubah, Anda bisa menggunakan pilihan regex untuk git blame -L. Sebagai contoh:

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

Tetapi ini hanya menemukan kecocokan pertama untuk regex itu, jadi jika Anda tidak memiliki cara yang baik untuk mencocokkan garis, itu tidak terlalu membantu.

Anda bisa meretas sesuatu, saya kira. Saya tidak punya waktu untuk menulis kode barusan, tapi ... sesuatu seperti ini. Lari git blame -n -L $n,$n $file. Field pertama adalah sebelumnya komit menyentuh, dan kolom kedua adalah jumlah baris dalam yang komit, karena bisa saja berubah. Ambil itu, dan jalankan git blame -n $n,$n $commit^ $file, yaitu hal yang sama dimulai dari komit sebelum terakhir kali file diubah.

(Perhatikan bahwa ini akan mengecewakan Anda jika komit terakhir yang mengubah baris adalah komit gabungan. Cara utama ini bisa terjadi jika baris diubah sebagai bagian dari resolusi konflik gabungan.)

Sunting: Saya kebetulan berada di pos milis ini sejak Maret 2011 hari ini, yang menyebutkan itu tigdan git guimemiliki fitur yang akan membantu Anda melakukan ini. Sepertinya fitur tersebut telah dipertimbangkan, tetapi belum selesai, untuk git itu sendiri.

Cascabel
sumber
6

Ini akan memanggil git blameuntuk setiap revisi yang berarti untuk menunjukkan baris $LINEfile $FILE:

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

Seperti biasa, kesalahan menunjukkan nomor revisi di awal setiap baris. Anda bisa menambahkan

| sort | uniq -c

untuk mendapatkan hasil agregat, sesuatu seperti daftar komit yang mengubah baris ini. (Tidak sepenuhnya, jika kode hanya telah dipindahkan, ini mungkin menunjukkan ID komit yang sama dua kali untuk konten baris yang berbeda. Untuk analisis yang lebih rinci Anda harus melakukan perbandingan git blamehasil yang tertinggal untuk komit yang berdekatan. Siapa saja? )

krlmlr
sumber
Sekali lagi saya pikir ini tidak berhasil, karena tidak melacak lokasi sebelumnya dari garis itu. Jadi jika sebuah baris ditambahkan 2 komit yang lalu, Anda akan melihat baris lain
Vic Seedoubleyew
6

Ini adalah solusi yang mendefinisikan alias git, jadi Anda bisa menggunakannya seperti itu:

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

Contoh keluaran:

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

Anda dapat mendefinisikan alias di .gitconfig Anda atau cukup menjalankan perintah berikut

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

Ini adalah one-liner jelek, jadi di sini adalah fungsi bash setara yang tidak dikaburkan:

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
}

Solusi beliung ( git log --pickaxe-regex -S'REGEX ' ) hanya akan memberi Anda penambahan baris / penghapusan, bukan perubahan lain dari baris yang berisi ekspresi reguler.

Keterbatasan solusi ini adalah bahwa git menyalahkan hanya mengembalikan pertandingan REGEX 1, jadi jika ada beberapa pertandingan rekursi dapat "melompat" untuk mengikuti baris lain. Pastikan untuk memeriksa keluaran riwayat lengkap untuk menemukan "lompatan" itu dan kemudian perbaiki REGEX Anda untuk mengabaikan garis parasit.

Akhirnya, berikut adalah versi alternatif yang menjalankan git show pada setiap commit untuk mendapatkan perbedaan penuh:

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
Lucas Cimon
sumber
2

Anda dapat menggabungkan git blamedan git logmemerintahkan untuk mengambil ringkasan dari setiap komit di perintah git menyalahkan dan menambahkannya. Sesuatu seperti skrip bash + awk berikut. Ini menambahkan ringkasan komit sebagai inline komentar kode.

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

Dalam satu baris:

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

Dalam kasus saya, nomor baris telah banyak berubah seiring waktu. Saya juga di git 1.8.3 yang tidak mendukung regex di "git menyalahkan -L". (RHEL7 masih memiliki 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>"

Ini tentu saja dapat dibuat menjadi skrip atau fungsi.

sastorsl
sumber