Bagaimana saya bisa menekan komit X terakhir saya bersama menjadi satu komit menggunakan Git?
git
rebase
squash
git-squash
markdorison
sumber
sumber
Jawaban:
Gunakan
git rebase -i <after-this-commit>
dan ganti "pilih" pada komit kedua dan selanjutnya dengan "squash" atau "fixup", seperti yang dijelaskan dalam manual .Dalam contoh ini,
<after-this-commit>
apakah hash SHA1 atau lokasi relatif dari KEPALA cabang saat ini dari mana komit dianalisis untuk perintah rebase. Misalnya, jika pengguna ingin melihat 5 commit dari HEAD saat ini di masa lalu perintahnya adalahgit rebase -i HEAD~5
.sumber
<after-this-commit>
?<after-this-commit>
komit X + 1 yaitu induk dari komit tertua yang ingin Anda squash.rebase -i
pendekatan ini danreset --soft
adalah,rebase -i
memungkinkan saya untuk mempertahankan pembuat komit, sementarareset --soft
memungkinkan saya untuk berkomitmen kembali. Kadang-kadang saya perlu menekan komitmen untuk melakukan tarik namun mempertahankan informasi penulis. Terkadang saya perlu mengatur ulang lunak pada komit saya sendiri. Terpilih untuk kedua jawaban yang bagus.Anda dapat melakukan ini dengan cukup mudah tanpa
git rebase
ataugit merge --squash
. Dalam contoh ini, kita akan menekan 3 komit terakhir.Jika Anda ingin menulis pesan komit baru dari awal, ini sudah cukup:
Jika Anda ingin mulai mengedit pesan komit baru dengan gabungan dari pesan komit yang ada (yaitu mirip dengan apa yang
git rebase -i
akan dimulai dengan daftar instruksi pick / squash / squash / ... / squash ), maka Anda perlu mengekstrak pesan-pesan itu dan meneruskannya mereka untukgit commit
:Kedua metode tersebut menekan tiga komit terakhir menjadi satu komit baru dengan cara yang sama. Soft reset hanya menunjukkan kembali HEAD ke komit terakhir yang tidak ingin Anda tekan. Baik indeks maupun pohon kerja tidak tersentuh oleh soft reset, meninggalkan indeks dalam keadaan yang diinginkan untuk komit baru Anda (yaitu sudah memiliki semua perubahan dari komit yang akan Anda “buang”).
sumber
git rebase --squash-recent
, atau bahkangit commit --amend-many
.branch@{upstream}
(atau hanya@{upstream}
untuk cabang saat ini; dalam kedua kasus, bagian terakhir dapat disingkat menjadi@{u}
; lihat pembagian git ). Ini mungkin berbeda dari Anda “lalu mendorong komit” (misalnya jika seseorang mendorong sesuatu yang dibangun di atas dorongan terbaru Anda dan kemudian Anda diambil itu), tetapi tampaknya seperti itu mungkin dekat dengan apa yang Anda inginkan.push -f
tetapi sebaliknya itu indah, terima kasih.git push --force
setelah itu sehingga dibutuhkan komitAnda dapat menggunakan
git merge --squash
ini, yang sedikit lebih elegan daripadagit rebase -i
. Misalkan Anda berada di master dan Anda ingin memeras 12 komit terakhir menjadi satu.PERINGATAN: Pertama-tama pastikan Anda melakukan pekerjaan Anda — periksa apakah
git status
sudah bersih (karenagit reset --hard
akan membuang perubahan yang dipentaskan dan tidak dipentaskan)Kemudian:
The dokumentasi untuk
git merge
menggambarkan--squash
pilihan secara lebih rinci.Pembaruan: satu-satunya keuntungan nyata dari metode ini daripada yang lebih sederhana yang
git reset --soft HEAD~12 && git commit
disarankan oleh Chris Johnsen dalam jawabannya adalah bahwa Anda mendapatkan pesan komit yang dipopulasi dengan setiap pesan komit yang Anda hancurkan.sumber
git rebase -i
, tetapi Anda tidak memberikan alasan mengapa. Untuk sementara, saya menganggap ini karena menurut saya sebenarnya yang terjadi adalah sebaliknya dan ini adalah peretasan; tidakkah Anda melakukan lebih banyak perintah daripada yang diperlukan hanya untuk memaksagit merge
melakukan salah satu hal yanggit rebase
secara khusus dirancang untuk?git merge --squash
juga lebih mudah digunakan dalam skrip. Pada dasarnya, alasannya adalah bahwa Anda tidak memerlukan "interaktivitas"git rebase -i
sama sekali untuk ini.git merge --squash
adalah lebih kecil kemungkinannya untuk menghasilkan konflik penggabungan dalam menghadapi gerakan / penghapusan / penggantian nama dibandingkan dengan rebasing, terutama jika Anda bergabung dari cabang lokal. (Penafian: berdasarkan hanya pada satu pengalaman, koreksi saya jika ini tidak benar dalam kasus umum!)HEAD@{1}
hanya berada di sisi yang aman misalnya ketika alur kerja Anda terganggu selama satu jam oleh pemadaman listrik dll.Saya sarankan menghindari
git reset
jika memungkinkan - terutama untuk pemula Git. Kecuali jika Anda benar-benar perlu mengotomatiskan proses berdasarkan sejumlah komitmen, ada cara yang kurang eksotis ...git merge --squash (working branch name)
git commit
Pesan komit akan dipopulasi berdasarkan squash.
sumber
gitk
untuk memberi label pada baris kode yang Anda tekan dan juga memberi label pada basis yang akan digunakan squash. Dalam kasus normal, kedua label ini sudah ada, sehingga langkah (1) dapat dilewati.git branch your-feature && git reset --hard HEAD~N
cara yang paling nyaman. Namun, itu melibatkan git reset lagi, yang coba dihindari oleh jawaban ini.Berdasarkan jawaban Chris Johnsen ,
Tambahkan alias "squash" global dari bash: (atau Git Bash di Windows)
... atau menggunakan Prompt Perintah Windows:
Sekarang Anda
~/.gitconfig
harus mengandung alias ini:Pemakaian:
... Yang secara otomatis terjepit bersama dengan
N
komitmen terakhir , inklusif.Catatan: Pesan komit yang dihasilkan adalah kombinasi dari semua komit terjepit, secara berurutan. Jika Anda tidak puas dengan itu, Anda selalu
git commit --amend
dapat memodifikasinya secara manual. (Atau, edit alias agar sesuai dengan selera Anda.)sumber
git squash -m "New summary."
dan telahN
menentukan secara otomatis jumlah komit yang tidak dicopot.git commit --amend
untuk lebih lanjut mengubah pesan, tetapi alias ini memungkinkan Anda memiliki awal yang baik tentang apa yang seharusnya ada dalam pesan komit.Berkat posting blog praktis ini saya menemukan bahwa Anda dapat menggunakan perintah ini untuk menekan 3 komit terakhir:
Ini berguna karena berfungsi bahkan ketika Anda berada di cabang lokal tanpa informasi pelacakan / repo jarak jauh.
Perintah akan membuka editor rebase interaktif yang kemudian memungkinkan Anda untuk menyusun ulang, squash, reword, dll seperti biasa.
Menggunakan editor rebase interaktif:
Editor rebase interaktif menunjukkan tiga komit terakhir. Batasan ini ditentukan oleh
HEAD~3
saat menjalankan perintahgit rebase -i HEAD~3
.Komit terbaru,,
HEAD
ditampilkan pertama kali pada baris 1. Baris yang dimulai dengan#
komentar / dokumentasi.Dokumentasi yang ditampilkan cukup jelas. Pada baris mana pun Anda dapat mengubah perintah dari
pick
menjadi perintah pilihan Anda.Saya lebih suka menggunakan perintah
fixup
karena ini "menekan" komit berubah menjadi komit pada baris di atas dan membuang pesan komit.Karena komit pada baris 1 adalah
HEAD
, dalam kebanyakan kasus Anda akan membiarkan ini sebagaipick
. Anda tidak dapat menggunakansquash
ataufixup
karena tidak ada komit lain untuk memeras komit ke.Anda juga dapat mengubah urutan komitmen. Ini memungkinkan Anda untuk menekan atau memperbaiki komit yang tidak berdekatan secara kronologis.
Contoh praktis sehari-hari
Saya baru-baru ini melakukan fitur baru. Sejak itu, saya telah melakukan dua perbaikan bug. Tapi sekarang saya telah menemukan bug (atau mungkin hanya kesalahan ejaan) di fitur baru yang saya komit. Menyebalkan sekali! Saya tidak ingin komit baru mencemari riwayat komit saya!
Hal pertama yang saya lakukan adalah memperbaiki kesalahan dan membuat komit baru dengan komentar
squash this into my new feature!
.Saya kemudian menjalankan
git log
ataugitk
dan mendapatkan SHA komit dari fitur baru (dalam hal ini1ff9460
).Selanjutnya, saya membawa editor rebase interaktif dengan
git rebase -i 1ff9460~
. The~
setelah komit SHA memberitahu editor untuk memasukkan yang komit dalam editor.Selanjutnya, saya memindahkan komit yang berisi perbaikan (
fe7f1e0
) ke bawah komit fitur, dan berubahpick
menjadifixup
.Saat menutup editor, perbaikannya akan dimasukkan ke dalam fitur commit dan riwayat komit saya akan terlihat bagus dan bersih!
Ini bekerja dengan baik ketika semua komit adalah lokal, tetapi jika Anda mencoba untuk mengubah komit yang sudah didorong ke remote Anda benar-benar dapat menyebabkan masalah bagi pengembang lain yang telah memeriksa cabang yang sama!
sumber
pick
baris 1. Jika Anda memilihsquash
ataufixup
untuk komit pada baris 1, git akan menampilkan pesan yang mengatakan "kesalahan: tidak dapat 'memperbaiki' tanpa komit sebelumnya". Maka itu akan memberi Anda opsi untuk memperbaikinya: "Anda dapat memperbaikinya dengan 'git rebase --edit-todo' dan kemudian jalankan 'git rebase --continue'." atau Anda dapat membatalkan dan memulai dari awal: "Atau Anda dapat membatalkan rebase dengan 'git rebase --abort'."Jika Anda menggunakan TortoiseGit, Anda dapat fungsinya
Combine to one commit
:Show Log
Combine to one commit
dari menu konteksFungsi ini secara otomatis menjalankan semua langkah git tunggal yang diperlukan. Sayangnya hanya tersedia untuk Windows.
sumber
Untuk melakukan ini, Anda dapat menggunakan perintah git berikut.
n (= 4 di sini) adalah jumlah komit terakhir. Maka Anda mendapat opsi berikut,
Perbarui seperti di bawah
pick
satu komit dansquash
yang lainnya ke yang terbaru,Untuk detail klik pada Tautan
sumber
Berdasarkan artikel ini saya menemukan metode ini lebih mudah untuk usecase saya.
Cabang 'dev' saya berada di depan 'origin / dev' sebanyak 96 komit (jadi komit ini belum didorong ke remote).
Saya ingin memeras komitmen ini menjadi satu sebelum mendorong perubahan. Saya lebih suka mereset cabang ke status 'asal / dev' (ini akan membuat semua perubahan dari 96 komit tidak dipentaskan) dan kemudian melakukan perubahan sekaligus:
sumber
Di cabang yang ingin Anda gabungkan komit, jalankan:
contoh:
Ini akan membuka editor teks dan Anda harus mengganti 'pick' di depan setiap komit dengan 'squash' jika Anda ingin komit ini digabungkan. Dari dokumentasi:
p, pilih = gunakan komit
s, squash = gunakan komit, tetapi berbaur menjadi komit sebelumnya
Misalnya, jika Anda ingin menggabungkan semua komit menjadi satu, 'pilih' adalah komit pertama yang Anda buat dan semua yang akan datang (ditempatkan di bawah yang pertama) harus disetel ke 'squash'. Jika menggunakan vim, gunakan : x dalam mode sisipkan untuk menyimpan dan keluar dari editor.
Kemudian untuk melanjutkan rebase:
Untuk lebih lanjut tentang ini dan cara-cara lain untuk menulis ulang riwayat komit Anda lihat posting bermanfaat ini
sumber
--continue
dan vim:x
.git add
konfigurasi yang benar dalam file Anda yang Anda gunakangit rebase --continue
untuk pindah ke komit berikutnya dan mulai bergabung.:x
adalah salah satu perintah yang akan menyimpan perubahan file saat menggunakan vim, lihat iniJawaban Anomies bagus, tapi saya merasa tidak aman tentang hal ini jadi saya memutuskan untuk menambahkan beberapa tangkapan layar.
Langkah 0: git log
Lihat di mana Anda berada
git log
. Yang paling penting, cari hash dari commit pertama yang tidak ingin Anda hancurkan. Jadi hanya:Langkah 1: git rebase
Jalankan
git rebase -i [your hash]
, dalam kasus saya:Langkah 2: pilih / squash apa yang Anda inginkan
Dalam kasus saya, saya ingin menekan semua komit yang pertama kali. Pemesanan adalah dari pertama hingga terakhir, demikian juga sebaliknya
git log
. Dalam kasus saya, saya ingin:Langkah 3: Sesuaikan pesan
Jika Anda hanya memilih satu komit dan menghancurkan sisanya, Anda dapat menyesuaikan satu pesan komit:
Itu dia. Setelah Anda menyimpan ini (
:wq
), Anda selesai. Lihatlah dengangit log
.sumber
git log
Prosedur 1
1) Identifikasi hash pendek komit
Di sini pun
git log --oneline
bisa digunakan untuk mendapatkan hash pendek.2) Jika Anda ingin melakukan squash (menggabungkan), lakukan dua komit terakhir
3) Ini membuka
nano
editor untuk digabung. Dan sepertinya di bawah ini4) Ubah nama kata
pick
untuksquash
yang hadir sebelumabcd1234
. Setelah ganti nama itu harus seperti di bawah ini.5) Sekarang simpan dan tutup
nano
editor. Tekanctrl + o
dan tekanEnter
untuk menyimpan. Dan kemudian tekanctrl + x
untuk keluar dari editor.6) Kemudian
nano
editor kembali terbuka untuk memperbarui komentar, jika perlu memperbaruinya.7) Sekarang tergencet dengan sukses, Anda dapat memverifikasinya dengan memeriksa log.
8) Sekarang dorong untuk repo. Catatan untuk menambahkan
+
tanda sebelum nama cabang. Ini berarti dorongan paksa.Catatan: Ini didasarkan pada penggunaan git on
ubuntu
shell. Jika Anda menggunakan os yang berbeda (Windows
atauMac
) maka perintah di atas sama kecuali editor. Anda mungkin mendapatkan editor yang berbeda.Prosedur 2
--fixup
opsi danOLDCOMMIT
harus di mana kita perlu menggabungkan (squash) komit ini.Sekarang ini menciptakan komit baru di atas KEPALA dengan
fixup1 <OLDCOMMIT_MSG>
.OLDCOMMIT
.Di sini
^
berarti komitmen sebelumnya untukOLDCOMMIT
.rebase
Perintah ini membuka jendela interaktif pada editor (vim atau nano) bahwa kita tidak perlu melakukan apa-apa cukup simpan dan keluar sudah cukup. Karena opsi yang diteruskan ke ini akan secara otomatis memindahkan komit terbaru ke komit lama dan mengubah operasi kefixup
(setara dengan squash). Kemudian rebase berlanjut dan selesai.Prosedur 3
--amend
dapat digunakan dengangit-commit
.Di sini,
--amend
gabungkan perubahan baru ke komit terakhircdababcd
dan hasilkan ID komit baru1d4ab2e1
Kesimpulan
sumber
Untuk memeras 10 komit terakhir menjadi 1 komit tunggal:
Jika Anda juga ingin memperbarui cabang jarak jauh dengan komit terjepit:
sumber
Jika Anda berada di cabang jarak jauh (disebut
feature-branch
) yang diklon dari Golden Repository (golden_repo_name
), maka inilah teknik untuk memecah komit Anda menjadi satu:Lihat repo emas
Buat cabang baru darinya (golden repo) sebagai berikut
Squash bergabung dengan cabang lokal Anda yang sudah Anda miliki
Komit perubahan Anda (ini akan menjadi satu-satunya komit yang masuk di dev-branch)
Dorong cabang ke repositori lokal Anda
sumber
Apa yang bisa benar-benar nyaman:
Temukan hash komit yang ingin Anda tekan, katakan
d43e15
.Sekarang gunakan
sumber
Ini adalah super-duper Kludgy, tetapi dalam semacam cara yang keren, jadi saya hanya akan melemparkannya ke atas ring:
Terjemahan: berikan "editor" baru untuk git yang, jika nama file yang akan diedit adalah
git-rebase-todo
(prompt rebase interaktif) mengubah semua kecuali "pilih" menjadi "squash", dan jika tidak, akan menghasilkan vim - sehingga saat Anda diminta untuk mengedit pesan komit terjepit, Anda mendapatkan vim. (Dan jelas saya menekan lima commit terakhir di branch foo, tetapi Anda bisa mengubahnya sesuka Anda.)Saya mungkin akan melakukan apa yang disarankan Mark Longair .
sumber
Jika Anda ingin memadatkan setiap komit ke dalam komit tunggal (mis. Saat merilis proyek untuk pertama kalinya), coba:
sumber
2020 Solusi sederhana tanpa rebase:
git reset --soft HEAD~2
git commit -m "new commit message"
git push --force
2 berarti dua komit terakhir akan tergencet. Anda dapat menggantinya dengan nomor apa pun
sumber
Saya pikir cara termudah untuk melakukan ini adalah dengan membuat cabang baru dari master dan melakukan gabungan --squash dari cabang fitur.
Maka Anda memiliki semua perubahan yang siap untuk dilakukan.
sumber
Satu kalimat sederhana yang selalu berfungsi, mengingat Anda saat ini berada di cabang yang ingin Anda squash, master adalah cabang tempat asalnya, dan komit terbaru berisi pesan komit dan penulis yang ingin Anda gunakan:
sumber
jika misalnya Anda ingin menekan 3 komit terakhir ke komit tunggal di cabang (repositori jarak jauh) di misalnya: https://bitbucket.org
Apa yang saya lakukan adalah
sumber
⚠️ PERINGATAN: "X terakhir saya komit" mungkin ambigu.
Dalam riwayat https://github.com/fleetwood-mac/band-history repositori yang sangat singkat ini, Anda telah membuka permintaan tarik untuk menggabungkan komitmen Bill Clinton ke komit asli (
MASTER
) Fleetwood Mac.Anda membuka permintaan tarik dan di GitHub Anda melihat ini:
Empat komitmen:
Berpikir bahwa tidak ada yang mau membaca riwayat repositori lengkap. (Sebenarnya ada repositori, klik tautan di atas!) Anda memutuskan untuk menghancurkan komit ini. Jadi kamu pergi dan lari
git reset --soft HEAD~4 && git commit
. Maka kamugit push --force
ke GitHub untuk membersihkan PR Anda.Dan apa yang terjadi? Anda baru saja membuat komitmen tunggal yang mendapatkan dari Fritz ke Bill Clinton. Karena Anda lupa bahwa kemarin Anda mengerjakan versi Buckingham Nicks dari proyek ini. Dan
git log
tidak cocok dengan yang Anda lihat di GitHub.🐻 MORAL KISAH
git checkout
merekagit reset --soft
itugit commit
bengkok itu langsung dari dari ke kesumber
Jika Anda tidak peduli tentang pesan komit di antara komitmen, Anda dapat menggunakan
sumber
Jika Anda bekerja dengan GitLab, Anda bisa mengklik opsi Squash di Gabung Permintaan seperti yang ditunjukkan di bawah ini. Pesan komit akan menjadi judul Permintaan Gabung.
sumber
di mana jumlah ^ adalah X
(dalam hal ini, tekan dua komit terakhir)
sumber
Selain jawaban luar biasa lainnya, saya ingin menambahkan bagaimana
git rebase -i
selalu membingungkan saya dengan perintah komit - lebih lama ke yang lebih baru atau sebaliknya? Jadi ini adalah alur kerja saya:git rebase -i HEAD~[N]
, dengan N adalah jumlah komit yang ingin saya gabung, mulai dari yang terbaru . Jadigit rebase -i HEAD~5
berarti "squash the 5 commit terakhir menjadi yang baru";Sumber & bacaan tambahan: # 1 , # 2 .
sumber
Bagaimana dengan jawaban untuk pertanyaan yang terkait dengan alur kerja seperti ini?
merge --squash
setelah PR, tetapi tim berpikir itu akan memperlambat proses.)Saya belum melihat alur kerja seperti itu di halaman ini. (Itu mungkin mataku.) Jika aku mengerti
rebase
dengan benar, banyak penggabungan akan membutuhkan beberapa resolusi konflik . Aku bahkan tidak mau memikirkan hal itu!Jadi, ini sepertinya bekerja untuk kita.
git pull master
git checkout -b new-branch
git checkout -b new-branch-temp
git checkout new-branch
git merge --squash new-branch-temp
// menempatkan semua perubahan di panggunggit commit 'one message to rule them all'
git push
sumber
Saya menemukan solusi yang lebih umum bukan untuk menentukan komit 'N', melainkan cabang / komit-id yang ingin Anda tekan di atas. Ini lebih rentan kesalahan daripada menghitung komit hingga komit tertentu — cukup tentukan tag secara langsung, atau jika Anda benar-benar ingin menghitung, Anda dapat menentukan HEAD ~ N.
Dalam alur kerja saya, saya memulai cabang, dan komit pertama saya di cabang itu merangkum tujuan (yaitu biasanya apa yang akan saya dorong sebagai pesan 'final' untuk fitur ke repositori publik.) Jadi ketika saya selesai, semua Yang ingin saya lakukan adalah
git squash master
kembali ke pesan pertama dan kemudian saya siap untuk mendorong.Saya menggunakan alias:
Ini akan membuang sejarah yang tergencet sebelum melakukannya — ini memberi Anda kesempatan untuk memulihkan dengan mengambil ID komit lama dari konsol jika Anda ingin kembali. (Pengguna Solaris mencatat bahwa ia menggunakan
-i
opsi sed GNU , pengguna Mac dan Linux tidak masalah dengan ini.)sumber
git squash master
saat kami diperiksa pada budak. apa yang akan terjadi akankah kita menyembunyikan konflik?Dalam pertanyaan itu bisa jadi ambigu apa yang dimaksud dengan "terakhir".
misalnya
git log --graph
menghasilkan yang berikut (disederhanakan):Kemudian komit terakhir berdasarkan waktu adalah H0, bergabung, B0. Untuk menekan mereka, Anda harus rebase cabang gabungan Anda di komit H1.
Masalahnya adalah bahwa H0 mengandung H1 dan H2 (dan umumnya lebih banyak melakukan sebelum penggabungan dan setelah percabangan) sementara B0 tidak. Jadi, Anda harus mengelola perubahan dari setidaknya H0, menggabungkan, H1, H2, B0.
Dimungkinkan untuk menggunakan rebase tetapi dengan cara yang berbeda maka dalam jawaban lain disebutkan:
rebase -i HEAD~2
Ini akan menunjukkan kepada Anda opsi pilihan (sebagaimana disebutkan dalam jawaban lain):
Masukkan squash alih-alih pilih ke H0:
Setelah menyimpan dan keluar, rebase akan menerapkan komit setelah H1. Itu berarti bahwa itu akan meminta Anda untuk menyelesaikan konflik lagi (di mana HEAD akan menjadi H1 pada awalnya dan kemudian mengumpulkan komitmen saat mereka diterapkan).
Setelah rebase akan selesai, Anda dapat memilih pesan untuk H0 dan B0 terjepit:
PS Jika Anda baru saja melakukan reset ke BO: (misalnya, menggunakan
reset --mixed
yang dijelaskan secara lebih rinci di sini https://stackoverflow.com/a/18690845/2405850 ):kemudian Anda menekan B0 perubahan H0, H1, H2 (kehilangan sepenuhnya berkomitmen untuk perubahan setelah bercabang dan sebelum bergabung.
sumber
1) git reset --kepala KEPALA ~ n
n - Jumlah komit, perlu squash
2) git commit -m "pesan komit baru"
3) git dorong asal branch_name --force
sumber