Bisakah git mengabaikan baris tertentu?

115

Saya menggunakan git untuk menyinkronkan ke phonegap saat menguji di browser asli ponsel. Karena itu saya memiliki baris berikut:

var isPhoneGap = false;

Jelas saya mengubah ini saat membangun, tetapi adakah cara saya dapat mengatur git untuk mengabaikan satu baris ini atau apakah saya harus pergi dan memasukkannya ke dalam file sendiri dan mengabaikannya seperti itu?

Saya menggunakan Gitx dan terminal di OSX 10.6.

Iolo
sumber
@ user494461: Filter Git adalah cara untuk melakukannya: stackoverflow.com/a/16244970/520162
eckes
1
Bisakah Anda tidak mendeteksi lingkungan dan menggunakan file konfigurasi eniroment?
exussum
Singkatnya: Tidak. Tapi saya telah menulis skrip preprocessor yang mencari kode komentar tertentu dan menghapusnya sebelum publikasi ke git. Lihat di sini: github.com/franklinchou/ahk_config/blob/master/preprocess.sh
franklin

Jawaban:

104

Jika file Anda berjenis tertentu, Anda dapat mendeklarasikan driver filter konten , yang dapat Anda deklarasikan dalam .gitattributesfile (seperti yang ditampilkan dalam "Perluasan kata kunci" dari " Atribut Git "):

http://git-scm.com/figures/18333fig0702-tn.png

*.yourType filter=yourFilterName

(Anda bahkan dapat mengatur filter itu untuk file tertentu , jika Anda mau)

Melaksanakan:

  • yourFilterName.smudge(dipicu pada git checkout) dan

    git config --global filter.yourFilterName.smudge 'sed "s/isPhoneGap = .*/isPhoneGap = true/"'
    
  • yourFilterName.clean(dipicu pada git add)

    git config --global filter.yourFilterName.clean 'sed "s/isPhoneGap = .*/isPhoneGap = false/"'
    

File Anda akan tampak tidak berubah pada git status, namun versi yang diperiksa akan memiliki nilai yang tepat untuk isPhoneGap.

VonC
sumber
1
Terima kasih untuk ini. membuatnya bekerja. Apakah Anda tahu cara membuat git diff or status git`, mengabaikan filternya? Jadi saya masih bisa melihat apa yang berbeda? Kasus penggunaan saya adalah untuk log debug ... yang akhirnya saya ingin menghapus ... @jthill @VonC
timh
1
@timh jika filter berfungsi, status git atau git diff seharusnya tidak menampilkan apa pun.
VonC
1
Sayang sekali tidak ada cara yang lebih sederhana di GIT. git ignore <filename> <linenumber> akan sangat berguna!
kiedysktos
22
@kiedysktos linenumber? Bagaimana jika nomor baris berubah?
VonC
Ini berfungsi dengan baik, tetapi pengguna Windows berhati-hatilah, gitconfig sangat pilih-pilih dengan karakter mana yang ingin dipegangnya, jadi ketika mencoba beberapa ekspresi reguler semi-eksotis Anda mungkin mengalami masalah. Saya akhirnya menempatkan panggilan sed saya di file helper.sh terpisah yang saya panggil dari gitconfig saya dengan sh ".git/helper.sh"memastikan untuk melewati parameter apa pun ke sed "$@"(saya berasumsi hanya jalur file yang dilewatkan).
ohaal
43

Kamu bisa memakai

git update-index --assume-unchanged [file]

untuk mengabaikan perubahan satu file yang tidak ingin Anda lacak. Saya menggunakan solusi ini ketika saya perlu memiliki file di repositori tetapi file ini memiliki beberapa bagian yang berubah sehingga saya tidak perlu selalu melacak.

Ketika file memiliki perubahan yang penting, Anda harus melakukan ini:

git update-index --no-assume-unchanged [file]

Juga, lihat Git doc update-index for --[no-]assume-unchangedparameter.

Saat bendera ini ditentukan, nama objek yang direkam untuk jalur tidak diperbarui. Sebaliknya, opsi ini menyetel dan menghapus bit "asumsikan tidak berubah" untuk jalur. Ketika bit "asumsikan tidak berubah" aktif, git berhenti memeriksa file pohon kerja untuk kemungkinan modifikasi, jadi Anda perlu menghapus bit secara manual untuk memberi tahu git saat Anda mengubah file pohon kerja.

Carlos
sumber
2
Apakah melakukan ini masih mengambil versi baru saat saya melakukan git pull?
Saad Rehman Shah
1
@Caffeine ketika Anda melakukan git pull Anda mendapatkan versi terakhir yang telah dikomit, ini akan menjadi yang terakhir sebelum Anda mengubah ke '--assume-unchanged' file.
Carlos
1
Saya yakin --skip-worktreeini adalah pilihan yang lebih baik untuk sebagian besar tujuan. stackoverflow.com/a/39583010/4233593
Jeff Puckett
3
ini mengabaikan pembaruan ke seluruh file bukan baris tertentu
nikoss
6

Gitx harus membiarkan Anda menjalankan atau mengabaikan baris individu (Anda mungkin sudah mengetahuinya), tetapi Anda harus melakukannya setiap kali Anda berkomitmen. Saya pikir akan lebih baik untuk memiliki file konfigurasi per target penyebaran (Anda dapat versi itu), dan beberapa parameter runtime untuk bagaimanapun Anda memulai server (seperti ./myserver --config=whatever.js).

Andy Ray
sumber
5

Melanjutkan https://stackoverflow.com/a/20574486/4935114 , @Mike mengusulkan untuk membuat pre-commitpengait yang akan ada grepdi file bertahap untuk baris yang mungkin ingin diabaikan. Pengait akan memeriksa apakah garis itu dipentaskan. Jika demikian, itu echoadalah peringatan dan itu exitdengan kode 1sehingga proses komit tidak akan dilanjutkan.

Terinspirasi oleh jawaban @ Mike , saya menemukan diri saya mungkin menggunakan versi yang lebih baik dari hooknya yang secara otomatis reset s (dengan -pbendera) baris spesifik yang ingin kita abaikan.

Saya tidak yakin hook ini akan bekerja untuk situasi di mana Anda memiliki banyak file dengan baris ini untuk diabaikan, tetapi pre-commithook ini mencari perubahan pada baris ini di file tertentu buildVars.java. Skrip hook terlihat seperti ini ketika saya mengujinya di mesin saya.

#!/bin/sh

# this hook looks for lines with the text `var isPhoneGap = false;` in the file `buildVars.java` and it resets these lines to the previous state before staged with `reset -p`

if [[ $(git diff --no-ext-diff --cached buildVars.java | grep --count -e "var\ isPhoneGap[\ ]*=[\ ]*") -ne 0 ]]; then
    cat <<EOW
WARNING: You are attempting to commit changes which are not supposed to be commited according to this \`pre-commit\` hook
This \`pre-commit\` hook will reset all the files containing this line to it's previous state in the last commit.
EOW
    echo /$'\n'isPhoneGap$'\n'y$'\n'q | git reset -p
    # BONUS: Check if after reseting, there is no actual changes to be commited and if so, exit 1 so the commit process will abort.
    if [[ $(git diff --no-ext-diff --cached | wc -l) -eq 0 ]]; then
        echo there are no actual changes to be commited and besides the change to the variable \'isPhoneGap\' so I won\'t commit.
        exit 1
    fi
fi

Penjelasan

Apa yang saya lakukan adalah menggemakan urutan kontrol yang mencari regex isPhoneGapselama resetproses interaktif . Jadi meniru pengguna yang menekan /untuk mencari isPhoneGap, menekan yketika ditanya apakah dia ingin membuang tambalan ini dan akhirnya menekan quntuk keluar dari interaktif reset.

Proses tambalan terbalik interaktif didokumentasikan di sini: https://git-scm.com/docs/git-add#git-add-patch


CATATAN: Skrip di atas mengasumsikan bahwa variabel interactive.singleKeyadalah false. Jika Anda mengkonfigurasi milik Anda ke true, hapus salah satu $'\n'dari echoperintah tepat setelah peringatan.

Doron Behar
sumber
3

Beginilah cara Anda melakukannya dengan filter git :

  1. Buat / Buka file gitattributes:
    • <project root> /. gitattributes (akan dimasukkan ke dalam repo)
      ATAU
    • <project root> /. git / info / atribut (tidak akan dimasukkan ke dalam repo)
  2. Tambahkan baris yang menentukan file yang akan difilter:
    • *.rb filter=gitignore, yaitu menjalankan filter bernama gitignorepada semua *.rbfile
  3. Tentukan gitignorefilter di gitconfig:
    • $ git config --global filter.gitignore.clean "sed '/#gitignore$/'d", yaitu hapus baris ini
    • $ git config --global filter.gitignore.smudge cat, yaitu tidak melakukan apa-apa saat menarik file dari repo

Catatan:
Tentu saja, ini untuk file ruby, diterapkan saat baris diakhiri dengan #gitignore, diterapkan secara global dalam ~/.gitconfig. Ubah ini sesuka Anda untuk tujuan Anda.

Peringatan!!
Ini membuat file kerja Anda berbeda dari repo (tentu saja). Setiap check out atau rebasing berarti baris ini akan hilang! Trik ini mungkin tampak tidak berguna karena garis-garis ini berulang kali hilang saat check out, rebase, atau pull, tetapi saya memiliki kasus penggunaan khusus untuk memanfaatkannya.

Saat git stash save "proj1-debug" filter tidak aktif (nonaktifkan untuk sementara waktu gitconfigatau sesuatu). Dengan cara ini, kode debug saya selalu dapat git stash applyd ke kode saya kapan saja tanpa takut baris ini pernah tidak sengaja dilakukan.

Saya memiliki ide yang mungkin untuk mengatasi masalah ini, tetapi saya akan mencoba menerapkannya lain kali.

Terima kasih kepada Rudi dan jw013 karena telah menyebutkan filter git dan atribut git.

Kache
sumber
2

Pengandar filter konten bukanlah solusi yang baik. Anda mungkin dapat menyembunyikan baris ini dari git status/ etc tetapi tidak benar-benar diabaikan. Segera setelah Anda mengubah nilainya, direktori kerja Anda akan ditandai kotor meskipun perubahannya mungkin tidak terlihat.

Jika Anda benar-benar ingin baris ini keluar dari kontrol versi, mengubahnya menjadi argumen baris perintah atau menempatkannya di file include atau build yang diabaikan mungkin merupakan satu-satunya cara praktis.

patricktokeeffe.dll
sumber
"Segera setelah Anda mengubah nilainya, direktori kerja Anda akan ditandai kotor meskipun perubahan itu mungkin tidak terlihat": seharusnya tidak, jika skrip bersih masih memulihkan file dalam konten aslinya.
VonC
Itulah yang saya pikirkan. Saya menggunakan GitExtensions dan ini akan menampilkan file sebagai diubah meskipun panel diff kosong. Mungkin karena filter bersih tidak berjalan sampai file check-in. Mungkin karena ini msysgit, bukan git-git. IDK, YMMV
patricktokeeffe
1

Saya menduga ini mungkin sesuatu yang muncul di lebih dari satu baris sumber Anda.

Saya pikir akan lebih bersih jika memiliki file .userbuildconfig dari beberapa jenis yang baru saja Anda sertakan dan memiliki default yang dicentang. Kemudian Anda dapat menggunakan saran Carlos untuk menandai file itu sendiri sebagai anggap tidak berubah. Dengan cara ini, perubahan lain pada file di mana Anda perlu memeriksa pengaturan tidak terlewatkan.

Ini dapat memungkinkan Anda menyetel makro preprocessor secara lokal (Atau untuk java seperti ini https://stackoverflow.com/a/1813873/1270965 ).

johnb003
sumber
-1

Nggak. Anda hanya dapat mengabaikan file satu per satu (dan lainnya) karena baris dalam .gitignore cocok dengan nama file dan bukan konten file. Anda telah menyebutkan solusi untuk ini, yaitu mengabaikan satu file yang berisi konten yang ingin Anda abaikan.

ralphtheninja
sumber
Saya setuju, dalam kasus saya itu cukup dan mungkin untuk hanya memasukkan konten itu dari file yang diabaikan. Jadi memindahkan semua pengaturan yang dapat diabaikan. sana. Selain itu, saya membuat salinan file yang diabaikan itu dan menambahkannya ke indeks sebagai referensi, sehingga informasi tentang apa yang ada di file itu tidak akan hilang.
Urs