git俺俺メモ
Git(Github)の最低限checkout add commit pushはしているがそれくらいしかわからんので、これどーしたらいいっけというのをメモ。
用語
working tree: ファイルの最新状態。addすることでstage(index)に遷移。
stage(index): ファイルのaddした状態。commitすることでlocal repositoryに遷移。
local repository(HEAD): 最新のcommit状態(直前におこなったcommit状態)。現在のlocal repositoryともいえる。
HEAD^: 1つ前のcommit状態
working tree → stage → local repositoryと遷移する。ここまでは自分の作業環境(local)の話で、ここからpushをすることでlocal repositoryを共有の作業場であるremote repositporyにあげることができる。
この記事の図がとてもわかりやすい。
Gitコマンド
addを取り消す
いくつかまとめてaddをしてしまったがcommitをすると全addがcommitされる。このとき、一部のみcommit対象にしたい場合はaddしたファイルを取り消す。
つまり、addでstagedになっている一部ファイルを最新のcommit状態(HEAD)に戻すのでgit reset HEAD file_name。
最新のcommit状態→何か修正→Addなので、修正部分が消えるように思えるが、git reset HEAD file_nameは正確にはgit reset HEAD --mixed file_nameなので、 インデックスの変更(addした内容)のみ を戻している。
なお、同じファイルにcommitせず複数回Addをしている場合はまとめて1回のAddと同じ意味なのでまとめてAdd自体は取り消される(修正内容は破棄されないが、stagedにはない状態)。
また、git reset --hard HEAD file_name だと、stage, working treeの変更 = commit以降の全変更が取り消されて最新のcommitした状態になる(=変更は破棄)。
なお、以下の記事ではいろいろな「もとに戻す」がまとめられている。
複数commitを1つにまとめたい
commitした後に細かいミスを見つけたため再度commitして修正する、、、みたいなことをすると無駄に2commitになってわかりづらい。
そういうときはcommit をsquachして1つにまとめる。
branchにoriginの情報を取り込む
branchにいるときはbranchを切ったとき段階での状態だが、その間にリモートリポジトリ(origin)が更新されると更新されたファイルはそのbranch上では最新版でなくなる。 fetch&merge?
作業途中で別branchの作業をする
あるbranckの作業中に別branch(または新規作業内容)が差込で入った。
一回commitしてからbranchを移動することもできるが、いい感じのcommit粒度じゃない場合commitをしたくない。
そのようなときは、stashをする。
git stash save 'メッセージ' でcommitしていないもの(addしてないもの含む)一時的に退避する。メッセージは省略可。
stash@{0}: WIP on test: xxxx みたいな感じで表示される。xxxはメッセージが表示される。メッセージを省略した場合、HEAD(直前のcommit)時のメッセージが表示される(※ちゃんとcommit以降のaddなどの変更部分も含めて退避される(。
git stash list でstash一覧が表示でき、git stash pop stash@{N} でN番目のstashを復元する。stash@{N}を省略すると最新のstashが適用される。
git stash show stash@{N} でN番目に変更したファイルの一覧を、git stash show -p stash@{N} でN番目に変更した差分一覧が表示できる。
これでいったん現branchでの作業途中を退避できるのでいったんcommitをしなくても別branchに移動することができる。
状態間の差分
branchで作業しているときに、他タスクが差込で入ったりしたときに「どこまでやったっけ?」となる。
また、「作業した記憶ないけどなんでこれ変更された扱いになってるんだ?」ということも個人的にはちょくちょくある(Rスクリプトで、commitしたあとに一瞬データを見るために出力コマンドだけ書いたりしたときによくある)。
基本的に、git diff [状態1] [状態2] [file name] で状態1と2の[file name]の差分を見ることができる。
また、git diff以降に指定するオプションなどでどの状態間を比較するかが変わるし、[状態]部分も省略によって変わる。
直前のAdd(staged)から現在の変更部分を見る
直前のAdd(staged)から現在の変更部分はgit diff [file path] で見られる。
最新のcommit(HEAD)から現在の変更部分を見る
最新のcommit = HEADから、現在とHEADの差分なので git diff HEAD [file path] で変更箇所が見れる。
なお、[file path]を指定しないとHEAD ~ 現在で変更があった全ファイルの変更点が全て確認できる。
変更があったファイルの確認はgit status
直前のAdd(staged)から最新のcommit(HEAD)の変更部分を見る
直前のAdd = stagedなので、git diff --staged [file path]で確認できる。
cachedも同じ意味なのでgit diff --cached [file path]でもよい。
直前のAdd(stage)から現在の差分は表示されない
最新のcommitとその前のcommitの差分を見る
基本形のgit diff [状態1] [状態2] [file name] における、状態1 = HEAD^、状態2=HEADとなるため git diff HEAD^ HEADで見ることができる。
直近のcommitメッセージを取り消す(push前)
タイピングミスや内容のミスをした場合など。
直前のcommitの場合はgit commit --amendで修正をする。
直前よりも前の場合、まずはgit log --oneline で直近の操作logを見ていつのcommitか調べる。
その後、git rebase -i HEAD~nでn番目までのcommit履歴のpickをeditにして上書き保存で閉じてからメッセージの修正をし、git commit --amendをする。
一部ファイルを管理対象外にする
基本的に決まってるファイルはgitignoreに追加するとして、データソースはgitにあげたくないときはいちいち追加するのが面倒なので、ignoreではなく都度データソース用フォルダ毎まとめて指定をしたいときなど。
git rm --cache file_name
フォルダの場合は-rをつける。
git rm --cached -r cache/
gitignoreは既に管理対象の場合は記述しても外れないらしい。
オプションなしでgit rm file_nameだとファイル自体が削除されるので注意。
Gitでのやりとり
commit粒度
どういう粒度でcommitをするか。
「xxxの修正と、yyy機能の追加と、リファクタリングしました!」みたいなcommitだとどのdiffがどれかよくわからん。
そのため、commitの粒度は意識する。
例えば、上記だと
- xxxの修正
- yyy機能の追加
- リファクタリング
の3commitに分けた方が良い。そうするとそれぞれのcommitのdiffを見ると「そのdiffは何をしたやつなのか」が明確にわかる。
なお、上記3commit粒度は例えば「xxxの修正」は「xxxの修正のために、データ処理の変更」「処理の変更に伴い影響がある部分を修正」のように更に細かく分けることができる場合もある。
このようなときは必要に応じて更にcommitを分けたほうが良い。
結局、「どういう粒度ならレビュー者(および未来の自分)がわかりやすいか?」ということを考えてcommitする必要がある。
commitメッセージ
そのcommitが「バグの修正」なのか「機能の追加」なのか「リファクタリング」なのか、メッセージ文章を読めばわかるかもしれないがパっと見で理解できると便利。
そのため、メッセージの接頭に
- バグの修正なら
Fix - 機能の追加なら
Add - リファクタリングなら
Refaxt
と付けるなどするとレビュー者の理解の助けになる。
以下の記事がよくまとまっている。
プルリクの書き方
- 変更内容の詳細(要約はcommit メッセージに書いている)
- どういう観点で見てほしいか
- 特に見て欲しい箇所
- 注意点
- プルリク作業想定時間
- 期限
また、分析系の業務の場合はデータそのものが無いと処理の理解がしづらいので、場合によっては読み込むデータをGoogle Driveなどにアップロードするとよりよいかも*1。
また本記事の趣旨とはそれるが、データは各処理をするたびにちゃんとコメントをしたり、headした結果を貼っているとレビュー者の負担が減るかも。まぁコードが煩雑になるというデメリットはあるが。。。
また、コミットメッセージは複数行書くことができる。
デファクトスタンダードとしては、1行目に50文字以内で要約、2行目を空白、3行目以降は詳細を書くのが基本なようだ。
なお、コミットメッセージはcommit -m 'hoge' -m '' -m 'hoge'のように複数回-mをすると複数行メッセージを書ける。また、 -mなしだとvimでの記載となる。
*1:データ容量がデカいからgitに上げたくないとかあると思うので、自分は基本的にgit上ではなくDriveにアップロードしている