Câu hỏi Tách kho lưu trữ Git lớn thành nhiều kho nhỏ hơn


Sau khi chuyển đổi thành công một kho lưu trữ 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 lưu trữ nhỏ hơn và duy trì lịch sử.

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

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

Vào hai kho lưu trữ trông như thế này:

MyABRepo/
   .git
   DIR_A/
   DIR_B/

My12Repo/
   .git
   DIR_1/
   DIR_2/

Tôi đã thử hướng dẫn sau trong câu hỏi trước đây 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 (Mở thư mục con (di chuyển) vào kho lưu trữ Git riêng biệt).


76
2017-10-11 22:32


gốc


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. - Ben Fowler
Đối với bất cứ 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: stackoverflow.com/a/19957874/164439 - thaddeusmt


Các câu trả lời:


Đ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 vẫn còn. Bạn có thể loại bỏ đ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 gặp lỗi liên quan đến .git-rewrite, bạn có thể thử cách 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

Điều này sẽ tạo 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ỳ con đường 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.


71
2017-10-11 23:37



'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. - Jakub Narębski
@ Jakub: Cảm ơn sự điều chỉnh. - unutbu
Tôi đã thử điều này và có một lỗi khi nó đã cố gắng để xóa các thư mục .git-viết lại ở cuối. - MikeM
-d <path-on-another-physical-disk> khác làm việc cho tôi và loại bỏ các lỗi 'mv' stange bên trong --tree-filter. - Vertigo
Tôi không nhận ra toàn bộ phân nhánh của filter-branch. Đối với những người không nhận thức, nó viết lại lịch sử, vì vậy nếu bạn có kế hoạch đẩy repo sau khi bạn đã làm điều này, băm cam kết sẽ khác nhau bây giờ và nó sẽ không hoạt động. - thaddeusmt


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 từ các bản sao / bản sao của kho lưu trữ ban đầu của bạn.

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' "$@") &&
    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 xóa từng nhánh hoặc thẻ không cần thiết của mỗi kho lưu trữ (ví dụ: nếu bạn có feature-x-for-AB chi nhánh, sau đó bạn có thể muốn xóa nó từ kho "12").


9
2017-10-12 00:01



: không phải là một nhân vật bình luận trong bash. Bạn nên sử dụng # thay thế. - Daenyth
@Daenyth, : là lệnh tích hợp truyền thống ( cũng được quy định trong POSIX). 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ó theo sở thích # bởi vì không phải tất cả các vỏ đều # với tư cách là người 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. - Chris Johnsen
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
Odd, với tôi nó dừng lại với git remote rm origin, mà luôn luôn có vẻ trở lại 1. Do đó tôi đã thay thế && bởi ; cho dòng này. - kynan
Nice, $ @ làm việc cho hơn hai dir khi cần. Khi kết thúc, tôi gọi git remote add origin $TARGET; git push origin master. - Walter A


Đây là một kịch bản ruby ​​sẽ làm điều đó. https://gist.github.com/4341033


3
2017-12-19 22:26





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ữ của chính 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.

3
2018-01-06 02:45





Cảm ơn câu trả lời của bạn nhưng tôi đã kết thúc chỉ cần sao chép kho hai lần sau đó xóa các tập tin tôi không muốn từ mỗi. 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 làm việc cho những gì tôi cần.

EDIT: Tất nhiên, điều tương tự đã được thực hiện trong My12Repo chống lạ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.


0
2017-10-20 17:34



Điều này không bảo tồn lịch sử cam kết. - Daenyth
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
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ơ của các 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ó. - Steve Clay