ikeike443のブログ

ソフトウェアビジネスに関心がある系のブログ

gitでマージとかdiffとかコミットまとめてpushするとか

今までもgithubにpushするためだけにgitは使ってたんだけど、最近他人と共同作業するようになって、真面目にgitを学び始めた。


とりあえず今日わかったこと。
困ったら git reflog しろ!


ということで終わりなんだけど、一応以下にメモ的に書いておく。
ツッコミ大歓迎というか、いろいろ教えて欲しいのでむしろツッコンでください。。

自分の作業はこまめにcommitしたいけど、共同リポジトリには意味のある単位でpushしたい

こんな風にやればいいのかなという感触を持った。

  • 作業ブランチ(branch1)を作る。
$ git branch branch1
  • ブランチを切り替える
$ git checkout branch1


で、作業ブランチでいろいろ作業してコミットを積み重ねた後、

  • master に切り替える
$ git checkout master
  • 作業ブランチの変更をマージする

のだが、マージの際にコミットせずに変更だけ取り込むようにしたいので下記のようにする。

$ git merge --squash branch1

これにより、コミットせずに変更だけをステージングできる

  • ステージ状態の変更と、HEADのDiffを見る
$ git diff --cached

HEADは暗黙的に選択されるので上記で良い。


比較したいコミットを明示的に指定することもできる。

$ git diff --cached <comit-ish>
  • 複数の変更をまとめてひとつのコミットにする

上記のように --squash 付きで merge しておけば、ブランチでの複数の変更をまとめてひとつのコミットにできる。
下記のようにするだけで良い。

$ git commit -m "message"

実際にどの変更がコミットされるのかを確認したい場合は、-m なしで実行すれば、コミットログ用に vi が開いたときに詳細を確認できる。

以上で master のコミットログがきれいに作成できたので、push する。

$ git push <repository>

これで、ローカルではこまめにコミットしておいて、いざ共同リポジトリに push するときには意味のあるひとつの単位にまとめる、ということができる。

リモートリポジトリから変更を取り込む場合

  • リモートリポジトリとワーキングコピーの差分を見たい場合

まずfetch。

$ git fetch <repository>


次に下記のようにdiff。

$ git diff FETCH_HEAD


マージも同様に。squashも使える。

$ git merge --squash FETCH_HEAD

コミットの取り消しとか、取り消しの取り消しとか。。

  • コミットを取り消す

まずログから戻したいコミットを特定

$ git log


で、下記のコマンド。にコミットのハッシュ値を入れてやれば良い。

$ git reset <commit-ish>


にはシンボルも使える。例えば一つ前のコミットに戻したい(たった今コミットした内容を取り消したい)場合は下記になる。

$ git reset [--soft|--hard] HEAD^
  • コミットの取り消しの取り消しとか

コミット、取り消し、再コミット、取り消し、と続けてると訳が分からなくなる。
その場合、gitでの作業ログを下記コマンドですべて参照できる。

$ git reflog
7fcf079 HEAD@{0}: commit: aa1
aef3c53 HEAD@{1}: commit: merge from remote
8ec3acb HEAD@{2}: HEAD^^: updating HEAD
e07c83f HEAD@{3}: HEAD^: updating HEAD
a9553af HEAD@{4}: checkout: moving from b1 to b2
...


reflog を参照して戻したいコミットを特定して、そいつに向かってリセットする。

$ git reset [--soft/--hard] HEAD@{1}


このあたりは下記が参考になる
http://d.hatena.ne.jp/idesaku/20091106/1257507849
要は reset って取り消すというよりも、HEADを付け替えるというイメージなのかな



で、だ

よく巷で見かけるHEADとかORIG_HEADとかって何を表してるの?

僕の理解だと下記。ツッコミ待ちです

  • HEAD:

現在の最新コミット

  • HEAD^:

一つ前のコミット(以降、^の数が増えた分だけ前に戻る)

  • ORIG_HEAD:

コミット変更操作をしたときに簡単にもとに戻せるように用意されたUndo用領域(reflogのHEAD@{1}とほぼ同義)

  • FETCH_HEAD:

リモートからfetchした際のfetch先のHEAD


manは全部読めてなくて、拾い読みと、下記のやりとりからの類推です
http://stackoverflow.com/questions/964876/head-and-orig-head-in-git



あとは、diff は vimdiff でみたいよね

diffをvimdiffで見る

ここを見て diff.external を設定すれば良い
diff.external にどのような引数がどういう順番で渡されるかは、manを参考に


以下に引用

GIT_EXTERNAL_DIFF環境変数 GIT_EXTERNAL_DIFF が設定されている場合、 上述の diff が実行される代わりに、ここで指定されているプログラム が呼び出されます。追加、削除、変更されたパスに対して GIT_EXTERNAL_DIFF が7つのパラメータとともに呼び出されます:
パス 古いファイル 古いhex 古いモード 新しいファイル 新しいhex 新しいモード
各パラメータの説明:
<古い|新しい>ファイル GIT_EXTERNAL_DIFF が <古い|新しい>ファイルの中身を 読み込む為のファイル名 <古い|新しい>hex40桁の16進の SHA1 ハッシュ値、<古い|新しい>hexファイルモードの8進数表現。


とりあえず、なんとかなるようにはなってきました。。