Dua sistem operasi tidak sepakat soal cara mengakhiri satu baris teks: Windows memakai dua karakter (carriage return dan line feed, CRLF), sedangkan Linux dan macOS memakai satu (line feed, LF). Perbedaan ini tidak terlihat di editor biasa, tetapi terlihat jelas oleh Git: bagi Git, kedua versi berkas adalah isi yang berbeda, sehingga satu berkas yang diedit lintas sistem operasi bisa muncul sebagai perubahan di seluruh barisnya. Chapter Instalasi Git di WSL sudah memperlihatkan gejala ini; sekarang kita atur obatnya — kunci core.autocrlf untuk konversi otomatis per mesin, dan berkas .gitattributes untuk aturan yang berlaku bagi seluruh anggota tim.

Melihat Masalahnya Secara Nyata #

Kita buat berkas berakhiran CRLF lalu mengamatinya dengan cat -A, yang menandai akhir baris sebagai $ dan carriage return sebagai ^M:

bash
cd demo-ch11
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf 'baris pertama\r\nbaris kedua\r\n' > berkas-crlf.txt
cat -A berkas-crlf.txt

Output yang Dihasilkan:

text
baris pertama^M$
baris kedua^M$

Tanda ^M$ di akhir tiap baris berarti carriage return dan line feed hadir bersamaan. Tanpa pengaturan apa pun, Git menyimpan berkas apa adanya — kita buktikan dengan memasukkannya ke staging area lalu membaca status akhir barisnya:

bash
git add berkas-crlf.txt
git ls-files --eol

Output yang Dihasilkan:

text
i/crlf  w/crlf  attr/                	berkas-crlf.txt

Tiga kolom pada keluaran tersebut adalah kunci pembacaannya: i/ menggambarkan isi yang tersimpan di repository (index), w/ menggambarkan isi berkas di direktori kerja (working copy), dan attr/ menampilkan aturan .gitattributes yang berlaku. Keluaran i/crlf menegaskan bahwa Git akan menyimpan CRLF mentah-mentah ke dalam repository — rekan tim yang memakai Linux kemudian menerima berkas penuh carriage return, dan diff antar sistem operasi menjadi penuh derau.

core.autocrlf: Tiga Mode #

Kunci core.autocrlf menginstruksikan Git mengonversi akhir baris secara otomatis pada dua titik: saat berkas masuk repository dan saat berkas keluar repository. Tiga nilainya memberi kombinasi berbeda:

NilaiSaat masuk repositorySaat keluar repositoryCocok untuk
falsetanpa konversitanpa konversiLinux/macOS; atau tim yang sudah memakai .gitattributes
inputCRLF menjadi LFtanpa konversiLinux/macOS yang sering menerima berkas hasil editor Windows
trueCRLF menjadi LFLF menjadi CRLFWindows tanpa .gitattributes

Kita uji mode input pada repository sandbox. Nilainya cukup diatur level local agar demo tidak menyentuh konfigurasi akun:

bash
git config core.autocrlf input
git rm --cached berkas-crlf.txt
git add berkas-crlf.txt

Output yang Dihasilkan:

text
rm 'berkas-crlf.txt'
warning: in the working copy of 'berkas-crlf.txt', CRLF will be replaced by LF the next time Git touches it

Baris rm mengeluarkan berkas lama dari staging area — caranya memastikan berkas di-add ulang, karena Git membiarkan berkas yang statusnya tak berubah. Baris warning bukan galat: Git sekadar mengingatkan bahwa berkas di direktori kerja masih CRLF, dan versi LF akan menimpanya saat Git menulis ulang berkas itu. Sekarang kita baca ulang status akhir barisnya:

bash
git ls-files --eol

Output yang Dihasilkan:

text
i/lf    w/crlf  attr/                	berkas-crlf.txt

Kolom i/ berubah menjadi lf — isi yang tersimpan di repository kini LF, sementara berkas di direktori kerja tetap CRLF. Isi repository itu bisa kita lihat langsung dari blob yang tersimpan:

bash
git cat-file -p :berkas-crlf.txt | cat -A

Output yang Dihasilkan:

text
baris pertama$
baris kedua$

Hanya $ yang tersisa — carriage return tidak pernah sampai ke repository. Mode true melengkapi lingkarannya di sisi Windows: berkas keluar sebagai CRLF saat checkout, masuk kembali sebagai LF saat commit. Kita bisa membuktikan putaran itu di sandbox: simpan kondisi bersih ini sebagai commit, hapus berkas dari direktori kerja, lalu ambil kembali dengan core.autocrlf true:

bash
git config core.autocrlf true
git commit -m "Simpan berkas dengan LF di repository"
rm berkas-crlf.txt
git checkout -- berkas-crlf.txt
cat -A berkas-crlf.txt

Output yang Dihasilkan:

text
baris pertama^M$
baris kedua^M$

Repository menyimpan LF, mesin berkerja dalam CRLF — tidak ada satu pun byte yang berubah di repository karena perpindahan sistem operasi.

.gitattributes: Solusi Lintas Platform #

core.autocrlf hidup di konfigurasi tiap mesin, dan itulah kelemahannya: perilaku repository menjadi bergantung pada pengaturan komputer masing-masing anggota tim. Berkas .gitattributes menempatkan aturan di dalam repository itu sendiri — ikut di-commit, ikut di-clone, berlaku sama bagi semua orang. Untuk akhir baris, satu baris aturan sudah cukup:

bash
echo '* text=auto' > .gitattributes

Aturan * text=auto berarti: semua berkas yang Git anggap teks akan dinormalkan ke LF di repository, apa pun pengaturan core.autocrlf di mesin pembuka. Kejujuran teknisnya: pendekatan ini lebih deterministik daripada core.autocrlf, karena hasilnya tidak lagi tergantung pada konfigurasi mesin. Kita buktikan dengan meniadakan konfigurasi autocrlf sepenuhnya:

bash
git config core.autocrlf false
printf 'baris pertama\r\nbaris kedua\r\n' > berkas-crlf.txt
git add .gitattributes
git rm --cached berkas-crlf.txt
git add berkas-crlf.txt
git ls-files --eol

Output yang Dihasilkan:

text
i/lf    w/lf    attr/text=auto        	.gitattributes
i/lf    w/crlf  attr/text=auto        	berkas-crlf.txt

Dua hal terbaca dari keluaran tersebut. Kolom attr/ kini terisi text=auto — bukti aturan aktif dan berlaku pada kedua berkas. Dan meski core.autocrlf sudah false, berkas CRLF tetap tersimpan sebagai i/lf — konversi terjadi karena aturan .gitattributes, bukan karena pengaturan mesin.

Rekomendasi lengkap ketiga pendekatan ini, termasuk alasan Git for Windows menyarankan core.autocrlf true pada penginstalnya, tersedia di Pro Git: Git Configuration . Dengan akhir baris aman, pengaturan teknis kita sudah layak pakai — tinggal satu polesan terakhir untuk kenyamanan harian: pintasan perintah lewat alias, chapter berikutnya.