การรวมหลายที่เก็บคอมไพล์


207

สมมติว่าฉันมีการตั้งค่าที่ดูเหมือน

phd/code/
phd/figures/
phd/thesis/

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

cd phd/code
git commit 
cd ../figures
git commit

มันเป็นการดีที่จะแสดง

cd phd
git commit

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

cd phd
git init
git add [[everything that's already in my other repositories]]

แต่นั่นดูเหมือนจะไม่เป็นหนึ่งซับ มีสิ่งใดบ้างgitที่สามารถช่วยฉันได้


ลองพิจารณาวิธีการที่ยอดเยี่ยมเช่นนี้: stackoverflow.com/questions/1425892/…
Johan Sjöberg

ลองพิจารณาอีกครั้ง: saintgimp.org/2013/01/22/…
ptim

join-git-repos.pyสคริปต์ไม่ได้งานที่ดีถ้าคุณมีที่เก็บแยกกันกับสาขาหลักที่คุณต้องการรวม
ทำเครื่องหมาย

คำตอบ:


149

นี่คือทางออกที่ฉันให้ที่นี่ :

  1. ก่อนอื่นทำการสำรองข้อมูลไดเรกทอรี phd ของคุณให้เสร็จสมบูรณ์: ฉันไม่ต้องการรับผิดชอบต่อการทำงานหนักของคุณ! ;-)

    $ cp -r phd phd-backup
    
  2. ย้ายเนื้อหาของphd/codeไปที่phd/code/codeและแก้ไขประวัติเพื่อให้ดูเหมือนว่ามีอยู่เสมอ (นี่ใช้คำสั่งตัวกรองสาขาของ git ):

    $ cd phd/code
    $ git filter-branch --index-filter \
        'git ls-files -s | sed "s#\t#&code/#" |
         GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
         git update-index --index-info &&
         mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
    
  3. เหมือนกันสำหรับเนื้อหาของphd/figuresและphd/thesis(เพียงแทนที่codeด้วยfiguresและthesis)

    ตอนนี้โครงสร้างไดเรกทอรีของคุณควรมีลักษณะดังนี้:

    phd
      |_code
      |    |_.git
      |    |_code
      |         |_(your code...)
      |_figures
      |    |_.git
      |    |_figures
      |         |_(your figures...)
      |_thesis
           |_.git
           |_thesis
                |_(your thesis...)
    
  4. จากนั้นสร้างที่เก็บ git ในไดเรกทอรีรากดึงทุกอย่างลงในนั้นและลบที่เก็บเก่า:

    $ cd phd
    $ git init
    
    $ git pull code
    $ rm -rf code/code
    $ rm -rf code/.git
    
    $ git pull figures --allow-unrelated-histories
    $ rm -rf figures/figures
    $ rm -rf figures/.git
    
    $ git pull thesis --allow-unrelated-histories
    $ rm -rf thesis/thesis
    $ rm -rf thesis/.git
    

    สุดท้ายคุณควรมีสิ่งที่คุณต้องการ:

    phd
      |_.git
      |_code
      |    |_(your code...)
      |_figures
      |    |_(your figures...)
      |_thesis
           |_(your thesis...)
    

อีกด้านหนึ่งที่ดีของโพรซีเดอร์นี้คือปล่อยไฟล์และไดเร็กทอรีที่ไม่มีเวอร์ชันไว้

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


เตือนเพียงคำเดียว: หากcodeไดเรกทอรีของคุณมีcodeไดเรกทอรีย่อยหรือไฟล์อยู่แล้วสิ่งต่าง ๆ อาจผิดปกติมาก (เหมือนเดิมfiguresและthesisแน่นอน) หากเป็นกรณีนี้ให้เปลี่ยนชื่อไดเรกทอรีหรือไฟล์นั้นก่อนที่จะทำตามขั้นตอนทั้งหมดนี้:

$ cd phd/code
$ git mv code code-repository-migration
$ git commit -m "preparing the code directory for migration"

และเมื่อขั้นตอนเสร็จสิ้นให้เพิ่มขั้นตอนสุดท้ายนี้:

$ cd phd
$ git mv code/code-repository-migration code/code
$ git commit -m "final step for code directory migration"

แน่นอนถ้าcodeไดเรกทอรีย่อยหรือไฟล์ไม่ได้เป็นรุ่นให้ใช้mvแทนgit mvและลืมเกี่ยวกับgit commits


13
ขอบคุณสำหรับตัวอย่างนี้ - มันทำสิ่งที่ฉันต้องการ (เมื่อฉันคิดว่าสำหรับ Mac OS X ไม่ได้ประมวลผล "\ t" (ฉันต้องใช้ ^ V ^ ฉันแทน)
Craig Trader

6
ฉันไม่สามารถทำให้มันทำงานได้ในตอนแรกและในที่สุดก็พบวิธีแก้ปัญหาบนกระดานข้อความเก่าอีกอัน ในบรรทัดสุดท้ายฉันต้องใส่เครื่องหมายคำพูดล้อมรอบชื่อไฟล์ดังนี้: mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEADแล้วก็ใช้งานได้ดีมาก!
Jorin

3
คำสั่ง funky filter-branch มาจาก man page ของ filter-branch คุณควรบอกว่าเป็น: ก) ควรนำมาประกอบอย่างถูกต้อง b) ฉันจะไม่เรียกใช้คำสั่งดังกล่าวเพียงเพราะบางคนที่มีชื่อเสียงสูงได้โพสต์ไว้ใน StackOverflow ฉันรู้ว่ามันมาจากหน้าคน
tymtam

5
ระวัง! MacOS X ไม่ใช้ส่วนขยายของ GNU sed ดังนั้นจึงไม่ทราบลำดับ \ t ผลที่ได้คือประวัติศาสตร์สับสน! ทางออกของฉันคือการวางรหัสในไฟล์สคริปต์เขียนตัวอักษร <TAB> จริงในนั้น จากเทอร์มินัลสามารถป้อนแท็บได้โดยกด ctrl + v แล้วเขียน <TAB> ฉันยังไม่ได้ลองวิธีแก้ปัญหาของ Craig
Gil Vegliach

4
ระวัง (2)! โปรดสังเกตด้วยว่าหากไฟล์หรือไดเรกทอรีบางตัวมียัติภังค์ ('-') คำสั่ง sed จะล้มเหลว ในกรณีนี้คุณสามารถแทนที่มันด้วย 's ~ \ t ~ & code / ~' ที่นี่ใช้ตรรกะเดียวกันระวัง '~' ในชื่อ
Gil Vegliach

75

git-stitch-repoจะประมวลผลเอาต์พุตของgit-fast-export --all --date-orderบนที่เก็บ git ที่กำหนดบนบรรทัดคำสั่งและสร้างสตรีมที่เหมาะสมสำหรับการgit-fast-importที่จะสร้างพื้นที่เก็บข้อมูลใหม่ที่มีการคอมมิตทั้งหมดในแผนผังการคอมมิทใหม่ที่เคารพประวัติของแหล่งเก็บข้อมูลทั้งหมด


33
เอ่อมันเป็นเครื่องมือของบุคคลที่สามไม่ใช่ส่วนหนึ่งของคอมไพล์… :-)
Aristotle Pagaltzis

1
แน่นอนตอนนี้คุณบอกฉัน :) โอ้ดีฉันคิดว่าฉันต้องเรียนรู้วิธีการติดตั้งแพคเกจ CPAN วันหนึ่ง ...
Will Robertson

1
ขอขอบคุณที่ชี้คำสั่งนั้นออกมา เพิ่งใช้มันเพื่อช่วยในการย้าย repos สองสามตัวจาก SVN ไปยัง Git
signine

1
คำเตือนอาจไม่ทำงานหากคุณมีสาขา / การรวม! จากหน้าgit-stich-repo : "git-stich-repo ทำงานได้อย่างสมบูรณ์แบบด้วยที่เก็บที่มีประวัติเชิงเส้น (ไม่มีการรวมกัน). การปรับปรุงอัลกอริธึมการเย็บที่เพิ่มเข้าไปในเวอร์ชั่น 0.06 ควรจะเหมาะสมกับการทำงานกับที่เก็บ สาขาและการผสาน "
ไบรอัน P

6
นี่เป็นสคริปต์ภายนอกคำตอบสั้นเกินไปและไม่เป็นประโยชน์จริง ๆ สคริปต์นี้มีปัญหาเกี่ยวกับการรวมการกระทำไม่หลายคนจะจัดการ Perl หรือ CPAN และนี่ไม่ใช่คำอธิบายที่ดีในคำตอบ ดังนั้น ... -1, ขอโทษ
Haralan Dobrev

20

บางทีง่ายๆ (คล้ายกับคำตอบก่อนหน้านี้ แต่ใช้คำสั่งที่ง่ายกว่า) การสร้างที่เก็บเก่าที่แยกจากกันเป็นการกระทำที่ย้ายเนื้อหาไปยังส่วนย่อยที่มีชื่อเหมาะสมเช่น:

$ cd phd/code
$ mkdir code
# This won't work literally, because * would also match the new code/ subdir, but you understand what I mean:
$ git mv * code/
$ git commit -m "preparing the code directory for migration"

จากนั้นจึงรวม repos ทั้งสามแยกเป็นหนึ่งใหม่โดยทำ smth เช่น:

$ cd ../..
$ mkdir phd.all
$ cd phd.all
$ git init
$ git pull ../phd/code
...

จากนั้นคุณจะบันทึกประวัติของคุณ แต่จะไปกับ repo เดียว


ไม่เป็นไร แต่ถ้าคุณรวม repo หนึ่งเข้าไปอีกอันหนึ่ง (เช่น phd เป็น repo ที่ไม่มีอยู่แล้ว) ถ้า phd มีโฟลเดอร์ที่มีชื่อเหมือนกับโฟลเดอร์ย่อยในไดเรคทอรีโค้ดคุณจะพบปัญหาเหมือนกับ 'git pull .. / phd / code 'ดึงคอมมิตทั้งหมดด้วยพา ธ แบบดั้งเดิมและเฉพาะตอนท้ายเท่านั้นที่ใช้ mv commit
tymtam

1
@Tymek: แต่นี่จะยังคงทำงานในสถานการณ์นั้นโดยไม่มีปัญหา สิ่งที่ไม่ดีคือเส้นทางในประวัติศาสตร์จะไม่ "ถูกต้อง" (ตรงกับเส้นทางใหม่)
imz - Ivan Zakharyaschev

19

คุณสามารถลองใช้กลยุทธ์การผสานทรีย่อย มันจะช่วยให้คุณรวม repo B เข้ากับ repo A ข้อดีเหนือgit-filter-branchคือไม่ต้องให้คุณเขียนประวัติ repo A ของคุณใหม่ (ทำลายผลรวมของ SHA1)


ลิงค์ไม่ทำงานและสิ่งนี้จะไม่รักษาประวัติศาสตร์ใช่ไหม
tymtam

3
@Tymek (ขออภัยส่วนของ kernel.org ยังคงลงหลังจากการละเมิดความปลอดภัย) มันทำลาย SHA1 ของ repo B. ที่เข้ามา แต่ A ยังคงสภาพเหมือนเดิม
Leif Gruenwoldt

2
นี่เป็นภาพสะท้อนของเอกสารนั้นในตอนนี้ftp.sunet.se/pub/Linux/kernel.org/software/scm/git/docs/howto/?hl=th
Leif Gruenwoldt

1
@LeifGruenwoldt ลิงก์ที่ 1 ใช้งานได้ในขณะนี้ และลิงก์มิเรอร์นั้นหายไปคุณควรลบมันออกไป
Vadim Kotov

9

โซลูชัน git-filter-branch ทำงานได้ดี แต่โปรดทราบว่าถ้า repo git ของคุณมาจากการนำเข้า SVN อาจล้มเหลวด้วยข้อความเช่น:

Rewrite 422a38a0e9d2c61098b98e6c56213ac83b7bacc2 (1/42)mv: cannot stat `/home/.../wikis/nodows/.git-rewrite/t/../index.new': No such file or directory

ในกรณีนี้คุณต้องแยกการแก้ไขเริ่มต้นจากตัวกรองสาขา - เช่นเปลี่ยนHEADที่ท้ายเป็น[SHA of 2nd revision]..HEAD- ดู:

http://www.git.code-experiments.com/blog/2010/03/merging-git-repositories.html


2
ขอบคุณ! ฉันเกาหัวแล้วทำไมมันถึงใช้งานไม่ได้! ธุรกรรมซื้อคืนมาจาก SVN แน่นอน
Arthur Maltson

1
ข้อผิดพลาดเดียวกันเมื่อฉันทำอย่างนั้น ทำให้ฉันมีความหวัง นอกจากนี้ลิงก์จะใช้งานไม่ได้
Ryan

คุณช่วยอธิบายสิ่งที่คุณหมายถึงโดย "เปลี่ยนหัวที่ไปที่ ... ", repo ของฉันมาจากการนำเข้า SVN และฉันกำลังเผชิญกับปัญหานี้อย่างแน่นอนจะขอบคุณช่วยเหลือมาก!

5

โซลูชัน @MiniQuark ช่วยฉันได้มาก แต่น่าเสียดายที่มันไม่ได้คำนึงถึงแท็กบัญชีที่อยู่ในแหล่งเก็บข้อมูลของแหล่งที่มา (อย่างน้อยก็ในกรณีของฉัน) ด้านล่างนี้เป็นการปรับปรุงคำตอบ @MiniQuark ของฉัน

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

    $ mkdir new_phd
    $ mkdir new_phd / รหัส
    $ mkdir new_phd / ตัวเลข
    $ mkdir new_phd / วิทยานิพนธ์

  2. ดึงที่เก็บแต่ละอันและดึงแท็กทั้งหมด (นำเสนอคำแนะนำเฉพาะสำหรับcodeไดเรกทอรีย่อย)

    $ cd new_phd / รหัส
    $ git เริ่มต้น
    $ git pull ../../original_phd/code master
    $ git fetch ../../original_phd/code refs / tags / *: refs / tags / *

  3. (นี่คือการปรับปรุงเพื่อจุดที่ 2 ในคำตอบ MiniQuark) ย้ายเนื้อหาของ new_phd/codeไปที่new_phd/code/codeและเพิ่มcode_prefeix ก่อนแต่ละแท็ก

    $ git filter-branch --index-filter 'git ls-files -s | sed "s- \ t \" * - & รหัส / - "| GIT_INDEX_FILE = $ GIT_INDEX_FILE.new ดัชนีการอัพเดทคอมไพล์ใหม่ - ดัชนีข้อมูล && mv $ GIT_INDEX_FILE '- แท็กชื่อตัวกรอง' sed 's -. * - code _ & - "'HEAD

  4. หลังจากทำเช่นนั้นจะมีแท็กมากถึงสองเท่าเหมือนก่อนที่จะทำการกรองสาขา แท็กเก่ายังคงอยู่ใน repo และเพิ่มแท็กใหม่พร้อมcode_คำนำหน้า

    $ git แท็ก
    mytag1
    code_mytag1

    ลบแท็กเก่าด้วยตนเอง:

    $ ls .git / refs / tags / * | grep -v "/ code_" | xargs rm

    ทำซ้ำจุด 2,3,4 สำหรับไดเรกทอรีย่อยอื่น ๆ

  5. ตอนนี้เรามีโครงสร้างของไดเรกทอรีใน @MiniQuark anwser point 3

  6. ทำตามข้อ 4 ของ MiniQuark anwser แต่หลังจากทำการดึงและก่อนที่จะทำการกำจัด.gitdir ให้ดึงแท็ก:

    $ git ดึงแคตตาล็อก refs / tags / *: refs / tags / *

    ดำเนินต่อไป ..

นี่เป็นเพียงทางออกอื่น หวังว่าจะช่วยใครบางคนมันช่วยฉัน :)


5

git-stitch-repo จากคำตอบของ Aristotle Pagaltzisใช้ได้กับที่เก็บที่มีประวัติเชิงเส้นเรียบง่ายเท่านั้น

คำตอบของ MiniQuarkใช้ได้กับที่เก็บทั้งหมด แต่ไม่สามารถจัดการกับแท็กและสาขาได้

ฉันสร้างโปรแกรมที่ทำงานในลักษณะเดียวกับที่ MiniQuark อธิบาย แต่ใช้การรวมหนึ่งคอมมิท (กับผู้ปกครอง N) และสร้างแท็กและสาขาทั้งหมดอีกครั้งเพื่อชี้ไปที่การคอมมิชชันเหล่านี้

ดูที่เก็บgit-merge-reposสำหรับตัวอย่างวิธีใช้



3

ที่จริงตอนนี้ git-stitch-repo รองรับสาขาและแท็กรวมถึงแท็กที่มีคำอธิบายประกอบ (ฉันพบว่ามีข้อผิดพลาดที่ฉันรายงานและได้รับการแก้ไข) สิ่งที่ฉันพบว่ามีประโยชน์คือด้วยแท็ก เนื่องจากแท็กแนบมากับคอมมิชชันและโซลูชันบางอย่าง (เช่นแนวทางของ Eric Lee) จึงไม่สามารถจัดการกับแท็กได้ คุณพยายามที่จะสร้างสาขานอกแท็กที่นำเข้าและมันจะเลิกทำการคอมไพล์ / ย้ายและส่งคุณกลับมาเหมือนที่เก็บรวมที่อยู่ใกล้กับที่เก็บแท็กที่มา นอกจากนี้ยังมีปัญหาหากคุณใช้แท็กเดียวกันกับที่เก็บหลายแห่งที่คุณ 'รวม / รวม' ตัวอย่างเช่นหากคุณมีโฆษณา A repo ของ A ทั้งคู่มีแท็ก rel_1.0 คุณรวม repo A และ repo B เข้ากับ repo AB เนื่องจาก rel_1.0 แท็กอยู่ในการกระทำที่แตกต่างกันสองรายการ (หนึ่งแท็กสำหรับ A และอีกแท็กสำหรับ B) แท็กใดที่จะปรากฏใน AB อาจเป็นแท็กจาก repo A ที่นำเข้าหรือจาก repo B ที่นำเข้า แต่ไม่ใช่ทั้งคู่

git-stitch-repo ช่วยแก้ไขปัญหานั้นด้วยการสร้าง rel_1.0-A และ rel_1.0-B แท็ก คุณอาจไม่สามารถชำระเงินแท็ก rel_1.0 และคาดหวังว่าทั้งคู่ แต่อย่างน้อยคุณสามารถเห็นได้ทั้งสองอย่างและในทางทฤษฎีคุณสามารถรวมเข้ากับสาขาท้องถิ่นทั่วไปจากนั้นสร้างแท็ก rel_1.0 บนสาขาที่ผสานนั้น ผสานและไม่เปลี่ยนรหัสต้นฉบับ) จะดีกว่าถ้าคุณทำงานกับสาขาเนื่องจากคุณสามารถรวมเหมือนสาขาจาก repo แต่ละแห่งเป็นสาขาท้องถิ่น (dev-a และ dev-b สามารถรวมเข้ากับสาขา dev ท้องถิ่นซึ่งสามารถผลักไปที่จุดกำเนิด)


2

ลำดับที่คุณแนะนำ

git init
git add *
git commit -a -m "import everything"

จะทำงานได้ แต่คุณจะสูญเสียประวัติการกระทำของคุณ


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

1

ในการรวมโปรเจ็กต์ที่สองภายใน mainProject:

A) ในโครงการที่สอง

git fast-export --all --date-order > /tmp/secondProjectExport

B) ในโครงการหลัก:

git checkout -b secondProject
git fast-import --force < /tmp/secondProjectExport

ในสาขานี้ทำการแปลงอย่างหนักทั้งหมดที่คุณต้องทำและกระทำ

C) จากนั้นกลับไปที่ต้นแบบและการผสานแบบคลาสสิกระหว่างสองสาขา:

git checkout master
git merge secondProject

สิ่งนี้จะรวมไฟล์และโฟลเดอร์ทั้งหมดไว้ที่รูทของโครงการ git ทั้งสองเข้าในโครงการเดียว ฉันสงสัยว่า _anyone_ ต้องการให้สิ่งนี้เกิดขึ้น
Clintm

0

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

https://github.com/Oakleon/git-join-repos


0

สคริปต์ทุบตีนี้แก้ปัญหาอักขระแท็บ sed (บน MacOS เป็นต้น) และปัญหาไฟล์ที่หายไป

export SUBREPO="subrepo"; # <= your subrepository name here
export TABULATOR=`printf '\t'`;
FILTER='git ls-files -s | sed "s#${TABULATOR}#&${SUBREPO}/#" |
  GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
  git update-index --index-info &&
  if [ -f "$GIT_INDEX_FILE.new" ]; then mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE; else echo "git filter skipped missing file: $GIT_INXEX_FILE.new"; fi'

git filter-branch --index-filter "$FILTER" HEAD

นี่คือการรวมกันของโพสต์miniquark , marius-butucและryan ไชโย!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.