LoginSignup
50
48

More than 5 years have passed since last update.

subtree コマンドで別のリポジトリを指定したフォルダに取り込んでpushとかpullをできるようにする

Last updated at Posted at 2013-05-18

前提

parent リポジトリと child リポジトリがある

目標

  1. parent リポジトリの /parent_child/ フォルダに child リポジトリをsubtreeとして取り込む
  2. child リポジトリの更新を /parent_child/に反映する (subtree pull)
  3. parent_child フォルダの更新を child リポジトリに反映する (subtree push)

    こんなかんじ
    parent--parenttxt (ここはparent repo)
          |-parent_child--child.txt (ここのフォルダに child repoを反映)

手順

1. child リポジトリ の取り込み

  • parent リポジトリと child リポジトリを作成する(すでにあれば飛ばす)
mkdir parent && pushd parent && git init && popd
mkdir child && pushd child && git init && popd
pushd parent && touch parent.txt && git add . && git commit -m "parent 1st commit" && popd
pushd child && touch child.txt && git add . && git commit -m "child 1st commit" && popd
  • subtreeとして取り込む
cd parent
# child リポジトリを remoteとして登録 -f で fetch も行なっておく
git remote add -f child_remote ../child/
# subtreeとして登録 --squashで一つのコミットとして取り込む
# git subtree add --prefix=`subtreeのフォルダ名` `subtreeに取り込むリポジトリ` `取り込むブランチ` --squash
git subtree add --prefix=parent_child child_remote master --squash
# parent_child フォルダ内がchild リポジトリの構成になっていることを確認
ls parent_child/
# 取り込まれたコミットを確認
git log HEAD^2 -1 -p

2. child リポジトリの更新の反映

  • child リポジトリの更新
cd ../child/
# child リポジトリの更新
echo "update text after subtree-add" > child.txt 
git commit -am "update child #1"
cd ../parent/
  • child リポジトリを parent リポジトリの parent_child フォルダに反映
# child リポジトリの反映
# git subtree pull --prefix `subtreeのフォルダ名` child_remote master --squash
# `subtreeのフォルダ名` の最後が / だとうまく動かないので注意
git subtree pull --prefix parent_child child_remote master --squash
# 反映されたコミットを確認
git log HEAD^2 -1 -p
  • childリポジトリの複数のコミットがひとつのコミットとしてparentリポジトリに反映されることを確認
# childリポジトリに二つのコミットを作成
cd ../child/
echo "update text after subtree-add #2" for 2 commit pull >> child.txt 
git commit -am "update child #2"
echo "update text after subtree-add #3" for 2 commit pull >> child.txt 
git commit -am "update child #3"
cd ../parent/

# child リポジトリの反映
git subtree pull --prefix parent_child child_remote master --squash

# ひとつのコミットとして反映されていることを確認
git log HEAD^2 -1 -p

3. parent リポジトリの parent_child内の変更を childリポジトリへ反映

  • bareではないリポジトリへのpushでエラーが出ないように下記を設定
# このサンプルでは bare リポジトリを使っていないため下記コマンドを実行する
# bare に対してpushする場合は不要
cd ../child/
git config receive.denyCurrentBranch ignore
cd ../parent/
  • parent_child内にファイルを作成するコミットを2回実行
cd parent_child/
touch parent_add1.txt && git add . && git commit -m "add from parent #1"
touch parent_add2.txt && git add . && git commit -m "add from parent #2"
cd ..
  • child リポジトリへ subtree push
git subtree push --prefix parent_child child_remote master

# 反映されていることを確認
cd ../child/ && git log -3 -p
  • subtree外のファイルがpush で反映されないことを確認
# subtree内にファイルを作成しcommit
cd ../parent/parent_child/
touch parent_add3.txt && git add . && git commit -m "add from parent #3"

# subtree外にファイルを作成しcommit
cd ..
touch parent_add4.txt && git add . && git commit -m "add from parent #4"

# subtree内とsubtree外にファイルを作成しcommit
# 内
cd parent_child && touch parent_add5.txt 
# 外
cd .. && touch parent_add6.txt 
git add . && git commit -m "add from parent #5 & #6"

# child リポジトリへ subtree push
git subtree push --prefix parent_child child_remote master

# subutree内の変更のみ反映されていることを確認
# parent_add4.txtの追加コミットが反映されないことを確認 および
# parent_add5.txt,parent_add6.txt を追加したコミットに、
# parent_add6.txt がないことを確認
cd ../child/ && git log -3 -p

まとめ

  • subtreeの取り込みは git subtree add
  • subtreeとして取り込んだリポジトリの変更は subtree pull で簡単に取り込める
  • subtreeとして取り込んだリポジトリへの変更は subtree push で簡単に反映させることができる
    • 注意点としてsubtree外のファイルを同時に変更したコミットがあった場合、subtree外のファイルはcommitから削除された状態でpushされる
  • 挙動が理解できたら subtree コマンド便利そう

参考

Alternatives To Git Submodule: Git Subtree

50
48
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
50
48