概要
設定ファイルに含まれるパスワードなどの機密情報を伏せて Git の管理下に置き、各自がローカルで書き入れた部分の変更を無視させたいことがあるが、Git にはそのための機能はない。
どうすべきか
例えば以下のような方法で代替する。
機密情報を含むファイルを config.ini
とすると、
-
.gitignore
にconfig.ini
を追加する
- 機密情報を伏せて
config.ini.tmpl
のような別名で保存する -
config.ini
がすでにコミットされている場合、git rm --cached config.ini
で削除する - 変更をコミットする
README などに、リポジトリをクローンしたら config.ini.tmpl
を config.ini
にコピーしたうえで機密情報を書き入れるよう指示しておくと良い。
うまくいかない方法
検索すると以下の方法がよく挙げられているが、いずれも有効なのはローカルにおいてのみである。
.gitignore に追加して git rm --cached する
ファイルが Git 管理下にある限り、変更は追跡される。
Git による管理から外すが、ローカルにあるファイルは削除したくない場合には有効。
検証
$ echo PUT_SECRET_HERE > config.ini
$ git add . && git commit -m "機密情報を含む設定ファイル"
[master (root-commit) 02a5408] 機密情報を含む設定ファイル
1 file changed, 1 insertion(+)
create mode 100644 config.ini
$ echo config.ini > .gitignore
$ git add . && git commit -m "gitinogreに追加"
[master f30c427] gitinogreに追加
1 file changed, 1 insertion(+)
create mode 100644 .gitignore
$ echo my_secret > config.ini
$ git diff
diff --git a/config.ini b/config.ini
index 68c539e..0506d9e 100644
--- a/config.ini
+++ b/config.ini
@@ -1 +1 @@
-PUT_SECRET_HERE
+my_secret
変更が追跡されていることが分かる
この変更を元に戻したうえで、git rm --cached
してみる。
$ git checkout config.ini
Updated 1 path from the index
$ git rm --cached config.ini
rm 'config.ini'
$ git commit -a -m "いったん追跡から外す"
[master f09e4fc] いったん追跡から外す
1 file changed, 1 deletion(-)
delete mode 100644 config.ini
すると config.ini
は Git の管理化から外れた。
さて、.gitignore
に追加した後であれば、変更は無視されるだろうか?
config.ini
を再度 Git 管理下に入れてみよう。config.ini
は .gitignore
により無視されておりgit add
ではステージングできないため、 -f
オプションをつける必要がある。
$ git add -f config.ini
$ git commit -m "再度追跡させる"
[master 2fc25de] 再度追跡させる
1 file changed, 1 insertion(+)
create mode 100644 config.ini
$ echo new_secret > config.ini
$ git diff
diff --git a/config.ini b/config.ini
index 68c539e..ff0ae85 100644
--- a/config.ini
+++ b/config.ini
@@ -1 +1 @@
-PUT_SECRET_HERE
+new_secret
変更の追跡が再開していることが分かる。
git update-index --skip-worktree する
ローカルでは追跡されなくなるが、 upstream はこの設定を保持しない。
つまり、共有リポジトリでこれを運用するなら、すべてのコミッターがこの設定を行う必要がある。
いずれ何も知らない新人によって機密情報は公開されてしまうだろう。
検証
$ cat config.ini
PUT_SECRET_HERE
$ git update-index --skip-worktree config.ini
$ echo my_secret > config.ini
$ git diff
$ cat config.ini
my_secret
config.ini
の変更が追跡されていないことが分かる。
この状態では変更がなくコミットできないので、適当なファイルを追加してプッシュしてみよう。
$ touch something
$ git add . && git commit -m "skip-worktreeを実行"
[master 377ba4a] skip-worktreeを実行
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 something
$ git push
これを別のディレクトリにクローンして、config.ini
を変更してみる。
$ git clone https://example.com/repo.git new_repo
$ Cloning into 'new_repo'...
$ cd new_repo
$ echo new_secret > config.ini
$ git diff
diff --git a/config.ini b/config.ini
index 68c539e..ff0ae85 100644
--- a/config.ini
+++ b/config.ini
@@ -1 +1 @@
-PUT_SECRET_HERE
+new_secret
やはり config.ini
の変更は追跡されていることが分かる。
公式ドキュメントでも、特定ファイルの変更を無視する目的に update-index --skip-worktree
ないし --assume-unchanged
を使用できないことが注記されている。
Users often try to use the assume-unchanged and skip-worktree bits to tell Git to ignore changes to files that are tracked. This does not work as expected, since Git may still check working tree files against the index when performing certain operations.
参考
How to stop tracking and ignore changes to a file in Git? - Stack Overflow