Menggabungkan Banyak Komit Menjadi Satu Sebelum Dorong


131

Pertanyaan ini tidak hanya berkaitan dengan bagaimana menyelesaikan tugas ini, tetapi juga apakah melakukan itu adalah praktik yang baik atau buruk dengan Git.

Pertimbangkan bahwa secara lokal saya melakukan sebagian besar pekerjaan pada cabang master, tetapi saya telah membuat cabang topikal yang saya sebut "topical_xFeature". Dalam proses bekerja pada "topical_xFeature" dan beralih bolak-balik untuk melakukan pekerjaan lain di cabang master, ternyata saya telah membuat lebih dari satu komit di cabang "topical_xFeature", tetapi di antara setiap komit, saya belum melakukan Dorong.

Pertama , apakah Anda menganggap praktik buruk ini? Tidakkah lebih bijaksana untuk tetap dengan satu komit per cabang per push? Dalam kasus apa akan lebih baik untuk memiliki banyak komit pada cabang sebelum dorongan dilakukan?

Kedua , bagaimana saya sebaiknya menyelesaikan membawa banyak komit pada cabang topical_xFeature ke cabang master untuk dorongan? Apakah itu gangguan untuk tidak khawatir tentang hal itu dan lakukan saja dorongan di mana banyak komit didorong, atau apakah kurang mengganggu entah bagaimana menggabungkan komit menjadi satu dan kemudian mendorong? Sekali lagi, bagaimana melakukan ini?

Jawaban:


139

Untuk pertanyaan pertama Anda, tidak, tidak ada salahnya mendorong banyak komitmen sekaligus. Sering kali, Anda mungkin ingin memecah pekerjaan menjadi beberapa komit kecil yang logis, tetapi hanya mendorongnya begitu Anda merasa seluruh seri siap. Atau Anda mungkin membuat beberapa komit secara lokal saat terputus, dan Anda mendorong semuanya setelah terhubung kembali. Tidak ada alasan untuk membatasi diri Anda pada satu komit per dorongan.

Saya biasanya menemukan bahwa itu adalah ide yang baik untuk menjaga setiap komit melakukan perubahan tunggal, logis, koheren, yang mencakup semua yang diperlukan untuk bekerja (jadi, itu tidak meninggalkan kode Anda dalam keadaan rusak). Jika Anda memiliki dua komit, tetapi mereka akan menyebabkan kode rusak jika Anda hanya menerapkan yang pertama, mungkin ide yang baik untuk menekan komit kedua ke dalam komit pertama. Tetapi jika Anda memiliki dua komit di mana masing-masing membuat perubahan yang masuk akal, mendorong mereka sebagai komit terpisah adalah baik.

Jika Anda ingin memeras beberapa komit bersama, Anda dapat menggunakannya git rebase -i. Jika Anda berada di cabang topical_xFeature, Anda akan lari git rebase -i master. Ini akan membuka jendela editor, dengan sekelompok komit terdaftar diawali oleh pick. Anda bisa mengubah semua kecuali yang pertama squash, yang akan memberi tahu Git untuk menyimpan semua perubahan itu, tetapi masukkan ke komit pertama. Setelah Anda selesai melakukannya, periksa masterdan gabungkan cabang fitur Anda:

git checkout topical_xFeature
git rebase -i master
git checkout master
git merge topical_xFeature

Atau, jika Anda hanya ingin topical_xFeaturememasukkan semuanya ke dalam master, Anda bisa melakukan hal berikut:

git checkout master
git merge --squash topical_xFeature
git commit

Yang mana yang Anda pilih terserah Anda. Secara umum, saya tidak akan khawatir tentang memiliki beberapa komit yang lebih kecil, tetapi kadang-kadang Anda tidak ingin repot dengan komit ekstra kecil, jadi Anda cukup memecahnya menjadi satu.


1
Setelah saya bergabung dengan --squash, saya tidak dapat menghapus cabang topik dengan git branch -d topic. Mengapa git tidak dapat mengidentifikasi bahwa semua perubahan digabungkan?
balki

7
@balki Karena Git mendeteksi apakah tambalan digabung berdasarkan apakah tambalan tersebut muncul dalam sejarah cabang yang diberikan. Squashing commit mengubahnya; mereka menjadi komit baru, dan sementara komit baru itu terjadi untuk melakukan hal yang sama seperti yang lain, Git tidak bisa mengatakan itu, itu hanya dapat mengetahui apakah komit adalah sama jika mereka memiliki ID komit yang sama (SHA-1) . Jadi setelah Anda menekannya, Anda perlu memberitahu git untuk menghapus cabang lama dengan git branch -D topicmenghapusnya secara paksa.
Brian Campbell

66

Ini adalah cara yang biasanya saya ikuti untuk menggabungkan beberapa Komit menjadi komit tunggal sebelum saya mendorong kode.

Untuk mencapai ini, saya sarankan Anda menggunakan konsep ' squash ' yang disediakan oleh GIT.

Ikuti langkah-langkah di bawah ini.

1) git rebase -i master (alih-alih master, Anda juga dapat menggunakan komit tertentu)

buka editor interaktif rebase, di mana ia akan menunjukkan semua komitmen Anda. Pada dasarnya di mana Anda perlu mengidentifikasi komit yang ingin Anda gabungkan menjadi satu komit.

Bayangkan ini adalah komitmen Anda dan ditampilkan seperti ini di editor.

pick f7f3f6d changed my name a bit    
pick 310154e updated README formatting and added blame   
pick a5f4a0d added cat-file  

Penting untuk dicatat bahwa komit ini terdaftar dalam urutan yang berlawanan dari yang biasanya Anda lihat menggunakan perintah log. Berarti, komit yang lebih lama akan ditampilkan terlebih dahulu.

2) Ubah 'pilih' menjadi 'squash' untuk perubahan yang dilakukan terakhir. sesuatu seperti yang ditunjukkan di bawah ini. Dengan melakukan itu, 2 komit terakhir Anda akan digabung dengan yang pertama.

pick f7f3f6d changed my name a bit         
squash 310154e updated README formatting and added blame   
squash a5f4a0d added cat-file

Anda juga dapat menggunakan formulir pendek jika Anda memiliki banyak komitmen untuk digabungkan:

p f7f3f6d changed my name a bit         
s 310154e updated README formatting and added blame   
s a5f4a0d added cat-file

untuk mengedit menggunakan 'i', itu akan memungkinkan editor untuk dimasukkan. Ingatlah bahwa sebagian besar komit (tertua) tidak dapat dihancurkan karena tidak ada komit sebelumnya untuk digabungkan. Jadi itu harus dipilih atau 'p'. Gunakan 'Esc' untuk keluar dari mode penyisipan.

3) Sekarang, simpan editor dengan perintah berikut. : wq

Saat Anda menyimpannya, Anda memiliki satu komit yang memperkenalkan perubahan dari ketiga komit sebelumnya.

Semoga ini bisa membantu Anda.


5
Mungkin ini jelas bagi orang lain tetapi, ketika Anda mengatakan "git rebase -i", Anda juga perlu menentukan komit yang Anda mulai. Ini adalah sesuatu yang tidak saya sadari ketika saya mencoba mengikuti contoh ini. Jadi, dalam contoh ini, itu akan menjadi "git rebase -i xxxxx" di mana xxxxx adalah komit tepat sebelum f7f3f6d secara kronologis. Setelah saya mengetahuinya, semuanya berjalan persis seperti yang dijelaskan di atas.
nukeguy

Itu menarik @ nukeguy, saya tidak punya masalah tidak menentukan komit tertentu. Itu hanya default ke apa yang ada di sana.
JCrooks

Mungkin seperti @nukeguy, git rebase -i HEAD~2adalah tempat yang membantu bagi saya untuk memulai. Maka jawaban ini sangat membantu. Kemudian, saya git statusmenunjukkan "Cabang Anda dan 'asal / fitur / xyz' telah berbeda, dan masing-masing memiliki 1 dan 1 komit yang berbeda, masing-masing." Jadi saya perlu git push origin feature/xyz --force-with-leaseMelihat stackoverflow.com/a/59309553/470749 dan freecodecamp.org/forum/t/…
Ryan

11

Pertama : tidak ada yang memberitahu Anda untuk hanya memiliki satu komit per cabang per dorongan: dorongan adalah mekanisme publikasi yang memungkinkan Anda untuk mempublikasikan riwayat lokal (yaitu kumpulan komit) pada repo jarak jauh.

Kedua : a git merge --no-ff topical_xFeatureakan merekam master sebagai satu komit pekerjaan topik Anda, sebelum mendorong master.
(Dengan begitu, Anda tetap bertahan topical_xFeatureuntuk evolusi lebih lanjut, yang dapat Anda catat mastersebagai satu komit baru pada penggabungan berikutnya --tidak-ff.
Jika menyingkirkan topical_xFeatureadalah tujuannya, maka git merge --squashmerupakan pilihan yang tepat, sebagaimana dirinci dalam Brian Campbell 's jawaban .)


Saya pikir --squash, bukan --no-ffitu yang Anda inginkan. --no-ffakan membuat gabungan komit, tetapi juga meninggalkan semua komit dari topical_xFeature.
Brian Campbell

@Brian: Saya setuju dan meningkatkan jawaban Anda, tetapi saya pertama-tama memikirkan opsi --no-ff karena saya ingin mempertahankan topical_featurecabang, dan hanya mencatat satu komit di mastercabang.
VonC

8

Beralihlah ke cabang utama dan pastikan Anda mutakhir.

git checkout master

git fetch ini mungkin diperlukan (tergantung pada konfigurasi git Anda) untuk menerima pembaruan pada origin / master

git pull

Gabungkan cabang fitur ke cabang master.

git merge feature_branch

Setel ulang cabang master ke status asal.

git reset origin/master

Git sekarang menganggap semua perubahan sebagai perubahan yang tidak dipentaskan. Kami dapat menambahkan perubahan ini sebagai satu komit. Menambahkan. juga akan menambahkan file yang tidak dilacak.

git add --all

git commit

Ref: https://makandracards.com/makandra/527-squash-several-git-commits-into-a-single-commit


3
jawaban ini mudah diikuti dan sangat mudah divisualisasikan.
jokab

6
  1. Pertama-tama pilih komit yang Anda inginkan setelahnya.

    git reflog
    5976f2b HEAD@{0}: commit: Fix conflicts
    80e85a1 HEAD@{1}: commit: Add feature
    b860ddb HEAD@{2}: commit: Add something
    
  2. Atur ulang ke kepala yang Anda pilih (saya telah memilih HEAD@{2})

    git reset b860ddb --soft
    
  3. git status (hanya untuk memastikan)

  4. Tambahkan komit baru Anda

    git commit -m "Add new commit"
    

Catatan: HEAD@{0}& HEAD@{1}Sekarang digabung menjadi 1 komit, ini dapat dilakukan untuk beberapa komit juga.

git reflog lagi harus menampilkan:

git reflog
5976f2b HEAD@{0}: commit: Add new commit
b860ddb HEAD@{1}: commit: Add something

0

Alat Untuk Mengotomatiskan Banyak Komit Menjadi Satu

seperti kata Kondal Kolipaka . Menggunakan "git rebase -i"

Logika "git rebase"

Saat menggunakan "git rebase -i", git menghasilkan file git-rebase-todo di direktori .git / rebase-merge saat ini, dan kemudian memanggil editor git untuk memungkinkan pengguna mengedit file git-rebase-todo untuk diproses. Jadi alat ini perlu dipenuhi:

  1. Ubah editor git ke alat yang kami sediakan;
  2. Alat ini memproses file git-rebase-todo.

Ubah editor git default

git config core.editor #show current default git editor
git config --local --replace-all  core.editor NEW_EDITOR # set the local branch using NEW_EDITOR as git editor

Jadi, alat tersebut perlu mengubah editor git dan memproses file git-rebase-todo. Alat menggunakan python di bawah ini:

#!/usr/bin/env python3
#encoding: UTF-8

import os
import sys

def change_editor(current_file):
    os.system("git config --local --replace-all  core.editor " + current_file) # Set current_file as git editor
    os.system("git rebase -i") # execute the "git rebase -i" and will invoke the python file later with git-rebase-todo file as argument
    os.system("git config --local --replace-all core.editor vim") # after work reset the git editor to default

def rebase_commits(todo_file):
    with open(todo_file, "r+") as f:
        contents = f.read() # read git-rebase-todo's content
        contents = contents.split("\n")
        first_commit = True
        f.truncate()
        f.seek(0)
        for content in contents:
            if content.startswith("pick"):
                if first_commit:
                    first_commit = False
                else:
                    content = content.replace("pick", "squash") # replace the pick to squash except for the first pick
            f.write(content + "\n")

def main(args):
    if len(args) == 2:
        rebase_commits(args[1]) # process the git-rebase-todo
    else:
        change_editor(os.path.abspath(args[0])) # set git editor

if __name__ == "__main__":
    main(sys.argv)

Ref: https://liwugang.github.io/2019/12/30/git_commits_en.html


4
Harap turunkan promosi situs web Anda. Lihat juga Bagaimana tidak menjadi spammer.
tripleee
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.