จะสร้างสาขา "root" ใหม่ (และว่างเปล่า!) ได้อย่างไร


136

ฉันต้องการกำหนดสาขา "root" ใหม่ในที่เก็บ git นี้ โดย "ราก" สาขาที่ผมหมายถึงสาขาที่เป็นอิสระทั้งหมดของทุกสาขาอื่นในพื้นที่เก็บข้อมูล1

น่าเสียดายที่แม้แต่การกระทำ (ขอเรียกมันว่าA) ที่ฐานสุดของโครงสร้างคอมมิตของ repo นั้นมีไฟล์จำนวนมาก (นี่คือที่เก็บที่เริ่มต้นในโปรเจ็กต์ที่เป็นผู้ใหญ่แล้ว)

ซึ่งหมายความว่าแม้ว่าฉันจะให้Aเป็นสาขาใหม่ แต่สาขาใหม่<start-point>นี้จะไม่เริ่มต้นจาก "กระดานชนวนที่สะอาด" แต่จะมีไฟล์ทั้งหมดที่ถูกส่งเข้าAมา

มีวิธีใดบ้างที่ฉันสามารถสร้างสาขาที่ว่างเปล่าทั้งหมดในที่เก็บนี้โดย<start-point>ให้ใกล้เคียงAที่สุด


1 BTW ไม่เทียบเท่ากับการสร้าง repo ใหม่ repos แยกกันจะสะดวกน้อยลงด้วยเหตุผลหลายประการ


แก้ไข : ตกลงนี่คือสิ่งที่ฉันทำตามคำตอบของvcsjones :

# save rev of the current earliest commit
OLDBASE=$(git rev-list --max-parents=0 HEAD)

# create a new orphan branch and switch to it
git checkout --orphan newbranch
# make sure it's empty
git rm -rf .

# create a new empty commit in the new branch, and
# save its rev in NEWBASE
git commit --allow-empty -m 'base commit (empty)'
NEWBASE=$(git rev-list HEAD)

# specify $NEWBASE as the new parent for $OLDBASE, and
# run filter-branch on the original branch
echo "$OLDBASE $NEWBASE" > .git/info/grafts
git checkout master
git filter-branch

# NOTE: this assumes that the original repo had only one
# branch; if not, a git-filter-branch -f <branch> command
# need to be run for each additional branch.

rm .git/info/grafts

แม้ว่าขั้นตอนนี้จะเกี่ยวข้องเล็กน้อย แต่ผลลัพธ์ที่ได้คือการคอมมิตฐานว่างที่สามารถใช้เป็น<start-point>"clean-slate branch" ใหม่ได้ สิ่งที่ฉันต้องทำก็คือ

git checkout -b cleanslate $(git rev-list --max-parents=0 HEAD)

ในอนาคตฉันจะสร้างที่เก็บใหม่เช่นนี้เสมอ:

git init
git commit --allow-empty -m 'base commit (empty)'

... เพื่อให้คอมมิตแรกว่างเปล่าและพร้อมใช้งานสำหรับการเริ่มสาขาอิสระใหม่เสมอ (ฉันรู้ว่านี่เป็นสิ่งอำนวยความสะดวกที่ไม่ค่อยจำเป็นนัก แต่ก็ค่อนข้างง่ายที่จะทำให้พร้อมใช้งาน)



1
@Anonymoose: เพียงเพื่อการบันทึก (แทนที่จะอภิปราย): ฉันไม่เห็นด้วยกับความคิดเห็นของคุณ
kjo

1
ดูเหมือนจะมีวิธีแก้ปัญหาที่ง่ายกว่ามากgit rebase --ontoโปรดดูที่stackoverflow.com/questions/645450/…
Stéphane Gourichon

คำตอบ:


224

ใช้--orphanเมื่อสร้างสาขา:

git checkout --orphan YourBranchName

การดำเนินการนี้จะสร้างสาขาใหม่โดยไม่มีการคอมมิต แต่ไฟล์ทั้งหมดของคุณจะถูกจัดฉาก เมื่อถึงจุดนั้นคุณสามารถลบออกได้
("ลบออก": A git reset --hardจะทำให้ดัชนีว่างเปล่าทำให้คุณมีโครงสร้างการทำงานที่ว่างเปล่า)

ดูที่หน้าคนสำหรับการชำระเงินสำหรับข้อมูลเพิ่มเติมเกี่ยวกับ --orphan


สิ่งนี้เป็นการสร้างกระดานชนวนเปล่าหรือไม่? เช่นเดียวกับตั้งแต่เริ่มต้น? หรือเก็บการเปลี่ยนแปลงก่อนหน้านี้ไว้ทั้งหมด แต่ไม่อยู่ในประวัติคอมไพล์?
Con Antonakos

4
@ConAntonakos สิ่งนี้จะสร้างสาขาใหม่โดยไม่มีผู้ปกครอง สาขาอื่น ๆ ไม่ได้รับผลกระทบการเปลี่ยนแปลงทั้งหมดจะถูกเก็บไว้
fuz

11

หากต้องการเพิ่มคำตอบที่ได้รับการยอมรับแนวทางปฏิบัติที่ดีที่สุดในการเปลี่ยนกลับเป็นสถานะสะอาดคือการสร้างการคอมมิตว่างเริ่มต้นเพื่อให้คุณสามารถตั้งฐานใหม่ได้อย่างง่ายดายในขณะที่ตั้งค่าสาขาของคุณสำหรับลูกหลาน นอกจากนี้เนื่องจากคุณต้องการสถานะที่สะอาดคุณอาจมีไฟล์ที่ไม่ควรทำดังนั้นคุณต้องลบออกจากดัชนี เมื่อคำนึงถึงสิ่งเหล่านี้คุณควร:

$ git checkout --orphan dev2
Switched to a new branch 'dev2'
$ git reset # unstage all the files, you probably don't want to commit all of them
$ git commit --allow-empty -m 'Initial empty commit'
[dev2 (root-commit) a515c28] Initial empty commit

1
ฉันเชื่อว่าสิ่งนี้ไม่จำเป็นในปี 2555 เพราะคุณสามารถสร้างฐานข้อมูลใหม่ในรูทได้
Timmmm


1

มีวิธีใดบ้างที่ฉันสามารถสร้างสาขาที่ว่างเปล่าในที่เก็บนี้ได้

คำสั่งที่ใช้จริง (กับ Git 2.28+) คือ:

git switch --discard-changes --orphan newBranch
# or
git switch -f --orphan newBranch

git switchสามารถใช้ได้จาก Git 2.23 (สิงหาคม 2019) และแทนที่สับสนเก่าgit checkoutคำสั่ง

แต่ฉันอยากจะแนะนำ Git 2.28 (Q3 2020) เพราะgit switch --discard-changes --orphanได้รับการปรับให้เหมาะสมในเวอร์ชันนั้นแล้ว

ดูกระทำ 8d3e33d , กระทำ 8186128 (21 พฤษภาคม 2020) โดยไบรอันเมตร คาร์ลสัน ( bk2204) .
(ผสานโดยJunio ​​C Hamano - gitster-ในการกระทำ ded44af , 09 มิ.ย. 2020)

builtin/checkout: ลดความซับซ้อนของการเริ่มต้นข้อมูลเมตา

ลงนามโดย: brian m. คาร์ลสัน
บทวิจารณ์โดย: Derrick Stolee

เมื่อเราโทรinit_checkout_metadataเข้าreset_tree,เราต้องการส่งผ่าน ID อ็อบเจ็กต์ของการคอมมิตที่เป็นปัญหาเพื่อให้สามารถส่งผ่านไปยังฟิลเตอร์หรือหากไม่มีคอมมิตต้นไม้

เราคาดว่ากรณีหลังนี้ซึ่งอาจเกิดขึ้นที่อื่นในรหัสชำระเงิน แต่ไม่สามารถเกิดขึ้นได้ที่นี่

เป็นเพียงกรณีที่เราไม่ได้มีการกระทำวัตถุคือเมื่อกล่าวอ้างด้วย git switch--orphan

ยิ่งไปกว่านั้นเราสามารถตีเส้นทางรหัสนี้ได้โดยไม่ต้องมีวัตถุกระทำเพิ่มเติม --force--discard-changesหรือ

ในกรณีเช่นนี้ไม่มีจุดเริ่มต้นของข้อมูลเมตาการชำระเงินด้วยคอมมิตหรือโครงสร้างเนื่องจาก

  • (ก) ไม่มีข้อผูกมัดมีเพียงต้นไม้ว่างเปล่าและ
  • (b) เราจะไม่ใช้ข้อมูลเนื่องจากจะไม่มีไฟล์ใด ๆ เปื้อนเมื่อตรวจสอบสาขาที่ไม่มีไฟล์

ส่งรหัสอ็อบเจ็กต์ศูนย์ทั้งหมดในกรณีนี้เนื่องจากเราต้องการค่าบางอย่างซึ่งเป็นตัวชี้ที่ถูกต้อง

ทดสอบ:

git switch master
echo foo >foo.txt
git switch --discard-changes --orphan new-orphan2
git ls-files >tracked-files
# test_must_be_empty tracked-files
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.