Apa artinya squash komit di git?

117

Apa maksud Squashing di git. Bagaimana cara menghentikan komitmen di Github?

Saya baru mengenal Git dan saya meminta untuk ditugaskan ke bug pendatang baru di coala-analyzer. Saya memperbaiki bugnya, dan sekarang saya diminta untuk menghentikan komitmen saya. Bagaimana saya melakukannya?

Lakshmanan Meiyappan
sumber
Hai @Lakshman, jangan ragu untuk menerima jawaban dengan suara terbanyak. Ini menjawab pertanyaan Anda dengan benar.
Mostafiz Rahman

Jawaban:

180

Anda dapat menganggap Git sebagai database lanjutan dari snapshot direktori kerja Anda.

Salah satu fitur yang sangat bagus dari Git adalah kemampuannya untuk menulis ulang sejarah komit.
Alasan utama untuk melakukan ini adalah bahwa banyak riwayat seperti itu hanya relevan untuk pengembang yang membuatnya, jadi itu harus disederhanakan, atau dibuat lebih bagus, sebelum mengirimkannya ke repositori bersama.

Menekan komit berarti, dari sudut pandang idiomatik, untuk memindahkan perubahan yang diperkenalkan dalam komit tersebut ke induknya sehingga Anda berakhir dengan satu komit, bukan dua (atau lebih).
Jika Anda mengulangi proses ini beberapa kali, Anda dapat mengurangi n komit menjadi satu.

Secara visual, jika Anda mulai pekerjaan Anda di komit ditandai Mulai , Anda ingin ini

Git melakukan squashing

Anda mungkin memperhatikan bahwa komit baru memiliki warna biru yang sedikit lebih gelap. Ini disengaja.

Dalam Git squashing dicapai dengan Rebase , dengan bentuk khusus yang disebut Rebase Interaktif .
Menyederhanakan saat Anda melakukan rebase satu set komit ke dalam cabang B , Anda menerapkan semua perubahan yang diperkenalkan oleh komit tersebut saat sudah selesai, mulai dari B, bukan dari leluhur aslinya.

Petunjuk visual

masukkan deskripsi gambar di sini

Perhatikan lagi corak biru yang berbeda.

Sebuah rebase interaktif memungkinkan Anda memilih bagaimana komit harus di-rebase. Jika Anda menjalankan perintah ini:

 git rebase -i branch

Anda akan mendapatkan file yang mencantumkan komit yang akan di-rebased

 pick ae3...
 pick ef6...
 pick 1e0...
 pick 341...

Saya tidak menyebutkan komitmennya, tetapi keempat komitmen ini dimaksudkan sebagai komitmen dari Awal hingga Kepala

Hal yang menyenangkan tentang daftar ini adalah dapat diedit .
Anda dapat menghilangkan komit, atau menghentikannya .
Yang harus Anda lakukan adalah mengubah kata pertama menjadi squash .

 pick ae3...
 squash ef6...
 squash 1e0...
 squash 341...

Jika Anda menutup editor dan tidak ada konflik penggabungan yang ditemukan, Anda akan mendapatkan riwayat ini:

masukkan deskripsi gambar di sini

Dalam kasus Anda, Anda tidak ingin melakukan rebase ke cabang lain, melainkan ke commit sebelumnya.
Untuk mengubah sejarah seperti yang ditunjukkan pada contoh pertama, Anda harus menjalankan sesuatu seperti

git rebase -i HEAD~4

ubah "perintah" untuk menghentikan semua komitmen selain yang pertama, lalu tutup editor Anda.


Catatan tentang mengubah sejarah

Di Git, komit tidak pernah diedit. Mereka dapat dipangkas, dibuat tidak dapat dijangkau, dikloning tetapi tidak diubah.
Saat Anda melakukan rebase, Anda sebenarnya sedang membuat komitmen baru.
Yang lama tidak lagi dapat dijangkau oleh wasit mana pun, jadi tidak ditampilkan dalam riwayat tetapi mereka masih ada!

Inilah yang sebenarnya Anda dapatkan untuk rebase:

masukkan deskripsi gambar di sini

Jika Anda telah mendorongnya ke suatu tempat, menulis ulang histori sebenarnya akan membuat cabang!

Margaret Bloom
sumber
Bagus - apa yang terjadi pada komentar komit asli - apakah mereka digabungkan menjadi satu komentar komit besar atau hilang?
Paul R
Dari man git rebase: Pesan komit yang disarankan untuk komit terlipat adalah rangkaian pesan komit dari komit pertama dan pesan dengan perintah "squash"
Margaret Bloom
1
Ini penjelasan terbaik yang pernah saya lihat tentang rebasing, terima kasih.
Kerry Jones
Tentang squashing pada gambar pertama anda: Dapatkah anda membuat contoh dimana HEAD memiliki direktori kerja yang berbeda sebelum (biru muda) dan setelah (biru tua) squashing? Dalam semua contoh yang saya coba squashing sepertinya baru saja menghapus tiga komit antara START dan HEAD.
actual_panda
@actualgroup Saya tidak yakin saya ikuti. HEAD adalah referensi untuk komit. Melakukan delta toko. Direktori kerja adalah properti dari repositori secara keseluruhan, itu tergantung pada komit mana yang Anda periksa. Secara umum, dua referensi (seperti HEAD dan START) selalu memberikan dua workdir yang berbeda saat check out. Jika Anda me-rebase squash di cabang yang sama, efeknya adalah "melepaskan" komitmen perantara tetapi pada kenyataannya, git membuat yang baru dengan semua delta. git diffdapat membantu Anda menunjukkan apa yang terjadi.
Margaret Bloom
22

Perintah rebase memiliki beberapa opsi luar biasa yang tersedia dalam mode --interactive(atau -i), dan salah satu yang paling banyak digunakan adalah kemampuan untuk menekan komit. Apa yang dilakukannya adalah mengambil komitmen yang lebih kecil dan menggabungkannya menjadi yang lebih besar, yang dapat berguna jika Anda menyelesaikan pekerjaan hari itu atau jika Anda hanya ingin mengemas perubahan Anda secara berbeda. Kami akan membahas bagaimana Anda dapat melakukan ini dengan mudah.

Peringatan: Lakukan ini hanya pada komit yang belum didorong ke repositori eksternal. Jika orang lain mendasarkan pekerjaan dari komit yang akan Anda hapus, banyak konflik dapat terjadi. Hanya saja, jangan menulis ulang riwayat Anda jika telah dibagikan dengan orang lain.

Jadi katakanlah Anda baru saja membuat beberapa komitmen kecil, dan Anda ingin membuat satu komitmen yang lebih besar darinya. Sejarah repositori kami saat ini terlihat seperti ini:

masukkan deskripsi gambar di sini

4 komit terakhir akan jauh lebih bahagia jika digabungkan, jadi mari kita lakukan melalui rebasing interaktif:

$ git rebase -i HEAD~4

pick 01d1124 Adding license
pick 6340aaa Moving license into its own file
pick ebfd367 Jekyll has become self-aware.
pick 30e0ccb Changed the tagline in the binary, too.

# Rebase 60709da..30e0ccb onto 60709da
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Jadi, beberapa hal telah terjadi di sini. Pertama-tama, saya memberi tahu Git bahwa saya ingin melakukan rebase menggunakan empat commit terakhir dari tempat HEAD berada dengan HEAD ~ 4. Git sekarang telah menempatkan saya sebagai editor dengan teks di atas di dalamnya, dan sedikit penjelasan tentang apa yang bisa dilakukan. Anda memiliki banyak opsi yang tersedia untuk Anda dari layar ini, tetapi sekarang kami hanya akan memadatkan semuanya menjadi satu komitmen. Jadi, mengubah empat baris pertama file menjadi ini akan melakukan triknya:

pick 01d1124 Adding license
squash 6340aaa Moving license into its own file
squash ebfd367 Jekyll has become self-aware.
squash 30e0ccb Changed the tagline in the binary, too.

Pada dasarnya ini memberitahu Git untuk menggabungkan keempat komit ke dalam komit pertama dalam daftar. Setelah ini selesai dan disimpan, editor lain muncul dengan yang berikut:

# This is a combination of 4 commits.
# The first commit's message is:
Adding license

# This is the 2nd commit message:

Moving license into its own file

# This is the 3rd commit message:

Jekyll has become self-aware.

# This is the 4th commit message:

Changed the tagline in the binary, too.

    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    # Explicit paths specified without -i nor -o; assuming --only paths...
    # Not currently on any branch.
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   new file:   LICENSE
    #   modified:   README.textile
    #   modified:   Rakefile
    #   modified:   bin/jekyll
    #

Karena kita menggabungkan begitu banyak komit, Git mengijinkan Anda untuk mengubah pesan komit baru berdasarkan komit lainnya yang terlibat dalam proses. Edit pesan sesuai keinginan Anda, lalu simpan dan keluar. Setelah selesai, komit Anda berhasil dihilangkan!

Created commit 0fc4eea: Creating license file, and making jekyll self-aware.
 4 files changed, 27 insertions(+), 30 deletions(-)
  create mode 100644 LICENSE
    Successfully rebased and updated refs/heads/master.

Dan jika kita melihat sejarah lagi… masukkan deskripsi gambar di sini

Jadi, sejauh ini relatif tidak menimbulkan rasa sakit. Jika Anda mengalami konflik selama rebase, itu biasanya cukup mudah untuk diselesaikan dan Git menuntun Anda sebanyak mungkin. Dasar-dasarnya adalah memperbaiki konflik yang dimaksud, git addfile, dan kemudian git rebase --continuemelanjutkan proses. Tentu saja, melakukan a git rebase --abortakan membawa Anda kembali ke keadaan sebelumnya jika Anda mau. Jika karena alasan tertentu Anda kehilangan komit di rebase, Anda dapat menggunakan reflog untuk mendapatkannya kembali.

Detail dapat ditemukan di tautan ini .

0xAliHn
sumber
3
Terima kasih! Jika ada orang yang tidak nyaman dengan VIM seperti saya ... ketika Anda mencapai titik di mana Anda memasukkan tindakan untuk mengedit, tekan 'i' untuk masuk ke mode edit. Ketika Anda selesai dengan perubahan, tekan escape lalu ketik ": wq" dan itu akan membuat Anda maju. (Mac)
Farasi78
1 untuk kehati-hatian dan konteks kapan harus melakukan ini. Dalam pengalaman pribadi saya, ada baiknya jika Anda bekerja sendiri di cabang fitur dan memiliki banyak komitmen sepele seperti "update readme", "melakukan sesuatu yang tidak dipedulikan siapa pun" dan Anda siap untuk menggabungkan cabang, mungkin seperti baik saja, hancurkan ini semua menjadi satu komit. Tidak ada yang ingin kembali ke "melakukan sesuatu yang tidak ada yang peduli" dan itu mencemari sejarah komit
Adam Hughes