LoginSignup
31
24

More than 5 years have passed since last update.

めざせGitマスター 〜Git Challengeに参加して学んだこと〜

Last updated at Posted at 2016-03-05

はじめに

本日mixiが主催するGit challengeというイベントに参加してきました。
git版CTFみたいなもんなので、普段ちょっと使っているだけの自分が解けるか不安でしたが、参加した結果大変勉強になったので、学んだことや知っとくと得になりそうなことを纏めておきたいと思います。

イベントの性質的に普段使うか微妙ものも多いですがいざという時のために知っておくと便利だと思います。(今後もgit challengeは開かれるようですしね!)
え、結果?別にどうだっていいじゃないですか(お察し下さい)

基礎知識

すっごく大雑把に説明します。分からなかったら調べて下さい(放棄)

commit

gitの一番コアな部分。gitはこれの積み重ねでversion管理をしています。
大雑把な説明ですが、コミットは自分の親コミットと変更点を持っています。(よく有向グラフで表せられますよね。)

branch

コミットへのポインタのようなもの。多くの場合ブランチで作業をします。(「多くの場合」ということはそうでないこともあるのか?→ある。"detached HEAD"とか)
あれ、説明が難しい?イメージ的に単方向連結リストなんだが...

merge

2つのコミットの 共通祖先を見つけて そこからの変更点を一方に取り込みます。
このときfast-forwardとかno-fast-forwardとかある。
git-mergeの--ff, --no-ff, --squashの違い

pull

pull=fetch+merge
fetchはremoteのレポジトリを取ってくることです。

push

pushはpush。
--forceとかいう恐ろしいオプションがあって極力使うべきではないが、歴史を改ざんするときは諦めて使ったほうがいい時もあるかも。

gitの便利なやつら

amend

使い方

git commit --amend

直前のコミットを変更します。このときインデックスに入れていたやつもコミットに含まれます。
直前のコミットにファイルを追加したい時やコミットメッセージを変えたい時に使います。
ただし、コミットオブジェクトを変更してしまうのですでにpushしてあるコミットを変えては駄目です。

rebase -i

rebase --interactiveの略。とても便利。
以下のことが出来きます。

  • コミットメッセージを変更する
  • コミット内容を修正する
  • コミットを分割する
  • コミットをまとめる
  • コミットを削除する

git rebase -i の使い方

tip

過去すべてのコミットについて見たかったら以下のようにしたら出来きます。

git rebase -i $(git rev-list --reverse HEAD | head -n 1)

reset

headの位置を変更できます。前のコミットに戻りたい時に使えます。
--softと--hardというオプションがあって、softだとheadだけを戻します。つまりworking tree自体はそのままです。逆にhardだとそのコミットの時点までworking treeも戻します。(コミット以降の変更は消されます。)

reflog

git reflogをすると、コミットだけではなくcheckoutの履歴までみることが出来ます。
resetを元に戻したい時や、branchを復活したい時に使えます。

show

違うコミットのファイルをみることが出来ます。

git show <branch名やコミットのsha1>:<ファイル名>

checkout

多くの場合branchの移動に使っている思います。でもbranchって結局コミットのポインタのようなものなので、コミットに対しても使えます。このときdetached headになります。

git checkout <コミットのsha1>

また、特定のファイルだけ持ってくる事もできます。

git checkout <branch名やコミットのsha1> <ファイル名やディレクトリ名>

log

あたりまえのように使っていると思いますが、様々なオプションがあるということを知っておくと便利です。詳細を見たり、ワンラインで表示したり、色つけたり、楽しい!

よく使うオプション

オプション 効果
-n <数字> <数字>分のコミットを表示します。
-p コミットでのdiffを表示します。
--pretty フォーマット別に表示を切り替えれます。
--after 指定日以降のコミットだけを表示します。
--before 指定した日付以前のコミットだけを表示します。
--grep キーワードに一致するものだけ表示します。

詳しくはここを

自分はgit logをglogにエイリアスして使っています。

$ which glog
glog: aliased to git log --oneline --decorate --color --graph

revert

すでにpushしてしまったものなど、reset出来ないコミットを打ち消すために使います。

その他

hook

gitはコマンドを実行した時にフックしてスクリプトを走らせることが出来ます。
なので、pushされたらテストを走らせるとかデプロイするとかそのようなことが出来ます。
git フック

履歴含めて完全削除

gitに管理されては困るものは.gitignoreに書くべきなのですが、間違ってコミットしてしまうことは多々あります。pushする前ならどうともなるのですが、pushしてしまっていたらrevertなどで消せません。もしくは昔から含まれて閉まっていた場合もresetして戻すわけにはいきません。そこでgitの歴史から特定のファイルを消す方法があります。
filter-branchを使うと、コミットに機械的にコマンドを実行できます。

git filter-branch -f --index-filter 'git rm --ignore-unmatch filename' HEAD

あとはpush --forceしましょう。

bisect

いつの間にかバグっていたり、新たな脆弱性が発見された時何時からあったのか知りたい時があります。(たぶん)
そのときテストは作ったけど全てのリビジョンについて実行するにはO(n)の時間がかりますし、スクリプトかなにか書かないといけません。
そこでgitにはbisectというテストスクリプトを二分探索で実行できる素晴らしい機能があります。

詳しくはここを参考に

いや知らねーよ、といった感じです。

gitの内部

キーワード:tree,blob,commit,tag,ref,sha1,pack,cat-file

コミットのツリー構造がイメージが出来たらgitを使う分には十分だと思うんですが、gitの中身を知っておいて損はないです。
まあ、説明は 面倒 こちらの方が分かりやすいのでここを参考にして下さい
また、公式リファレンスも丁寧に説明してくれます。

頑張って理解したら、普段gitの中の人がやってくれる.git以下の分からないオブジェクトを手動で作れるようになると思いますよ。

さらなる高みに

もっと知りたいって?好奇心旺盛ですね。仕方ありません、とっておきの参考資料を教えてあげましょう。これを理解できたらgitの全てを理解したといって過言ではないでしょう。
gitの真髄

さいごに

git challengeの問題を見返しながら、必要だった知識を書きだしているのでかなりとっちらかってしまいました。「こんな機能があるんだ」と参考程度に読んでくれれば幸いです。
最後にmixiさん、楽しくためになるイベントを企画していただきありがとうございました。

IMG_6152.jpg

31
24
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
24