リモートにpushする前に git pull --rebase を使ってみた

10月中旬頃から業務で本格的にプログラミングをし始めたのですが、gitが怖すぎるのでお試しでgit pull --rebaseを使ってみました。ただ使ってみただけだとすぐ忘れるので、せっかくなので書き残しておこうと思います。

やりたいこと

今回実現したいことは、git pull --rebaseを使って

リモートにpushする前に今作業しているブランチを最新の状態にする

 です。

masterからブランチを切ってしばらく作業している内に、masterがどんどん更新されていって自分のブランチが古くなってきたなー、なんて時はありませんか?
そんな時にgit pull --rebaseを使うと便利です。

例えば、masterからhogeブランチを切って作業していたとしましょう。そのhogeブランチをリモートにpushする前にgit pull --rebaseを使います。そうすると、hogeブランチを最新のmasterに合わせてそこにhogeブランチのcommitを付け足すことができます。

つまり、最新のmasterからhogeブランチを切ったことにできます。

今回はこれを実際にやって行きたいと思います。

前提

  1. try-gitというディレクトリの中にsample.htmlがあります
  2. 同じmasterからbranchAとbranchBが作られています
  3. 先にbranchAの変更をmasterにマージします

この段階でbranchBの状態を、branchAがマージされた後のmasterに合わせていきます。

sample.htmlを編集

branchAとbranchBでsample.htmlを編集していきます。
まだ何もマージされていない状態のmasterブランチでは以下のようになっています。

master

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>try-git</title>
</head>

<body>
  <h2>リスト1</h2>
  <ul>
    <li>コンテンツ1</li>
    <li>コンテンツ2</li>
    <li>コンテンツ3</li>
  </ul>
</body>

</html>

この状態からまずはbranchAを以下のように編集します。

branchA

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>try-git</title>
</head>

<body>
  <h2>リスト1</h2>
  <ul>
    <li>コンテンツ1</li>
    <li>コンテンツ2</li>
    <li>コンテンツ3</li>
  </ul>
  <h2>リスト2</h2>        ⬅︎ ここから
  <ul>
    <li>コンテンツ1</li>
    <li>コンテンツ2</li>
    <li>コンテンツ3</li>
  </ul>           ⬅︎ ここまで追加
</body>

</html>

この変更をmasterにpushし、マージします。

次に、ブランチをbranchBに切り替え、sample.htmlを編集します。

branchB

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>try-git</title>
</head>

<body>
  <h1>Welcome!!</h1>      ⬅︎ ここを追加
  <h2>リスト1</h2>
  <ul>
    <li>コンテンツ1</li>
    <li>コンテンツ2</li>
    <li>コンテンツ3</li>
  </ul>
</body>

</html>

branchBではまだpushはせず、commitだけしておきます。

git pull --rebaseでbranchAを最新のmasterに合わせる

今、masterではbranchAがマージされたのでsample.htmlは以下のようになっています。

master

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>try-git</title>
</head>

<body>
  <h2>リスト1</h2>
  <ul>
    <li>コンテンツ1</li>
    <li>コンテンツ2</li>
    <li>コンテンツ3</li>
  </ul>
  <h2>リスト2</h2>
  <ul>
    <li>コンテンツ1</li>
    <li>コンテンツ2</li>
    <li>コンテンツ3</li>
  </ul>
</body>

</html>

リスト2が追加されていますね。branchBでもこの変更を反映したいです。
そこで活躍するのが、git pull --rebaseです。

まずはブランチをmasterに切り替え、ローカルのmasterを最新の状態にします。

$ git pull --rebase origin master

これでローカルのmasterにもリスト2が追加されました。
次にbranchBに移動します。ここでgit pull --rebaseを実行します。

$ git pull --rebase origin master

コンフリクトが起きていなければ問題なく成功するはずです。
エディタでsample.htmlを確認すると、以下のようになっているかと思います。

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>try-git</title>
</head>

<body>
  <h1>Welcome!!</h1>
  <h2>リスト1</h2>
  <ul>
    <li>コンテンツ1</li>
    <li>コンテンツ2</li>
    <li>コンテンツ3</li>
  </ul>
  <h2>リスト2</h2>
  <ul>
    <li>コンテンツ1</li>
    <li>コンテンツ2</li>
    <li>コンテンツ3</li>
  </ul>
</body>

</html>

branchBにもリスト2が追加されました。
branchBをリモートにpushすると、branchAをマージ後のmasterからbranchBを切ったことになっているのがGitHub上でわかると思います。

せっかくなのでコンフリクトさせてみる

今回コンフリクトさせた状態でgit pull --rebaseを試してみたので、そちらについてもまとめておこうと思います。

コンフリクトした状態でgit pull --rebaseを実行すると以下のようになると思います。

$ git pull --rebase origin master

From https://github.com/ユーザー名/try-git
 * branch            master     -> FETCH_HEAD
First, rewinding head to replay your work on top of it...
Applying: コミットメッセージ
Using index info to reconstruct a base tree...
M   sample.html
Falling back to patching base and 3-way merge...
Auto-merging sample.html
CONFLICT (content): Merge conflict in sample.html
error: Failed to merge in the changes.
Patch failed at 0001 コミットメッセージ
hint: Use 'git am --show-current-patch' to see the failed patch
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

これはgit pull --rebaseが失敗しています。
エラーメッセージをよく見てみると、

Resolve all conflicts manually, mark them as resolved with "git add/rm <conflicted_files>", then run "git rebase --continue".

となっています。
これを簡単に訳すと

コンフリクトを解消してgit add、もしくはgit rmを実行してgit rebase --continueを実行してね

ということです。

なので、言われた通りにやってみましょう。
Visual Studio Codeを使っている場合、この段階でエディタを開くとコンフリクト解消画面になっていると思うので、コンフリクトを解消してgit addします。
そして、git rebase --continueを実行しましょう。

$ git add sample.html
$ git rebase --continue Applying: コミットメッセージ

となっていればgit pull --rebaseの完了です。

ただ、コミットを複数している状態だと何度かコンフリクトを修正しなければいけないことがあるようです。これは、git pull --renbaseの仕様によるものなのですが、ここでは説明を割愛させていただきます。
こちらにかなり詳しく書いてあるので、ぜひ一度読んでみることをお勧めします!

https://www.clear-code.com/blog/2016/9/2.html

コンフリクトした場合の対処方法だけではなく、「--rebase」なしのgit pullとの違いなどもまとめられています。