Làm cách nào để tôi có thể di chuyển một thư mục từ kho lưu trữ git sang kho lưu trữ mới trong khi vẫn duy trì lịch sử?


110

Tôi đã kế thừa một kho lưu trữ git chứa nhiều dự án trong các thư mục riêng biệt. Tôi muốn chia kho lưu trữ thành các kho lưu trữ riêng lẻ mới, một kho cho mỗi dự án và sau đó có kho lưu trữ chính chứa các dự án dưới dạng mô-đun con. Tôi muốn làm tất cả điều này trong khi vẫn duy trì lịch sử sửa đổi của các dự án riêng lẻ nếu có thể.

Tôi có thể sao chép kho lưu trữ cho từng dự án và xóa tất cả các dự án khác mỗi lần, nhưng có cách nào tốt hơn để tránh có lịch sử nhân bản trong từng kho lưu trữ dự án mới không?


2
Đã thêm thẻ git-submodules vì ​​thẻ này rất hữu ích để chuyển đổi một phần của repo thành một submodule.
idbrii

Câu trả lời:


99

Bạn có thể sử dụng git filter-branchđể viết lại lịch sử của một dự án. Từ tài liệu:

Để viết lại kho lưu trữ để trông như thể foodir / đã là gốc dự án của nó và loại bỏ tất cả lịch sử khác:

git filter-branch --subdirectory-filter foodir -- --all

Tạo một vài bản sao của kho lưu trữ của bạn, làm điều đó cho từng thư mục con bạn muốn tách ra và bạn sẽ kết thúc với những gì bạn đang tìm kiếm.


1
Điều gì sẽ xảy ra nếu tôi muốn loại trừ foodir và xóa tất cả lịch sử của nó?
saeedgnu

1
Lưu ý: nếu bạn muốn nhiều thư mục, Bạn sẽ cần chỉ định --subdirectory-filternhiều lần. EG git filter-branch --subdirectory-filter foodir --subdirectory-filter bardir, v.v. --subdirectorysẽ không mất nhiều dirs, nhưng có thể được chỉ định nhiều lần.
EnabrenTane

3
@Adam Nếu bạn muốn giữ lịch sử của foodirdự án gốc, không viết lại lịch sử của nó, chỉ git rm -r foodircần đủ (điều đó cũng sẽ xóa bản sao trong cây làm việc của bạn; nếu bạn không muốn, hãy sử dụng --cached). Nếu bạn muốn loại bỏ nó hoàn toàn từ lịch sử (trả lời câu hỏi @ ilius của quá), bạn muốn một cái gì đó giống nhưgit filter-branch --index-filter 'git rm -r --cached --ignore-unmatched foodir' -- --all
Brian Campbell

2
@ilius Xin lỗi, tôi đã bỏ lỡ câu hỏi của bạn trước đó, hãy xem câu trả lời của tôi ở trên để biết câu trả lời về cách xóa thư mục và lịch sử của nó.
Brian Campbell

2
@ilius Yep, điều đó cũng hoạt động. Đối với một dự án lớn, --index-filtergiải pháp này nhanh hơn --tree-filter, vì nó không phải thực sự kiểm tra các tệp, nó có thể thao tác trực tiếp với chỉ mục. Các --tree-filtercó thể là một chút dễ dàng hơn để sử dụng tuy nhiên, như bạn có thể sử dụng các hoạt động filsystem bình thường thay vì phải làm việc với các hoạt động chỉ số thao tác.
Brian Campbell

4

Để xuất một thư mục dưới dạng một kho lưu trữ mới, bạn cần:

  1. Để sao chép kho lưu trữ nơi chứa thư mục bạn muốn xuất.
  2. Để tạo một kho lưu trữ trống trên nhà cung cấp dịch vụ lưu trữ của bạn dưới dạng GitHub, để lưu trữ thư mục đã xuất.
  3. Mở thư mục kho lưu trữ nhân bản và chạy lệnh này:

    git subtree push --prefix=YourFolderNameToExport https://github.com/YourUserName/YourNewCleanRepoName master
    

1
git subtreekhông có sẵn dưới dạng gói Cygwin. Nếu bạn cần: stackoverflow.com/a/27116828/2484903
Jack Miller

2

Điểm của git là lịch sử được thể hiện trong mỗi cam kết bằng cách băm cam kết mẹ. Bạn có thể "phát lại" các cam kết (về cơ bản đây là cách svn-importers hoạt động) vào một kho lưu trữ mới và chỉ giữ mỗi dự án con. Tuy nhiên, điều này sẽ phá hủy ý nghĩa của các băm cam kết. Nếu bạn không có vấn đề gì với điều đó thì cứ như vậy.

Trong quá khứ, tôi chỉ nhân bản nó và tiếp tục. Điều này làm cho mọi thứ lớn hơn nhưng không gian đĩa rẻ; thời gian của tôi là tốn kém.

Tôi cũng không biết bất kỳ công cụ nào để tách một thư mục. Tôi cho rằng bạn có thể git-log trên thư mục để tìm tất cả các cam kết trên đó sau đó phát lại các cam kết đó với một cái gì đó như git-fast-export?


Tôi upvoted vì vì điều này không xứng đáng để được tiêu cực - Tôi chắc chắn sẽ không làm theo phương pháp này nhưng có thể thấy ông đã cố gắng
Alvin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.