Gitメモ

branchで作業中に他のbranchで (ry

git-new-workdir*1を使っていたが、いつの間にかworkdirの内容がpushされていて余計なmergeをすることになったので、ちゃんと調べてみるとgit stash(save)があった。すると、以下のような面倒なことを、git stash save/git stash popだけで行える。

$ git diff --no-prefix > patch
$ git reset --hard HEAD
$ git checkout hoge
...
$ git checkout master
$ patch -p0 < patch 

stashはスタックに入れられるので、popで出す。git stash listでstash@{}を確認してpopで指定すれば、任意の位置のstashをpopすることも可能。popしたらdropは不要。他のbranchにもそのまま持っていけるので便利。stashの内容はgit stash show (stash@{0})で表示できる。

git stash pop でコンフリクトが起こった場合は、スタックからdropされない。 * Unmerged path hoge.sh こんなのが出て差分が一部表示されない。(でもちゃんとマージはされててworking treeには入っている)

pオプションが便利

addと同様にstash (save)も-pが便利。変更箇所を細かくcommitとstashに分ける、というのが簡単にできる。-pで編集中にsを選択することで、さらに細かく分けることができる。

変更を元に戻したいときのreset/revertコマンド

  • git resetは --hard/なし/--soft がそれぞれ、ワーキングツリーをHEADに戻す/インデックスをワーキングツリーに戻す/HEADをインデックスに戻す に対応する。git reset ファイル で、個別のファイルをインデックスからワーキングツリーへアンステージングするが、オプションを付けた場合は、ファイルの個別指定はできない。--hardオプションをつけてファイルを個別指定する場合は、resetではなくgit checkout HEAD -- ファイル とする。
  • git resetとgit revert

    • 変更のコミットを無かったことにする場合はgit reset
    • 変更を新たなコミットで元に戻したい場合はgit revert
    • git push でリポジトリに反映したあとは、リポジトリの履歴と整合が取れなくなるので、git resetは使えない
    • その場合は、変更を新たなコミットで元に戻す必要があるので、git revertを使う
    • コミットの一部の変更のみ適用し直したい(一部のみを無かったことにしたい)場合は、git revert -n < commit > とすることで、revert時にコミットせずにインデックスにステージングするだけになるので、git revert -n < commit > した後に、さらにgit reset HEAD(オプション無し)でアンステージングする
    • そのうえで必要な修正のみをgit add -p などでワーキングツリーからインデックスにステージングすればよい
    • revert HEADは、あるHEADコミットなくす、という意味でHEADを指定する(つまりrevert直後は、そのコミットをなくす新たなコミットを行う)
    • reset HEADは、HEADコミットまで戻す、という意味でHEADを指定する(つまりreset直後では、何も起こらない)
  • c.f. d.hatena.ne.jp

特定のコミットをマージするcherry-pickコマンド

  • git cherry-pick < commit hash > で特定のコミットのみをマージすることができる。つまり、別ブランチの適用したい修正だけを持ってこれる。
  • マージコミットに対してcherry-pickを実施する場合、-mオプションを使う。-m 1でマージしたブランチのコミットを、-m 2でマージを実行したブランチのコミットを、まとめて持ってくることができる。

リポジトリの内容を持ってくるpull/clone/fetchコマンドまとめ

  • ローカルにmaster以外のブランチを持ってくるにはどうするか、を考えたときに、pull/clone/fetchの違いや、masterとorigin/masterの違いをきちんと意識しないといけないので、それが一目で分かる図があるといいですね、ということで作ってみました。 f:id:nishidy:20150808121458p:plain

過去のコミットログを修正するときのrebaseコマンド

  • 1個前のコミットではなく、n個前のコミットのログを修正したいときのコマンド。
$ git log --oneline # 修正したいコミットを確認。
$ git rebase HEAD~n -i # nは数字。iはinteractive?
# エディタ上で、修正したいコミットの先頭の文字を"pick"から"edit"に修正する
$ git commit --amend
$ git rebase --continue

mergeではなくrebaseを使う利点

  • mergeはそれぞれのbranchの歴史を残した上でコミットを統合する(--no-first-forwardの場合)
  • rebaseは一方のbranchを無かったことにして、そのコミットをもう一方のbranchに適用する。どちらのbranchにも別の修正が入っている状態にも関わらず、mergeにおいて--first--forwardを実行したかのように振る舞う。
  • mergeはbranchの存在を歴史に残しておくことができるが、rebaseは(不要だったと判断された)branchを消すことで余分な歴史を消すことができる。

修正箇所のAuthorを確認するblameコマンド

  • git blame ファイルで、各行のAuthorとCommitを確認することができる。バグ発見時には、これでバグ混入者を特定できる。