Git 困ったときのtips集

Pocket

こんにちは、平奥です!

これはTECHSCORE Advent Calendar 2015の23日目の記事です。

はじめに

開発でソースの管理をするのに、分散型バージョン管理システムのGitを使うようになりました。
はじめは慣れていないので、git addしてgit commitしてgit pushするというような基本的な操作しかせず、また慎重に行うので大きな失敗は少ないです。しかし慣れてくるとそうはいきません。

「えっ、何でこーなるの?」
「あっ、間違えちゃった…」

そういうこと多々ありませんか??
そういう場面に出くわした場合に、手助けできるような内容を書きたいと思います。

Gitの基本概念

まずは最低限の基本概念!!ソフトウェアの思想と振る舞いを知ることが一番の上達の近道だと思いますので押さえておくべきです!!

用語解説

はじめに用語を説明します。

リポジトリとは

ファイルやディレクトリの状態を記録する場所です。プロジェクト開始以来の、すべてのリビジョンを集めて記録しているデータベースをリポジトリと呼びます。

リビジョン、コミット

プロジェクトの状態を記録した一つの単位を、リビジョンとかコミットとか言う言葉で表します。リビジョンとコミットの違いはあるようですが、意味合いはリビジョン=コミットで考えていても問題ないと思います。

ブランチ

ブランチとは、コミットの履歴の流れを記録したものです。特定のコミットを指し示すことによって、そのブランチの現在の状態、プロジェクトの歴史の中における、ブランチの位置づけを記録したり、変更をした場合に次に作られるコミットがどこに作られるかを示すために使われます。

fix-Aとかfeature-Bとかの矢印がそれぞれの先頭の状態を指し示しています。これらの特定のコミットを指し示した矢印を、ブランチと呼びます。

インデックス

インデックスはコミットするための情報を準備するためのものになります。具体的には変更内容をgit addなどのコマンドでコミット対象にしますが、そのコミット対象を管理するものがインデックスになります。インデックスはステージという言い方もされます。

ワークツリー

リビジョンに記録されている内容を展開したディレクトリ領域をワークツリーと呼びます。git checkoutしてファイルがディレクトリ領域に保存されますが、そのディレクトリ領域のことを指しています。

tips集

それでは以下に例をあげて対処法を書いていきます。


・ログメッセージに変なことを書いてしまった。コミットに追加するファイルを忘れていた

ログメッセージを何も書かずにcommitしたり、恥ずかしいことを書いたりすることたまにありますよね。
そんな時は、

でログを書き換えてしまいましょう。
ちなみにこのコマンドはコミットをやり直すコマンドですので、例えばコミットに追加するファイルを忘れていた場合

でコミット内容を修正することができます。


・一気にいろんな修正をしてしまったが、それぞれ別々にコミットにして履歴を残したい

を使ってインデックスを更新する。
このコマンドを使うと、変更箇所を対話形式で確認してくれて、インデックスに追加するかの選択をすることができます。
1つのファイルであっても部分的にインデックスに追加することができます。

ですので今回のコミットではAの修正分だけをインデックスに反映して、次回のコミットではBの修正分をインデックスに反映してコミットするというようなことができます。

また、たとえばテストコードなどを実装していて、テストコードはコミットしたくないとか、間違った修正をコミットしないように修正内容を確認しながらインデックスに追加したいなどの用途にも使えます。


・ローカルで編集したファイルを元に戻したい

ファイルを修正していて、やっぱり元に戻したい場合に使います。またブランチを切り替えるときにファイルを変更していた時は切り替えられないのですが、git stashで退避するまでもない修正や要らない修正の場合はこのコマンドを使って変更を取り消し、ブランチを切り替えたりします。

またgit addでインデックスを更新してしまっている場合は以下のコマンドでインデックスの変更内容も直前のコミットの状態に戻すことができます。

そもそもgit resetにはオプションで--soft--mixed(オプションなし)、--hardとあるのですが、どう違うのか。
--softは今までのおこなってきたコミットのみをなかったことにします
--mixed(オプションなし)はコミットとインデックスに対しておこなった変更をなかったことにします。
--hardはコミット、インデックスの変更、ワークツリーに対して行った変更をなかったことにします。

用途に応じて使い分けてもらえばと思います。

ワークツリーの要らないファイルやディレクトリをすっきり削除したい場合は以下のコマンドを使用します。

-xオプションはgitで通常は無視されるファイルも削除します。
-fオプションはファイルを削除するときに指定します。--forceの略です。
-dオプションは追跡されていないファイルに加え、追跡されていないディレクトリも削除します。


・必要なブランチ、コミットを消してしまった場合

上記で紹介したgit resetで間違えて必要なコミットを消してしまった場合、以下のコマンドで元に戻せます。

でまずコミット一覧を確認、そして

を実行します。

git reflogは過去のあらゆるコミットを参照することができます。

ブランチを消してしまったときは

で元に戻せます。


・ブランチ間の比較をしたい

AブランチにはBブランチから派生してC修正を加えているはずなので、差分はC修正のはずだけど、確認する方法はないかなと思うことがあります。そういう時は

で確認することができます。

これは正確にはコミット間の比較になります。
ですので、以下のコマンドでコミット間の比較も行うことができます。

コミットIDの取得をします。


・修正していたブランチが目的のブランチと違っていた

ワークツリーやインデックスにした変更は間違いではなく、ブランチを切り替えるのを忘れていて、目的のブランチとは違うブランチに修正を行っていたってことよくあります。そういう場合の解決方法は、まずこのコマンドを試します。

branchは目的のブランチを指定してください。

もしこのコマンドが成功して、目的のブランチをcheckoutできたら、何も悩むことはありません。
間違ったブランチに行った内容は目的のブランチに正しくコミットすることができます。
Gitではワークツリーとインデックスにした変更は、どのブランチにも属しているものではないので、目的のブランチとは違うブランチにおこなった変更が、こうやって目的のブランチに移ってコミットしてしまうことができるんです。

しかし以下のようなエラーが出る場合、修正したファイルが間違ったブランチと目的のブランチとで異なっている可能性があります。

こういう場合の対処法はいくつかあります。

トピックブランチを始めてマージする

間違ったと判断した時点でトピックブランチを始めてしてマージします。

トピックブランチを始めてチェリーピックする

先ほどのトピックブランチを始めてマージするの最後の手順でマージの代わりにチェリーピックを行います。
チェリーピックとはブランチの登録されたコミットを別のブランチに適用することをいいます。

git logでコミットIDを取得します。

git stashで退避する

git stashを使って今の変更を退避させ、目的のブランチをチェックアウトして変更を反映します。

まずは変更を退避。

目的のブランチをチェックアウト。

変更内容を反映します。

・マージを取り消したい

マージしたけど、そのマージを取り消したい。そんな時はgit revertを使います。

マージを行いましたが、この時点でやっぱり元に戻したい。。

ログでマージのコミットIDを取得

-mオプションは「1がマージされた側のブランチ」「2がマージする側のブランチ」となります。多くの場合はマージされた側のブランチを基に戻すと場合が多いので1を指定することが多いと思います。

まとめ

今まで書いてきた内容である程度は、問題を解決することが出来ると思います。しかしGitは複数人で使った場合にさらに複雑な問題も出てきます。また、ブランチをどのように使うかなどのブランチモデル、git-flowとかも有名ですが、そういう運用も考えたりとかGitの奥は深く、使いこなすと、私たちに素晴らしい恩恵を与えてくれるものであると実感しました。

参考文献

入門Git 濱野 純(Junio C Hamano)

Pocket

Comments are closed, but you can leave a trackback: Trackback URL.

Advent Calendar 2015の連載記事

  1. TECHSCORE Advent Calendar 2015
  2. Redshift と PostgreSQL に同時に JDBC 接続する
  3. Lombok で Spice up your Java!
  4. 画像を指定するだけ!非デザイナーでも簡単にそれっぽい配色ができるツールを作ってみた
  5. 新卒文系エンジニアの記録:配属半年間の失敗を振り返ってみた
  6. 非同期処理のすすめ
  7. ioDrive2の導入で支える、そのIOPS - 導入検討編.
  8. GoでパイプラインからSlackに通知する
  9. fuse でオレオレファイルシステムを作ってみた (Haskell で)
  10. Erlang はじめました
  11. ちょっと地味なビルドとリリースの話 (レガシーシステム改革、はじめの一歩)
  12. Java8 最速 boolean[] to Stream 選手権
  13. Google Apps の Directory API にてWebブラウザを介さずに認証する
  14. 風データをビジュアルに表現する
  15. マイクロフレームワーク「Ninja」を使ってみる
  16. 赤ちゃんvimmerからよちよちvimmerにクラスチェンジを果たすためのTips
  17. PostgreSQL FDW を作ってSQLでログ検索してみた
  18. Goで偽名ジェネレータを作りました
  19. 書き込み中に削除されたファイルを救出する
  20. 運用情報更新のススメ
  21. ちゃんと読んでくれましたか?
  22. Presto コネクターを実装する 第三回
  23. Ruby2.3を触ってみる
  24. Git 困ったときのtips集
  25. 5分で読む入門編:Java 8 ラムダ式 コレクション編(2)リストの検索
  26. CloudFront (+ S3) + JWPLAYER で様々なデバイスのブラウザから動画をストリーミング再生する