連載
» 2012年07月11日 00時00分 公開

かんばん!〜もし女子高生がRedmineでスクラム開発をしたら(5):「うわっ…私のバージョン管理、ダメ過ぎ…?」を解決するGitの使い方“超”入門 (3/3)

[岡本隆史, イラスト:本橋ゆうこ,@IT]
前のページへ 1|2|3       

プルとフェッチで、ほかの編集者の変更を取り込む

まいん

共有リポジトリの変更内容を取り込む仕組みとしては、「プル」と「フェッチ」があるんだよ。


ぷりん

ふ〜ん、プルとフェッチって何が違うの?


まいん

プルは、共有リポジトリのコミットをローカルリポジトリと作業ツリーに取り込むの。作業ツリーの状態は、ほかのユーザーの変更(コミット)が反映され状態になるの。フェッチは共有リポジトリの変更をローカルリポジトリにのみ取り込み、作業ツリーには反映しないの……。作業ツリー(編集するファイル)に、反映するには、ローカルリポジトリに取り込んだ修正をマージする必要があるんだよ。


図10 プルとフェッチの違い 図10 プルとフェッチの違い
ぷりん

う〜ん、動きは何とな〜く分かったんだけど、やっぱり、どう違うのかよく分かんないなぁー。どういうときにプルを使って、どういうときにフェッチを使うのかなぁ?


まいん

そうね。簡単に長所と短所をまとめると、下記のような感じかな。


表2 プルとフェッチの長所と短所
プル フェッチ
長所 即座に作業ツリーに反映されるので、手間が掛からない 共有リポジトリの変更を取り込む前に変更点を確認できる
短所 取り込む前に、作業ツリーにどのような変更を及ぼすのか確認しづらい マージの手間が掛かる
ぷりん

うーん、難しいなぁ。神経質なA型の人は他人の変更を細かく確認したいだろうからフェッチを使って、大ざっぱなO型の人は「取りあえず取り込んじゃえ、えい!!」って感じでプルを使えばいいのかな。あ、でもB型の人はどうすればいいんだろう……。


まいん

まぁ、血液型でどっちを使うのか決めるのは悪くない選択肢ね。実際のコマンドの説明は亜琉美ちゃんお願いね。


亜琉美

承知しました。プルは、下記コマンドで行うことができます。


$ git pull
亜琉美

フェッチは、下記コマンドで行います。


$ git fetch
亜琉美

ただし、フェッチはローカルリポジトリへ更新を取り込んだだけで、作業ツリーや作業中のブランチには変更は反映されません。「git fetch」でローカルリポジトリに取り込んだ変更内容を確認するには、下記のようにします。


$ git diff FETCH_HEAD
亜琉美

確認した変更内容を作業ツリー(正確には現在作業しているブランチ)へ取り込むには、下記のようにします。


$ git merge FETCH_HEAD
まいん

この変更を取り込む作業を「マージ」って呼ぶんだよ。


コラム プルでエラーになったとき

プルを行うときに、下記のようなエラーが出ることがあります。

$ git pull
remote: Counting objects: 55, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 31 (delta 22), reused 27 (delta 18)
Unpacking objects: 100% (31/31), done.
From https://github.com/alminium/alminium
   b3c9e63..ee81015  master     -> origin/master
Updating b3c9e63..ee81015
error: Your local changes to 'README.txt' would be overwritten by merge.  Aborting.
Please, commit your changes or stash them before you can merge.

これは、README.txtが作業ツリー上で変更されているので、変更の取り込みに失敗したことを示しています。このメッセージが出た場合、下記コマンドで作業ツリー上の変更をコミットするか、

$ git commit -a

下記コマンドで作業ツリーの変更を取り消して(注:コミットしていない変更は破棄されるので注意)、

$ git reset --hard

下記コマンドで変更点の取り込めます。

$ git merge FETCH_HEAD

「マージ」は魔法使いではありません

ぷりん

「マージ」っていう言葉が出てきたけど、「僕と契約して、ほにゃらら」っていうやつ?


まいん

それは多分魔法使いの英語の「メイジ(Mage)」……。いや、そもそもメイジは男の魔法使いだし、読者は魔法少女にしか興味ないと思うけど……。


まいん

話を戻すと、ほかの人、あるいはほかのブランチの変更点を取り込む操作を「マージ(統合)」って呼ぶんだよ。


図11 マージの概念 図11 マージの概念
まいん

例えば、さっきのプル/フェッチの図10だと、ほかのユーザーのコミットをローカルリポジトリに一回取り込んでから、作業ツリー(正確には作業ツリーで作業をしているブランチ)に取り込んでいるけど、このローカルリポジトリから作業ツリー、正確には作業中のブランチに取り込む操作がマージと呼ばれる作業なんだよ。


まいん

マージは、例えば作業ツリー上での変更点とほかのユーザーの変更点がバッティングすると失敗して、「コンフリクト(競合)」と呼ばれる状態になることがあるの。


図12 コンフリクトの概念図 図12 コンフリクトの概念図
まいん

例えば、図12の例で説明すると、Talkクラスを重複して実装し、亜琉美ちゃんが共有リポジトリにコミットしたときにおねーちゃんがプルすると、編集個所が重複しているから、競合した状態が発生するのよ。この状態で、ローカルリポジトリでプルを実行すると、下記のようにエラーになるの。


$ git pull
remote: Counting objects: 13, done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 7 (delta 4), reused 0 (delta 0)
Unpacking objects: 100% (7/7), done.
From https://192.168.56.101/git/test
   e2a59bc..aedc9d1  master     -> origin/master
Auto-merging java/websocket-chat/app/models/ChatRoom.java
CONFLICT (content): Merge conflict in java/websocket-chat/app/models/ChatRoom.java
Automatic merge failed; fix conflicts and then commit the result.
亜琉美

ここで、「git status」を実行すると、下記のように表示されます。


$ git status -s
UU java/websocket-chat/app/modiels/ChatRoom.java
まいん

「UU」っていうのは、そのファイルがコンフリクトを起こしていることを示しているの。ここで、コンフリクトを起こしたChatRoom.javaをエディタで開くと、図13のようになっているよ。


図13 コンフリクトしたファイル 図13 コンフリクトしたファイル
まいん

コンフリクトしたファイルを開くと、編集が競合した場所が「<<<<」と「>>>>」に囲まれ、図13のようになっているよ。「====」を区切りとして、上側にローカルリポジトリの内容が、下側にpullで取り込もうとした共有リポジトリ上の変更の内容が記述されているの。


まいん

競合を起こした場所を編集し、どちらの変更を取るか選択しましょう。例えば、図13の例だと赤の変更はユーザーとメッセージだけをパラメータとして取っているけど、青の変更はユーザーとメッセージに加え、写真の扱いも追加してあるよ。写真も使える方がいいから、青の変更を選択する場合、競合が発生している部分を編集し、下記のようにしてね(<<<<、====、>>>>などのセパレータも削除)。


……
  }
 
  public static class Talk {
 
        final String user;
        final String text;
        final String picture;
 
        public Talk(String user, String text, String picture) {
            this.user = user;
            this.text = text;
            this.picture = picture;
        }
 
    }
 
    public static class Quit {
……
亜琉美

下記のようにadd、コミットすると、マージは完了です。


$ git add java/websocket-chat/app/modiels/ChatRoom.java
$ git commit -m "競合を解決し、会話クラス(Talk)で写真を扱えるようにする"

ファイル単位で「コンフリクト」を解決

ぷりん

マージするのに、いちいちコンフリクトが起こったところを編集するのは、面倒くさいよー。一括して、ローカルリポジトリの編集と、共有リポジトリの編集を選択できないかなぁ。


亜琉美

下記のようにすると、一括してどちらかのファイルの変更を採用できます。


マージするブランチの変更(ここでは共有リポジトリ上の変更)を採用
$ git checkout MERGE_HEAD - java/websocket-chat/app/modiels/ChatRoom.java
$ git commit
カレントブランチの変更(ここではローカルリポジトリ上の変更)を採用
$ git checkout ORIG_HEAD - java/websocket-chat/app/modiels/ChatRoom.java
$ git commit

コンフリクトが起きたときの注意

まいん

コンフリクトになったときは、競合した変更をコミットした人と相談して修正するようにしましょう。意識合わせをせずに勝手に他の人の編集を上書きすると、トラブルの基になるんだよ。


ぷりん

確かに、こっちのリソースの競合とか考えずに仕事を取ってくる課長とかって超ムカつくよね。競合が発生したときは、話し合いによる解決は重要だよね〜。


亜琉美

コンフリクトした場所を誰が編集したか確認するには、ログを確認します。まず、コンフリクトを起こした場所の最後にある、以下の部分に競合したコミットのコミットIDが記述されています。


<<<<<<< HEAD
……
========
……
>>>>>> aedc9d1106f2e68888c4ac82b2
亜琉美

このコミットIDを指定して下記のようにログを確認すると誰が編集したのか一目で確認できます。


$ git log -1 aedc9d
commit aedc9d1106f2e68888c4ac82b2cf03d549f42bfd
Author: 亜琉美 <alminium@example.com>
Date:   Thu Jun 21 20:33:57 2012 +0900
 
    会話機能の実装
亜琉美

上記のログからは、亜琉美が競合するコミットを行ったことが分かります。


ぷりん

コンフリクトの解決しようとしてファイルを編集してたら、ファイルがグチャグチャになっちゃんだけど、そういうときはどうすればいーの?


まいん

競合を解決していて、ファイルがグチャグチャになって、最初からマージをやり直したい場合は、下記コマンドのようにすると、マージ前の状態――ここでは共有リポジトリの変更を取り込む前の状態――に戻るよ。


$ git reset --hard
亜琉美

resetで元に戻してから、下記コマンドのようにしてマージすると、もう一度共有リポジトリ上のコミットをマージできます。


$ git merge FETCH_HEAD

コミットはソースコードの年輪

まいん

まあコミットは、「ソースコードの年輪」みたいなものかな。コミットを見ていけば、どのようにソースコードが変更していったか分かるよ。例えば、コミットによる変更履歴は「git log」コマンドで確認できるの。


$ git log
commit b89a8befe5b4da63fd356609220ef074192c8ae1
Author: mikoto20000 <mikoto20000@gmail.com>
Date:   Wed Jun 6 08:21:09 2012 +0900
 
    Redmine 2.0.2にアップデート
 
commit da2e10fab985ed7969404455d47a436bf22b93d8
Author: mikoto20000 <mikoto20000@gmail.com>
Date:   Fri Jun 1 02:06:03 2012 +0900
 
    smeltに実行権限を付与
 
commit ada129bfde3adf11fa338d53adfbed867beeea3c
Author: mikoto20000 <mikoto20000@gmail.com>
Date:   Fri Jun 1 18:59:30 2012 +0900
 
    Backlogsプラグインをサポート。
 
commit dce70618e2a96b1ac751449db299c233e13c66ba
Author: mikoto20000 <mikoto20000@gmail.com>
Date:   Thu May 31 00:38:49 2012 +0900
 
    リポジトリの不正な上書きとブランチの削除を禁止
まいん

開発中のあるコミットからプログラムが正しく動かなかった場合や、過去のプログラムの変更を参考にしたい場合など、コミットによる変更内容を確認したい場合は、次のように「git show」コマンドを使いましょう。


$ git show ada129df
ぷりん

さて、今日はGitリポジトリの作り方とGitのキホンについて紹介したよ。次回はGitとRedmineとの連携についてと、ブランチについてのお話しだよ。ホームワークで確認して待っててね!



ホームワーク!
亜琉美

今日の宿題を出します。Gitに限らずですが、本当に理解するには実践あるのみですよ。


問1

 ALMiniumを利用してGitリポジトリ付きのプロジェクトを作成してください。

問2

 問1で作成したプロジェクトにユーザーを追加してください。

問3

 問2で追加したユーザーでリポジトリをクローンしてください。

問4

 クローンしたリポジトリの作業ツリーにファイルを作成し、コミットしてください。

問5

 コミットした変更を共有リポジトリへプッシュしてください。

問6

 git logコマンドやgit showコマンドでコミットメッセージと変更点を確認してください。

本稿の図版について本稿の図版について

 本稿の図版は京風子(Kyoko)氏作成の「あんずもじ」フォントを利用しています。

著者紹介

文:認定スクラムマスター 岡本隆史

イラスト:本橋ゆうこ



前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。