Bagaimana cara memindahkan submitule Git yang ada dalam repositori Git?

356

Saya ingin mengubah nama direktori dari sebuah submodule Git di proyek super Git saya.

Mari kita anggap saya memiliki entri berikut di .gitmodulesfile saya :

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

Apa yang harus saya ketik untuk memindahkan .emacs.d/vimpulsedirektori .emacs.d/vendor/vimpulsetanpa menghapusnya terlebih dahulu (dijelaskan di sini dan di sini ) dan kemudian menambahkannya kembali.

Apakah Git benar-benar membutuhkan seluruh path dalam tag submodule

[submodule ".emacs.d/vimpulse"]

atau mungkinkah hanya menyimpan nama proyek?

[submodule "vimpulse"]
inich
sumber
CATATAN: OP menjawab pertanyaannya sendiri dengan git mvperintah, tepat di pertanyaan.
Dan Rosenstark
NAMUN, Anda tidak dapat menggunakan git mvseperti ini. Gunakan deinitkemudian rm seperti yang ditentukan stackoverflow.com/a/18892438/8047 .
Dan Rosenstark
14
@ Yar: setidaknya pada git 2.0.0, git mv hanya berfungsi untuk submodules juga, tidak perlu untuk yang lain.
Pedro Romano
9
Dimulai dengan Git, 1.8.5submodula yang bergerak didukung secara native menggunakan git mvperintah ( dari catatan rilis , pertama kali ditautkan oleh @thisch sendiri). Juga dijawab di sini
dennisschagt
git mvtidak memindahkan submodule di ruang kerja, dan memperbarui file .git submodule dengan benar, tetapi subfolder di dalam folder .git / modules dari repo induk tetap sama - apakah itu oke? (Saya menggunakan git 2.19.0 di Windows)
yoyo

Jawaban:

377

Catatan: Seperti disebutkan dalam komentar, jawaban ini merujuk pada langkah-langkah yang diperlukan dengan versi git yang lebih lama. Git sekarang memiliki dukungan asli untuk memindahkan submodula:

Sejak git 1.8.5, git mv old/submod new/submodbekerja seperti yang diharapkan dan melakukan semua pipa ledeng untuk Anda. Anda mungkin ingin menggunakan git 1.9.3 atau yang lebih baru, karena itu termasuk perbaikan untuk pemindahan submodule.


Prosesnya mirip dengan cara Anda menghapus submodule (lihat Bagaimana cara menghapus submodule? ):

  1. Edit .gitmodulesdan ubah jalur submodule dengan tepat, dan masukkan ke dalam indeks bersama git add .gitmodules.
  2. Jika perlu, buat direktori induk dari lokasi baru submodule ( mkdir -p new/parent).
  3. Pindahkan semua konten dari yang lama ke direktori baru ( mv -vi old/parent/submodule new/parent/submodule).
  4. Pastikan Git melacak direktori ini ( git add new/parent).
  5. Hapus direktori lama dengan git rm --cached old/parent/submodule.
  6. Pindahkan direktori .git/modules/old/parent/submoduledengan semua kontennya ke .git/modules/new/parent/submodule.
  7. Edit .git/modules/new/parent/configfile tersebut, pastikan item butir kerja menunjuk ke lokasi baru, jadi dalam contoh ini seharusnya worktree = ../../../../../new/parent/module. Biasanya harus ada dua lebih ..dari direktori di jalur langsung di tempat itu.
  8. Edit file new/parent/module/.git, pastikan path di dalamnya menunjuk ke lokasi baru yang benar di dalam .gitfolder proyek utama , jadi dalam contoh ini gitdir: ../../../.git/modules/new/parent/submodule.

    git status output terlihat seperti ini untuk saya setelahnya:

    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   .gitmodules
    #       renamed:    old/parent/submodule -> new/parent/submodule
    #
    
  9. Akhirnya, lakukan perubahan.

Axel Beckert
sumber
37
Ketika Anda memperbarui .gitmodules pastikan Anda memperbarui pathkonfigurasi itu dan nama submodule itu. Misalnya, dalam bergerak foo / modul untuk bar / modul Anda harus mengubah di .gitmodules bagian [submodule "foo/module"]untuk [submodule "bar/module"], dan di bawah yang bagian yang sama path = foo/moduleuntuk path = bar/module. Juga, Anda harus mengubah .git / config bagian [submodule "foo/module"]ke [submodule "bar/module"].
wilhelmtell
3
Itu tidak bekerja untuk saya juga ... solusi terdekat yang saya temukan adalah menghapus submodule (sakit) dan kemudian menambahkannya kembali di lokasi yang berbeda.
Pablo Olmos de Aguilera C.
33
Catatan yang sangat-sangat penting: Jika Anda fatal: 'git status --porcelain' failed in...menghapus saja file .git atau direktori dalam submodule.
antitoksik
19
Sepertinya posting ini merindukan beberapa langkah, seperti mengedit .git/modules/old/parent/submodule, pindah ke lokasi baru, memperbarui gitdirdi old/parent/submodule/.git...
SZX
38
Sejak git 1.8.5, git mv old/submod new/submodbekerja seperti yang diharapkan dan melakukan semua pipa ledeng untuk Anda. Anda mungkin ingin menggunakan git 1.9.3+ karena menyertakan perbaikan untuk pemindahan submodule.
Valloric
232

Jawaban paling modern, diambil dari komentar Valloric di atas:

  1. Tingkatkan ke Git 1.9.3 (atau 2.18 jika submodule berisi submodules bersarang )
  2. git mv old/submod new/submod
  3. Setelah itu .gitmodules dan direktori submodule sudah dipentaskan untuk komit (Anda dapat memverifikasi ini dengan git status.)
  4. Komit perubahan dengan git commitdan Anda baik untuk pergi!

Selesai!

Phatmann
sumber
3
Ini memang bekerja dengan 1.9.3 kecuali untuk submodule di dalam submodule yang dipindahkan. Itu membutuhkan beberapa pembersihan manual.
Pascal
3
Ini seharusnya sudah berfungsi dalam versi 1.8.5seperti yang dijelaskan dalam catatan rilis .
dennisschagt
6
Jawaban ini seharusnya mendapatkan 1000 upvotes, saya hampir membuat kekacauan dengan repo saya melakukan langkah-langkah yang dijelaskan di atas, benar-benar StackOverflow harus memiliki usecase untuk situasi ini.
MGP
5
Wow, ini bekerja seperti mantra (git 1.9.5), saya berharap itu adalah jawaban yang dipilih.
Alex Ilyaev
7
Satu hal yang tidak dilakukan adalah tidak mengubah label awal untuk submodule. Jika Anda memeriksa .gitmodulesfile, old/submodmasih digunakan sebagai label untuk submodule sementara path telah diubah. Untuk mengubah label juga, tampaknya Anda harus benar-benar memindahkan jalur direktori modul ke dalam .git, dan kemudian secara manual mengubah label .gitmodules.
CMCDragonkai
55

Dalam kasus saya, saya ingin memindahkan submodule dari satu direktori ke subdirektori, misalnya "AFNetworking" -> "ext / AFNetworking". Ini adalah langkah-langkah yang saya ikuti:

  1. Edit .gitmodules yang mengubah nama dan jalur submodule menjadi "ext / AFNetworking"
  2. Pindahkan direktori git submodule dari ".git / modules / AFNetworking" ke ".git / modules / ext / AFNetworking"
  3. Pindahkan perpustakaan dari "AFNetworking" ke "ext / AFNetworking"
  4. Edit ".git / modules / ext / AFNetworking / config" dan perbaiki [core] worktreejalurnya. Milik saya berubah dari ../../../AFNetworkingmenjadi../../../../ext/AFNetworking
  5. Edit "ext / AFNetworking / .git" dan perbaiki gitdir. Milik saya berubah dari ../.git/modules/AFNetworkingmenjadi../../git/modules/ext/AFNetworking
  6. git add .gitmodules
  7. git rm --cached AFNetworking
  8. git submodule add -f <url> ext/AFNetworking

Akhirnya, saya melihat dalam status 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. Contoh di atas tidak mengubah kedalaman direktori, yang membuat perbedaan besar pada kompleksitas tugas, dan tidak mengubah nama submodule (yang mungkin tidak benar-benar diperlukan, tapi saya melakukannya agar konsisten dengan apa akan terjadi jika saya menambahkan modul baru di jalur itu.)

Matt Connolly
sumber
4
Terima kasih, Matt. Saya bingung dengan jawaban yang diterima. Terima kasih telah meliput lebih dari kasus dasar. Ini bekerja seperti pesona.
Andrew Hubbs
Anda tidak perlu mengacak jalur .git / modules, atau mengubah nama submodule (seperti yang disebutkan oleh arand dan Bob Bell). Padahal, melakukan hal itu dapat menjaga kebersihan.
gatoatigrado
Jangan lupa untuk melakukan langkah 2, 3, 4 dan 5 secara rekursif untuk setiap sub-submodula.
herzbube
22

[Pembaruan: 2014-11-26] Saat Yar merangkum dengan baik di bawah ini, sebelum Anda melakukan apa pun, pastikan Anda tahu URL dari submodule. Jika tidak diketahui, buka .git/.gitmodulesdan periksa kuncinyasubmodule.<name>.url .

Yang berhasil bagi saya adalah menghapus submodule lama menggunakan git submodule deinit <submodule>diikuti oleh git rm <submodule-folder>. Kemudian tambahkan submodule lagi dengan nama folder baru dan komit. Memeriksa status git sebelum melakukan menunjukkan submodule lama diubah namanya menjadi nama baru dan .gitmodule dimodifikasi.

$ 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"
Mark Mikofski
sumber
1
Ini membutuhkan git 1.8.3 atau lebih tinggi. Lihat posting ini untuk memutakhirkan git Anda: evgeny-goldin.com/blog/3-ways-install-git-linux-ubuntu
Michael Cole
1
Atau, cara yang lebih baik: sudo add-apt-repositori ppa: git-core / ppa sudo apt-get update sudo apt-get install git
Michael Cole
@MichaelCole Terima kasih! Kamu benar! Lihat Git-1.8.3 Catatan Rilis . FYI: Ubuntu-13.10 (Saucy Salamander) memiliki Git-1.8.3.2 , tetapi senang mengetahui ada ppa . Juga, strategi gree subtree IMHO git adalah pendekatan yang lebih baik; Saya telah meninggalkan submodules untuk proyek saya sendiri. Masih bagus untuk memahami proyek yang ada.
Mark Mikofski
Saya mencoba beberapa solusi tetapi milik Anda adalah yang terbaik. Hanya gunakan baris perintah sehingga Anda tidak perlu (dan tidak seharusnya) memodifikasi file git. Terima kasih!
nahung89
12

Triknya tampaknya memahami bahwa .gitdirektori untuk submodula sekarang disimpan di repositori master, di bawah .git/modules, dan setiap submodule memiliki .gitfile yang mengarah ke sana. Ini adalah prosedur yang Anda butuhkan sekarang:

  • Pindahkan submodule ke rumah barunya.
  • Edit .gitfile dalam direktori kerja submodule, dan modifikasi path yang dikandungnya sehingga menunjuk ke direktori yang benar di direktori master repositori .git/modules.
  • Masukkan .git/modulesdirektori master repositori , dan temukan direktori yang sesuai dengan submodule Anda.
  • Edit configfile, perbarui worktreepath sehingga menunjuk ke lokasi baru direktori kerja submodule.
  • Edit .gitmodulesfile di root repositori master, perbarui path ke direktori kerja submodule.
  • git add -u
  • git add <parent-of-new-submodule-directory>(Sangat penting bahwa Anda menambahkan orang tua , dan bukan direktori submodule itu sendiri.)

Beberapa catatan:

  • The [submodule "submodule-name"]garis dalam .gitmodulesdan .git/configharus cocok satu sama lain, tetapi tidak sesuai dengan apa-apa lagi.
  • Direktori dan direktori kerja submodule .githarus saling menunjuk dengan benar.
  • File .gitmodulesdan .git/configharus disinkronkan.
Paul Gideon Dann
sumber
9

String dalam tanda kutip setelah "[submodule" tidak masalah. Anda dapat mengubahnya ke "foobar" jika Anda mau. Ini digunakan untuk menemukan entri yang cocok di ". Git / config".

Karena itu, jika Anda melakukan perubahan sebelum menjalankan "git submodule init", itu akan berfungsi dengan baik. Jika Anda melakukan perubahan (atau mengambil perubahan melalui penggabungan), Anda harus mengedit secara manual .git / config atau menjalankan "git submodule init" lagi. Jika Anda melakukan yang terakhir, Anda akan dibiarkan dengan entri "terlantar" yang tidak berbahaya dengan nama lama di .git / config.

Bob Bell
sumber
Ini benar-benar menjengkelkan, tetapi Anda benar. Bagian terburuknya adalah, jika Anda hanya mengubah URL, menjalankan git init tampaknya tidak memperbaruinya, Anda harus mengedit .git / config secara manual.
crimson_penguin
1
dalam hal ini git submodule syncmenyebarkan perubahan ke .git/configsecara otomatis
CharlesB
9

Anda bisa menambahkan submodule baru dan menghapus submodule lama menggunakan perintah standar. (harus mencegah kesalahan yang tidak disengaja di dalam. git)

Pengaturan contoh:

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>

Coba pindahkan 'jquery' ke 'vendor / 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}"

Metode bonus untuk submodula besar:

Jika submodule besar dan Anda memilih untuk tidak menunggu klon, Anda dapat membuat submodule baru menggunakan yang lama sebagai asal, dan kemudian beralih asal.

Contoh (gunakan pengaturan contoh yang sama)

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
...
Lance Bergegas
sumber
Jika Anda tidak menggunakan head, Anda mungkin perlu memeriksa versi modul yang benar di newPath.
paulmelnikow
2

Solusi yang diberikan tidak bekerja untuk saya, namun versi yang sama tidak ...

Ini dengan repositori kloning, maka repos submodule git terkandung dalam repositori top. Dir git. Semua kation berasal dari repositori atas:

  1. Edit .gitmodules dan ubah pengaturan "path =" untuk submodule yang dimaksud. (Tidak perlu mengubah label, atau menambahkan file ini ke indeks.)

  2. Edit .git / modules / name / config dan ubah pengaturan "worktree =" untuk submodule yang dimaksud

  3. Lari:

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

Saya ingin tahu apakah ada bedanya jika repositori adalah atom, atau submodula relatif, dalam kasus saya itu relatif (submodule / .git adalah ref kembali ke topproject / .git / modules / submodule)

Arand
sumber
2

Cukup gunakan skrip shell git-submodule-move .

Flimm
sumber
Heh, saya mencari pertanyaan ini lagi, dan menggunakan salah satu jawaban yang lebih tinggi, dan sekarang saya berharap saya menggulir ke bawah dan melihat jawaban saya sebelumnya yang saya lupa.
Flimm
2

Saya baru saja mengalami cobaan ini kemarin dan jawaban ini bekerja dengan sempurna. Inilah langkah-langkah saya, untuk kejelasan:

  1. Pastikan submodule masuk dan didorong ke servernya. Anda juga perlu tahu cabang apa itu.
  2. Anda membutuhkan URL dari submodule Anda! Menggunakanmore .gitmodules karena begitu Anda menghapus submodule itu tidak akan ada
  3. Sekarang Anda bisa menggunakannya deinit, rmlalusubmodule add

CONTOH

PERINTAH

    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 

CATATAN: git mv tidak melakukan ini. Sama sekali.

Dan Rosenstark
sumber
3
Ringkasan yang bagus. +1 git mvharus lebih baik di versi terakhir Git.
VonC
@VonC Saya diuji pada git 1.8.5, cukup yakin itu sama baiknya dengan yang didapat mv. Terima kasih!
Dan Rosenstark