開発環境の設定ファイルを守りたい話
保守の直近のリリースに突然異動になったものの
開始1時間くらいローカル環境の修復に費やしてしまったので
今後発生させないために対処法まとめ
症状 : eclipseとDB(vagrant)の接続ができなくなる
原因 : git stashでcatalina.propertiesの変更を取り戻せなくなる
対処法:git update-index --skip-worktree ファイル名 でgitの管理外にする
前から原因は知ってたんですけど
java案件から離れていて放置してたのでいい加減対策しようということで
stash popできずローカル変更が取り戻せなくなる問題対策します (catalina.properties で実験)
stashするに至った原因
$ git pull # ローカルに変更があるとpullできない Cannot pull with rebase: You have unstaged changes. Please commit or stash them. $ git checkout develop_20150709 # 別のブランチに切り替えることもできない error: Your local changes to the following files would be overwritten by checkout: catalina.properties Please, commit your changes or stash them before you can switch branches. Aborting $ git status On branch develop_20151118 Your branch is up-to-date with 'origin/develop_20151118'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: catalina.properties # ←こいつのせいでpullできない Untracked files: (use "git add <file>..." to include in what will be committed) ...
諦めてstashしてpullする
$ git stash $ git pull First, rewinding head to replay your work on top of it... # よし!pullできた! $ git stash pop error: Your local changes to the following files would be overwritten by merge: catalina.properties Please, commit your changes or stash them before you can merge. Aborting # stashしたものを取り戻せなくなった!?
pullした結果、ローカルに差分が発生するとpopさせてくれません
その結果catalinaの設定がstashから取り出せなくなるという罠にはまり続けていました
解決策1:gitの追跡対象から外す(Untracked filesのみ)
プロジェクトの中で除外する必要があるファイルは.gitignoreに書くけど、
自分の環境だけで除外したいファイルがある場合は.git/info/excludeに書くのがよいです。
覚えておくと便利なgitのtipsをいくつか - Webtech Walker
※ ↑ ただしUntracked filesに限る
.git/info/excludeに追記してみた
# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ gittest.txt # Untracked filesであればこれでgitの管理対象から外れます
※ すでにgitの追跡対象になっているファイルはgitignoreに書いても追跡されます(Changes not staged for commitのやつ)
.gitignoreに追記する場合は、一度gitの管理下から外さなければ反映されません
さらに、このリポジトリの.gitignoreはgitで管理されているので
変更すると変更があるファイルとみなされてしまうため厄介です
解決策2:gitの追跡対象から外す(Changes not staged for commit)
そして変更があった時にgitの管理下に戻す
コマンド
# ファイルの変更を無視 $ git update-index --skip-worktree ファイル名 # ↑ 解除 $ git update-index --no-skip-worktree ファイル名 # 設定確認 $ git ls-files -v
やってみる
$ git status On branch develop_20151118 Your branch is up-to-date with 'origin/develop_20151118'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: catalina.properties # こいつを除外します $ git ls-files -v | grep catalina.properties H catalina.properties $ git update-index --skip-worktree catalina.properties $ git ls-files -v | grep catalina.properties # 設定の確認 S catalina.properties # HからSになりました # 確認 $ git status On branch develop_20151118 Your branch is up-to-date with 'origin/develop_20151118'. # なくなってます
コマンド詳細
$ git update-index -h --assume-unchanged mark files as "not changing" --no-assume-unchanged clear assumed-unchanged bit --skip-worktree mark files as "index-only" --no-skip-worktree clear skip-worktree bit
違い
・assume-unchanged : そのファイルが作業ツリー上で変更されているときでも、git はその変更を無視して変更されていないとみなします
・skip-worktree : そのファイルが作業ツリー上で変更されているときには、git はその変更を保ちます。作業ツリー上でもリポジトリ上でもファイル更新があって、それをマージするとき
・assume-unchanged : 作業ツリー上の更新は破棄されて、リポジトリの内容が取り込まれます。
・skip-worktree : 作業ツリー上の更新は保持されて、リポジトリの内容は取り込まれません。作業ツリー上でファイル更新があって、git reset --hard を実行したとき
・assume-unchanged : 作業ツリー上の更新は破棄されます。
・skip-worktree : 作業ツリー上の更新は保持されます。
既に git 管理しているファイルをあえて無視したい - Qiita
skip-worktreeしておくのが無難かなと
必要になればすぐ戻せますし自分の環境だけに設定できるので
他の人やリポジトリに影響を与えないのが素敵
解決策3:stash save してapplyする
popできないから使えないけど設定をstashして復元する方法の1つってことで...
git stash save settings # settingsという名前でstashする git stash list # stash一覧 git stash apply stash@\{1\} # stashされたものを適用するが削除しない ← これ大事 git stash pop stash@\{1\} # stashされたものを適用して削除 # 環境によってはstash@{1}でいけるかも(エスケープいらない?)
stashで fatal: ambiguous argument がでるとき
$ git stash pop stash@{7} 'stash@7': unknown revision or path not in the working tree. Use '--' to separate paths from revisions, like this: 'git <command> [<revision>...] -- [<file>...]' $ git stash pop stash@\{7\}
# iTermの問題かもしれませんがエスケープすると動きます
名前をつけてsaveして使いまわしたいものをわかりやすくして
applyすることでstash上には残します(popはapply→dropします)
$ git stash save settings Saved working directory and index state On develop_20151118: settings HEAD is now at f562188 Merge branch 'develop_20151116' into develop_20151118 $ git stash list stash@{0}: On develop_20151118: settings # ここにいる stash@{1}: WIP on develop_20151118: hoge Merge branch 'develop_20151116' into develop_20151118 stash@{2}: WIP on develop_20151118: fuga Merge branch 'develop_20151116' into develop_20151118 $ git stash apply stash@\{0\} On branch develop_20151118 Your branch is up-to-date with 'origin/develop_20151118'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: catalina.properties # おかえりなさい!! .... $ git stash list stash@{0}: On develop_20151118: settings # stashには残ってます stash@{1}: WIP on develop_20151118: f562188 Merge branch 'develop_20151116' into develop_20151118 stash@{2}: WIP on develop_20151118: f562188 Merge branch 'develop_20151116' into develop_20151118 # ちなみにpopした場合 git stash pop stash@\{0\} On branch develop_20151118 Your branch is up-to-date with 'origin/develop_20151118'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: catalina.properties no changes added to commit (use "git add" and/or "git commit -a") Dropped stash@{0} (920e8c3b79e06893161405f038db5c32fca7c9bf) # ← ここでDROPされてる
解決策4:.gitignoreに書いてpush
個人の開発環境の問題解決を目的としているため超絶非推奨
- .git/info/excludeに.gitignore追記
- リポジトリ内の.gitignoreにgitから外したいファイルを書く
- git rm --cached ファイル名 でキャッシュ削除
- commit, pushする\(^o^)/
- 晴れて管理外に☆
git rm --cached . して苦しんだのでもう二度とやらない
おまけ
stash使いすぎてstash list が散らかってきたとき
$ git stash list stash@{0}: On develop_20151118: settings stash@{1}: WIP on develop_20151118: f562188 Merge branch 'develop_20151116' into develop_20151118 stash@{2}: WIP on develop_20151118: f562188 Merge branch 'develop_20151116' into develop_20151118 stash@{3}: On develop_20151118: settigns # ← これを抹消したい $ git stash drop stash@\{3\} # stash list から削除 Dropped stash@{3} (c7e0ab5453da05289432f9aec151cec4791d8f1f) $ git stash list # 消えていることを確認 stash@{0}: On develop_20151118: settings stash@{1}: WIP on develop_20151118: f562188 Merge branch 'develop_20151116' into develop_20151118 stash@{2}: WIP on develop_20151118: f562188 Merge branch 'develop_20151116' into develop_20151118 stash@{3}: WIP on develop_20151118: 32ac549 TDPRINT-1102 障害票No.29対応
.gitignoreの変更を共有するのであればpushしますが
個人の環境でgitに変更を追跡されたくないため
gitの管理下から外しました
これで個人で変更・追加したファイルがあってもgitから外しちゃえば
git add . で気持ち良くcommitすることも夢じゃないはず!
最後に
今回の私の実験のために壊れてくれた環境たちありがとう
私は git update-index --skip-worktree を使っていこうと思います
ちなみにリリースは無事完了しました( ′◡‵ )
参考
既に git 管理しているファイルをあえて無視したい - Qiita
gitignoreまとめ - maeharin log