Membuat 'git log' mengabaikan perubahan untuk jalur tertentu

121

Bagaimana saya bisa membuat git loghanya pertunjukan yang mengubah file selain yang saya tentukan?

Dengan git log, saya dapat memfilter komit yang saya lihat untuk mereka yang menyentuh serangkaian jalur tertentu. Yang saya inginkan adalah membalikkan filter itu sehingga hanya melakukan jalur sentuh itu selain yang ditentukan yang akan dicantumkan.

Saya bisa mendapatkan apa yang saya inginkan

git log --format="%n/%n%H" --name-only | ~/filter-log.pl | git log --stdin --no-walk

dimana filter-log.pl:

#!/usr/bin/perl
use strict;
use warnings;

$/ = "\n/\n";
<>;

while (<>) {
    my ($commit, @files) = split /\n/, $_;

    if (grep { $_ && $_ !~ m[^(/$|.etckeeper$|lvm/(archive|backup)/)] } @files) {
        print "$commit\n";
    }
}

kecuali saya ingin sesuatu yang lebih elegan dari itu.

Perhatikan bahwa saya tidak menanyakan cara membuat git mengabaikan file. File-file ini harus dilacak dan dijalankan. Hanya saja, seringkali, saya tidak tertarik untuk melihat mereka.

Pertanyaan terkait: Bagaimana membalikkan `git log --grep = <pattern>` atau Bagaimana menampilkan log git yang tidak cocok dengan pola Ini pertanyaan yang sama kecuali untuk pesan komit dan bukan jalur.

Diskusi forum tentang hal ini dari tahun 2008: Perihal: Mengecualikan file dari git-diff Ini tampak menjanjikan tetapi utas tampaknya telah mengering.

Anonymoose
sumber
Saya tidak yakin apakah ada cara bawaan, dan solusi perl Anda terlihat cukup baik. Jika Anda memodifikasinya untuk menerima jalur sebagai argumen baris perintah, Anda bisa membuat alias seperti itu !f() { git log ... | path/to/filter-log.pl "$@" | git log --stdin --no-walk; f, atau bahkan menggabungkan bagian pipa itu ke dalam skrip juga.
Cascabel
Sebagai solusinya, saya menggunakan finduntuk menyaring direktori yang komitnya tidak ingin saya lihat. Jika saya ingin mengabaikan entri log dari komitmen yang dibuat ke direktori tingkat akar SiteConfigmaka saya akan mengatakan:git log `find . -type d -mindepth 1 -maxdepth 1 ! -name *SiteConfig`
Noah Sussman
Untuk Git 1.9 / 2.0 (Q1 2014), lihat jawaban saya di bawah ini : git log --oneline --format=%s -- . ":!sub"akan bekerja (dengan sihir pathspec :(exclude)dan bentuk singkatnya:! )
VonC

Jawaban:

214

Ini diimplementasikan sekarang (git 1.9 / 2.0, Q1 2014) dengan pengenalan pathspec magic :(exclude)dan bentuk singkatnya:! di commit ef79b1f dan commit 1649612 , oleh Nguyễn Thái Ngọc Duy ( pclouds) , dokumentasi dapat ditemukan di sini .

Anda sekarang dapat mencatat semuanya kecuali konten sub-folder:

git log -- . ":(exclude)sub"
git log -- . ":!sub"

Atau Anda dapat mengecualikan elemen tertentu dalam sub-folder itu

  • file tertentu:

      git log -- . ":(exclude)sub/sub/file"
      git log -- . ":!sub/sub/file"
  • file apa pun yang diberikan di dalam sub:

      git log -- . ":(exclude)sub/*file"
      git log -- . ":!sub/*file"
      git log -- . ":(exclude,glob)sub/*/file"

Anda dapat membuat pengecualian itu tidak peka huruf besar kecil!

git log -- . ":(exclude,icase)SUB"

Seperti yang dicatat Kenny Evitt

Jika Anda menjalankan Git di shell Bash, gunakan ':!sub'atau ":\!sub"sebagai gantinya untuk menghindari bash: ... event not foundkesalahan


Catatan: Git 2.13 (Q2 2017) akan menambahkan sinonim ^ke!

Lihat commit 859b7f1 , commit 42ebeb9 (08 Feb 2017) oleh Linus Torvalds ( torvalds) .
(Digabung oleh Junio ​​C Hamano - gitster- di commit 015fba3 , 27 Feb 2017)

pathspec magic: tambahkan ' ^' sebagai alias untuk ' !'

Pilihan ' !' untuk pathspec negatif akhirnya tidak hanya tidak cocok dengan apa yang kami lakukan untuk revisi, itu juga karakter yang mengerikan untuk ekspansi shell karena perlu kutipan.

Jadi tambahkan ' ^' sebagai alias alternatif untuk entri pathspec yang tidak termasuk.


Perhatikan bahwa, sebelum Git 2.28 (Q3 2020), penggunaan pathspec negatif, saat mengumpulkan path termasuk yang tidak terlacak di pohon kerja, telah rusak.

Lihat commit f1f061e (05 Jun 2020) oleh Elijah Newren ( newren) .
(Digabung oleh Junio ​​C Hamano - gitster- di commit 64efa11 , 18 Jun 2020)

dir: memperbaiki pengobatan pathspec yang dinegasikan

Dilaporkan oleh: John Millikin
Ditandatangani oleh: Elijah Newren

do_match_pathspec()memulai hidup sebagai match_pathspec_depth_1()dan untuk kebenaran hanya seharusnya dipanggil dari match_pathspec_depth(). match_pathspec_depth()kemudian diubah namanya menjadi match_pathspec(), sehingga kemungkinan yang kami harapkan saat ini adalah do_match_pathspec()tidak ada penelepon langsung di luar match_pathspec().

Sayangnya, niat ini hilang dengan penggantian nama kedua fungsi tersebut, dan panggilan tambahan ke do_match_pathspec()telah ditambahkan di commit 75a6315f74 (" ls-files: add pathspec matching for submodules", 2016-10-07, Git v2.11.0-rc0 - merge terdaftar di batch # 11 ) dan 89a1f4aaf7 (" dir: jika pathspec kami mungkin cocok dengan file di bawah dir, rekurse ke dalamnya", 2019-09-17, Git v2.24.0-rc0).

Tentu saja, do_match_pathspec()memiliki keuntungan penting match_pathspec()- match_pathspec()akankah hardcode menandai salah satu dari dua nilai, dan pemanggil baru ini perlu meneruskan beberapa nilai lain untuk flag.

Selain itu, meskipun memanggil do_match_pathspec()secara langsung tidak benar, kemungkinan besar tidak ada perbedaan dalam hasil akhir yang dapat diamati, karena bug itu hanya berarti fill_diretory()akan muncul kembali ke direktori yang tidak diperlukan.

Karena pemeriksaan do-this-path-match selanjutnya pada jalur individu di bawah direktori akan menyebabkan jalur tambahan tersebut difilter, satu-satunya perbedaan dari penggunaan fungsi yang salah adalah komputasi yang tidak perlu.

Panggilan buruk kedua untuk do_match_pathspec()dilibatkan - baik melalui perpindahan langsung atau melalui penyalinan + pengeditan - ke sejumlah pemfaktor berikutnya.

Lihat komit 777b420347 (" dir: sinkronkan treat_leading_path()dan read_directory_recursive()", 2019-12-19, Git v2.25.0-rc0 - merge ), 8d92fb2927 (" dir: ganti algoritme eksponensial dengan yang linear", 2020-04-01, Git v2.27.0 -rc0 - merge terdaftar di batch # 5 ), dan 95c11ecc73 ("Perbaiki fill_directory()API yang rawan kesalahan ; buat itu hanya mengembalikan kecocokan", 2020-04-01, Git v2.27.0-rc0 - merge terdaftar di batch # 5 ) .

Yang terakhir memperkenalkan penggunaan do_match_pathspec()pada file individual, dan dengan demikian menghasilkan jalur individual dikembalikan yang seharusnya tidak dikembalikan.

Masalah dengan pemanggilan do_match_pathspec()alih-alih match_pathspec()adalah bahwa setiap pola yang dinegasikan seperti '``:! Unwanted_path`` akan diabaikan .

Tambahkan match_pathspec_with_flags()fungsi baru untuk memenuhi kebutuhan menentukan flag khusus sambil tetap memeriksa pola yang dinegasikan dengan benar, tambahkan komentar besar di atas do_match_pathspec()untuk mencegah orang lain menyalahgunakannya, dan perbaiki pemanggil saat ini do_match_pathspec()untuk menggunakan salah satu match_pathspec()atau match_pathspec_with_flags().

Satu catatan terakhir adalah yang DO_MATCH_LEADING_PATHSPECmembutuhkan pertimbangan khusus saat bekerja dengannya DO_MATCH_EXCLUDE.

Intinya DO_MATCH_LEADING_PATHSPECadalah jika kita memiliki pathspec seperti

*/Makefile

dan kami memeriksa jalur direktori seperti

src/module/component

bahwa kami ingin menganggapnya cocok sehingga kami masuk kembali ke direktori karena _might_ memiliki file bernama Makefiledi bawah.

Namun, saat kita menggunakan pola pengecualian, yaitu kita memiliki pathspec seperti

:(exclude)*/Makefile

kami TIDAK ingin mengatakan bahwa path direktori seperti

src/module/component

adalah pertandingan (negatif).

Meskipun mungkin ada file bernama 'Makefile' di suatu tempat di bawah direktori itu, mungkin juga ada file lain dan kami tidak dapat mengatur semua file di bawah direktori itu terlebih dahulu; kita perlu mengulang dan kemudian memeriksa file satu per satu.

Sesuaikan DO_MATCH_LEADING_PATHSPEClogika agar hanya diaktifkan untuk spesifikasi jalur positif.

VonC
sumber
7
Bisakah Anda melakukan banyak file?
Justin Thomas
12
@JustinThomas Saya percaya (belum diuji) bahwa Anda dapat mengulangi pola pengecualian jalur itu beberapa kali ":(exclude)pathPattern1" ":(exclude)pathPattern2", sehingga mengabaikan banyak folder / file.
VonC
7
Jika Anda menjalankan Git di shell Bash, gunakan ':!sub'untuk menghindari bash: ... event not foundkesalahan . ":\!sub"tidak bekerja.
Kenny Evitt
1
@KennyEv Terima kasih atas suntingan dan komentar Anda. Saya telah memasukkan yang terakhir dalam jawaban untuk visibilitas lebih.
VonC
2
Bagi mereka yang bertanya-tanya di mana dokumentasi resmi tentang fungsi ini, lihat git help glossary(yang saya temukan tercantum di git help -g[yang saya temukan disarankan di git help]).
ravron
4

tl; dr: shopt -s extglob && git log !(unwanted/glob|another/unwanted/glob)

Jika Anda menggunakan Bash, Anda seharusnya dapat menggunakan fitur globbing yang diperluas untuk hanya mendapatkan file yang Anda butuhkan:

$ cd -- "$(mktemp --directory)" 
$ git init
Initialized empty Git repository in /tmp/tmp.cJm8k38G9y/.git/
$ mkdir aye bee
$ echo foo > aye/foo
$ git add aye/foo
$ git commit -m "First commit"
[master (root-commit) 46a028c] First commit
 0 files changed
 create mode 100644 aye/foo
$ echo foo > bee/foo
$ git add bee/foo
$ git commit -m "Second commit"
[master 30b3af2] Second commit
 1 file changed, 1 insertion(+)
 create mode 100644 bee/foo
$ shopt -s extglob
$ git log !(bee)
commit ec660acdb38ee288a9e771a2685fe3389bed01dd
Author: My Name <[email protected]>
Date:   Wed Jun 5 10:58:45 2013 +0200

    First commit

Anda dapat menggabungkan ini dengan globstaruntuk tindakan rekursif.

l0b0
sumber
7
Ini tidak menunjukkan komit yang mempengaruhi file yang sudah tidak ada. Peretasan yang sangat dekat dan bagus semuanya sama.
Anonymoose
-2

Anda dapat mengabaikan sementara perubahan dalam file dengan:

git update-index --skip-worktree path/to/file

Ke depan, semua perubahan ke file-file akan diabaikan oleh git status, git commit -a, dll Bila Anda siap untuk melakukan file-file, hanya membalikkannya:

git update-index --no-skip-worktree path/to/file

dan berkomitmen seperti biasa.

rubysolo.dll
sumber
9
Ini tampaknya untuk mengatasi situasi yang sedikit berbeda. git update-index --skip-worktreetidak menyebabkan git logpenyaringan komit yang telah dibuat.
Anonymoose