Jak przenieść istniejący podmoduł Git w repozytorium Git?

356

Chciałbym zmienić nazwę katalogu submodułu Git w moim superprojekcie Git.

Załóżmy, że mam następujący wpis w moim .gitmodulespliku:

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

Co muszę wpisać, aby przenieść .emacs.d/vimpulsekatalog .emacs.d/vendor/vimpulsebez uprzedniego usunięcia go (wyjaśnione tutaj i tutaj ), a następnie dodania go ponownie.

Czy Git naprawdę potrzebuje całej ścieżki w znaczniku submodułu

[submodule ".emacs.d/vimpulse"]

lub czy można również zapisać tylko nazwę podprojektu?

[submodule "vimpulse"]
strzecha
źródło
UWAGA: OP odpowiada na swoje pytanie git mvpoleceniem bezpośrednio w pytaniu.
Dan Rosenstark,
JEDNAK nie możesz tego używać git mv. Użyj deinitwtedy, rm jak określono stackoverflow.com/a/18892438/8047 .
Dan Rosenstark,
14
@Yar: przynajmniej na git 2.0.0, git mv działa również dla podmodułów, nie trzeba nic więcej.
Pedro Romano
9
Począwszy od Git 1.8.5ruchome podmoduły są obsługiwane natywnie za pomocą git mvpolecenia ( z informacji o wersji , najpierw połączonych przez samego @thischa). Odpowiedział
dennisschagt
git mvprzesuwa submoduł w obszarze roboczym i poprawnie aktualizuje pliki .git submodułu, ale podfolder w folderze .git / modules repozytorium nadrzędnego pozostaje taki sam - czy to w porządku? (Używam gita 2.19.0 w systemie Windows)
yoyo

Odpowiedzi:

377

Uwaga: Jak wspomniano w komentarzach, ta odpowiedź odnosi się do kroków wymaganych w starszych wersjach git. Git ma teraz natywne wsparcie dla przenoszenia submodułów:

Od wersji 1.8.5 git git mv old/submod new/submoddziała zgodnie z oczekiwaniami i wykonuje całą instalację wodociągową. Możesz użyć gita 1.9.3 lub nowszego, ponieważ zawiera poprawki do przenoszenia podmodułów.


Proces jest podobny do sposobu usuwania submodułu (zobacz Jak usunąć submoduł? ):

  1. Edytuj .gitmodulesi zmień odpowiednio ścieżkę submodułu i umieść ją w indeksie za pomocą git add .gitmodules.
  2. W razie potrzeby utwórz katalog nadrzędny nowej lokalizacji submodula ( mkdir -p new/parent).
  3. Przenieś całą zawartość ze starego do nowego katalogu ( mv -vi old/parent/submodule new/parent/submodule).
  4. Upewnij się, że Git śledzi ten katalog ( git add new/parent).
  5. Usuń stary katalog za pomocą git rm --cached old/parent/submodule.
  6. Przenieś katalog .git/modules/old/parent/submodulez całą zawartością do .git/modules/new/parent/submodule.
  7. Edytuj .git/modules/new/parent/configplik, upewnij się, że element z drzewa roboczego wskazuje nowe lokalizacje, więc w tym przykładzie powinno to być worktree = ../../../../../new/parent/module. Zazwyczaj ..w bezpośredniej ścieżce w tym miejscu powinny znajdować się dwa katalogi więcej niż katalogi.
  8. Edytuj plik new/parent/module/.git, upewnij się, że ścieżka w nim wskazuje poprawną nową lokalizację w głównym .gitfolderze projektu , więc w tym przykładzie gitdir: ../../../.git/modules/new/parent/submodule.

    git status dane wyjściowe wyglądają dla mnie następująco:

    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   .gitmodules
    #       renamed:    old/parent/submodule -> new/parent/submodule
    #
    
  9. Na koniec zatwierdz zmiany.

Axel Beckert
źródło
37
Podczas aktualizacji .gitmodules upewnij się, że zaktualizowałeś zarówno tę pathkonfigurację, jak i nazwę submodułu. Na przykład, przy przenoszeniu foo / module do bar / module musisz zmienić w .gitmodules sekcję [submodule "foo/module"]na [submodule "bar/module"]i pod tą samą sekcją path = foo/modulena path = bar/module. Musisz także zmienić w .git / config sekcję [submodule "foo/module"]na [submodule "bar/module"].
wilhelmtell,
3
Dla mnie to też nie zadziałało ... najbliższym rozwiązaniem, jakie znalazłem, jest usunięcie submodułu (bólu), a następnie ponowne dodanie go w innym miejscu.
Pablo Olmos de Aguilera C.
33
Bardzo, bardzo ważna uwaga: jeśli otrzymasz fatal: 'git status --porcelain' failed in...tylko pliki .git lub katalogi w podmodule.
antytoksyczny
19
Wygląda na to, że w tym poście brakuje kilku kroków, takich jak edycja .git/modules/old/parent/submodule, przeniesienie go do nowej lokalizacji, aktualizacja gitdirw old/parent/submodule/.git...
szx
38
Od wersji 1.8.5 git git mv old/submod new/submoddziała zgodnie z oczekiwaniami i wykonuje całą instalację wodociągową. Prawdopodobnie zechcesz użyć git 1.9.3+, ponieważ zawiera on poprawki do przenoszenia submodułów.
Valloric
232

Najnowocześniejsza odpowiedź zaczerpnięta z powyższego komentarza Vallorica:

  1. Uaktualnij do Git 1.9.3 (lub 2.18, jeśli podmoduł zawiera zagnieżdżone podmoduły )
  2. git mv old/submod new/submod
  3. Następnie .gitmodules i katalog podmodułów są już przemieszczane dla zatwierdzenia (możesz to zweryfikować za pomocą git status.)
  4. Zatwierdź zmiany za pomocą git commiti możesz zacząć!

Gotowy!

phatmann
źródło
3
To rzeczywiście działało z 1.9.3 wyjątkiem podmodułu w przeniesionym podmodule. To wymagało ręcznego czyszczenia.
Pascal
3
Powinno to już działać w wersji 1.8.5opisanej w uwagach do wydania .
dennisschagt
6
Ta odpowiedź powinna uzyskać 1000 głosów pozytywnych, prawie zrobiłem bałagan z moim repozytorium wykonując kroki opisane powyżej, naprawdę StackOverflow powinien mieć przypadek użycia w tej sytuacji.
MGP,
5
Wow, zadziałało to jak urok (git 1.9.5), chciałbym, żeby to była wybrana odpowiedź.
Alex Ilyaev
7
Jedną z rzeczy, których to nie robi, jest to, że nie zmienia początkowej etykiety dla submodułu. Jeśli zaznaczysz .gitmodulesplik, old/submodnadal będzie on używany jako etykieta submodułu, gdy ścieżka zostanie zmieniona. Aby zmienić również etykietę, wydaje się, że musisz przenieść ścieżkę do katalogu modułów .git, a następnie ręcznie zmienić etykietę .gitmodules.
CMCDragonkai
55

W moim przypadku chciałem przenieść submoduł z jednego katalogu do podkatalogu, np. „AFNetworking” -> „ext / AFNetworking”. Oto kroki, które wykonałem:

  1. Edytuj .gitmodules zmieniając nazwę i ścieżkę submodułu na „ext / AFNetworking”
  2. Przenieś katalog git submodułu z „.git / modules / AFNetworking” do „.git / modules / ext / AFNetworking”
  3. Przenieś bibliotekę z „AFNetworking” do „ext / AFNetworking”
  4. Edytuj „.git / modules / ext / AFNetworking / config” i napraw [core] worktreelinię. Mój zmienił się z ../../../AFNetworkingna../../../../ext/AFNetworking
  5. Edytuj „ext / AFNetworking / .git” i napraw gitdir. Mój zmienił się z ../.git/modules/AFNetworkingna../../git/modules/ext/AFNetworking
  6. git add .gitmodules
  7. git rm --cached AFNetworking
  8. git submodule add -f <url> ext/AFNetworking

Wreszcie zobaczyłem w statusie 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

Zrobione. Powyższy przykład nie zmienia głębokości katalogu, co ma duży wpływ na złożoność zadania i nie zmienia nazwy submodułu (co może nie jest tak naprawdę konieczne, ale zrobiłem to, aby zachować spójność z tym, co tak by się stało, gdybym dodał nowy moduł na tej ścieżce).

Matt Connolly
źródło
4
Dzięki Matt. Zgubiłem się na przyjętej odpowiedzi. Dziękujemy za pokrycie czegoś więcej niż przypadek podstawowy. To działało jak urok.
Andrew Hubbs
Nie musisz przeszukiwać ścieżek .git / modułów ani zmieniać nazwy submodułu (jak wspominają arand i Bob Bell). Chociaż takie postępowanie może utrzymać czystość.
gatoatigrado
Nie zapomnij wykonać czynności 2, 3, 4 i 5 rekurencyjnie dla dowolnych podmodułów.
herzbube
22

[Aktualizacja: 26.11.2014] Jak Yar ładnie podsumowuje poniżej, zanim cokolwiek zrobisz, upewnij się, że znasz adres URL podmodułu. Jeśli jest nieznany, otwórz .git/.gitmodulesi sprawdź klucz submodule.<name>.url.

Dla mnie zadziałało usunięcie starego podmodułu za pomocą, git submodule deinit <submodule>a następnie git rm <submodule-folder>. Następnie ponownie dodaj submoduł z nową nazwą folderu i zatwierdź. Sprawdzanie statusu git przed zatwierdzeniem pokazuje, że stary podmoduł został przemianowany na nową nazwę i zmodyfikowany .gitmodule.

$ 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
źródło
1
Wymaga to git 1.8.3 lub wyższej. Zobacz ten post dotyczący uaktualnienia twojego gita: evgeny-goldin.com/blog/3-ways-install-git-linux-ubuntu
Michael Cole
1
Lub lepszy sposób: sudo add-apt-repository ppa: git-core / ppa sudo apt-get update sudo apt-get install git
Michael Cole
@MichaelCole Thanks! Masz rację! Zobacz informacje o wersji Git-1.8.3 . FYI: Ubuntu-13.10 (Saucy Salamander) ma Git-1.8.3.2 , ale dobrze wiedzieć, że jest ppa . Również strategia scalania poddrzewa IMHO git jest lepszym podejściem; Porzuciłem submoduły dla własnych projektów. Nadal dobrze rozumiem dla istniejących projektów.
Mark Mikofski
Wypróbowałem kilka rozwiązań, ale twoje jest najlepsze. Używaj tylko wiersza poleceń, abyś nie potrzebował (i nie powinien) modyfikować żadnego pliku git. Dzięki!
nahung89
12

Sztuką wydaje się być zrozumienie, że .gitkatalog podmodułów jest teraz przechowywany w głównym repozytorium pod .git/modules, a każdy podmoduł ma .gitplik, który na to wskazuje. Oto procedura, której potrzebujesz teraz:

  • Przenieś submoduł do nowego domu.
  • Zmodyfikuj .gitplik w katalogu roboczym podmodułu i zmodyfikuj zawartą w nim ścieżkę, tak aby wskazywał właściwy katalog w katalogu głównego repozytorium .git/modules.
  • Wejdź do .git/moduleskatalogu głównego repozytorium i znajdź katalog odpowiadający Twojemu podmodułowi.
  • Edytuj configplik, aktualizując worktreeścieżkę, tak aby wskazywała nową lokalizację katalogu roboczego podmodułu.
  • Edytuj .gitmodulesplik w katalogu głównym repozytorium głównego, aktualizując ścieżkę do katalogu roboczego podmodułu.
  • git add -u
  • git add <parent-of-new-submodule-directory>(Ważne jest, aby dodać nadrzędny , a nie sam katalog podmodułu).

Kilka uwag:

  • Te [submodule "submodule-name"]linie .gitmodulesi .git/configmusi pasować do siebie, ale nie odpowiadają cokolwiek innego.
  • Podmodułowy katalog roboczy i .gitkatalog muszą poprawnie wskazywać na siebie.
  • .gitmodulesI .git/configpliki powinny być zsynchronizowane.
Paul Gideon Dann
źródło
9

Ciąg w cudzysłowie po „[submodule” nie ma znaczenia. Możesz go zmienić na „foobar”, jeśli chcesz. Służy do znalezienia pasującego wpisu w „.git / config”.

Dlatego, jeśli dokonasz zmiany przed uruchomieniem „git submodule init”, będzie działać dobrze. Jeśli dokonasz zmiany (lub przejmiesz ją poprzez scalenie), będziesz musiał albo ręcznie edytować .git / config lub ponownie uruchomić „git submodule init”. Jeśli zrobisz to drugie, pozostanie ci nieszkodliwy wpis „spleciony” ze starą nazwą w .git / config.

Bob Bell
źródło
To naprawdę denerwujące, ale masz rację. Najgorsze jest to, że jeśli po prostu zmienisz adres URL, uruchomienie git init nie wydaje się go aktualizować, musisz ręcznie edytować .git / config.
crimson_penguin
1
w tym przypadku git submodule syncpropaguje zmianę .git/configautomatycznie
CharlesB
9

Możesz po prostu dodać nowy submoduł i usunąć stary submoduł za pomocą standardowych poleceń. (powinien zapobiec przypadkowym błędom w .git)

Przykładowa konfiguracja:

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>

Przykład przeniesienia „jquery” do „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}"

Metoda bonusowa dla dużych submodułów:

Jeśli podmoduł jest duży i wolisz nie czekać na klon, możesz utworzyć nowy podmoduł, używając starego jako źródła, a następnie przełączyć źródło.

Przykład (użyj tej samej konfiguracji przykładowej)

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 pędzi
źródło
Jeśli nie używasz głowicy, być może będziesz musiał sprawdzić poprawną wersję modułu na newPath.
paulmelnikow
2

Podane rozwiązanie nie działało dla mnie, jednak podobna wersja działała ...

Dzieje się tak ze sklonowanym repozytorium, dlatego podmoduły repozytorium git znajdują się w najlepszych repozytoriach .git reż. Wszystkie kationy pochodzą z górnego repozytorium:

  1. Edytuj .gitmodules i zmień ustawienie „path =” dla danego submodułu. (Nie trzeba zmieniać etykiety ani dodawać tego pliku do indeksu).

  2. Edytuj .git / modules / name / config i zmień ustawienie „worktree =” dla danego podmodułu

  3. biegać:

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

Zastanawiam się, czy robi to różnicę, jeśli repozytoria są atomowe, czy względne submoduły, w moim przypadku były względne (submoduł / .git jest odnośnikiem do topproject / .git / modules / submodule)

arand
źródło
2

Wystarczy użyć skryptu powłoki git-submodule-move .

Flimm
źródło
Heh, ponownie spojrzałem na to pytanie i użyłem jednej z wyżej głosowanych odpowiedzi, a teraz żałuję, że nie przewinąłem i nie zobaczyłem mojej poprzedniej odpowiedzi, o której zapomniałem.
Flimm
2

Właśnie przeszedłem tę próbę wczoraj i ta odpowiedź zadziałała idealnie. Oto moje kroki dla jasności:

  1. Upewnij się, że podmoduł jest zalogowany i przekazany na swój serwer. Musisz także wiedzieć, na jakiej gałęzi się znajduje.
  2. Potrzebujesz adresu URL swojego modułu podrzędnego! Użyj, more .gitmodulesponieważ po usunięciu submodułu nie będzie go w pobliżu
  3. Teraz możesz użyć deinit, rma następniesubmodule add

PRZYKŁAD

POLECENIA

    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 

UWAGA: git mv tego nie robi. W ogóle.

Dan Rosenstark
źródło
3
Dobre podsumowanie. +1 git mvpowinno być lepsze w ostatnich wersjach Gita.
WonC
@VonC Testowałem na git 1.8.5, jestem całkiem pewien, że jest tak dobry, jak to tylko możliwe mv. Dzięki!
Dan Rosenstark