のーずいだんぷ

主に自分用メモですが、もしかしたら誰かの役に立つかもしれません

エンジニアのためのGitの教科書を読んだのでまとめる

はじめに

プログラマとして早くも10ヶ月が経過した。 これまでgitについての情報は以下のgit公式を読んで理解して、プラスでQiitaを読んで補完する形態で進めていたが、本をいつの間にか購入していたようだったので読んでみた。

git-scm.com

今回使用する書籍は以下。ターゲットは初心者向けなのでGitに知らない人も本書で十分可能だろうと思う。

エンジニアのためのGITの教科書 (WEB Engineer’s Books)

エンジニアのためのGITの教科書 (WEB Engineer’s Books)

  • 作者: 株式会社リクルートテクノロジーズ,株式会社リクルートマーケティングパートナーズ,河村聖悟,太田智彬,増田佳太,山田直樹,葛原佑伍,大島雅人,相野谷直樹
  • 出版社/メーカー: 翔泳社
  • 発売日: 2016/01/20
  • メディア: 大型本
  • この商品を含むブログ (3件) を見る

個人的にもこれはあまり知らなかったなんてことがいくつかあったので、ピックアアップしてまとめておこうと思う。

Gitの知識は使うものは使うけどそれ以外は全然…なんてことが多々あると思うので網羅的に学ぶことで何かしらの価値は得られると思う。 私も正直かなり断片的に学んだクチなので、こんなこと知らずにやってのかお前…というものがいくつかあると思う。

git checkout が本当にしていること

ワーキングディレクトリに表示するコミットを変更すること。この一言に全てが詰まっている。 多くの場合、以下の用途でしか使用しないのではないだろうか?(自分の場合はこれだけだった)

  1. git checkout -b <new-branch> [base-branch]
  2. git checkout .
  3. git checkout

上記のうち1は新しいブランチを作成する、2は現在のワーキングディレクトリの変更を消去するのみ使用する。3はブランチの切り替えだ。

これらについて、1,3についてはそのまま理解が進むと思うが、2についてどうだろう?「そういうもの」として使用している人も多いのではないだろうか?

これも現在のブランチの最新のコミットを現在のワーキングディレクトリに反映する、という行為だがいいかえると

「最後にセーブしたところからやり直す」

と言えるのだと思う。自分で考えてみてすごくしっくり来た。

つまりこのコマンドはブランチ以外のコミットに対してもcheckoutできるのだが、用途としては確認のみで使用することは多いが、resetとしての用途で使用されるケースは少ないようだ。

もし過去のコミットの状態に戻す場合はgit reset --hard <戻るコミット>を実行する場合が多いようで、これは自分もそうだった。

2つのアンステージングの違い

git addすることでコミットする内容を決定することをステージング呼ぶが、この指定をコミット前に取り消すことをアンステージングと呼ぶ。

想定されるケースは以下だ。


  1. とあるファイルを変更し、ステージングする。

2.ステージングしたファイルをワーキングディレクトリで変更を加える。(このときの変更はステージングしない)

3.1でステージングした内容をアンステージングする。→①ステージングした内容をワーキングディレクトリに上書きし、ワーキングディレクトリには1で変更した内容が残る。

② ステージングした内容は取り消し、ワーキングディレクトリには2で変更した内容が残る


(正直図を書くべきなのだがめんどくさかった)

かなり見にくくなったが、①,②のケース、要はアンステージング時にステージングしていた変更内容でワーキングディレクトリを上書きするかしないかということなのだがこれはそれぞれ以下のコマンドで解決できる。

  • ①:上書きする→ git checkout <アンステージングするファイル> した後にgit reset <アンステージングするファイル>orgit rm --cached <アンステージングするファイル>`
  • ②:上書きしない→ git reset

自分は②のケースはよくあるので使用していたが、①のやり方については知らなかった。

①では何が起きているかというと

  1. git checkout <アンステージングするファイル>でステージングする内容にワーキングディレクトリを変更
  2. アンステージングする

という流れのようだ。 正直1の操作が成り立つ理由があまり良くわかっていない。もともとcheckoutはHEAD(指定したコミット)の内容にワーキングディレクトリを変更させるものだという認識だからだ。

もしかしたら、checkoutはより抽象的な言い方をすると、「指定対象にあわせてワーキングディレクトリの内容を変更する」といえるのかもしれない。だとすれば、指定対象がコミットであればその内容に変更され、ファイルならそのファイルのみがステージングされた内容に変更されるのも納得できる。 とはいえこれはまだ推測なので説明としては危うさがある。

ちなみに、現在の最新のgitではgit restoregit switchが実験的に導入されており、このうちgit restoreは上記のgit checkout .git checkout <ステージングしたファイル>の代わり、同等の機能を提供する。 これについてはまた別途まとめたい。

ブランチ名の変更

これは全く目新しくないが、たまにしか使用しないので毎回忘れるため一応載せておく。

git switch <名前を変更するブランチ>
git branch -m <変更したいブランチ名>

コンフリクトの事前検出

方法はいくつかあるが、それぞれコンフリクトを検出するための方法ではないようだ

--no-commitによる方法

git merge --no-commit <マージするブランチ>
git merge --abort

上記の方法はマージコミットを作成せずワーキングディレクトリを変更することでコンフリクトを検知する。 コミットは作成しないのでgit logの内容は変化しないが、merge自体は進行しているので--abortでmergeは中止する必要がある。。

git format-patchによる方法

// パッチを作成する
git checkout <マージしたいブランチ>
git format-patch <マージ先のブランチ> --stdout > <マージしたいブランチ名>.patch

//パッチを当ててみる
git checkout <マージ先のブランチ>
git apply <作成したパッチファイル> --check

これは結局git mergeが行われていることを自分でやっていることに近い。が--checkオプションによりdry-runと同様の操作になっている。 メリットとしてコンフリクトの箇所が表示されるものの、dry-runのためにコンフリクトマーカーは作成されない、つまりコンフリクトした箇所を探すのが大変になる。

やっぱり一番はお試しのマージ用ブランチを作ること

これはそのまま。マージ先のブランチ(例えばdevelop)をコピーして、マージしてみる。 自分はいつもこれを使用してコンフリクトの確認をしている。

最後に

今回はいくつかのトピックについて上げたが、本の中には他にも実際に使用しているものがたくさんあった。今更ながら、もっと早く読んでおけばより時間の節約ができたと思う。

一部話話が膨らみそうなものについては別記事にまとめたい。