Stellen Sie Git-Submodule aus Git-Modulen wieder her


77

Ich habe einen Ordner, der ein Git-Repo war. Es enthält einige Dateien und .gitmodules-Dateien. Nun, wenn ich es tuegit init danngit submodule init , ist die letztere Befehlsausgabe nichts. Wie kann ich git helfen, Submodule zu sehen, die in der .gitmodules-Datei definiert sind, ohne git submodule adderneut von Hand ausgeführt zu werden?

Update: Dies ist meine .gitmodules-Datei:

[submodule "vim-pathogen"]
    path = vim-pathogen
    url = git://github.com/tpope/vim-pathogen.git
[submodule "bundle/python-mode"]
    path = bundle/python-mode
    url = git://github.com/klen/python-mode.git
[submodule "bundle/vim-fugitive"]
    path = bundle/vim-fugitive
    url = git://github.com/tpope/vim-fugitive.git
[submodule "bundle/ctrlp.vim"]
    path = bundle/ctrlp.vim
    url = git://github.com/kien/ctrlp.vim.git
[submodule "bundle/vim-tomorrow-theme"]
    path = bundle/vim-tomorrow-theme
    url = git://github.com/chriskempson/vim-tomorrow-theme.git

und hier ist eine Auflistung dieses Verzeichnisses:

drwxr-xr-x  4 evgeniuz 100 4096 июня  29 12:06 .
drwx------ 60 evgeniuz 100 4096 июня  29 11:43 ..
drwxr-xr-x  2 evgeniuz 100 4096 июня  29 10:03 autoload
drwxr-xr-x  7 evgeniuz 100 4096 июня  29 12:13 .git
-rw-r--r--  1 evgeniuz 100  542 июня  29 11:45 .gitmodules
-rw-r--r--  1 evgeniuz 100  243 июня  29 11:18 .vimrc

es ist also definitiv auf höchstem Niveau. das git Verzeichnis nicht geändert wird, nur git initgeschieht ,


Sind die Submodule bereits vorhanden, in dem Sinne, dass beim Wechsel in ein Submodulverzeichnis Dateien vorhanden sind und git rev-parse --show-toplevelSie das Submodul anstelle des Verzeichnisses "Supermodul" erhalten?
Mark Longair

Nein, Submodul-Verzeichnisse sind nicht vorhanden. Stellen Sie sich vor, dieser Ordner ist komplett leer mit nur .gitmodulesDatei
evgeniuz

Ah, ich sehe, was das Problem ist - ich habe meine Antwort aktualisiert.
Mark Longair

Antworten:


103

git submodule initBerücksichtigt nur Submodule, die sich bereits im Index befinden (dh "inszeniert"), für die Initialisierung. Ich würde ein kurzes Skript schreiben, das analysiert .gitmodulesund für jedes urlund jedes pathPaar Folgendes ausführt :

git submodule add <url> <path>

Sie können beispielsweise das folgende Skript verwenden:

#!/bin/sh

set -e

git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
    while read path_key path
    do
        url_key=$(echo $path_key | sed 's/\.path/.url/')
        url=$(git config -f .gitmodules --get "$url_key")
        git submodule add $url $path
    done

Dies basiert darauf, wie das git-submodule.shSkript selbst die .gitmodulesDatei analysiert .


1
meinst du git submodule update --init? Alle diese Befehle schlagen stillschweigend fehl. Es sieht so aus, als ob Git keine Module sieht, die nur in.gitmodules
evgeniuz

Nach dem git submodule init, sehen Sie eine Ausgabe aus git config --list | grep submodule? (Wie in der Dokumentation angegeben, git submodule initsollte "die Submodule initialisieren, dh jeden in .gitmodules gefundenen Submodulnamen und jede URL in .git/config" registrieren .)
Mark Longair

Nein, nichts. git config --listgibt nur Standardwerte an, keine Erwähnung von Submodulen
evgeniuz

@Shark: Das ist seltsam - könnten Sie Ihre Frage mit dem Inhalt Ihrer .gitmodulesDatei aktualisieren ? Befindet sich Ihre .gitmodulesDatei definitiv auf der obersten Ebene Ihres Repositorys und nicht in einem Unterverzeichnis?
Mark Longair

Danke, ich dachte, es gibt einen allgemeineren Weg als ein Skript :)
evgeniuz

15

Als Erweiterung der Antwort von @Mark Longair habe ich ein Bash-Skript geschrieben, um die Schritte 2 und 3 des folgenden Prozesses zu automatisieren:

  1. Klonen Sie ein 'Boilerplate'-Repo, um ein neues Projekt zu starten
  2. Entfernen Sie den Ordner .git und initialisieren Sie ihn als neues Repo neu
  3. Initialisieren Sie die Submodule neu und fordern Sie zur Eingabe auf, bevor Sie Ordner löschen

#!/bin/bash

set -e
rm -rf .git
git init

git config -f .gitmodules --get-regexp '^submodule\..*\.path$' > tempfile

while read -u 3 path_key path
do
    url_key=$(echo $path_key | sed 's/\.path/.url/')
    url=$(git config -f .gitmodules --get "$url_key")

    read -p "Are you sure you want to delete $path and re-initialize as a new submodule? " yn
    case $yn in
        [Yy]* ) rm -rf $path; git submodule add $url $path; echo "$path has been initialized";;
        [Nn]* ) exit;;
        * ) echo "Please answer yes or no.";;
    esac

done 3<tempfile

rm tempfile

Hinweis: Die Submodule werden an der Spitze ihres Hauptzweigs anstelle des gleichen Commits wie das Boilerplate-Repo ausgecheckt. Sie müssen dies also manuell tun.

Das Weiterleiten der Ausgabe von git config in die Leseschleife verursachte Probleme mit der Eingabeaufforderung, sodass sie stattdessen in eine temporäre Datei ausgegeben wird. Alle Verbesserungen an meinem ersten Bash-Skript wären sehr willkommen :)


Vielen Dank an Mark, https://stackoverflow.com/a/226724/193494 , bash: verschachteltes interaktives Lesen in einer Schleife, die auch read verwendet , und tnettenba @ chat.freenode.net, die mir geholfen haben, zu dieser Lösung zu gelangen!


6

Erweiterung der exzellenten Antwort von @Mark Longair um ein Submodul, das den Zweig- und Reponamen berücksichtigt.

#!/bin/sh

set -e

git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
    while read path_key path
    do
        name=$(echo $path_key | sed 's/\submodule\.\(.*\)\.path/\1/')
        url_key=$(echo $path_key | sed 's/\.path/.url/')
        branch_key=$(echo $path_key | sed 's/\.path/.branch/')
        url=$(git config -f .gitmodules --get "$url_key")
        branch=$(git config -f .gitmodules --get "$branch_key" || echo "master")
        git submodule add -b $branch --name $name $url $path || continue
    done

1
Dies hat hervorragend funktioniert, es wurde jedoch auch jeder Eintrag in der .gitmodules-Datei dupliziert, der nachträglich manuell bereinigt werden muss.
Marcus Ottosson

3

Ich hatte ein ähnliches Problem. git submodule initscheiterte lautlos.

Als ich das tat:

git submodule add <url> <path>

Ich habe:

The following path is ignored by one of your .gitignore files: ...

Ich denke, dass .gitignore (d) -Pfade die Ursache sein könnten.


1

Ich weiß, dass es eine Weile her ist, aber ich möchte diese Version teilen, die git confignur einmal aufruft , kein Skript benötigt und auch Zweige verarbeitet:

git config -f .gitmodules --get-regexp '^submodule\.' | perl -lane'
$conf{$F[0]} = $F[1]}{
@mods = map {s,\.path$,,; $_} grep {/\.path$/} keys(%conf);
sub expand{$i = shift; map {$conf{$i . $_}} qw(.path .url .branch)}
for $i (@mods){
    ($path, $url, $branch) = expand($i);
    print(qq{rm -rf $path});
    print(qq{git submodule add -b $branch $url $path});
}
'

Der einzige Nebeneffekt ist die Ausgabe der Befehle. Es wird nichts ausgeführt, sodass Sie die Prüfung durchführen können, bevor Sie sie festlegen.

Dies funktioniert mit einem einfachen Kopieren und Einfügen in der Konsole, sollte jedoch trivial sein, um es in ein Shell-Skript einzufügen.

Beispielausgabe:

rm -rf third-party/dht
git submodule add -b post-0.25-transmission https://github.com/transmission/dht third-party/dht
rm -rf third-party/libutp
git submodule add -b post-3.3-transmission https://github.com/transmission/libutp third-party/libutp
rm -rf third-party/libb64
git submodule add -b post-1.2.1-transmission https://github.com/transmission/libb64 third-party/libb64
rm -rf third-party/libnatpmp
git submodule add -b post-20151025-transmission https://github.com/transmission/libnatpmp third-party/libnatpmp
rm -rf third-party/miniupnpc
git submodule add -b post-2.0.20170509-transmission https://github.com/transmission/miniupnpc third-party/miniupnpc
rm -rf third-party/libevent
git submodule add -b post-2.0.22-transmission https://github.com/transmission/libevent third-party/libevent

1

Eine aktualisierte Version des Skripts von @ mark-longair. Dieser unterstützt auch Verzweigungen, behandelt den Fall, in dem einige der Submodule bereits vorhanden sind .git/config, und sichert bei Bedarf vorhandene Verzeichnisse mit demselben Namen wie die Submodulpfade.

git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
    while read path_key path
    do
        url_key=$(echo $path_key | sed 's/\.path/.url/');
        branch_key=$(echo $path_key | sed 's/\.path/.branch/');
        # If the url_key doesn't yet exist then backup up the existing
        # directory if necessary and add the submodule
        if [ ! $(git config --get "$url_key") ]; then
            if [ -d "$path" ] && [ ! $(git config --get "$url_key") ]; then
                mv "$path" "$path""_backup_""$(date +'%Y%m%d%H%M%S')";
            fi;
            url=$(git config -f .gitmodules --get "$url_key");
            # If a branch is specified then use that one, otherwise
            # default to master
            branch=$(git config -f .gitmodules --get "$branch_key");
            if [ ! "$branch" ]; then branch="master"; fi;
            git submodule add -f -b "$branch" "$url" "$path";
        fi;
    done;

# In case the submodule exists in .git/config but the url is out of date

git submodule sync;

# Now actually pull all the modules. I used to use this...
#
# git submodule update --init --remote --force --recursive
# ...but the submodules would check out in detached HEAD state and I 
# didn't like that, so now I do this...

git submodule foreach --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)';

0

Probieren Sie für zsh-Benutzer meine Funktion aus, die DRY_RUN=1unterstützt, um zu sehen, welche Befehle ausgeführt werden, und die nur gitzum Parsen der Datei verwendet wird sed.

gsub_file() {(
  set -eu

  cd "$(git rev-parse --show-toplevel)"

  submodule_paths=(
    "${(@f)$(git config --file ./.gitmodules --get-regexp "path" | awk '{ print $2 }')}"
  )
  submodule_urls=(
    "${(@f)$(git config --file ./.gitmodules --get-regexp "url" | awk '{ print $2 }')}"
  )
  submodule_branches=(
    "${(@f)$(git config --file ./.gitmodules --get-regexp "branch" | awk '{ print $2 }')}"
  )

  sh_c() {
    echo + "$*"
    if [ "${DRY_RUN-}" ]; then
      return
    fi
    eval "$@"
  }

  for (( i=1; i <= ${#submodule_paths[@]}; i++ )) do
    p="${submodule_paths[$i]}"
    if [ -d "$p" ]; then
      continue
    fi

    url="${submodule_urls[$i]}"
    unset b
    if [ "${submodule_branches[$i]-}" ]; then
      b="-b ${submodule_branches[$i]}" 
    fi
    sh_c git submodule add "${b-}" "$url" "$p"
  done
)}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.