2016-05-10 17 views
8

Mặc dù liên quan đến hai phụ, tôi yêu cầu này như là một câu hỏi kết hợp bởi vì cách nó được chia thành các phần không phải là những gì quan trọng. Tôi mở ra những cách khác nhau để đạt được những gì tôi muốn miễn là kết quả cuối cùng giữ lại tất cả lịch sử có ý nghĩa và khả năng kiểm tra, nghiên cứu và xây dựng/thử nghiệm các phiên bản lịch sử. Mục tiêu là để nghỉ hưu hg và mô hình subrepo đã được sử dụng cho đến nay và di chuyển đến một cây thống nhất trong git, nhưng không hy sinh lịch sử.hg để git chuyển đổi và subrepo hợp nhất

Tôi đang bắt đầu với một kho lưu trữ Mercurial bao gồm một số mã cấp cao nhất và một số phân đoạn phụ mà phần lớn lịch sử thú vị nằm. Các subrepos có một số phân nhánh/sáp nhập, nhưng không có gì quá điên rồ. Kết quả cuối cùng tôi muốn đạt được là một kho git duy nhất, không có các môđun con, chẳng hạn rằng:

  • Đối với mỗi cam kết trong bản gốc top-level repo hg, có một git commit để kiểm tra ra giống hệt nhau cây như bạn muốn kiểm tra ra hg tương ứng cam kết với tất cả các cam kết subrepo tham chiếu của nó.

  • Các cam kết git này tương ứng với các cam kết hg cấp cao nhất liên tiếp là hậu duệ của nhau, với các cam kết tương ứng với tất cả các cam kết phụ có liên quan ở giữa.

Ý tưởng cơ bản tôi đã cho làm thế nào để đạt được điều này là để lặp qua tất cả các cấp cao nhất hg cam kết, và đối với mỗi cấp cao nhất cam kết rằng những thay đổi .hgsubstate, cũng lặp qua tất cả các đường dẫn từ phiên bản cũ sang sửa đổi mới cho submodule (có thể liên quan đến phân nhánh). Tại mỗi bước:

  • Kiểm tra bản sửa đổi hg phù hợp cho cấp cao nhất và tất cả các phân mục phụ.
  • Xóa mọi thứ khỏi chỉ mục git.
  • Giai đoạn mọi thứ được kiểm tra từ hg đến chỉ mục git.
  • Sử dụng git-write-treegit-commit-tree để tạo cam kết với cha mẹ mong muốn, sử dụng quyền tác giả, ngày tháng và thư cam kết từ cam kết hg tương ứng.
  • Ghi lại sự tương ứng giữa cam kết git mới và hg để sử dụng trong việc tạo ra cha mẹ của các cam kết trong tương lai.

Công việc này có nên không? Có cách nào tốt hơn để đạt được những gì tôi muốn, có lẽ làm sụp đổ subrepo với hg đầu tiên? Điều lớn nhất tôi không rõ ràng là làm thế nào để thực hiện lặp đi lặp lại mong muốn, vì vậy lời khuyên thiết thực cho làm thế nào để đạt được nó sẽ là tuyệt vời.

Một hạn chế bổ sung: bản gốc có liên quan đến nội dung không thể xuất bản (bước bổ sung git-filter-branch sau khi chuyển đổi cơ bản được thực hiện) để các giải pháp liên quan đến việc tải lên repo để xử lý bởi bên thứ ba là không khả thi.

+0

Dường như với tôi như 'git fast-import' đã được tạo cho các công việc như thế này. – jthill

+0

@jthill: Bạn có thể xây dựng được không? Tôi không thấy bất cứ điều gì về việc sử dụng nó để hợp nhất lịch sử subrepo mà là một nhiệm vụ rất phi thường ngay cả ở mức cao. –

+0

Điều cần hiểu là, dag cam kết lịch sử là tất cả có. Nó không phải là một trừu tượng, và không có trạng thái toàn cầu. Bạn có thể sử dụng '.hgsubs' và' .hgsubstate' để tìm các phân đoạn con và nhập đệ quy chúng vào kho lưu trữ git chính của bạn, bắt đầu từ ví dụ: 'hg manifest --debug' đầu ra. Một khi bạn đã có tất cả chúng trong một repo git, bạn có thể xây dựng lịch sử bổ sung tùy ý bất kỳ cách nào bạn muốn. Điều này sẽ nhanh hơn rất nhiều so với các thao tác đọc cây/viết-cây. Việc xây dựng cần thiết tại thời điểm đó chỉ là chính xác những gì bạn muốn làm lịch sử kết quả của bạn? – jthill

Trả lời

2

Không liên quan Offtopic

tôi chắc chắn rằng, bạn đã chọn ý tưởng tồi tệ nhất của di cư (từ Mercurial để Git), nhưng nó là sự lựa chọn của bạn và trách nhiệm của bạn cuối cùng

Migration nhiên

Kiến thức của tôi về Git khá yếu, do đó đối với Mercurial + subrepo -> Git nguyên khối tôi có thể xem và mô tả theo cách như vậy:

Mercurial + subrepo -> khối Mercurial -> khối repo Git

  • Để hợp nhất lịch sử subrepos với lịch sử wrapper-repo bạn có thể (với chỉnh từ bình luận alexis của) sử dụng my idea from earlier question về Chuyển đổi mở rộng
  • Monolithic Mercurial repo với lịch sử được đánh bóng bổ sung (một gốc, không có đầu ẩn danh nào không có dấu trang được liên kết ít nhất) có thể dễ dàng đẩy trống Git-repo, sử dụng hg-git
5

Điều bạn viết có thể hoặc không giải quyết được vấn đề. Nhưng nó không đơn giản. Vấn đề chính là bạn cần cam kết theo thứ tự sao cho subrepos của bạn và repo chính là nhất quán. Tôi đã tạo lại vấn đề này ở quy mô nhỏ và có thể có sự nhất quán giữa subrepos cũng vậy).

Giải pháp của tôi:

  1. Sử dụng phần mở rộng chuyển đổi hg, tôi chuyển repo chính để một repo mà không subrepos (và các thông tin có liên quan).

    cd main 
    awk '{ print $1}' .hgsub | xargs -n 1 echo 'exclude' > ../filemap 
    echo exclude .hgsub >> ../filemap 
    echo exclude .hgsubstate >> ../filemap 
    cd .. 
    hg convert --filemap filemap main mainConv 
    cd mainConv 
    hg update 
    
  2. Chuyển đổi subrepo bằng cách sử dụng đổi tên trong --filemap.

    cd .. 
    echo rename . subRepo > subFileMap 
    hg convert --filemap main/subRepo subRepoConv 
    cd subRepoConv 
    hg update 
    
  3. Kéo subrepos vào repo chính đã chuyển đổi.

    cd ../mainConv 
    hg pull -f ../subRepoConv 
    
  4. Bạn sẽ thấy nhiều đầu trong repo trong khi kéo (vì subrepo có đầu riêng). Merge chúng:

    hg heads 
    hg merge <RevID from subrepo (not main repo)> 
    hg ci -mMergeOfSubRepo 
    

Bạn phải lặp lại 3 & 4 cho mỗi subrepo.

  1. Nhưng các cam kết sẽ không được sắp xếp. Vì vậy, đặt chúng theo thứ tự như thực hiện ở đây https://stackoverflow.com/a/16012597:

    cd .. 
    hg clone -r 0 mainConv mainOrdered 
    cd mainOrdered 
    for REV in `hg log -R ../main -r 'sort(1:tip, date)' --template '{rev}\n'` 
    do 
          hg pull ../main -r $REV 
    done 
    

Bây giờ chuyển đổi này đã ra lệnh repo lanh lợi để git sử dụng http://repo.or.cz/w/fast-export.git:

cd .. 
git clone git://repo.or.cz/fast-export.git 
git init mainGit 
cd mainGit 
../fast-export/hg-fast-export.sh -r ../mainOrdered 
git checkout HEAD 
+0

Bất kỳ biến chứng nào tôi cần lưu ý khi đặt chúng theo thứ tự khi lịch sử không hoàn toàn tuyến tính? Tôi không hiểu làm thế nào mà một phần được cho là hoạt động. –

+0

Có, tôi đã giả định rằng ngày tháng từ cùng một múi giờ. . Và gần như được đồng bộ hóa cho tất cả các nhà giao dịch. Lịch sử không bắt buộc phải tuyến tính để phân loại qua các ngày. Phần đó sắp xếp tất cả các sửa đổi trên cơ sở ngày tháng và sau đó kéo tất cả các bản sửa đổi, từng phiên bản một cho repo mới. Nó có thể tăng kích thước như đã đề cập trong liên kết tôi chia sẻ vì tính toán delta. (Đối với tôi nó giảm nhưng tôi không nghĩ rằng đó sẽ là trường hợp.) – khrm

+0

Câu trả lời này có thể là một cái gì đó, nhưng tôi không hiểu từ nội dung hiện tại cho dù/làm thế nào nó bảo tồn cấu trúc lịch sử hoặc đáp ứng các ràng buộc tôi đã yêu cầu trong câu hỏi. Sự thiếu hiểu biết của tôi với hg có thể là một phần của nguyên nhân, nhưng trong mọi trường hợp, tôi không cảm thấy đúng khi trao phần thưởng vào thời điểm này. (Tôi nghĩ rằng SO có thể gán nó theo mặc định khi tôi để cho nó hết hạn, mặc dù. Nếu không, và câu trả lời này hóa ra là những gì tôi kết thúc bằng cách sử dụng, tôi sẽ chỉ chạy một bounty và giải thưởng nó.) –

4

Yes. Đặt cược tốt nhất của bạn là tạo các cam kết thủ công với git commit-tree. Có rất nhiều công cụ chuyển đổi, nhưng chúng sẽ không bao giờ cung cấp cho bạn chính xác những gì bạn muốn. Mặt khác, một kịch bản viết tay sẽ cung cấp cho bạn tất cả sự linh hoạt mà bạn cần.

Tôi đã viết nhiều tập lệnh này, bao gồm cả git remote-hg chính nó.

+0

Tôi nghi ngờ đây là cách tiếp cận mà tôi sẽ phải mất, nhưng câu trả lời này không thực sự thêm bất cứ điều gì mới để làm cho nó xứng đáng với tiền thưởng. Nếu nó có chi tiết hơn và lời khuyên về các công cụ để sử dụng để làm cho kịch bản dễ dàng, tôi sẽ xem xét nó, nhưng bây giờ đã quá muộn, trừ khi tôi mở một tiền thưởng mới sau đó. –

+0

Vì vậy? Bạn đã hỏi liệu 'git write-tree' và' git commit-tree' có phải là cách tiếp cận đúng hay không, tôi đang nói với bạn nó. Bạn có muốn tôi bảo bạn sử dụng 'git remote-hg', hay cái gì đó" thêm "cái gì mới? Nó sẽ không giúp bạn. Tôi đã nói với bạn; bạn phải kiểm tra mỗi cam kết Mercurial, và tạo ra các cam kết bằng tay, nó đơn giản, và nó hoạt động. – FelipeC

+0

Tôi không có ý xúc phạm hay thù địch. Xin lỗi nếu bình luận của tôi đi qua theo cách đó. –

1

Đây là những gì tôi đã làm để giải quyết một vấn đề tương tự:

  1. Chuyển đổi mỗi kho lanh lợi với fast-export
  2. Thêm các thư mục của tiểu kho như từ xa trong repo mẹ
  3. Trong phụ huynh repo git checkout -b để đặt tên cho mỗi kho subrepo
  4. git read-tree --prefix=pathsubrepo/ -u subrepobranch cho mỗi subrepo

này là nhiều hơn hoặc ít hơn những gì tôi đã làm trong một chi tiết chút (chuyển thể từ lịch sử bash ... nhưng không thực sự chạy)

Bước 1

cd ~ 
git clone git://repo.or.cz/fast-export.git 
git init parent_repo 
cd parent_repo 
~/fast-export/hg-fast-export.sh -r /path/to/old/mercurial/parent 
git checkout HEAD 
cd ~ 
git init subrepo1 
cd subrepo1 
~/fast-export/hg-fast-export.sh -r /path/to/old/mercurial/parent/subrepo1 
git checkout HEAD 
cd ~ 
git init subrepo2 
cd subrepo2 
~/fast-export/hg-fast-export.sh -r /path/to/old/mercurial/parent/subrepo2 
git checkout HEAD 

Bước 2

cd ~/parent_repo 
git remote add sub1 $HOME/subrepo1/ 
git remote add sub2 $HOME/subrepo2/ 

Bước 3

cd ~/parent_repo 
git checkout -b sub1master sub1/master 
git checkout -b sub2master sub2/master 

Bước 4

cd ~/parent_repo 
git read-tree --prefix=subrepo1/ -u sub1master 
git read-tree --prefix=subrepo1/ -u sub2master 

Khi đã xong, bạn có thể git branch -D sub1mastergit branch -D sub2master vì bạn không cần chúng nữa.

+0

Tôi không thấy cách hoạt động của tính năng này. Ngay sau khi bạn chuyển đổi repos thành git mà không hợp nhất chúng trước, bạn đã mất tất cả thông tin về các bản sửa đổi phụ được liên kết với bản sửa đổi cấp cao nhất, vì tệp '.hgsubstate' tham chiếu đến bản sửa đổi hg, chứ không phải sửa đổi git. Trừ khi tất nhiên bạn giữ một bản đồ giữa hai - nhưng tôi không thấy rằng bất cứ nơi nào trong thủ tục bạn mô tả. –

-1

Dùng thử Hg < -> Bộ chuyển đổi Git: FbShipIt. Hầu hết những gì bạn mô tả sẽ hoạt động tốt với công cụ chuyển đổi cam kết này, sao chép các cam kết giữa Mercurial và Git.

FbShipIt có báo trước: nó không hiểu các cam kết hợp nhất, nhưng nó có thể được làm việc xung quanh thông qua git rebase.

+0

Tôi không thấy bất kỳ dấu hiệu nào cho thấy câu trả lời này dành riêng cho câu hỏi. Không có gì về việc sáp nhập subrepos (phần cứng), và trong khi câu hỏi cho biết có các cam kết hợp nhất, câu trả lời cung cấp 'git rebase' như một giải pháp cho công cụ không hỗ trợ cam kết hợp nhất, mặc dù thực tế là repo nguồn là hg, chứ không phải git và do đó các công cụ git sẽ vô dụng để giải quyết các vấn đề không tương thích với công cụ chuyển đổi trước khi thực hiện chuyển đổi. –

1

Có vẻ như những gì tôi đã bỏ lỡ trong câu hỏi của mình và thảo luận về các giải pháp có thể là sự hiểu biết đúng đắn về lý thuyết đồ thị có liên quan. Các ý tưởng như "lặp qua tất cả các đường dẫn từ phiên bản cũ sang bản sửa đổi mới" không thực sự được xác định rõ ràng, hoặc ít nhất không phản ánh những gì tôi mong đợi chúng phản ánh. Đến với nó từ một quan điểm nghiêm ngặt hơn, tôi nghĩ rằng tôi có một cách tiếp cận hoạt động.

Để bắt đầu, vấn đề: Các bản sửa đổi phụ chỉ thể hiện trạng thái của các subtrees riêng của họ tại một điểm nhất định trong lịch sử. Tôi muốn ánh xạ chúng tới các phiên bản đại diện cho trạng thái của toàn bộ cây kết hợp. Sau đó, subrepo DAG s có thể được hợp nhất với DAG cấp cao nhất theo cách có ý nghĩa.

Đối với bản R thay đổi subrepo, chúng tôi có thể yêu cầu các bản sửa đổi cấp cao nhất (hoặc phụ huynh-repo, nếu chúng tôi có nhiều cấp độ phụ) bao gồm R hoặc bất kỳ hậu duệ nào của R. Giả sử một gốc đơn. các bản sửa đổi có Lowest Common Ancestor (hoặc có thể nhiều hơn một), có vẻ như là một ứng cử viên tốt. Thật vậy, nếu đầu cấp phiên bản S chúng tôi sử dụng với R không phải là một tổ tiên chung của các phiên bản mà sử dụng R hoặc hậu duệ của nó (nhưng các bản đồ là nếu không hợp lý), sau đó R sẽ có một hậu duệ R' có liên quan cấp cao nhất phiên bản S 'không phải là hậu duệ của S.Nói cách khác, lịch sử bắt nguồn từ subrepo sẽ có những bước nhảy lộn xộn/vô lý giữa các phiên bản của cây cấp cao nhất. Bây giờ, nếu chúng ta muốn chọn một tổ tiên chung, cái thấp nhất có ý nghĩa từ quan điểm của việc sửa đổi một cái gì đó có thể được kiểm tra, xây dựng và thử nghiệm, và từ quan điểm đưa ra một ý tưởng hợp lý trạng thái của repo cấp cao nhất (và các subrepos khác) là vào thời điểm các thay đổi trong subrepo được thực hiện. Gốc của toàn bộ DAG cấp cao nhất tất nhiên cũng sẽ hoạt động, nhưng nó sẽ không đưa ra các bản sửa đổi có ý nghĩa, có thể sử dụng có thể được kiểm tra; việc chọn gốc sẽ tương đương (từ một quan điểm khả năng sử dụng) thành một repo-merge ngây thơ có một gốc cho mỗi subrepo và chỉ hợp nhất từ ​​lịch sử subrepo bất cứ khi nào repo cấp cao cập nhật các phiên bản mà nó đang sử dụng.

Vì vậy, nếu chúng ta có thể sử dụng LCA để gán một top-level sửa đổi T (R) cho mỗi subrepo phiên bản R, như thế nào mà chuyển thành

Bất cứ khi nào một phiên bản subrepo R có T (R) khác biệt với T (P) cho mỗi P mẹ R của R, nó kết hợp hiệu quả các thay đổi mới từ repo cấp cao nhất (và các subrepos khác) vào lịch sử subrepo. Chuyển đổi phải thể hiện điều này dưới dạng hai cam kết:

  1. Đường phụ thực tế cam kết R, sử dụng bản sửa đổi cấp cao nhất cũ. Nếu R có một đơn vị mẹ P (không phải là một cam kết hợp nhất), thì đây sẽ là T (P). Nếu R có nhiều cha mẹ, không rõ liệu có một sự lựa chọn hoàn hảo nào để sử dụng, nhưng T (P) cho bất kỳ P cha mẹ nào là hợp lý.

  2. Cam kết hợp nhất sáp nhập trở lại chuyển đổi C (T (R)) của cam kết cấp cao nhất T (R) được liên kết với R, trong đó C (T (R)) vừa sáp nhập (1) ở trên .

Ngoài C (T (R)), tham chiếu (1) làm phụ huynh hợp nhất, tất cả các tham chiếu khác đến R trong chuyển đổi nên sử dụng (2). Điều này bao gồm các chuyển đổi của bất kỳ hậu duệ nào của T (R) trong repo cấp cao nhất sử dụng R sửa đổi của subrepo này, và các chuyển đổi của trẻ em trực tiếp của R chính nó.

Tôi tin rằng mô tả ở trên (mặc dù ít được nói) chỉ định tất cả những gì cần thiết để hợp nhất các DAG cấp cao nhất và subrepo. Mỗi bản sửa đổi subrepo nhận được phiên bản đầy đủ của cây và kết thúc kết nối thành một DAG thống nhất cho repo được chuyển đổi thông qua "commit commits" (khi subrepo sáp nhập một bản sửa đổi cấp cao nhất liên quan và khi cấp cao nhất sáp nhập các bản sửa đổi subrepo đã thay đổi). Bước cuối cùng của việc tạo ra repo git, sau đó, chỉ đơn giản là phát lại DAG đã hợp nhất, hoặc ở dạng được sắp xếp topo hoặc thông qua một bước đi sâu đầu tiên, sao cho mỗi git commit-tree đã có tất cả các bản sửa đổi chính cần có.

Các vấn đề liên quan