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の違いをきちんと意識しないといけないので、それが一目で分かる図があるといいですね、ということで作ってみました。
過去のコミットログを修正するときのrebaseコマンド
- 1個前のコミットではなく、n個前のコミットのログを修正したいときのコマンド。
$ git log --oneline # 修正したいコミットを確認。 $ git rebase HEAD~n -i # nは数字。iはinteractive? # エディタ上で、修正したいコミットの先頭の文字を"pick"から"edit"に修正する $ git commit --amend $ git rebase --continue
- pushした後のコミットログを変更したい場合は、修正したコミットより後の履歴はrebaseしたもの以外は消えてしまうことを認識した上で、
git push origin master --force
する - c.f. 初心者から一歩抜け出すためのGitの業 〜 git rebase -i - Qiita
mergeではなくrebaseを使う利点
- mergeはそれぞれのbranchの歴史を残した上でコミットを統合する(--no-first-forwardの場合)
- rebaseは一方のbranchを無かったことにして、そのコミットをもう一方のbranchに適用する。どちらのbranchにも別の修正が入っている状態にも関わらず、mergeにおいて--first--forwardを実行したかのように振る舞う。
- mergeはbranchの存在を歴史に残しておくことができるが、rebaseは(不要だったと判断された)branchを消すことで余分な歴史を消すことができる。
修正箇所のAuthorを確認するblameコマンド
git blame ファイル
で、各行のAuthorとCommitを確認することができる。バグ発見時には、これでバグ混入者を特定できる。