ใน git มีวิธีง่ายๆในการแนะนำสาขาที่ไม่เกี่ยวข้องกับพื้นที่เก็บข้อมูล?


328

ในขณะที่ช่วยเพื่อนด้วยปัญหาคอมไพล์วันนี้ฉันต้องแนะนำสาขาที่ต้องแยกจากmasterสาขาโดยสิ้นเชิง เนื้อหาของสาขานี้มีต้นกำเนิดแตกต่างจากสิ่งที่พัฒนาบนmasterสาขา แต่จริง ๆ แล้วพวกเขาจะถูกรวมเข้ากับmasterสาขาในภายหลัง

ฉันจำได้จากการอ่านGitของ John Wiegley จากด้านล่างขึ้นมาว่ากิ่งเป็นป้ายกำกับการกระทำที่เป็นไปตามอนุสัญญาบางอย่างและผูกมัดผูกติดอยู่กับต้นไม้หรือไม่ เราไปสร้างคอมมิทแม่แบบคอมมิทกับที่เก็บที่มีอยู่โดยใช้ระบบประปาของ git:

ดังนั้นเราจึงกำจัดไฟล์ทั้งหมดในดัชนี ...

$ git rm -rf .

... ไดเรกทอรีที่แยกและไฟล์จาก tarball เพิ่มเหล่านั้นไปยังดัชนี ...

$ git add .

... และสร้างวัตถุต้นไม้ ...

$ git write-tree

( git-write-treeบอกเรา sha1sum ของวัตถุต้นไม้ที่สร้างขึ้น)

จากนั้นเรามุ่งมั่นที่ต้นไม้โดยไม่ต้องระบุผู้ปกครองกระทำ ...

$ echo "Imported project foo" | git commit-tree $TREE

( git-commit-treeบอก sha1sum ของวัตถุกระทำที่สร้างขึ้น)

... และสร้างสาขาใหม่ที่ชี้ไปที่ความมุ่งมั่นที่สร้างขึ้นใหม่ของเรา

$ git update-ref refs/heads/other-branch $COMMIT

ในที่สุดเรากลับไปที่masterสาขาเพื่อทำงานต่อที่นั่น

$ git checkout -f master

ดูเหมือนว่าจะทำงานได้ตามแผนที่วางไว้ แต่นี่ไม่ใช่วิธีการที่ชัดเจนที่ฉันอยากจะแนะนำให้คนที่เพิ่งเริ่มใช้งานคอมไพล์ มีวิธีที่ง่ายกว่าในการสร้างสาขาใหม่ที่ไม่เกี่ยวข้องกับทุกอย่างที่เกิดขึ้นในพื้นที่เก็บข้อมูลหรือไม่?

คำตอบ:


510

มีฟีเจอร์ใหม่ (ตั้งแต่ V1.7.2) ซึ่งทำให้งานนี้สูงขึ้นเล็กน้อยกว่าสิ่งที่อยู่ในคำตอบอื่น ๆ

git checkoutตอนนี้รองรับ--orphanตัวเลือก จากหน้าคน :

git checkout [-q] [-f] [-m] --orphan <new_branch> [<start_point>]

สร้างสาขาใหม่เด็กกำพร้าชื่อ <new_branch> เริ่มต้นจาก <start_point> และเปลี่ยนเป็น ความมุ่งมั่นแรกที่เกิดขึ้นในสาขาใหม่นี้จะไม่มีผู้ปกครองและมันจะเป็นรากฐานของประวัติศาสตร์ใหม่ที่ถูกตัดการเชื่อมต่อโดยสิ้นเชิงจากสาขาอื่น ๆ ทั้งหมดและมุ่งมั่น

นี้ไม่ได้ทำว่าสิ่งที่อยากถามเพราะมัน populates ดัชนีและต้นไม้ทำงานจาก<start_point>(ตั้งแต่นี้เป็นหลังจากที่ทุกคำสั่งที่เช็คเอาท์) การดำเนินการอื่น ๆ ที่จำเป็นเท่านั้นคือการลบรายการที่ไม่ต้องการออกจากแผนผังการทำงานและดัชนี น่าเสียดายที่git reset --hardใช้งานไม่ได้ แต่git rm -rf .สามารถใช้แทนได้ (ฉันเชื่อว่านี่เทียบเท่ากับrm .git/index; git clean -fdxคำตอบอื่น ๆ


สรุป:

git checkout --orphan newbranch
git rm -rf .
<do work>
git add your files
git commit -m 'Initial commit'

ฉัน<start_point>ไม่ได้ระบุเนื่องจากเป็นค่าเริ่มต้นที่ HEAD และเราก็ไม่สนใจจริงๆ ลำดับนี้จะเป็นหลักในสิ่งเดียวกันเป็นลำดับคำสั่งในคำตอบของ Artemเพียงโดยไม่ต้อง resorting คำสั่งประปาที่น่ากลัว


คุณรู้หรือไม่ว่ามันเป็นไปได้ที่จะสร้างสาขาเด็กกำพร้าที่ยังคงมองเห็นได้เมื่อคุณชำระเงินสาขาจาก "ต้นไม้" อื่น ๆ ?
JJD

1
@JJD: ฉันคิดว่าสิ่งที่คุณต้องการคือคอมไพล์ผสาน ( git checkout master && git merge --no-commit "orphan-branch" ) เทคนิคที่คล้ายกันบางอย่างจะทำงานโดยใช้ git-reset หรือเล่นกับดัชนี แต่ขึ้นอยู่กับขั้นตอนการทำงานที่คุณต้องการ
phord


@phord ฉันคิดถึงเด็กกำพร้าที่มีสิ่งต่าง ๆ มากมายเช่นการทดสอบหน่วยหรือเอกสารแยกต่างหากจากซอร์สโค้ดของโครงการ
JJD

2
@JJD: สคริปต์ที่ฉันให้ควรให้สิ่งที่คุณต้องการเว้นแต่ฉันจะเข้าใจผิด เมื่อคุณพูดว่า "ยังคงมองเห็นได้" หมายความว่าไฟล์จะยังคงอยู่ในไดเรกทอรีทำงานแม้ว่าคุณจะตรวจสอบสาขาอื่นหรือไม่ การใช้--no-commitบนgit mergeจะทำให้สำเร็จ คุณอาจต้องติดตามด้วยgit reset origin/masterเพื่อให้การกระทำครั้งต่อไปของคุณไปยังตำแหน่งที่คุณต้องการ แต่จากนั้นไฟล์จากเด็กกำพร้าสาขาของคุณจะแสดงเป็น "ไฟล์ที่ไม่ได้ติดตาม" เว้นแต่คุณจะใส่ไว้ในไฟล์. gitignore ด้วย
phord

32

จากGit Community Book :

git symbolic-ref HEAD refs/heads/newbranch 
rm .git/index 
git clean -fdx 
<do work> 
git add your files 
git commit -m 'Initial commit'

1
คำตอบถัดไปดีกว่าสำหรับ git รุ่นใหม่
kikito

14
@kikito: Re: "คำตอบต่อไปดีกว่า" ... การสั่งซื้อที่นี่บน SO ไม่เสถียร คุณช่วยเพิ่มลิงค์ที่ชี้ไปยังสิ่งที่คุณคิดว่าเป็นคำตอบที่ดีกว่าได้ไหม
เดวิดเจ

2
ฉันหมายถึงstackoverflow.com/a/4288660/312586 คุณพูดถูกฉันไม่ควรพูดว่า "ต่อไป" มันมีคะแนนน้อยกว่าคำตอบนี้เมื่อฉันแสดงความคิดเห็น
kikito


อันนี้ใช้งานได้ดีกว่าสำหรับกรณี "ฉันต้องการผูกมัดกับสาขาสร้างมันถ้ามันไม่ได้อยู่ก่อน"
max630

22

แม้ว่าโซลูชันที่มีgit symbolic-refและลบดัชนีทำงานอยู่ แต่อาจเป็นแนวคิดที่ชัดเจนกว่าในการสร้างที่เก็บใหม่

$ cd /path/to/unrelated
$ git init
[edit and add files]
$ git add .
$ git commit -m "Initial commit of unrelated"
[master (root-commit) 2a665f6] Initial commit of unrelated
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 foo

จากนั้นดึงข้อมูลจากมัน

$ cd /path/to/repo
$ git fetch /path/to/unrelated master:unrelated-branch
warning: no common commits
remote: Counting objects: 3, done.
Unpacking objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
From /path/to/unrelated
 * [new branch]      master     -> unrelated-branch

ตอนนี้คุณสามารถลบ / path / to / unrelated


ในความคิดของแนวคิดที่สะอาดจะเกี่ยวข้องกับตัวเลือกในการหรือgit branch git checkoutฉันดีใจที่ git ทำให้สิ่งเหล่านี้เป็นไปได้ แต่ทำไมมันไม่ควรง่ายกว่านี้?
hillu

3
เพราะมันเป็นและควรเป็นสิ่งที่หายาก หากคุณมีสาขาสิ่งที่ไม่เกี่ยวข้องมักจะเป็นของที่เก็บที่ไม่เกี่ยวข้องแทนการบรรจุในที่มีอยู่เดิม (แม้ว่าจะมีข้อยกเว้น)
Jakub Narębski

1
+1 สำหรับมือใหม่คอมไพล์เพื่อนคุณสามารถเห็นได้ชัดแล้วรายการสาขาผ่านและสลับระหว่างพวกเขาผ่านทางgit branch git checkout BRANCH_NAME
akavel

ขอบคุณสำหรับสิ่งนี้ฉันไม่ได้คิดเกี่ยวกับมันด้วยตัวเอง สิ่งนี้มีประโยชน์เป็นพิเศษเพราะมันเก็บประวัติ (ถ้ามี) สำหรับ repo อื่น ๆ
BM5k

13

Githubมีคุณสมบัติที่เรียกว่าProject Pagesซึ่งคุณสามารถสร้างสาขาที่มีชื่อเฉพาะในโครงการของคุณเพื่อให้ไฟล์ที่ Github ให้บริการ คำแนะนำของพวกเขามีดังนี้:

$ cd /path/to/fancypants
$ git symbolic-ref HEAD refs/heads/gh-pages
$ rm .git/index
$ git clean -fdx

จากตรงนั้นคุณจะมีที่เก็บว่างซึ่งคุณสามารถเพิ่มเนื้อหาใหม่ของคุณ


10

คำตอบที่เลือกไว้ในปัจจุบันนั้นถูกต้องฉันจะเพิ่มโดยบังเอิญ ...

นี้เป็นจริงว่าวิธี github.com ช่วยให้ผู้ใช้สามารถสร้างหน้า Github สำหรับ Repos gh-pagesของพวกเขาผ่านสาขากำพร้าที่เรียกว่า ขั้นตอนที่สวยงามได้รับและอธิบายที่นี่:

https://help.github.com/articles/creating-project-pages-manually

โดยทั่วไปคำสั่ง git เพื่อตั้งค่านี้มีดังนี้:

  1. git checkout --orphan gh-pages (สร้างสาขาที่ไม่มี parent เรียกว่า gh-pages ใน repo ของคุณ)
  2. git rm -rf . (ลบไฟล์ใด ๆ จากแผนผังการทำงานสาขา)
  3. rm '.gitignore' (แม้แต่ gitignore)
  4. ตอนนี้เพิ่มเนื้อหาของเว็บไซต์ (เพิ่ม index.html ฯลฯ ) และกระทำและผลักดัน
  5. กำไร.

หมายเหตุคุณยังสามารถกำหนดโฟลเดอร์ / docsใน repo ของคุณให้เป็นที่มาของ "Project Site" ที่ Github ใช้เพื่อสร้างเว็บไซต์

หวังว่านี่จะช่วยได้!


3

บางครั้งฉันต้องการสร้างสาขาที่ว่างเปล่าในโครงการทันทีจากนั้นเริ่มทำงานฉันจะต้องออกคำสั่งดังนี้:

git checkout --orphan unrelated.branch.name
git rm --cached -r .
echo "init unrelated branch" > README.md
git add README.md
git commit -m "init unrelated branch"

1

หากเนื้อหาที่มีอยู่ของคุณได้รับการยืนยันแล้วคุณในตอนนี้ (Git 2.18 Q2 2018) สามารถแยกออกเป็นสาขาใหม่ของเด็กกำพร้าเนื่องจากการดำเนินการของ " git rebase -i --root" ได้รับการอัปเดตเพื่อใช้เครื่องจักรซีเควนเซอร์เพิ่มเติม

ซีเควนที่เป็นหนึ่งในขณะนี้ช่วยให้การปลูกโครงสร้างทั้งหมดของการกระทำอื่น ๆ กราฟ

ดูกระทำ 8fa6eea , กระทำ 9c85a1c , กระทำ ebddf39 , กระทำ 21d0764 , กระทำ d87d48b , กระทำ ba97aea (3 พฤษภาคม 2018) โดยโยฮันเน Schindelin (dscho )
(ผสานโดยJunio ​​C Hamano - gitster- in c5aa4bc , 30 พฤษภาคม 2018)

ซีเควนเซอร์: อนุญาตให้มีการแนะนำรูทใหม่

ในบริบทของ--rebase-mergesโหมดใหม่ซึ่งได้รับการออกแบบมาโดยเฉพาะเพื่อให้สามารถเปลี่ยนโทโพโลยีสาขาที่มีอยู่อย่างอิสระผู้ใช้อาจต้องการแยกการคอมมิตเข้าสู่สาขาใหม่ที่สมบูรณ์ซึ่งเริ่มต้นด้วยคอมมิชชันที่สร้างขึ้นใหม่

ตอนนี้เป็นไปได้ด้วยการแทรกคำสั่งreset [new root]ก่อนที่จะ pickส่งมอบการกระทำที่ต้องการที่จะกลายเป็นรากกระทำ ตัวอย่าง:

reset [new root]
pick 012345 a commit that is about to become a root commit
pick 234567 this commit will have the previous one as parent

สิ่งนี้ไม่ขัดแย้งกับการใช้resetคำสั่งอื่นเนื่องจาก [new root]ไม่ใช่ (บางส่วน) ชื่ออ้างอิงที่ถูกต้อง: ทั้งวงเล็บเปิดและพื้นที่ว่างนั้นผิดกฎหมายในชื่ออ้างอิง


0

พบสคริปต์นี้ที่http://wingolog.org/archives/2008/10/14/merging-in-unrelated-git-branchesและทำงานได้ดีมาก!

#!/bin/bash

set -e

if test -z "$2" -o -n "$3"; then
    echo "usage: $0 REPO BRANCHNAME" >&2
    exit 1
fi

repo=$1
branch=$2

git fetch "$repo" "$branch"

head=$(git rev-parse HEAD)
fetched=$(git rev-parse FETCH_HEAD)
headref=$(git rev-parse --symbolic-full-name HEAD)

git checkout $fetched .

tree=$(git write-tree)

newhead=$(echo "merged in branch '$branch' from $repo" | git commit-tree $tree -p $head -p $fetched)
git update-ref $headref $newhead $head
git reset --hard $headref

1
git fetch $REMOTE $REMOTE_BRANCH:$LOCAL_BRANCHผมเชื่อว่าผลเช่นเดียวกันสามารถทำได้โดยใช้ ฉันพลาดอะไรไปรึเปล่า?
hillu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.