Git のすでにあるリポジトリーからサブモジュールにするためのリポジトリーを作成しました

Hugo でウェブサイトを作っていて、テーマも自分で作っていたのですが、ウェブサイトとテーマが同じリポジトリーに含まれてしまっていたため、テーマだけのリポジトリーを独立して作成してみました。

既存のリポジトリからサブモジュールを分離する - Qiita の記事を参考にしました。

流れは、次のようになるみたいです。

  1. 今回の作業のためのワーキングディレクトリーを作成(git clone)(dir2)
  2. ワーキングディレクトリーの内容を変更(git filter-branch)(dir2)
  3. GitHub にリポジトリーを作成
  4. remote url を変更(git remote set-url)(dir2)
  5. GitHub に push(git push)(dir2)
  6. ディレクトリーを削除(dir1)
  7. GitHub に push(git push)(dir1)
  8. サブモジュールを追加(dir1)
  9. GitHub に push(git push)(dir1)

リポジトリーとディレクトリー

repo1 リポジトリーがあって、 repo1 のディレクトリーは次のようになっています。

$ tree -L 2
.
├── archetypes
├── config.toml
├── content
│   ├── about.md
│   ├── _index.md
│   ├── post
│   └── privacy.md
├── data
├── deploy.sh
├── layouts
├── public
│   ├── 404.html
│   ├── about
│   ├── categories
│   ├── css
│   ├── googlebc830b58d80exxxx.html
│   ├── img
│   ├── index.html
│   ├── index.xml
│   ├── js
│   ├── post
│   ├── privacy
│   ├── robots.txt
│   ├── sitemap.xml
│   └── tags
├── README.md
├── static
│   ├── googlebc830b58d80exxxx.html
│   ├── img
│   └── robots.txt
└── themes
    ├── an6474
    └── theme1

19 directories, 14 files

これの一番下にある themes/theme1 ディレクトリーを新しいリポジトリーとして独立して作りたいと思います。 これを repo2 とします。

$ ls themes/theme1/
archetypes  gulpfile.js  layouts  LICENSE.md  package.json  package-lock.json  src-static  static  theme.toml

themes/theme1/ ディレクトリーの内容が repo2 リポジトリーの内容になるように進めていきます。

ワーキングディレクトリーを作成

すでにローカルにワーキングディレクトリーを作成してあったとしても、それは使わずに、新しくワーキングディレクトリーを作成するようです。 それに対して内容を変更していくことになるようです。 新しいリポジトリーの名前を repo2 にしようとしているため、 git clone のところでローカルのワーキングディレクトリーの名前を repo2 にしてしまいます。

$ git clone https://github.com/username/repo1.git repo2
Cloning into 'repo2'...
remote: Counting objects: 2325, done.
remote: Compressing objects: 100% (756/756), done.
remote: Total 2325 (delta 685), reused 1054 (delta 501), pack-reused 1061
Receiving objects: 100% (2325/2325), 86.36 MiB | 7.16 MiB/s, done.
Resolving deltas: 100% (1073/1073), done.
Checking connectivity... done.

git clone できました。

ワーキングディレクトリーの中に移動します。

$ cd repo2/

ワーキングディレクトリーの内容を変更

今回は、 themes/theme1/ ディレクトリーの内容を新しいリポジトリーとして作成したいので、 repo2/ ディレクトリーの内容が themes/theme1/ ディレクトリーの内容になるように変更します。 サブディレクトリーの内容でリポジトリー直下のディレクトリーの内容を置き換えます。

# repo2/ ディレクトリーの内容
$ ls
archetypes  config.toml  content  data  deploy.sh  layouts  public  README.md  static  themes
# themes/theme1/ ディレクトリーの内容
$ ls themes/theme1/
archetypes  gulpfile.js  layouts  LICENSE.md  package.json  package-lock.json  src-static  static  theme.toml

git filter-branch でそれができるようです。 git filter-branch を使うと、履歴を引き継いでくれるようです。

--prune-empty のオプションを指定すると、プロセスの後に空のままなっているコミットを削除してくれるようです。 --subdirectory-filter <directory> のオプションを指定すると、指定したサブディレクトリーの履歴だけを対象にすることができるようです。

$ git filter-branch --prune-empty --subdirectory-filter themes/theme1 master
Rewrite 1c8476b8235014ba34affeca38513566649be49e (21/21) (41 seconds passed, remaining 0 predicted)
Ref 'refs/heads/master' was rewritten

少し時間がかかりました。 が、内容が変更できたようです。

$ ls
archetypes  gulpfile.js  layouts  LICENSE.md  package.json  package-lock.json  src-static  static  theme.toml

repo2/ ディレクトリーの内容が themes/theme1/ ディレクトリーの内容に置き換わったようです。

$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 21 and 324 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)
nothing to commit, working directory clean

git status を見ると、 have diverged のメッセージが出ています。 が、気にせず進めて良さそうなので、そのまま進めます。

GitHub にリポジトリーを作成

GitHub にサインインして、右上の + のマークから New repository を選択します。 Create a new repository の Repository name あたりを入力して、下にある緑の Create repository ボタンをクリックします。

すると、次のようなページが表示されました。

git push するまでについて記載されているようでした。

remote url を変更

ローカルのワーキングディレクトリーに戻って。 このまま git push してしまうと、今の remote url に設定されている repo1 のリポジトリーの内容が変わってしまいます。 ので、先ほど新しく作成した GitHub のリポジトリー (repo2) の url に変更します。

git remote set-url で url を変更します。

$ git remote set-url origin https://github.com/username/repo2.git

url を確認します。

$ git remote -v
origin  https://github.com/username/repo2.git (fetch)
origin  https://github.com/username/repo2.git (push)

変更できたみたいです。

GitHub に push

$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 21 and 324 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)
nothing to commit, working directory clean

git status を見ると have diverged のメッセージが出ています。 でもそのまま git push してしまって良さそうなので、してしまいます。

$ git push -u origin master
Counting objects: 183, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (93/93), done.
Writing objects: 100% (183/183), 73.91 KiB | 0 bytes/s, done.
Total 183 (delta 68), reused 161 (delta 68)
remote: Resolving deltas: 100% (68/68), done.
To https://github.com/username/repo2.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

repo2 リポジトリーに push できたみたいです。

git status を見ると、 up-to-date のメッセージに変わりました。

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

GitHub からも確認できました。

ディレクトリーの削除

ここからは、もともとあったワーキングディレクトリー (repo1) に移動して、先ほど作成したリポジトリー (repo2) をサブモジュールとして追加していきたいと思います。

最初に、今あるディレクトリー (themes/theme1) を削除します。 (ローカルにワーキングディレクトリーがない場合は git clone しておきます)

# もともとローカルにあったワーキングディレクトリーの repo1
$ cd /path/to/repo1/
$ ls themes/theme1/
archetypes   layouts     node_modules  package-lock.json  static
gulpfile.js  LICENSE.md  package.json  src-static         theme.toml
$ rm -rf themes/theme1
$

node_modules があって時間がかかりました。 が、削除できたみたいです。

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        deleted:    themes/theme1/.babelrc
        deleted:    themes/theme1/.eslintrc
        deleted:    themes/theme1/LICENSE.md
        deleted:    themes/theme1/archetypes/default.md
        deleted:    themes/theme1/gulpfile.js
        deleted:    themes/theme1/layouts/404.html
        deleted:    themes/theme1/layouts/_default/li.html
        deleted:    themes/theme1/layouts/_default/list.html
        deleted:    themes/theme1/layouts/_default/single.html
        deleted:    themes/theme1/layouts/_default/terms.html
        deleted:    themes/theme1/layouts/index.html
        deleted:    themes/theme1/layouts/partials/adsense.html
        deleted:    themes/theme1/layouts/partials/analytics.html
        deleted:    themes/theme1/layouts/partials/disqus.html
        deleted:    themes/theme1/layouts/partials/footer.html
        deleted:    themes/theme1/layouts/partials/header.html
        deleted:    themes/theme1/layouts/partials/pagination.html
        deleted:    themes/theme1/layouts/shortcodes/img.html
        deleted:    themes/theme1/layouts/shortcodes/mail.html
        deleted:    themes/theme1/package-lock.json
        deleted:    themes/theme1/package.json
        deleted:    themes/theme1/src-static/css/style.scss
        deleted:    themes/theme1/src-static/js/js.js
        deleted:    themes/theme1/static/css/html5reset-1.6.1.css
        deleted:    themes/theme1/static/css/style.css
        deleted:    themes/theme1/static/img/apple-touch-icon.png
        deleted:    themes/theme1/static/img/favicon.png
        deleted:    themes/theme1/static/img/logo.png
        deleted:    themes/theme1/static/js/js.js
        deleted:    themes/theme1/theme.toml

no changes added to commit (use "git add" and/or "git commit -a")

大量にファイルが削除されています。

GitHub に push

git add して、 git commit して、 git push していきます。

$ git add -A
$ git commit -m "message"
[master af52937] message
 30 files changed, 7383 deletions(-)
 delete mode 100644 themes/theme1/.babelrc
 delete mode 100644 themes/theme1/.eslintrc
 delete mode 100644 themes/theme1/LICENSE.md
 delete mode 100644 themes/theme1/archetypes/default.md
 delete mode 100644 themes/theme1/gulpfile.js
 delete mode 100644 themes/theme1/layouts/404.html
 delete mode 100644 themes/theme1/layouts/_default/li.html
 delete mode 100644 themes/theme1/layouts/_default/list.html
 delete mode 100644 themes/theme1/layouts/_default/single.html
 delete mode 100644 themes/theme1/layouts/_default/terms.html
 delete mode 100644 themes/theme1/layouts/index.html
 delete mode 100644 themes/theme1/layouts/partials/adsense.html
 delete mode 100644 themes/theme1/layouts/partials/analytics.html
 delete mode 100644 themes/theme1/layouts/partials/disqus.html
 delete mode 100644 themes/theme1/layouts/partials/footer.html
 delete mode 100644 themes/theme1/layouts/partials/header.html
 delete mode 100644 themes/theme1/layouts/partials/pagination.html
 delete mode 100644 themes/theme1/layouts/shortcodes/img.html
 delete mode 100644 themes/theme1/layouts/shortcodes/mail.html
 delete mode 100644 themes/theme1/package-lock.json
 delete mode 100644 themes/theme1/package.json
 delete mode 100644 themes/theme1/src-static/css/style.scss
 delete mode 100644 themes/theme1/src-static/js/js.js
 delete mode 100644 themes/theme1/static/css/html5reset-1.6.1.css
 delete mode 100644 themes/theme1/static/css/style.css
 delete mode 100644 themes/theme1/static/img/apple-touch-icon.png
 delete mode 100644 themes/theme1/static/img/favicon.png
 delete mode 100644 themes/theme1/static/img/logo.png
 delete mode 100644 themes/theme1/static/js/js.js
 delete mode 100644 themes/theme1/theme.toml
$ git push origin master
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 289 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/username/repo1.git
   38ac1ba..af52937  master -> master

push できたみたいです。

サブモジュールを追加

次に、新しく作成しておいたリポジトリー (repo2) をサブモジュールとして追加してみます。 themes/repo2 ディレクトリーに追加したかったので、ローカルのディレクトリーも指定しています。

$ git submodule add https://github.com/username/repo2.git themes/repo2
Cloning into 'themes/repo2'...
remote: Counting objects: 183, done.
remote: Compressing objects: 100% (93/93), done.
remote: Total 183 (delta 68), reused 183 (delta 68), pack-reused 0
Receiving objects: 100% (183/183), 73.91 KiB | 0 bytes/s, done.
Resolving deltas: 100% (68/68), done.
Checking connectivity... done.

追加されたみたいです。

$ ls themes/repo2/
archetypes  gulpfile.js  layouts  LICENSE.md  package.json  package-lock.json  src-static  static  theme.toml

repo2 リポジトリーのファイルがちゃんとワーキングディレクトリーにありました。

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   .gitmodules
        new file:   themes/repo2

git status するとファイルに変更がありました。 .gitmodules ファイルはサブモジュールを追加すると勝手に作られるファイルのようです。 この repo1 リポジトリーは、すでにサブモジュールを追加したことがあったので modified になっています。

GitHub に push

git addgit commitgit push をしておきます。

$ git add -A
$ git commit -m "message"
[master d3332f0] message
 2 files changed, 4 insertions(+)
 create mode 160000 themes/repo2
$ git push origin master
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 430 bytes | 0 bytes/s, done.
Total 4 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/username/repo1.git
   af52937..d3332f0  master -> master

終わり

サブモジュールにしようと思っていて、放置してしまっていたので、これでスッキリしました。

参考