เรามีพื้นที่เก็บข้อมูล Git ที่มีการกระทำมากกว่า 400 ครั้งสองสามคู่แรกนั้นมีการทดลองและข้อผิดพลาดมากมาย เราต้องการที่จะทำความสะอาดการกระทำเหล่านี้โดยการบีบลงไปในการกระทำเดียว ตามธรรมชาติแล้วการรีต git-reb ดูเหมือนจะเป็นไป ปัญหาของฉันคือมันจบลงด้วยการรวมความขัดแย้งและความขัดแย้งเหล่านี้ไม่ใช่เรื่องง่ายที่จะแก้ไข ฉันไม่เข้าใจว่าทำไมจึงควรมีข้อขัดแย้งใด ๆ เนื่องจากฉันเพิ่งจะคอมมิชชัน (ไม่ลบหรือจัดเรียงใหม่) เป็นไปได้อย่างมากที่สิ่งนี้แสดงให้เห็นว่าฉันไม่ได้เข้าใจอย่างสมบูรณ์ว่าการทำ git-rebase นั้นทำได้อย่างไร
นี่คือสคริปต์ที่ฉันใช้อยู่เวอร์ชันที่แก้ไข:
repo_squash.sh (นี่คือสคริปต์ที่ทำงานจริง):
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 (สคริปต์นี้ใช้โดย 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: (ไฟล์นี้ใช้โดย 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
ฉันจะฝากเนื้อหา "ข้อความใหม่" ไว้ในจินตนาการของคุณ เริ่มแรกฉันทำสิ่งนี้โดยไม่มีตัวเลือก "--strategy yours" (เช่นใช้กลยุทธ์เริ่มต้นซึ่งหากฉันเข้าใจว่าเอกสารถูกต้องจะเรียกซ้ำ แต่ฉันไม่แน่ใจว่าใช้กลยุทธ์แบบเรียกซ้ำ) และไม่ได้ใช้ ' ไม่ทำงาน นอกจากนี้ฉันควรชี้ให้เห็นว่าโดยใช้รหัสความคิดเห็นใน repo_squash_helper.sh ฉันบันทึกไฟล์ต้นฉบับที่สคริปต์ sed ทำงานและรันสคริปต์ sed เพื่อให้แน่ใจว่าทำในสิ่งที่ฉันต้องการ ( มันเป็น) อีกครั้งผมไม่ได้รู้ว่าทำไมมีจะเป็นความขัดแย้งจึงจะได้ดูเหมือนจะสำคัญมากที่จะใช้กลยุทธ์ คำแนะนำหรือข้อมูลเชิงลึกใด ๆ จะเป็นประโยชน์ แต่ส่วนใหญ่ฉันแค่ต้องการให้การบีบอัดนี้ทำงาน
อัปเดตด้วยข้อมูลเพิ่มเติมจากการสนทนากับ Jefromi:
ก่อนที่จะทำงานกับพื้นที่เก็บข้อมูล "ของจริง" ขนาดใหญ่ของฉันฉันใช้สคริปต์ที่คล้ายกันในที่เก็บข้อมูลการทดสอบ มันเป็นพื้นที่เก็บข้อมูลที่ง่ายมากและการทดสอบก็ใช้งานได้อย่างสมบูรณ์
ข้อความที่ฉันได้รับเมื่อล้มเหลวคือ:
Finished one cherry-pick.
# Not currently on any branch.
nothing to commit (working directory clean)
Could not apply 66c45e2... Needed subdir
นี่คือการเลือกครั้งแรกหลังจากการสควอชครั้งแรก การทำงานgit status
ให้ผลไดเรกทอรีการทำงานที่สะอาด ถ้าฉันทำgit rebase --continue
ฉันจะได้รับข้อความที่คล้ายกันมากหลังจากคอมมิทเพิ่มอีกสองสามข้อ ถ้าฉันทำมันอีกครั้งฉันจะได้รับข้อความที่คล้ายกันมากหลังจากทำสองสามครั้ง ถ้าฉันทำมันอีกครั้งคราวนี้ผ่านไปหนึ่งร้อยคอมมิชชันและให้ข่าวสาร:
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
ถ้าฉันวิ่งgit status
ฉันก็จะได้:
# 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
บิต "ทั้งแก้ไข" ฟังดูแปลกสำหรับฉันเนื่องจากนี่เป็นเพียงผลลัพธ์ของการเลือก นอกจากนี้ยังเป็นที่น่าสังเกตว่าถ้าฉันดูที่ "ความขัดแย้ง" มันจะลดลงไปเป็นบรรทัดเดียวโดยมีหนึ่งเวอร์ชันเริ่มต้นด้วยอักขระ [แท็บ] และอีกอันหนึ่งมีช่องว่างสี่ช่อง ดูเหมือนว่านี่อาจเป็นปัญหากับวิธีการตั้งค่าไฟล์ปรับแต่งของฉัน แต่ไม่มีการเรียงลำดับใด ๆ (ฉันทราบว่า core.ignorecase ถูกตั้งค่าเป็นจริง แต่เห็นได้ชัดว่า git-clone ทำโดยอัตโนมัติฉันไม่แปลกใจเลยเมื่อพิจารณาว่าแหล่งต้นฉบับอยู่บนเครื่อง Windows)
ถ้าฉันแก้ไข file_X.cpp ด้วยตนเองมันจะล้มเหลวหลังจากนั้นไม่นานด้วยความขัดแย้งครั้งนี้ระหว่างไฟล์ (CMakeLists.txt) ที่หนึ่งเวอร์ชันคิดว่าควรมีอยู่และเวอร์ชันหนึ่งคิดว่าไม่ควร ถ้าฉันแก้ไขข้อขัดแย้งนี้โดยบอกว่าฉันต้องการไฟล์นี้ (ซึ่งฉันทำ) ไม่กี่ข้อตกลงภายหลังฉันจะได้รับความขัดแย้งอื่น (ในไฟล์เดียวกันนี้) ซึ่งตอนนี้มีการเปลี่ยนแปลงที่ค่อนข้างเล็กน้อย ยังคงมีเพียงประมาณ 25% ของวิธีการผ่านความขัดแย้ง
ฉันควรจะชี้ให้เห็นเช่นนี้อาจเป็นสิ่งสำคัญเพราะโครงการนี้เริ่มต้นขึ้นในพื้นที่เก็บข้อมูล svn ประวัติเริ่มต้นนั้นน่าจะถูกนำเข้าจากที่เก็บ svn นั้น
อัปเดต # 2:
บนความสนุกสนาน (ได้รับอิทธิพลจากความคิดเห็นของ Jefromi) ฉันตัดสินใจเปลี่ยนแปลง repo_squash.sh ของฉันเป็น:
rm -rf repo_squash
git clone repo repo_squash
cd repo_squash/
git rebase --strategy theirs -i bd6a09a484b8230d0810e6689cf08a24f26f287a
แล้วฉันก็ยอมรับรายการต้นฉบับตามที่เป็นอยู่ คือ "การปฏิเสธ" ไม่ควรเปลี่ยนแปลงอะไรเลย มันจบลงด้วยผลลัพธ์เดียวกันอธิบายก่อนหน้านี้
อัปเดต # 3:
หรือถ้าฉันไม่ใช้กลยุทธ์และแทนที่คำสั่งสุดท้ายด้วย:
git rebase -i bd6a09a484b8230d0810e6689cf08a24f26f287a
ฉันไม่ได้รับปัญหาการ "ปฏิเสธที่จะยอมรับ" อีกต่อไป แต่ฉันยังเหลืออยู่กับความขัดแย้งอื่น ๆ
อัปเดตด้วยที่เก็บของเล่นที่สร้างปัญหาขึ้นใหม่:
test_squash.sh (นี่คือไฟล์ที่คุณใช้งานจริง):
#========================================================
# 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 (ใช้โดย 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: ใช่ฉันรู้ว่าคุณบางคนประจบประแจงเมื่อคุณเห็นฉันใช้ emacs เป็นบรรณาธิการถอยกลับ
PPS: เรารู้ว่าเราจะต้องทำลายพื้นที่เก็บข้อมูลที่มีอยู่ทั้งหมดหลังจากการรีบูต (ตามแนว "คุณจะไม่ต้องรีบูทพื้นที่เก็บข้อมูลหลังจากเผยแพร่แล้ว")
PPPS: ทุกคนสามารถบอกวิธีเพิ่มความโปรดปรานให้กับฉันได้ไหม ฉันไม่เห็นตัวเลือกใด ๆ บนหน้าจอนี้ไม่ว่าฉันจะอยู่ในโหมดแก้ไขหรือโหมดดู
rebase --interactive
- นั่นเป็นรายการการกระทำเพื่อให้คอมไพล์พยายาม ฉันหวังว่าคุณจะสามารถลดสิ่งนี้เป็นสควอชเดียวที่ก่อให้เกิดความขัดแย้งและหลีกเลี่ยงความซับซ้อนพิเศษทั้งหมดของสคริปต์ผู้ช่วยของคุณ ข้อมูลที่หายไปอื่น ๆ คือเมื่อความขัดแย้งเกิดขึ้น - เมื่อ git ใช้แพทช์เพื่อสร้างสควอชหรือเมื่อมันพยายามที่จะย้ายสควอชที่ผ่านมาและใช้แพทช์ต่อไป? (และคุณแน่ใจหรือว่าไม่มีอะไรเลวร้ายเกิดขึ้นกับกระบอง GIT_EDITOR ของคุณอีกโหวตสำหรับกรณีทดสอบง่ายๆ)
rebase -p
อยู่แล้ว)