Gabungkan (dengan squash) semua perubahan dari cabang lain sebagai satu komit

479

Di Git, apakah ada cara untuk menggabungkan semua perubahan dari satu cabang ke cabang lain, tetapi squash ke satu komit pada saat yang sama?

Saya sering bekerja pada fitur baru di cabang terpisah dan secara teratur akan melakukan / mendorong - terutama untuk cadangan atau untuk mentransfer apa yang saya kerjakan ke mesin lain. Sebagian besar yang melakukan mengatakan "Feature xxx WIP" atau sesuatu yang berlebihan.

Setelah pekerjaan itu selesai dan saya ingin menggabungkan cabang WIP kembali menjadi master, saya ingin membuang semua komitmen perantara, dan hanya memiliki satu komit bersih.

Apakah ada cara mudah untuk melakukan ini?

Atau, bagaimana dengan perintah yang menekan semua komit pada cabang sejak titik di mana ia bercabang?

Brad Robinson
sumber

Jawaban:

601

Pilihan lain git merge --squash <feature branch>kemudian akhirnya melakukan a git commit.

Dari Git merge

--squash

--no-squash

Hasilkan pohon kerja dan status indeks seolah-olah gabungan nyata terjadi (kecuali untuk informasi gabungan), tetapi tidak benar-benar membuat komit atau memindahkan HEAD, atau mencatat $GIT_DIR/MERGE_HEADuntuk menyebabkan git commitperintah berikutnya untuk membuat komit gabungan. Ini memungkinkan Anda untuk membuat komit tunggal di atas cabang saat ini yang efeknya sama dengan menggabungkan cabang lain (atau lebih dalam hal gurita).

fseto
sumber
1
Fitur keren! Saya suka git. Meskipun saya pasti akan menggunakan ini di masa depan sekarang, saya masih merekomendasikan untuk mengenal jalan sekitar Anda rebase -i Ini adalah keterampilan yang baik untuk dimiliki, kalau-kalau Anda benar-benar ingin membuatnya lebih dari satu komitmen.
Will Buck
4
Kata hati-hati: ini berfungsi, tetapi pesan komit default mencakup log dari cabang yang digabungkan. Masalahnya adalah tampilannya mirip dengan format yang biasanya Anda lihat di mana seluruh teks yang ditampilkan tidak benar-benar menjadi bagian dari pesan komit, tetapi dalam kasus ini memang demikian. Jadi, jika Anda tidak menginginkan semua itu, Anda perlu menghapus semuanya secara manual dari pesan komit Anda. Saya harus menguji ini sebelum menggunakannya ...
still_dreaming_1
23
Itu, dan, diperingatkan bahwa cabang tidak akan dilihat sebagai penggabungan. stackoverflow.com/questions/19308790/…
Ryan
3
IMHO ini seharusnya dipanggilrebase --squash
Andy
jadi (karena tidak benar-benar menggabungkan cabang fitur) ini akan sesuai jika Anda akan menghapus cabang fitur setelah komit. Apakah itu benar? (Saya bukan ahli git)
Andrew Spencer
214

Menemukannya! Perintah gabung memiliki --squashopsi

git checkout master
git merge --squash WIP

pada titik ini semuanya digabung, mungkin konflik, tetapi tidak dilakukan. Jadi sekarang saya bisa:

git add .
git commit -m "Merged WIP"
Brad Robinson
sumber
2
apa yang git add .dilakukan?
Michael Potter
1
@MichaelPotter Ia menambahkan semua file dan perubahan
Daksh Shah
2
git add .menambahkan semua file yang tidak diabaikan dalam direktori saat ini, saya akan berhati-hati dalam mengambil file yang tidak diinginkan dengan cara ini.
Jake Cobb
7
Sebagai alternatif git add .Anda git add -uhanya dapat menambahkan file yang sudah ditambahkan ke pohon.
Brandon Ogle
19
Menyarankan "git add." dilakukan juga membingungkan. Ketika saya melakukan "git merge --squash WIP", itu sudah memiliki perubahan terjepit dalam indeks. Yang diperlukan hanyalah komitmen mereka. Melakukan "git add." akan menambahkan perubahan yang kebetulan ada di direktori kerja, tetapi yang bukan bagian dari cabang fitur. Pertanyaannya adalah bagaimana melakukan perubahan di cabang fitur sebagai satu komit.
John Pankowicz
30

Coba git rebase -i masterdi cabang fitur Anda. Anda kemudian dapat mengubah semua kecuali satu 'pilih' menjadi 'squash' untuk menggabungkan komit. Lihat melakukan squashing dengan rebase

Akhirnya, Anda kemudian dapat melakukan penggabungan dari cabang master.

fseto
sumber
8
Ya itu berhasil, tetapi saya tidak ingin kerumitan rebase interaktif. Saya hanya ingin semuanya sejak cabang diratakan.
Brad Robinson
2
+1 Ini menjadikan riwayat bersih. Jauh lebih mudah untuk mengidentifikasi dan mengelola komit sebagai tambalan, kartu, cerita, dll.
Ryan
2

Menggunakan git merge --squash <feature branch>sebagai jawaban yang diterima menyarankan melakukan trik tetapi tidak akan menunjukkan cabang gabungan sebagai benar-benar bergabung.

Karena itu solusi yang lebih baik adalah:

  • Buat cabang baru dari master terbaru
  • Gabungkan <feature branch>ke dalam menggunakan di atasgit merge --squash
  • Gabungkan cabang yang baru dibuat menjadi master

Wiki ini menjelaskan prosedur secara terperinci.

raratiru
sumber
0

Saya telah membuat alias git saya sendiri untuk melakukan hal ini. Saya menyebutnya git freebase! Ini akan mengambil cabang fitur Anda yang berantakan dan tidak dapat diuraikan kembali dan membuatnya kembali sehingga menjadi cabang baru dengan nama yang sama dengan komit-komitnya diremas menjadi satu komit dan diubah kembali ke cabang yang Anda tentukan (master secara default). Pada akhirnya, ini akan memungkinkan Anda untuk menggunakan pesan komit apa pun yang Anda suka untuk cabang "bebas" baru Anda.

Instal dengan menempatkan alias berikut di .gitconfig Anda:

[alias]
  freebase = "!f() { \
    TOPIC="$(git branch | grep '\\*' | cut -d ' ' -f2)"; \
    NEWBASE="${1:-master}"; \
    PREVSHA1="$(git rev-parse HEAD)"; \
    echo "Freebaseing $TOPIC onto $NEWBASE, previous sha1 was $PREVSHA1"; \
    echo "---"; \
    git reset --hard "$NEWBASE"; \
    git merge --squash "$PREVSHA1"; \
    git commit; \
  }; f"

Gunakan dari cabang fitur Anda dengan menjalankan: git freebase <new-base>

Saya hanya menguji ini beberapa kali, jadi bacalah dulu dan pastikan Anda ingin menjalankannya. Sebagai tindakan keamanan kecil, printer ini mencetak starting sha1 sehingga Anda harus dapat memulihkan cabang lama Anda jika terjadi kesalahan.

Saya akan mempertahankannya dalam repo dotfile saya di github: https://github.com/stevecrozz/dotfiles/blob/master/.gitconfig

Stephen Crosby
sumber
bekerja seperti kebahagiaan! Anda mungkin juga kita lihat evernote.com/shard/s52/sh/7f8f4ff1-9a68-413f-9225-c49e3ee2fafd/...
Ilya Sheershoff
-1

git merge --squash <feature branch> adalah pilihan yang bagus. "git commit" memberi tahu Anda semua pesan fitur branch commit dengan pilihan Anda untuk menyimpannya.

Untuk penggabungan komit kurang.

git merge lakukan x kali --git atur ulang HEAD ^ --soft lalu git komit.

File yang dihapus risiko dapat kembali.

Arjun Mullick
sumber
-5

Anda dapat melakukan ini dengan perintah "rebase". Mari kita sebut cabang "utama" dan "fitur":

git checkout feature
git rebase main

Perintah rebase akan mengulang semua komit pada "fitur" sebagai satu komit dengan orangtua sama dengan "utama".

Anda mungkin ingin menjalankan git merge mainsebelumnya git rebase mainjika "main" telah berubah sejak "fitur" dibuat (atau sejak penggabungan terbaru). Dengan begitu, Anda masih memiliki riwayat lengkap seandainya Anda memiliki konflik gabungan.

Setelah rebase, Anda bisa menggabungkan cabang Anda ke utama, yang akan menghasilkan penggabungan maju-cepat:

git checkout main
git merge feature

Lihat halaman rebase Pengertian Git Secara Konseptual untuk ikhtisar yang baik

NamshubWriter
sumber
Ini tidak berhasil untuk saya. Saya baru saja membuat repo tes sederhana, dengan cabang WIP dan mencoba di atas dan mendapat konflik penggabungan (meskipun saya tidak membuat perubahan pada master).
Brad Robinson
Jika fitur dibuat dari main (git checkout -b fitur utama) dan Anda memiliki penggabungan baru-baru ini dari main, Anda seharusnya tidak mendapatkan konflik dari rebase
NamshubWriter
Oke, coba lagi. Tidak mendapatkan konflik saat ini, tetapi sejarah tidak terjepit.
Brad Robinson
Melihat dokumentasi git-merge lagi, Anda benar, beberapa commit akan tetap ada. Jika Anda telah melakukan penggabungan sebelumnya dari "main" ke "feature" maka rebase akan menghapus beberapa dari mereka, tetapi tidak semua.
NamshubWriter
Ingatlah bahwa rebasing mungkin cukup berbahaya jika cabang fitur telah diterbitkan sebelumnya. Info lebih lanjut tentang pertanyaan SO ini .
Robert Rossmann