Kami memiliki repositori Git dengan lebih dari 400 komit, beberapa lusin pertama adalah banyak trial-and-error. Kami ingin membersihkan komitmen ini dengan menekan banyak menjadi satu komit. Tentu saja, git-rebase sepertinya jalan yang harus ditempuh. Masalah saya adalah bahwa itu berakhir dengan menggabungkan konflik, dan konflik ini tidak mudah untuk diselesaikan. Saya tidak mengerti mengapa harus ada konflik sama sekali, karena saya hanya menekan komitmen (tidak menghapus atau mengatur ulang). Sangat mungkin, ini menunjukkan bahwa saya tidak sepenuhnya memahami bagaimana git-rebase melakukan squash-nya.
Ini versi modifikasi dari skrip yang saya gunakan:
repo_squash.sh (ini adalah skrip yang sebenarnya dijalankan):
rm -rf repo_squash
git clone repo repo_squash
cd repo_squash/
GIT_EDITOR=../repo_squash_helper.sh git rebase --strategy theirs -i bd6a09a484b8230d0810e6689cf08a24f26f287a
repo_squash_helper.sh (skrip ini hanya digunakan oleh repo_squash.sh):
if grep -q "pick " $1
then
# cp $1 ../repo_squash_history.txt
# emacs -nw $1
sed -f ../repo_squash_list.txt < $1 > $1.tmp
mv $1.tmp $1
else
if grep -q "initial import" $1
then
cp ../repo_squash_new_message1.txt $1
elif grep -q "fixing bad import" $1
then
cp ../repo_squash_new_message2.txt $1
else
emacs -nw $1
fi
fi
repo_squash_list.txt: (file ini hanya digunakan oleh repo_squash_helper.sh)
# Initial import
s/pick \(251a190\)/squash \1/g
# Leaving "Needed subdir" for now
# Fixing bad import
s/pick \(46c41d1\)/squash \1/g
s/pick \(5d7agf2\)/squash \1/g
s/pick \(3da63ed\)/squash \1/g
Saya akan meninggalkan konten "pesan baru" ke imajinasi Anda. Awalnya, saya melakukan ini tanpa opsi "--strategy theirs" (yaitu, menggunakan strategi default, yang jika saya memahami dokumentasi dengan benar adalah rekursif, tapi saya tidak yakin strategi rekursif mana yang digunakan), dan juga tidak t bekerja. Juga, saya harus menunjukkan bahwa, dengan menggunakan kode komentar di repo_squash_helper.sh, saya menyimpan file asli yang digunakan pada skrip sed dan menjalankan skrip sed terhadapnya untuk memastikan ia melakukan apa yang saya inginkan ( dulu). Sekali lagi, saya bahkan tidak tahu mengapa akan ada konflik, jadi sepertinya tidak masalah strategi mana yang digunakan. Setiap saran atau wawasan akan sangat membantu, tetapi kebanyakan saya hanya ingin agar squashing ini bekerja.
Diperbarui dengan informasi tambahan dari diskusi dengan Jefromi:
Sebelum mengerjakan repositori "nyata" kami yang besar, saya menggunakan skrip yang mirip pada repositori uji. Itu adalah repositori yang sangat sederhana dan tesnya bekerja dengan baik.
Pesan yang saya dapatkan saat gagal adalah:
Finished one cherry-pick.
# Not currently on any branch.
nothing to commit (working directory clean)
Could not apply 66c45e2... Needed subdir
Ini adalah pilihan pertama setelah komit squash pertama. Menjalankan git status
menghasilkan direktori kerja yang bersih. Jika saya kemudian melakukan git rebase --continue
, saya mendapatkan pesan yang sangat mirip setelah beberapa komitmen lagi. Jika saya melakukannya lagi, saya mendapatkan pesan yang sangat mirip setelah beberapa lusin melakukan. Jika saya melakukannya lagi, kali ini melewati sekitar seratus komit, dan menghasilkan pesan ini:
Automatic cherry-pick failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>', and
run 'git rebase --continue'
Could not apply f1de3bc... Incremental
Jika saya lari git status
, saya dapat:
# Not currently on any branch.
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: repo/file_A.cpp
# modified: repo/file_B.cpp
#
# Unmerged paths:
# (use "git reset HEAD <file>..." to unstage)
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: repo/file_X.cpp
#
# Changed but not updated:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted: repo/file_Z.imp
Bit "keduanya dimodifikasi" terdengar aneh bagi saya, karena ini hanya hasil dari pick. Perlu juga dicatat bahwa jika saya melihat "konflik", itu bermuara pada satu baris dengan satu versi memulainya dengan karakter [tab], dan yang lainnya dengan empat spasi. Ini terdengar seperti itu mungkin masalah dengan bagaimana saya mengatur file konfigurasi saya, tetapi tidak ada yang seperti itu di dalamnya. (Saya memang mencatat bahwa core.ignorecase disetel ke true, tetapi ternyata git-clone melakukannya secara otomatis. Saya tidak sepenuhnya terkejut dengan hal itu mengingat sumber aslinya ada di mesin Windows.)
Jika saya memperbaiki file_X.cpp secara manual, kemudian gagal tidak lama kemudian dengan konflik lain, kali ini antara file (CMakeLists.txt) yang menurut satu versi seharusnya ada dan satu versi berpikir tidak seharusnya. Jika saya memperbaiki konflik ini dengan mengatakan saya ingin file ini (yang saya lakukan), beberapa komitmen kemudian saya mendapatkan konflik lain (dalam file yang sama) di mana sekarang ada beberapa perubahan yang tidak sepele. Masih hanya sekitar 25% dari jalan melalui konflik.
Saya juga harus menunjukkan, karena ini mungkin sangat penting, bahwa proyek ini dimulai dalam repositori svn. Sejarah awal itu sangat mungkin diimpor dari repositori svn itu.
Perbarui # 2:
Pada lark (dipengaruhi oleh komentar Jefromi), saya memutuskan untuk melakukan perubahan repo_squash.sh saya menjadi:
rm -rf repo_squash
git clone repo repo_squash
cd repo_squash/
git rebase --strategy theirs -i bd6a09a484b8230d0810e6689cf08a24f26f287a
Dan kemudian, saya baru saja menerima entri asli, sebagaimana adanya. Yaitu, "rebase" seharusnya tidak mengubah apa pun. Itu berakhir dengan hasil yang sama dengan yang dijelaskan sebelumnya.
Perbarui # 3:
Atau, jika saya menghilangkan strategi dan mengganti perintah terakhir dengan:
git rebase -i bd6a09a484b8230d0810e6689cf08a24f26f287a
Saya tidak lagi mendapatkan masalah rebase "apa-apa untuk dilakukan", tetapi saya masih memiliki konflik lainnya.
Perbarui dengan repositori mainan yang menciptakan masalah:
test_squash.sh (ini adalah file yang sebenarnya Anda jalankan):
#========================================================
# Initialize directories
#========================================================
rm -rf test_squash/ test_squash_clone/
mkdir -p test_squash
mkdir -p test_squash_clone
#========================================================
#========================================================
# Create repository with history
#========================================================
cd test_squash/
git init
echo "README">README
git add README
git commit -m"Initial commit: can't easily access for rebasing"
echo "Line 1">test_file.txt
git add test_file.txt
git commit -m"Created single line file"
echo "Line 2">>test_file.txt
git add test_file.txt
git commit -m"Meant for it to be two lines"
git checkout -b dev
echo Meaningful code>new_file.txt
git add new_file.txt
git commit -m"Meaningful commit"
git checkout master
echo Conflicting meaningful code>new_file.txt
git add new_file.txt
git commit -m"Conflicting meaningful commit"
# This will conflict
git merge dev
# Fixes conflict
echo Merged meaningful code>new_file.txt
git add new_file.txt
git commit -m"Merged dev with master"
cd ..
#========================================================
# Save off a clone of the repository prior to squashing
#========================================================
git clone test_squash test_squash_clone
#========================================================
#========================================================
# Do the squash
#========================================================
cd test_squash
GIT_EDITOR=../test_squash_helper.sh git rebase -i HEAD@{7}
#========================================================
#========================================================
# Show the results
#========================================================
git log
git gc
git reflog
#========================================================
test_squash_helper.sh (digunakan oleh test_sqash.sh):
# If the file has the phrase "pick " in it, assume it's the log file
if grep -q "pick " $1
then
sed -e "s/pick \(.*\) \(Meant for it to be two lines\)/squash \1 \2/g" < $1 > $1.tmp
mv $1.tmp $1
# Else, assume it's the commit message file
else
# Use our pre-canned message
echo "Created two line file" > $1
fi
PS: Ya, saya tahu beberapa dari Anda merasa ngeri ketika melihat saya menggunakan emacs sebagai editor yang mundur.
PPS: Kami tahu kami harus membuang semua klon dari repositori yang ada setelah rebase. (Di sepanjang baris "kamu tidak boleh rebase repositori setelah itu diterbitkan".)
PPPS: Adakah yang bisa memberi tahu saya cara menambahkan hadiah untuk ini? Saya tidak melihat opsi di mana pun di layar ini apakah saya dalam mode edit atau mode tampilan.
rebase --interactive
- itu adalah semacam daftar tindakan untuk git untuk mencoba. Saya berharap Anda dapat mengurangi ini menjadi satu squash yang menyebabkan konflik, dan menghindari semua kerumitan tambahan dari skrip pembantu Anda. Informasi lain yang hilang adalah ketika konflik terjadi - kapan git menerapkan tambalan untuk membentuk squash, atau ketika ia mencoba bergerak melewati squash dan menerapkan tambalan berikutnya? (Dan Anda yakin tidak ada hal buruk terjadi dengan GIT_EDITOR kludge Anda? Voting lain untuk test case sederhana.)
rebase -p
lagi)