web-dev-qa-db-ja.com

un-submodule a gitサブモジュール

Gitサブモジュールのサブモジュールを解除するには(すべてのコードをコアに戻す)?

「最良の手順」のように、私がどのように「すべき」か...

340
Quickredfox

サブモジュールコードをメインリポジトリに配置するだけであれば、サブモジュールを削除してファイルをメインリポジトリに再追加するだけです。

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"

サブモジュールの履歴も保持したい場合は、小さなトリックを行うことができます。サブモジュールをメインリポジトリに「マージ」して、結果が以前と同じになるようにします。ただし、サブモジュールファイルはメインリポジトリ。

メインモジュールでは、次のことを行う必要があります。

# 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

結果のリポジトリは少し奇妙に見えます:最初のコミットが複数あるでしょう。しかし、gitに問題を引き起こすことはありません。

この2番目のソリューションでは、もともとサブモジュールにあったファイルに対してgit blameまたはgit logを実行できるという大きな利点があります。実際、ここで行ったことは、1つのリポジトリ内の多くのファイルの名前を変更することであり、gitはこれを自動検出する必要があります。それでもgitログに問題がある場合は、名前の変更/コピーの検出を改善するオプション(--follow、-M、-C)を試してください。

479
gyim

git 1.8.5(2013年11月 )(サブモジュールの履歴を保持せずに

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

それは:

  • 登録解除およびunload(つまり、サブモジュールの内容を削除()サブモジュール(deinit 、したがってmvfirst)、
  • .gitmodulesをクリーンアップします(rm)、
  • そして、親リポジトリ(rm)のインデックスにあるサブモジュールSHA1を表す 特別なエントリ を削除します。

サブモジュールの削除が完了すると(deinitおよびgit rm)、フォルダーの名前を元の名前に戻し、通常のフォルダーとしてgitリポジトリに追加できます。

注:サブモジュールが古いGit(<1.8)によって作成された場合、 commented by Simon East のように、サブモジュール自体内のネストされた.gitフォルダーを削除する必要がある場合があります


サブモジュールの履歴を保持する必要がある場合は、git filter-branchを使用する jsearsanswer を参照してください。

63
VonC

すべてのファイル履歴を保持しながら、サブモジュールを単純なディレクトリに変換するスクリプトを作成しました。他のソリューションが被るgit log --follow <file>問題に悩まされることはありません。また、すべての作業を行う非常に簡単な1行の呼び出しです。グラック。

彼のブログ投稿「 サブモジュールを親リポジトリに統合する 」で説明されているLucasJenßの優れた成果に基づいていますが、プロセス全体を自動化し、他のいくつかのコーナーケースをクリーンアップします。

最新のコードは https://github.com/jeremysears/scripts/blob/master/bin/git-submodule-rewrite のgithubのバグ修正で維持されますが、適切なスタックオーバーフローの答えのためにプロトコル、私はソリューション全体を以下に含めました。

使用法:

$ 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
52
jsears
  1. git rm --cached the_submodule_path
  2. .gitmodulesファイルからサブモジュールセクションを削除するか、それが唯一のサブモジュールである場合は、ファイルを削除します。
  3. 「削除されたサブモジュールxyz」をコミットします
  4. git add the_submodule_path
  5. 別のコミット「xyzのコードベースを追加」

簡単な方法はまだ見つかりませんでした。 git commit -a-好みの問題で3-5を1つのステップに圧縮できます。

21

ここにはたくさんの答えがありますが、それらはすべて非常に複雑であるように思われ、おそらくあなたが望むことをしません。ほとんどの人は自分の歴史を残したいと思っています。

この例では、メインリポジトリは[email protected]:main/main.gitであり、サブモジュールリポジトリは[email protected]:main/child.gitです。これは、サブモジュールが親リポジトリのルートディレクトリにあることを前提としています。必要に応じて指示を調整します。

親リポジトリを複製し、古いサブモジュールを削除することから始めます。

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

ここで、メインリポジトリにアップストリームの子リポジトリを追加します。

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

次の手順では、merge-prepブランチのファイルをサブモジュールが上記と同じ場所に移動することを前提としていますが、ファイルパスを変更することで簡単に場所を変更できます。

mkdir child

.gitフォルダーを除くすべてのフォルダーとファイルを子フォルダーに移動します。

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

これで、ファイルをmasterブランチに単純にマージできます。

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

git Pushを実行する前に、周りを見てすべてが正常に見えることを確認してください

覚えておく必要があることの1つは、gitログはデフォルトでは移動したファイルを追跡しないことですが、git log --follow filenameを実行すると、ファイルの完全な履歴を確認できます。

14
mschuett

偶然にも、2つのプロジェクトに対して2つのリポジトリを作成しましたが、それらは非常に結合していたので、それらを分離しても意味がありませんでした。それらをマージしました。

最初にそれぞれのマスターブランチをマージする方法を示し、次にこれを取得したすべてのブランチに拡張する方法を説明します。

サブモジュールが機能していて、それを適切なディレクトリに変換したい場合:

git clone project_uri project_name

ここで、正常なクローンを作成して動作させます。このプロセスでは、サブモジュールを初期化または更新する必要はありませんので、スキップしてください。

cd project_name
vim .gitmodules

お好みのエディター(またはVim)で.gitmodulesを編集して、置き換える予定のサブモジュールを削除します。削除する必要がある行は次のようになります。

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

ファイルを保存した後、

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

ここで、サブモジュールの関係を完全に削除して、他のリポジトリを作成し、プロジェクトにインプレースします。

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

ここで、マージするサブモジュールリポジトリを取得します。

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

ここでは、2つのリポジトリのマージ操作を開始しますが、コミットする前に停止します。

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

ここでは、サブモジュール内のmasterのコンテンツを、ディレクトリ名のプレフィックスを付ける前のディレクトリに送信します

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

ここで、マージの変更をコミットする手順を完了します。

これを完了したら、プッシュし、マージする他のブランチでもう一度開始し、変更を受信するリポジトリ内のブランチをチェックアウトし、マージおよびツリーの読み取り操作で持ってきたブランチを変更します。

12
dvicino

私が見つけたこれに対する最良の答えはここにあります:

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

この記事では手順を非常によく説明しています。

6
Luke H

ときのために

git rm [-r] --cached submodule_path

返す

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

コンテキスト:サブモジュールフォルダーでrm -r .git*を実行してから、追加したばかりのメインプロジェクトでサブモジュールをデサブモジュール化する必要があることに気付きました。一部のデサブモジュレーション時に上記のエラーが発生しましたが、すべてではありません。とにかく、実行して修正しました(もちろん、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"

これは履歴を保存しないことに注意してください。

3
brandones

現在のトップアンサーのわずかに改善されたバージョン(IMHO)は次のとおりです。

別のディレクトリで(間違いをより簡単にクリーンアップして再試行するために)トップレポとサブレポの両方をチェックアウトします。

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

最初にサブリポジトリを編集して、すべてのファイルを目的のサブディレクトリに移動します

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"

HEADをメモします

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

メインレポからサブレポを削除します

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"

そして最後に、それらをマージするだけです

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

できました!安全かつ魔法なし。

3
dataless

VonCの答え に基づいて、これを行う簡単なbashスクリプトを作成しました。最後のaddはワイルドカードを使用する必要があります。そうでない場合、サブモジュール自体の以前のrmが取り消されます。サブモジュールディレクトリのcontentsを追加することが重要であり、addコマンドでディレクトリ自体に名前を付けることは重要ではありません。

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

サブモジュールからローカルコミットデータを取得する方が(また?)より便利であることがわかりました。 (そのリモートにアクセスできないため、プッシュできませんでした)。そこで、submodule/.gitをremote_Origin2として追加し、コミットをフェッチして、そのブランチからマージしました。まだgitについて十分な知識がないため、Originとしてリモートのサブモジュールが必要かどうかはわかりません。

0
Rian Wouters