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"]

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.


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!


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).


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"

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.

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.


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
...

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)


2

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


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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.