2010-10-11 62 views
73

Sau khi chuyển đổi thành công kho SVN sang Git, bây giờ tôi có một kho lưu trữ Git rất lớn mà tôi muốn chia nhỏ thành nhiều kho nhỏ hơn và duy trì lịch sử.Tách kho Git lớn thành nhiều cái nhỏ hơn

Vì vậy, ai đó có thể giúp phá vỡ một repo rằng có thể trông như thế này:

MyHugeRepo/ 
    .git/ 
    DIR_A/ 
    DIR_B/ 
    DIR_1/ 
    DIR_2/ 

Into hai kho mà trông như thế này:

MyABRepo/ 
    .git 
    DIR_A/ 
    DIR_B/ 

My12Repo/ 
    .git 
    DIR_1/ 
    DIR_2/ 

tôi đã cố gắng hướng dẫn trong này sau câu hỏi trước nhưng nó không thực sự phù hợp khi cố gắng đặt nhiều thư mục vào một repo riêng biệt (Detach (move) subdirectory into separate Git repository).

+5

Khi bạn hài lòng với câu trả lời, vui lòng đánh dấu câu trả lời là được chấp nhận. –

+0

Đối với bất kỳ ai tìm cách chia nhỏ nhiều thư mục (lồng nhau) thành một repo mới (thay vì tìm cách xóa nhiều thư mục, điều này có thể khó hơn đối với một số dự án), câu trả lời này hữu ích cho tôi: http://stackoverflow.com/a/19957874/164439 – thaddeusmt

Trả lời

69

Điều này sẽ thiết lập MyABRepo; bạn có thể làm My12Repo tương tự như vậy.

git clone MyHugeRepo/ MyABRepo.tmp/ 
cd MyABRepo.tmp 
git filter-branch --prune-empty --index-filter 'git rm --cached --ignore-unmatch DIR_1/* DIR_2/*' HEAD 

Tham chiếu đến .git/refs/original/refs/heads/master master. Bạn có thể xóa điều đó bằng:

cd .. 
git clone MyABRepo.tmp MyABRepo 

Nếu mọi việc suôn sẻ, bạn có thể xóa MyABRepo.tmp.


Nếu vì một số lý do bạn nhận được một lỗi liên quan đến .git-viết lại, bạn có thể thử này:

git clone MyHugeRepo/ MyABRepo.tmp/ 
cd MyABRepo.tmp 
git filter-branch -d /tmp/git-rewrite.tmp --prune-empty --index-filter 'git rm --cached --ignore-unmatch DIR_1/* DIR_2/*' HEAD 
cd .. 
git clone MyABRepo.tmp MyABRepo 

này sẽ tạo ra và sử dụng /tmp/git-rewrite.tmp như một thư mục tạm thời , thay vì .git-rewrite. Đương nhiên, bạn có thể thay thế bất kỳ đường dẫn nào bạn muốn thay vì /tmp/git-rewrite.tmp, miễn là bạn có quyền ghi và thư mục chưa tồn tại.

+0

'git filter-branch' manpage khuyến nghị tạo một bản sao mới của kho lưu trữ được viết lại thay vì bước cuối cùng được đề cập ở trên. –

+0

@Jakub: Cảm ơn bạn đã sửa. – unutbu

+0

Tôi đã thử điều này và gặp lỗi khi cố xóa thư mục .git-rewrite ở cuối. – MikeM

8

Bạn có thể sử dụng git filter-branch --index-filter với git rm --cached để xóa các thư mục không mong muốn khỏi các bản sao/bản sao của kho lưu trữ ban đầu.

Ví dụ:

trim_repo() { : trim_repo src dst dir-to-trim-out... 
    : uses printf %q: needs bash, zsh, or maybe ksh 
    git clone "$1" "$2" && 
    (
    cd "$2" && 
    shift 2 && 

    : mirror original branches && 
    git checkout HEAD~0 2>/dev/null && 
    d=$(printf ' %q' "[email protected]") && 
    git for-each-ref --shell --format=' 
     o=%(refname:short) b=${o#origin/} && 
     if test -n "$b" && test "$b" != HEAD; then 
     git branch --force --no-track "$b" "$o" 
     fi 
    ' refs/remotes/origin/ | sh -e && 
    git checkout - && 
    git remote rm origin && 

    : do the filtering && 
    git filter-branch \ 
     --index-filter 'git rm --ignore-unmatch --cached -r -- '"$d" \ 
     --tag-name-filter cat \ 
     --prune-empty \ 
     -- --all 
) 
} 
trim_repo MyHugeRepo MyABRepo DIR_1 DIR_2 
trim_repo MyHugeRepo My12Repo DIR_A DIR_B 

Bạn sẽ cần phải tự xóa các chi nhánh không cần thiết của từng kho hoặc thẻ (ví dụ: nếu bạn đã có một tính năng-x-cho-AB chi nhánh, sau đó bạn có thể muốn xóa từ kho lưu trữ "12").

+0

':' không phải là một ký tự bình luận trong bash. Bạn nên sử dụng '#' thay thế. – Daenyth

+3

@Daenyth, ':' là lệnh được xây dựng theo kiểu truyền thống ([cũng được chỉ rõ trong POSIX] (http://www.opengroup.org/onlinepubs/009695399/utilities/colon.html)). Nó được bao gồm trong * bash *, nhưng nó không phải là một bình luận. Tôi đặc biệt sử dụng nó ưu tiên '#' vì không phải tất cả các trình bao lấy '#' làm trình giới thiệu nhận xét trong tất cả các ngữ cảnh (ví dụ: tương tác * zsh * mà không bật tùy chọn INTERACTIVE_COMMENTS). Sử dụng ':' làm cho toàn bộ văn bản phù hợp để dán vào bất kỳ trình bao tương tác nào cũng như lưu trong tệp tập lệnh. –

+0

Rực rỡ! Chỉ có giải pháp tôi thấy rằng giữ tất cả các chi nhánh còn nguyên vẹn – pheelicks

0

Cảm ơn câu trả lời của bạn nhưng tôi đã chỉ sao chép kho lưu trữ hai lần sau đó xóa các tệp tôi không muốn từ mỗi tệp. Tôi sẽ sử dụng bộ lọc-chi nhánh vào một ngày sau đó để loại bỏ tất cả các cam kết cho các tập tin đã xóa vì chúng đã được kiểm soát phiên bản ở nơi khác.

cp -R MyHugeRepo MyABRepo 
cp -R MyHugeRepo My12Repo 

cd MyABRepo/ 
rm -Rf DIR_1/ DIR_2/ 
git add -A 
git commit -a 

Điều này phù hợp với những gì tôi cần.

EDIT: Tất nhiên, điều tương tự đã được thực hiện trong My12Repo đối với thư mục A và B. Điều này đã cho tôi hai repos với lịch sử giống hệt nhau đến mức tôi đã xóa các thư mục không mong muốn.

+1

Điều này không giữ lại lịch sử cam kết. – Daenyth

+0

như thế nào? Tôi vẫn có tất cả lịch sử, ngay cả đối với các tập tin đã xóa. – MikeM

+1

Vì yêu cầu của bạn không phải là repo A phải giả vờ repo B chưa bao giờ tồn tại, tôi nghĩ điều này (để lại hồ sơ cam kết chỉ ảnh hưởng B) là một giải pháp thích hợp. Tốt hơn để lặp lại một chút lịch sử hơn xoài nó. –

3

Dự án git_split là một tập lệnh đơn giản thực hiện chính xác những gì bạn đang tìm kiếm.https://github.com/vangorra/git_split

Chuyển thư mục git vào kho lưu trữ riêng của chúng ở vị trí riêng của chúng. Không kinh doanh vui nhộn. Kịch bản lệnh này sẽ lấy một thư mục hiện có trong kho lưu trữ git của bạn và biến thư mục đó thành một kho lưu trữ độc lập của riêng nó. Trên đường đi, nó sẽ sao chép toàn bộ lịch sử thay đổi cho thư mục bạn đã cung cấp.

./git_split.sh <src_repo> <src_branch> <relative_dir_path> <dest_repo> 
     src_repo - The source repo to pull from. 
     src_branch - The branch of the source repo to pull from. (usually master) 
     relative_dir_path - Relative path of the directory in the source repo to split. 
     dest_repo - The repo to push to. 
Các vấn đề liên quan