gitサブモジュールのサブモジュールを解除するには(すべてのコードをコアに戻します)?
私がどのように「すべきか」のように、「最良の手順」のように...
gitサブモジュールのサブモジュールを解除するには(すべてのコードをコアに戻します)?
私がどのように「すべきか」のように、「最良の手順」のように...
回答:
サブモジュールコードをメインリポジトリに配置するだけの場合は、サブモジュールを削除して、ファイルをメインリポジトリに再度追加するだけです。
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 logに問題がある場合は、名前の変更/コピーの検出を改善するいくつかのオプション(--follow、-M、-C)を試してください。
git merge
は、すべてのファイルの「前のコミット」が(マージの2つの「サイド」の1つに)あることを確認します。
mkdir foo && git mv !(foo) foo && git commit
。
--allow-unrelated-histories
、私はなっていたとして、偽のマージでマージを強制的にfatal: refusing to merge unrelated histories
もっとここに、:github.com/git/git/blob/master/Documentation/RelNotes/...
git 1.8.5(2013年11月)以降(サブモジュールの履歴を保持しない):
mv yoursubmodule yoursubmodule_tmp
git submodule deinit yourSubmodule
git rm yourSubmodule
mv yoursubmodule_tmp yoursubmodule
git add yoursubmodule
それは:
deinit
mv
.gitmodules
(rm
)、rm
)。サブモジュールの削除が完了したら(deinit
およびgit rm
)、フォルダーの名前を元の名前に戻し、通常のフォルダーとしてgit repoに追加できます。
注:サブモジュールが古いGitリポジトリ(<1.8)で作成された場合は、ネストされた削除する必要があるかもしれない.git
として、サブモジュール自体の中にフォルダをコメントでサイモン・東
サブモジュールの履歴を保持する必要がある場合は、を使用するjsearsの回答を参照してくださいgit filter-branch
。
deinit
一人でサブモジュールから作業ツリーをクリーンアップしましたか?
すべてのファイル履歴を保持しながら、サブモジュールを単純なディレクトリに変換するスクリプトを作成しました。git log --follow <file>
他のソリューションが抱えている問題に悩まされることはありません。また、すべての作業を行う非常に簡単な1行の呼び出しでもあります。グラック。
彼のブログ投稿「サブモジュールを親リポジトリに統合する」で説明されているLucasJenßによる優れた成果に基づいて構築されていますが、プロセス全体を自動化し、他のいくつかのコーナーケースをクリーンアップします。
最新のコードは、https://github.com/jeremysears/scripts/blob/master/bin/git-submodule-rewriteの githubのバグ修正で維持されますが、適切なstackoverflow応答プロトコルのために、全体のソリューションを以下に示します。
使用法:
$ 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
curl https://raw.githubusercontent.com/jeremysears/scripts/master/bin/git-submodule-rewrite > git-submodule-rewrite.sh
と./git-submodule-rewrite.sh <submodule-name>
git rm --cached the_submodule_path
.gitmodules
ファイルからサブモジュールセクションを削除するか、それが唯一のサブモジュールである場合は、ファイルを削除します。git add the_submodule_path
まだ簡単な方法は見つかりませんでした。3-5を1ステップで圧縮できますgit commit -a
-好みの問題。
.gitmodules
代わりにすべきではない.submodules
ですか?
.gitmodules
はない.submodules
.git
前に、サブモジュールのディレクトリを削除する必要がありましたgit add
ここにはたくさんの答えがありますが、それらはすべて非常に複雑で、おそらくあなたが望むことをしないようです。ほとんどの人は自分の歴史を守りたいと思っています。
この例では、メインのリポジトリはgit@site.com:main/main.git
となり、サブモジュールのリポジトリはとなりますgit@site.com:main/child.git
。これは、サブモジュールが親リポジトリのルートディレクトリにあると想定しています。必要に応じて手順を調整します。
まず、親リポジトリのクローンを作成し、古いサブモジュールを削除します。
git clone git@site.com:main/main.git
git submodule deinit child
git rm child
git add --all
git commit -m "remove child submodule"
次に、メインのリポジトリの上流に子リポジトリを追加します。
git remote add upstream git@site.com: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 logは移動されたファイルを追跡しないことですが、実行git log --follow filename
するとファイルの完全な履歴を確認できます。
git merge merge-prep
進み、エラーを受け取りましたfatal: refusing to merge unrelated histories
。回避策はこれです:git merge --allow-unrelated-histories merge-prep
。
child
ディレクトリにフェッチする方法があるので、後で移動する必要はありませんか?サブモジュールとメインリポジトリに同じファイル名があります... 2つのファイルをマージしようとしているため、マージの競合が発生します。
2つのプロジェクト用に2つのリポジトリーを作成して、それらを分離しても意味がないほど結合したので、それらをマージしました。
最初に各マスターブランチをマージする方法を示し、次に、これを取得したすべてのブランチに拡張する方法を説明します。
サブモジュールが機能していて、適切なディレクトリに変換したい場合は、次のようにします。
git clone project_uri project_name
ここでは、クリーンなクローンを実行します。このプロセスでは、サブモジュールを初期化または更新する必要がないため、スキップしてください。
cd project_name
vim .gitmodules
.gitmodules
お好みのエディター(またはVim)で編集して、置き換える予定のサブモジュールを削除します。削除する必要がある行は、次のようになります。
[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
ここでは、サブモジュールのマスターのコンテンツを、ディレクトリ名をプレフィックスする前のディレクトリに送信します
git commit -am "submodule_name is now part of main project"
ここで、マージの変更をコミットする手順を完了します。
これが終了したら、プッシュして、マージする他のブランチから再開できます。変更を受け取るリポジトリ内のブランチをチェックアウトし、マージおよびツリーの読み取り操作で使用するブランチを変更します。
directory_of_submodule
git log original_path_of_file_in_submodule
ますが、サブモジュールファイルであっても、ファイルのgitリポジトリに登録されているパス(ファイルシステムに存在しない)を実行することで、マージされたサブモジュールファイルの履歴を取得できたと思います現在住んでいますsubmodule_path/new_path_of_file
私が見つけたこれに対する最良の答えはここにあります:
http://x3ro.de/2013/09/01/Integrating-a-submodule-into-the-parent-repository.html
この記事では、手順を非常によく説明しています。
@gyimの回答を少し改善したバージョン(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
# remove --allow-unrelated-histories if using git older than 2.9.0
git merge --allow-unrelated-histories $SUBREPO_HEAD
やった!安全かつ魔法なし。
subrepo
か?
git merge $SUBREPO_HEAD fatal: refusing to merge unrelated histories
に使用する必要がありますgit merge $SUBREPO_HEAD --allow-unrelated-histories
か?それともそれなしで動作するはずであり、私はミスをしましたか?
ときのために
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"
これは履歴を保存しないことに注意してください。
VonCの回答に基づいて、これを行う簡単なbashスクリプトを作成しました。add
最後には、それ以外の場合は、前を取り消しますワイルドカードを使用しているrm
サブモジュール自身のために。コマンドでディレクトリ自体に名前を付けるのではなく、サブモジュールディレクトリの内容を追加することが重要add
です。
次のファイルでgit-integrate-submodule
:
#!/usr/bin/env bash
mv "$1" "${1}_"
git submodule deinit "$1"
git rm "$1"
mv "${1}_" "$1"
git add "$1/**"
これが私が最もよく最も簡単に見つけたものです。
サブモジュールのリポジトリで、HEADからメインのリポジトリにマージしたい場合:
git checkout -b "mergeMe"
mkdir "foo/bar/myLib/"
(メインリポジトリのファイルが必要な場所と同じパス)git mv * "foo/bar/myLib/"
(すべてをパスに移動)git commit -m "ready to merge into main"
サブモジュールを削除してパス「foo / bar / myLib」をクリアした後、メインリポジトリに戻ります。
git merge --allow-unrelated-histories SubmoduleOriginRemote/mergeMe
ブームは終わった
保存された歴史
心配ない
これは他のいくつかの回答とほぼ同じであることに注意してください。しかし、これはあなたが自分のサブモジュールリポジトリを持っていることを前提としています。また、これにより、サブモジュールの将来のアップストリームの変更を簡単に取得できます。
git submodule deinit
ご覧ください