Làm cách nào để di chuyển một mô hình con Git hiện có trong kho Git?


356

Tôi muốn thay đổi tên thư mục của một mô hình con Git trong siêu dự án Git của tôi.

Giả sử tôi có mục sau trong .gitmodulestệp của mình :

[submodule ".emacs.d/vimpulse"]  
path = .emacs.d/vimpulse  
url = git://gitorious.org/vimpulse/vimpulse.git

Tôi phải gõ gì để di chuyển .emacs.d/vimpulsethư mục đến .emacs.d/vendor/vimpulsemà không xóa nó trước (giải thích ở đâyđây ) và sau đó thêm lại.

Git có thực sự cần toàn bộ đường dẫn trong thẻ mô đun con không

[submodule ".emacs.d/vimpulse"]

hoặc cũng có thể lưu trữ chỉ tên của tiểu dự án?

[submodule "vimpulse"]

LƯU Ý: OP trả lời câu hỏi của anh ấy / cô ấy bằng git mvlệnh, ngay trong câu hỏi.
Dan Rosenstark

TUY NHIÊN, bạn không thể sử dụng git mvnhư thế này. Sử dụng deinitsau đó rm như stackoverflow.com/a/18892438/8047 được chỉ định .
Dan Rosenstark

14
@Yar: ít nhất là trên git 2.0.0, git mv chỉ hoạt động cho các mô đun con, không cần bất cứ điều gì khác.
Pedro Romano

9
Bắt đầu với các 1.8.5mô đun con di chuyển Git được hỗ trợ nguyên bản bằng cách sử dụng git mvlệnh ( từ ghi chú phát hành , lần đầu tiên được liên kết bởi chính @thisch). Cũng đã trả lời ở đây
dennisschagt

git mvkhông di chuyển mô hình con trong không gian làm việc và cập nhật chính xác các tệp .git mô đun con, nhưng thư mục con trong thư mục .git / mô-đun của repo cha vẫn giữ nguyên - có ổn không? (Tôi đang sử dụng git 2.19.0 trên Windows)
yoyo

Câu trả lời:


377

Lưu ý: Như đã đề cập trong các bình luận, câu trả lời này đề cập đến các bước cần thiết với các phiên bản cũ hơn của git. Git hiện có hỗ trợ riêng cho các mô đun con di chuyển:

Kể từ git 1.8.5, git mv old/submod new/submodhoạt động như mong đợi và thực hiện tất cả các hệ thống ống nước cho bạn. Bạn có thể muốn sử dụng git 1.9.3 hoặc mới hơn, bởi vì nó bao gồm các bản sửa lỗi để di chuyển mô hình con.


Quá trình này tương tự như cách bạn loại bỏ một mô hình con (xem Làm cách nào để loại bỏ một mô hình con? ):

  1. Chỉnh sửa .gitmodulesvà thay đổi đường dẫn của mô hình con một cách thích hợp và đặt nó vào chỉ mục với git add .gitmodules.
  2. Nếu cần, hãy tạo thư mục mẹ của vị trí mới của mô hình con ( mkdir -p new/parent).
  3. Di chuyển tất cả nội dung từ thư mục cũ sang thư mục mới ( mv -vi old/parent/submodule new/parent/submodule).
  4. Hãy chắc chắn rằng Git theo dõi thư mục này ( git add new/parent).
  5. Xóa thư mục cũ với git rm --cached old/parent/submodule.
  6. Di chuyển thư mục .git/modules/old/parent/submodulevới tất cả nội dung của nó để .git/modules/new/parent/submodule.
  7. Chỉnh sửa .git/modules/new/parent/configtệp, đảm bảo rằng mục worktree trỏ đến các vị trí mới, vì vậy trong ví dụ này nó phải như vậy worktree = ../../../../../new/parent/module. Thông thường nên có nhiều hơn hai ..thư mục trong đường dẫn trực tiếp ở nơi đó.
  8. Chỉnh sửa tệp new/parent/module/.git, đảm bảo rằng đường dẫn trong đó trỏ đến đúng vị trí mới bên trong .gitthư mục dự án chính , vì vậy trong ví dụ này gitdir: ../../../.git/modules/new/parent/submodule.

    git status đầu ra trông như thế này đối với tôi sau đó:

    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   .gitmodules
    #       renamed:    old/parent/submodule -> new/parent/submodule
    #
    
  9. Cuối cùng, cam kết thay đổi.


37
Khi bạn cập nhật .gitmodules, hãy đảm bảo bạn cập nhật cả pathcấu hình đó và tên của mô hình con. Ví dụ: khi di chuyển foo / mô-đun sang thanh / mô-đun, bạn phải thay đổi trong .gitmodules phần [submodule "foo/module"]thành [submodule "bar/module"]và dưới cùng phần đó path = foo/modulethành path = bar/module. Ngoài ra, bạn phải thay đổi trong .git / config phần [submodule "foo/module"]để [submodule "bar/module"].
wilmustell

3
Nó cũng không hiệu quả đối với tôi ... giải pháp gần nhất tôi tìm thấy là xóa một mô hình con (một nỗi đau) và sau đó thêm lại nó ở vị trí khác.
Pablo Olmos de Aguilera C.

33
Một lưu ý rất quan trọng: Nếu bạn fatal: 'git status --porcelain' failed in...chỉ cần xóa bất kỳ tệp hoặc thư mục .git nào trong mô hình con.
chống độc

19
Có vẻ như bài đăng này bỏ lỡ một vài bước, chẳng hạn như chỉnh sửa .git/modules/old/parent/submodule, di chuyển nó đến vị trí mới, cập nhật gitdirtrong old/parent/submodule/.git...
szx

38
Kể từ git 1.8.5, git mv old/submod new/submodhoạt động như mong đợi và thực hiện tất cả các hệ thống ống nước cho bạn. Bạn có thể muốn sử dụng git 1.9.3+ vì nó bao gồm các bản sửa lỗi cho việc di chuyển mô hình con.
Valloric

232

Câu trả lời hiện đại nhất, được lấy từ nhận xét của Valloric ở trên:

  1. Nâng cấp lên Git 1.9.3 (hoặc 2.18 nếu mô hình con chứa các mô hình con lồng nhau )
  2. git mv old/submod new/submod
  3. Sau đó, .gitmodules và thư mục mô hình con đã được tổ chức cho một cam kết (bạn có thể xác minh điều này với git status.)
  4. Cam kết thay đổi git commitvà bạn tốt để đi!

Làm xong!


3
Điều này thực sự đã làm việc với 1.9.3 ngoại trừ một mô hình con bên trong mô hình con di chuyển. Điều đó cần một số dọn dẹp thủ công.
Pascal

3
Điều này đã hoạt động trong phiên bản 1.8.5như được mô tả trong ghi chú phát hành .
dennisschagt

6
Câu trả lời này sẽ nhận được 1000 lượt upvote, tôi gần như đã gây rối với repo của mình khi thực hiện các bước được mô tả ở trên, thực sự StackOverflow nên có một usecase cho tình huống này.
MGP

5
Wow, điều này làm việc như một bùa mê (git 1.9.5), tôi ước nó là câu trả lời được chọn.
Alex Ilyaev

7
Một điều không làm là nó không thay đổi nhãn ban đầu cho mô hình con. Nếu bạn kiểm tra .gitmodulestệp, tệp old/submodvẫn được sử dụng làm nhãn cho mô hình con trong khi đường dẫn đã được thay đổi. Để có được nhãn thay đổi, có vẻ như bạn cần phải thực sự di chuyển đường dẫn thư mục mô-đun bên trong .git, và sau đó thay đổi nhãn theo cách thủ công .gitmodules.
CMCDragonkai

55

Trong trường hợp của tôi, tôi muốn di chuyển một mô hình con từ một thư mục vào thư mục con, ví dụ: "AFNetworking" -> "ext / AFNetworking". Đây là các bước tôi đã làm theo:

  1. Chỉnh sửa .gitmodules thay đổi tên và đường dẫn mô hình con thành "ext / AFNetworking"
  2. Di chuyển thư mục git của mô hình con từ ".git / mô-đun / AFNetworking" sang ".git / mô-đun / ext / AFNetworking"
  3. Chuyển thư viện từ "AFNetworking" sang "ext / AFNetworking"
  4. Chỉnh sửa ".git / mô-đun / ext / AFNetworking / config" và sửa [core] worktreedòng. Mine thay đổi từ ../../../AFNetworkingđến../../../../ext/AFNetworking
  5. Chỉnh sửa "ext / AFNetworking / .git" và sửa lỗi gitdir. Mine thay đổi từ ../.git/modules/AFNetworkingđến../../git/modules/ext/AFNetworking
  6. git add .gitmodules
  7. git rm --cached AFNetworking
  8. git submodule add -f <url> ext/AFNetworking

Cuối cùng, tôi thấy trong trạng thái git:

matt$ git status
# On branch ios-master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   .gitmodules
#   renamed:    AFNetworking -> ext/AFNetworking

Et voila. Ví dụ trên không thay đổi độ sâu thư mục, điều này tạo ra sự khác biệt lớn đối với độ phức tạp của tác vụ và không thay đổi tên của mô hình con (có thể không thực sự cần thiết, nhưng tôi đã làm nó phù hợp với những gì sẽ xảy ra nếu tôi thêm một mô-đun mới vào đường dẫn đó.)


4
Cảm ơn Matt. Tôi đã bị mất trên câu trả lời được chấp nhận. Cảm ơn bạn đã bao gồm nhiều hơn trường hợp cơ sở. Điều này làm việc như một nét duyên dáng.
Andrew Hubbs

Bạn không cần xáo trộn xung quanh các đường dẫn .git / mô-đun hoặc thay đổi tên của mô hình con (như arand và Bob Bell đề cập). Mặc dù, làm như vậy có thể giữ cho mọi thứ sạch sẽ hơn.
gatoatigrado

Đừng quên thực hiện các bước 2, 3, 4 và 5 một cách đệ quy cho bất kỳ tiểu trình con nào.
herzbube

22

[Cập nhật: 2014-11-26] Khi Yar tóm tắt độc đáo bên dưới, trước khi bạn làm bất cứ điều gì, hãy đảm bảo bạn biết URL của mô hình con. Nếu không biết, mở .git/.gitmodulesvà kiểm tra chìa khóa submodule.<name>.url.

Những gì làm việc cho tôi là để loại bỏ các mô hình con cũ bằng cách sử dụng git submodule deinit <submodule>theo sau git rm <submodule-folder>. Sau đó thêm mô hình con một lần nữa với tên thư mục mới và cam kết. Kiểm tra trạng thái git trước khi cam kết cho thấy mô hình con cũ được đổi tên thành tên mới và .gitmodule được sửa đổi.

$ git submodule deinit foo
$ git rm foo
$ git submodule add https://bar.com/foo.git new-foo
$ git status
renamed:    foo -> new-foo
modified:   .gitmodules
$ git commit -am "rename foo submodule to new-foo"

1
Điều này đòi hỏi git 1.8.3 trở lên. Xem bài đăng này để nâng cấp git của bạn: evgeny-goldin.com/blog/3-ways-install-git-linux-ub Ubuntu
Michael Cole

1
Hoặc, một cách tốt hơn: sudo add-apt-repository ppa: git-core / ppa sudo apt-get update sudo apt-get install git
Michael Cole

@MichaelCole Cảm ơn! Bạn đúng! Xem Ghi chú phát hành Git-1.8.3 . FYI: Ubuntu-13.10 (Saucy Salamander) có Git-1.8.3.2 , nhưng thật tốt khi biết có ppa . Ngoài ra, chiến lược hợp nhất IMHO git Subree là một cách tiếp cận tốt hơn; Tôi đã từ bỏ các mô hình con cho các dự án của riêng tôi. Vẫn còn tốt để hiểu cho các dự án hiện có.
Đánh dấu Mikofski

Tôi đã thử một vài giải pháp nhưng bạn là tốt nhất. Chỉ sử dụng dòng lệnh để bạn không cần (và không nên) sửa đổi bất kỳ tệp git nào. Cảm ơn!
nahung89

12

Thủ thuật dường như hiểu rằng .gitthư mục cho các mô hình con hiện được lưu giữ trong kho lưu trữ chính, bên dưới .git/modulesvà mỗi mô hình con có một .gittệp trỏ đến nó. Đây là thủ tục bạn cần bây giờ:

  • Di chuyển mô hình con đến nhà mới của nó.
  • Chỉnh sửa .gittệp trong thư mục làm việc của mô hình con và sửa đổi đường dẫn chứa trong đó để nó trỏ đến thư mục bên phải trong thư mục của kho lưu trữ chính .git/modules.
  • Nhập .git/modulesthư mục của kho lưu trữ chính và tìm thư mục tương ứng với mô hình con của bạn.
  • Chỉnh sửa configtệp, cập nhật worktreeđường dẫn để nó trỏ đến vị trí mới của thư mục làm việc của mô hình con.
  • Chỉnh sửa .gitmodulestệp trong thư mục gốc của kho lưu trữ chính, cập nhật đường dẫn đến thư mục làm việc của mô hình con.
  • git add -u
  • git add <parent-of-new-submodule-directory>(Điều quan trọng là bạn thêm cha mẹ chứ không phải chính thư mục mô đun con.)

Một vài lưu ý:

  • Các [submodule "submodule-name"]dòng trong .gitmodules.git/configphải khớp với nhau, nhưng không tương ứng với bất kỳ thứ gì khác.
  • Thư mục làm việc mô đun con và .gitthư mục phải trỏ chính xác lẫn nhau.
  • Các tập tin .gitmodules.git/confignên được đồng bộ hóa.

9

Chuỗi trong dấu ngoặc kép sau "[mô hình con" không thành vấn đề. Bạn có thể thay đổi nó thành "foobar" nếu bạn muốn. Nó được sử dụng để tìm mục phù hợp trong ".git / config".

Do đó, nếu bạn thực hiện thay đổi trước khi chạy "git subodule init", nó sẽ hoạt động tốt. Nếu bạn thực hiện thay đổi (hoặc chọn thay đổi thông qua hợp nhất), bạn sẽ cần chỉnh sửa thủ công .git / config hoặc chạy lại "git subodule init". Nếu bạn làm sau, bạn sẽ bị bỏ lại một mục "bị mắc kẹt" vô hại với tên cũ trong .git / config.


Điều này thực sự gây phiền nhiễu, nhưng bạn đã đúng. Phần tồi tệ nhất là, nếu bạn chỉ thay đổi URL, chạy git init dường như không cập nhật nó, bạn phải chỉnh sửa thủ công .git / config.
crimson_penguin

1
trong trường hợp này git submodule synctuyên truyền thay đổi thành .git/configtự động
CharlesB

9

Bạn chỉ có thể thêm một mô hình con mới và loại bỏ mô hình con cũ bằng các lệnh tiêu chuẩn. (nên ngăn chặn mọi lỗi vô ý bên trong .git)

Thiết lập ví dụ:

mkdir foo; cd foo; git init; 
echo "readme" > README.md; git add README.md; git commit -m "First"
## add submodule
git submodule add git://github.com/jquery/jquery.git
git commit -m "Added jquery"
## </setup example>

Kiểm tra di chuyển 'jquery' sang 'nhà cung cấp / jquery / jquery':

oldPath="jquery"
newPath="vendor/jquery/jquery"
orginUrl=`git config --local --get submodule.${oldPath}.url`

## add new submodule
mkdir -p `dirname "${newPath}"`
git submodule add -- "${orginUrl}" "${newPath}"

## remove old submodule
git config -f .git/config --remove-section "submodule.${oldPath}"
git config -f .gitmodules --remove-section "submodule.${oldPath}"
git rm --cached "${oldPath}"
rm -rf "${oldPath}"              ## remove old src
rm -rf ".git/modules/${oldPath}" ## cleanup gitdir (housekeeping)

## commit
git add .gitmodules
git commit -m "Renamed ${oldPath} to ${newPath}"

Phương pháp thưởng cho các mô hình con lớn:

Nếu mô hình con lớn và bạn không muốn chờ bản sao, bạn có thể tạo mô hình con mới bằng cách sử dụng gốc cũ, sau đó chuyển đổi nguồn gốc.

Ví dụ (sử dụng cùng thiết lập ví dụ)

oldPath="jquery"
newPath="vendor/jquery/jquery"
baseDir=`pwd`
orginUrl=`git config --local --get submodule.${oldPath}.url`

# add new submodule using old submodule as origin
mkdir -p `dirname "${newPath}"`
git submodule add -- "file://${baseDir}/${oldPath}" "${newPath}"

## change origin back to original
git config -f .gitmodules submodule."${newPath}".url "${orginUrl}"
git submodule sync -- "${newPath}"

## remove old submodule
...

Nếu bạn không sử dụng head, bạn cũng có thể cần kiểm tra phiên bản chính xác của mô-đun tại newPath.
paulmelnikow

2

Giải pháp đã cho không phù hợp với tôi, tuy nhiên một phiên bản tương tự đã ...

Điều này là với một kho lưu trữ nhân bản, do đó các kho dữ liệu git mô đun con được chứa trong kho lưu trữ hàng đầu .git dir. Tất cả các cation là từ kho lưu trữ hàng đầu:

  1. Chỉnh sửa .gitmodules và thay đổi cài đặt "path =" cho mô hình con được đề cập. (Không cần thay đổi nhãn, cũng không cần thêm tệp này vào chỉ mục.)

  2. Chỉnh sửa .git / mô-đun / tên / cấu hình và thay đổi cài đặt "worktree =" cho mô hình con trong câu hỏi

  3. chạy:

    mv submodule newpath/submodule
    git add -u
    git add newpath/submodule
    

Tôi tự hỏi nếu nó làm cho một sự khác biệt nếu các kho lưu trữ là nguyên tử, hoặc các mô đun con tương đối, trong trường hợp của tôi nó là tương đối (mô đun con / .git là một tham chiếu trở lại topproject / .git / mô đun / mô đun con)


2

Chỉ cần sử dụng tập lệnh shell git-subodule-move .


Heh, tôi đã tra cứu câu hỏi này một lần nữa và sử dụng một trong những câu trả lời được bình chọn cao hơn, và bây giờ tôi ước rằng tôi đã cuộn xuống và xem câu trả lời trước đây mà tôi đã quên.
Flimm

2

Tôi vừa trải qua thử thách này ngày hôm qua và câu trả lời này đã hoạt động hoàn hảo. Dưới đây là các bước của tôi, để rõ ràng:

  1. Đảm bảo rằng mô hình con được kiểm tra và đẩy đến máy chủ của nó. Bạn cũng cần phải biết chi nhánh của nó trên.
  2. Bạn cần URL của mô hình con của bạn! Sử dụng more .gitmodulesbởi vì một khi bạn xóa mô hình con, nó sẽ không xuất hiện
  3. Bây giờ bạn có thể sử dụng deinit, rmvà sau đósubmodule add

THÍ DỤ

THÔNG TIN

    git submodule deinit Classes/lib/mustIReally
    git rm foo
    git submodule add http://developer.audiob.us/download/SDK.git lib/AudioBus

    # do your normal commit and push
    git commit -a 

LƯU Ý: git mv không làm điều này. Ở tất cả.


3
Tóm tắt tốt. +1 git mvnên tốt hơn trong các phiên bản cuối cùng của Git.
VonC

@VonC Tôi đã thử nghiệm trên git 1.8.5, khá chắc chắn rằng nó tốt như nó có được mv. Cảm ơn!
Dan Rosenstark
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.