Bitbucket + EGit^5

チーム開発をしているときに避けられないのが、コンフリクト(conflict;競合)。これはソースをプッシュしようとしたら、他の人も同じ箇所を修正していて、それが先にプッシュされた、という場合発生する。あるクラスの異なるメソッドを編集した、といった場合は、プッシュしたときgitがいい感じで解決してくれる(merge;マージ/併合)ので、コンフリクトにはならない。しかし変更箇所が同じ場合、gitはどちらを残すかのが適切か判断できないので*1、このコンフリクトという状態になる。そしてこのコンフリクトが解消されるまで、プッシュできなくなる。つまり自分の作業内容を、他のチームメンバーに取り込んでもらえなくなる、ということ。コンフリクトが起きたら、その解決を最優先ですべし。

以下はコンフリクトが発生する経緯と、その解決方法の説明。

■想定するシナリオ

ItemDaoクラスに以下のようなsaveメソッドがあった。

public int save(String id) throws DAOException {
    return 0;
}

これをaldebaranさんは以下のように変更した。

public int save(int id) throws DAOException {
    return 0;
}

一方、procyonさん以下のように変更した。結果としては、これを残したい。

public int save(ItemBean item) throws DAOException {
    return 0;
}

流れとしては下表なような感じになる。

# procyonさん aldebaranさん
0 プル プル
1 String id → int id へ変更
2 コミット・プッシュ → 成功
3 String id → ItemBean item へ変更
4 コミット・プッシュ → 失敗(コンフリクト)
5 プル
6 コンフリクト解消
7 コミット・プッシュ → 成功
8 プル → 成功

この例の場合、4でprocyonさんがプッシュする前に、同じ箇所を2でaldebaranさんがプッシュしているのでコンフリクトになる。以下その様子と、解決方法を示す。

1. aldebaranさん 変更

引数をint id へ変更。保存すると[ステージされていない変更]に表示される。 f:id:kktworks:20190624163939p:plain

[++]押下→[コミット・メッセージ]入力する。

f:id:kktworks:20190624164309p:plain

2. aldebaranさん コミット・プッシュ → 成功

[コミットおよびプッシュ(M)]押下すると、プッシュまで成功する。

f:id:kktworks:20190624164332p:plain

3. procyonさん 変更

一方、同じころ、procyonさんもsave()を修正した。

f:id:kktworks:20190624164931p:plain

4. procyonさん コミット・プッシュ → 失敗

しかし、[++]押下→[コミット・メッセージ]入力して、[コミットおよびプッシュ(M)]押下したが拒否された。 f:id:kktworks:20190624165106p:plain

このnon-fast-forwardというのは、

あなた(procyonさん)がプッシュしようとしたリソース(ItemDAO.java)は、ほかの人(aldebaranさん)が先に更新していて、しかもその更新箇所があなたのとぶつかっていて、どうすればいいかかわからないので、あなたがどうにかしてくれるまで、このプッシュは無かったことにするね(ニッコリ。

ということを表している。これがコンフリクト(Conflict;競合)。こうなったら、できるだけ速やかに、以下のような手順で解消すること。

5. procyonさん プル

まずプル操作で、ほかの人が変更した内容、つまりaldebaranさんがプッシュした内容を自分のEclipseプロジェクトへ取り込む。

プロジェクト・エクスプローラプロジェクト名 右クリック > チーム(E) > プル(U)を選択。 f:id:kktworks:20190624170435p:plain

やはり競合していることがわかる。

f:id:kktworks:20190624170851p:plain

6. procyonさん コンフリクト解消

上記プル操作でItemDAO.javaには、競合している内容が取り込まれる。 f:id:kktworks:20190624171059p:plain

競合しているのがこの部分。

<<<<<<< HEAD
public int save(ItemBean item) throws DAOException {
=======
public int save(int id) throws DAOException {
>>>>>>> branch 'master' of ...
    return 0;
}

これをコミット・プッシュしたいように編集する。(その前に、この部分をいじった競合相手であるaldebaranさんへ一声かけて確認するのが、いろいろとベターな気がする)

public int save(ItemBean item) throws DAOException {
    return 0;
}
7. procyonさん コミット・プッシュ → 成功

編集後、保存を押すとItemDAO.java[ステージされていない変更]に表示されるが、[++]押しても[ステージされた変更]には移らず消える。[コミット・メッセージ]を適宜入力して、[コミットおよびプッシュ(M)]押下する。 f:id:kktworks:20190624171819p:plain

今度はプッシュできた。 f:id:kktworks:20190624172151p:plain

8. aldebaranさん プル → 成功

この内容を取り込むには、aldebaranさんもプル操作しなければならない。プルするとこのように、procyonさんの編集内容がこちらにも取り込まれる。 f:id:kktworks:20190624172746p:plain

コンフリクトは避けがたいが、無用なマージ操作は避けたい。そのためには自分の作業に関係ないファイルやコードはいじらない!が鉄則。もしやっちまって、自分でコンフリクトを解決するのが難しいという場合は、いち早くテクニカルリーダーや講師にHelp!すること。

*1:あとからプッシュしたものを残すのが正しいとは限らないから