web-dev-qa-db-fra.com

annuler le sous-module d'un sous-module git

Comment dé-sous-moduler un sous-module git (ramener tout le code dans le noyau)?

Comme dans "comment" devrais-je, comme dans "Meilleure procédure" ...

348
Quickredfox

Si tout ce que vous voulez, c'est mettre votre code de sous-module dans le référentiel principal, il vous suffit de supprimer le sous-module et de rajouter les fichiers dans le référentiel principal:

git rm --cached submodule_path # delete reference to submodule HEAD (no trailing slash)
git rm .gitmodules             # if you have more than one submodules,
                               # you need to edit this file instead of deleting!
rm -rf submodule_path/.git     # make sure you have backup!!
git add submodule_path         # will add files instead of commit reference
git commit -m "remove submodule"

Si vous souhaitez également conserver l'historique du sous-module, vous pouvez effectuer une petite astuce: "fusionner" le sous-module dans le référentiel principal afin que le résultat soit identique à ce qu'il était auparavant, sauf que les fichiers de sous-module se trouvent maintenant dans le répertoire. référentiel principal.

Dans le module principal, vous devrez procéder comme suit:

# Fetch the submodule commits into the main repository
git remote add submodule_Origin git://url/to/submodule/Origin
git fetch submodule_Origin

# Start a fake merge (won't change any files, won't commit anything)
git merge -s ours --no-commit submodule_Origin/master

# Do the same as in the first solution
git rm --cached submodule_path # delete reference to submodule HEAD
git rm .gitmodules             # if you have more than one submodules,
                               # you need to edit this file instead of deleting!
rm -rf submodule_path/.git     # make sure you have backup!!
git add submodule_path         # will add files instead of commit reference

# Commit and cleanup
git commit -m "removed submodule"
git remote rm submodule_Origin

Le référentiel résultant aura l'air un peu bizarre: il y aura plus d'un commit initial. Mais cela ne posera aucun problème pour git.

Dans cette seconde solution, vous aurez l’avantage de pouvoir exécuter git log ou git log sur les fichiers qui se trouvaient à l’origine dans des sous-modules. En fait, ce que vous avez fait ici est de renommer de nombreux fichiers dans un même référentiel, et git devrait le détecter automatiquement. Si vous avez toujours des problèmes avec git log, essayez quelques options (--follow, -M, -C) qui permettent une meilleure détection des noms et des copies.

487
gyim

Depuis git 1.8.5 (nov. 201 ) ( sans conserver l'historique du sous-module ):

mv yoursubmodule yoursubmodule_tmp
git submodule deinit yourSubmodule
git rm yourSubmodule
mv yoursubmodule_tmp yoursubmodule
git add yoursubmodule

Cela va:

  • annuler l'enregistrement et décharger (c'est-à-dire supprimer le contenu de ) du sous-module (deinit, d'où le mv premier ),
  • nettoyer le .gitmodules pour vous (rm),
  • et supprimez le entrée spéciale représentant ce sous-module SHA1 dans l'index du référent parent (rm).

Une fois la suppression du sous-module terminée (deinit et git rm), vous pouvez renommer le dossier en son nom d'origine et l'ajouter au référentiel git en tant que dossier normal.

Remarque: si le sous-module a été créé par un ancien Git (<1.8), vous devrez peut-être supprimer le dossier imbriqué .git dans le sous-module lui-même, comme commenté par Simon East


Si vous devez conserver l'historique du sous-module, voir jsears 's answer , qui utilise git filter-branch.

64
VonC

J'ai créé un script qui traduira un sous-module dans un simple répertoire, tout en conservant l'historique des fichiers. Il ne souffre pas des problèmes _git log --follow <file>_ dont souffrent les autres solutions. C'est aussi une invocation très simple d'une ligne qui fait tout le travail pour vous. Allez-y.

Il s'appuie sur l'excellent travail de Lucas Jenß, décrit dans son billet de blog " Intégration d'un sous-module dans le référentiel parent ", mais automatise l'ensemble du processus et nettoie quelques autres cas critiques.

Le dernier code sera maintenu avec des corrections de bugs sur github à l’adresse suivante: https://github.com/jeremysears/scripts/blob/master/bin/git-submodule-rewrite , mais dans l’intérêt d’une réponse correcte à la pile protocole, j'ai inclus la solution dans son intégralité ci-dessous.

Usage:

_$ git-submodule-rewrite <submodule-name>
_

git-submodule-rewrite:

_#!/usr/bin/env bash

# This script builds on the excellent work by Lucas Jenß, described in his blog
# post "Integrating a submodule into the parent repository", but automates the
# entire process and cleans up a few other corner cases.
# https://x3ro.de/2013/09/01/Integrating-a-submodule-into-the-parent-repository.html

function usage(){
  echo "Merge a submodule into a repo, retaining file history."
  echo "Usage: $0 <submodule-name>"
  echo ""
  echo "options:"
  echo "  -h, --help                Print this message"
  echo "  -v, --verbose             Display verbose output"
}

function abort {
    echo "$(tput setaf 1)$1$(tput sgr0)"
    exit 1
}

function request_confirmation {
    read -p "$(tput setaf 4)$1 (y/n) $(tput sgr0)"
    [ "$REPLY" == "y" ] || abort "Aborted!"
}

function warn() {
  cat << EOF
    This script will convert your "${sub}" git submodule into
    a simple subdirectory in the parent repository while retaining all
    contents and file history.

    The script will:
      * delete the ${sub} submodule configuration from .gitmodules and
        .git/config and commit it.
      * rewrite the entire history of the ${sub} submodule so that all
        paths are prefixed by ${path}.
        This ensures that git log will correctly follow the original file
        history.
      * merge the submodule into its parent repository and commit it.

    NOTE: This script might completely garble your repository, so PLEASE apply
    this only to a fresh clone of the repository where it does not matter if
    the repo is destroyed.  It would be wise to keep a backup clone of your
    repository, so that you can reconstitute it if need be.  You have been
    warned.  Use at your own risk.

EOF

  request_confirmation "Do you want to proceed?"
}

function git_version_lte() {
  OP_VERSION=$(printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' '\n' | head -n 4))
  GIT_VERSION=$(git version)
  GIT_VERSION=$(printf "%03d%03d%03d%03d" $(echo "${GIT_VERSION#git version}" | tr '.' '\n' | head -n 4))
  echo -e "${GIT_VERSION}\n${OP_VERSION}" | sort | head -n1
  [ ${OP_VERSION} -le ${GIT_VERSION} ]
}

function main() {

  warn

  if [ "${verbose}" == "true" ]; then
    set -x
  fi

  # Remove submodule and commit
  git config -f .gitmodules --remove-section "submodule.${sub}"
  if git config -f .git/config --get "submodule.${sub}.url"; then
    git config -f .git/config --remove-section "submodule.${sub}"
  fi
  rm -rf "${path}"
  git add -A .
  git commit -m "Remove submodule ${sub}"
  rm -rf ".git/modules/${sub}"

  # Rewrite submodule history
  local tmpdir="$(mktemp -d -t submodule-rewrite-XXXXXX)"
  git clone "${url}" "${tmpdir}"
  pushd "${tmpdir}"
  local tab="$(printf '\t')"
  local filter="git ls-files -s | sed \"s/${tab}/${tab}${path}\//\" | GIT_INDEX_FILE=\${GIT_INDEX_FILE}.new git update-index --index-info && mv \${GIT_INDEX_FILE}.new \${GIT_INDEX_FILE}"
  git filter-branch --index-filter "${filter}" HEAD
  popd

  # Merge in rewritten submodule history
  git remote add "${sub}" "${tmpdir}"
  git fetch "${sub}"

  if git_version_lte 2.8.4
  then
    # Previous to git 2.9.0 the parameter would yield an error
    ALLOW_UNRELATED_HISTORIES=""
  else
    # From git 2.9.0 this parameter is required
    ALLOW_UNRELATED_HISTORIES="--allow-unrelated-histories"
  fi

  git merge -s ours --no-commit ${ALLOW_UNRELATED_HISTORIES} "${sub}/master"
  rm -rf tmpdir

  # Add submodule content
  git clone "${url}" "${path}"
  rm -rf "${path}/.git"
  git add "${path}"
  git commit -m "Merge submodule contents for ${sub}"
  git config -f .git/config --remove-section "remote.${sub}"

  set +x
  echo "$(tput setaf 2)Submodule merge complete. Push changes after review.$(tput sgr0)"
}

set -euo pipefail

declare verbose=false
while [ $# -gt 0 ]; do
    case "$1" in
        (-h|--help)
            usage
            exit 0
            ;;
        (-v|--verbose)
            verbose=true
            ;;
        (*)
            break
            ;;
    esac
    shift
done

declare sub="${1:-}"

if [ -z "${sub}" ]; then
  >&2 echo "Error: No submodule specified"
  usage
  exit 1
fi

shift

if [ -n "${1:-}" ]; then
  >&2 echo "Error: Unknown option: ${1:-}"
  usage
  exit 1
fi

if ! [ -d ".git" ]; then
  >&2 echo "Error: No git repository found.  Must be run from the root of a git repository"
  usage
  exit 1
fi

declare path="$(git config -f .gitmodules --get "submodule.${sub}.path")"
declare url="$(git config -f .gitmodules --get "submodule.${sub}.url")"

if [ -z "${path}" ]; then
  >&2 echo "Error: Submodule not found: ${sub}"
  usage
  exit 1
fi

if ! [ -d "${path}" ]; then
  >&2 echo "Error: Submodule path not found: ${path}"
  usage
  exit 1
fi

main
_
54
jsears
  1. git rm --cached the_submodule_path
  2. supprimez la section de sous-module du fichier .gitmodules ou, si c'est le seul sous-module, supprimez le fichier.
  3. faire un commit "sous-module supprimé xyz"
  4. git add the_submodule_path
  5. un autre commit "ajouté le code base de xyz"

Je n'ai pas encore trouvé de moyen plus facile. Vous pouvez compresser 3-5 en une étape via git commit -a - une question de goût.

22
Marcel Jackwerth

Beaucoup de réponses ici, mais toutes semblent être trop complexes et ne font probablement pas ce que vous voulez. Je suis sûr que la plupart des gens veulent garder leur histoire.

Pour cet exemple, le référentiel principal sera [email protected]:main/main.git et le sous-module de référentiel sera [email protected]:main/child.git. Cela suppose que le sous-module se trouve dans le répertoire racine du référent parent. Ajustez les instructions au besoin.

Commencez par cloner le référent parent et en supprimant l'ancien sous-module.

git clone [email protected]:main/main.git
git submodule deinit child
git rm child
git add --all
git commit -m "remove child submodule"

Nous allons maintenant ajouter les pensions en amont au dépôt principal.

git remote add upstream [email protected]:main/child.git
git fetch upstream
git checkout -b merge-prep upstream/master

L'étape suivante suppose que vous souhaitiez déplacer les fichiers de la branche fusion-préparation au même emplacement que celui du sous-module précédent, bien que vous puissiez facilement changer d'emplacement en modifiant le chemin d'accès au fichier.

mkdir child

déplacez tous les dossiers et fichiers sauf le dossier .git dans le dossier enfant.

git add --all
git commit -m "merge prep"

Maintenant, vous pouvez simplement fusionner vos fichiers dans la branche principale.

git checkout master
git merge merge-prep # --allow-unrelated-histories merge-prep flag may be required 

Regardez autour de vous et assurez-vous que tout va bien avant de lancer git Push

Vous devez maintenant vous rappeler que git log ne suit pas par défaut les fichiers déplacés. Toutefois, en exécutant git log --follow filename, vous pouvez voir l'historique complet de vos fichiers.

15
mschuett

Il nous est arrivé que nous ayons créé 2 référentiels pour 2 projets tellement couplés que cela n’a aucun sens de les séparer, nous les avons donc fusionnés.

Je vais vous montrer comment fusionner les branches principales dans chacune d’elles, puis je vais vous expliquer comment vous pouvez l’étendre à toutes les branches que vous avez, en espérant que cela vous aidera.

Si le sous-module fonctionne et que vous souhaitez le convertir en répertoire, vous pouvez effectuer les tâches suivantes:

git clone project_uri project_name

Ici, nous faisons un clone propre pour travailler. Pour ce processus, vous n'avez pas besoin d'initialiser ou de mettre à jour les sous-modules, donc ignorez-le.

cd project_name
vim .gitmodules

Éditez .gitmodules avec votre éditeur favori (ou Vim) pour supprimer le sous-module que vous souhaitez remplacer. Les lignes que vous devez supprimer doivent ressembler à ceci:

[submodule "lib/asi-http-request"]
    path = lib/asi-http-request
    url = https://github.com/pokeb/asi-http-request.git

Après avoir sauvegardé le fichier,

git rm --cached directory_of_submodule
git commit -am "Removed submodule_name as submodule"
rm -rf directory_of_submodule

Ici, nous supprimons complètement la relation de sous-module afin que nous puissions créer amener l'autre dépôt au projet en place.

git remote add -f submodule_Origin submodule_uri
git fetch submodel_Origin/master

Ici, nous allons chercher le référentiel de sous-modules à fusionner.

git merge -s ours --no-commit submodule_Origin/master

Ici, nous commençons une opération de fusion des 2 référentiels, mais nous nous arrêtons avant la validation.

git read-tree --prefix=directory_of_submodule/ -u submodule_Origin/master

Ici, nous envoyons le contenu du maître du sous-module au répertoire où il se trouvait avant de préfixer un nom de répertoire.

git commit -am "submodule_name is now part of main project"

Ici, nous terminons la procédure en effectuant une validation des modifications de la fusion.

Une fois cette opération terminée, vous pouvez appuyer sur Push et recommencer avec toute autre branche à fusionner. Il vous suffit de vérifier la branche de votre référentiel qui recevra les modifications et de modifier la branche sur laquelle vous apportez les opérations de fusion et de lecture.

12
dvicino

La meilleure réponse à cette question est la suivante:

http://x3ro.de/2013/09/01/Integrating-a-submodule-into-the-parent-repository.html

Cet article explique très bien la procédure.

6
Luke H

Lorsque

git rm [-r] --cached submodule_path

résultats

fatal: pathspec 'emr/normalizers/' did not match any files

Contexte: j'ai fait rm -r .git* dans mes dossiers de sous-modules avant de réaliser qu'ils devaient être démodulés dans le projet principal auquel je venais de les ajouter. J'ai eu l'erreur ci-dessus lors de la sous-modulation de certains, mais pas tous. En tout cas, je les ai corrigés en lançant (après, bien sûr, le rm -r .git*)

mv submodule_path submodule_path.temp
git add -A .
git commit -m "De-submodulization phase 1/2"
mv submodule_path.temp submodule_path
git add -A .
git commit -m "De-submodulization phase 2/2"

Notez que cela ne conserve pas l'histoire.

3
brandones

Voici une version légèrement améliorée (IMHO) de la réponse actuelle principale:

Dans un répertoire séparé (pour que les erreurs soient plus faciles à nettoyer et réessayer), vérifiez à la fois le dépôt en haut et le subrepo.

git clone ../main_repo main.tmp
git clone ../main_repo/sub_repo sub.tmp

Commencez par modifier le sous-répertoire pour déplacer tous les fichiers dans le sous-répertoire souhaité.

cd sub.tmp
mkdir sub_repo_path
git mv `ls | grep -v sub_repo_path` sub_repo_path/
git commit -m "Moved entire subrepo into sub_repo_path"

Prenez note de la tête

SUBREPO_HEAD=`git reflog | awk '{ print $1; exit; }'`

Maintenant, supprimez le subrepo du dépôt principal

cd ../main.tmp
rmdir sub_repo_path
vi .gitmodules  # remove config for submodule
git add -A
git commit -m "Removed submodule sub_repo_path in preparation for merge"

Et enfin, juste les fusionner

git fetch ../sub.tmp
git merge $SUBREPO_HEAD

Et fait! En toute sécurité et sans aucune magie.

3
dataless

Basé sur réponse de VonC , j'ai créé un script bash simple pour le faire. La add à la fin doit utiliser des caractères génériques, sinon elle annulera la précédente rm pour le sous-module lui-même. Il est important d'ajouter le contenu du répertoire du sous-module et de ne pas nommer le répertoire lui-même dans la commande add.

Dans un fichier nommé git-integrate-submodule:

#!/usr/bin/env bash
mv "$1" "${1}_"
git submodule deinit "$1"
git rm "$1"
mv "${1}_" "$1"
git add "$1/**"
2
void.pointer

J'ai trouvé plus pratique d'extraire (aussi?) Des données de validation locales du sous-module, car sinon je les perdrais. (Impossible de les pousser car je n’ai pas accès à cette télécommande). J'ai donc ajouté le sous-module/.git en tant que remote_Origin2, je l'ai récupéré, puis il a été fusionné à partir de cette branche. Je ne sais pas si j'ai toujours besoin de la télécommande de sous-module en tant que Origin, car je ne suis pas encore assez familiarisé avec git.

0
Rian Wouters