開発時、どの粒度でcommitするか考えながらコードを書きたくない。
特に、開発中は試行錯誤しながら実装を進めているので、最初から設計しきれていない場合も多い。怠慢と言われてしまうと弱いが、開発スピードも考慮すると、試行錯誤するのが早い。
確かにそんな状態で開発を進めていると、commit履歴が汚れてしまうのも現実だ。このままレビュワーにレビュー依頼をすると、レビュワーの側の負担が大きくなってしまう1。
要件の整理
以下ができると、あとはチームで運用ルールを定めればよさそうだ。
- 後で、ブランチを分割したい
後で、commitをまとめたい
(ついでに)masterが進んでしまった場合に、新しいHEADからbranchを分けたい2
これらを実現するため、試してみたやり方をメモとしてまとめる。
本記事では、「ブランチを分割したい」を検証する。
「commitをまとめたい」は以下の記事で別にした。
https://cipepser.hatenablog.com/entry/git-operation-merge-commitcipepser.hatenablog.com
前提
- conflictするパターンは考えない3
やりたいこと
commitが積み重なり、変更が大きくなったブランチを考える。レビュワーの負担減を目的に、このブランチを分割したい。
やり方
git cherry-pick
を使う
(準備)commit用のファイルを用意する
❯ ls
README.md a.txt b.txt
txtファイルの中身はファイル名が一文字書いてある。
例えばa.txt
ならa
とだけ書いてある。適当に用意しただけなので、意味はない。
❯ cat a.txt a
後続に、git diff
している箇所があるので、git log
を補足(これが初期状態)。
❯ git log --pretty=oneline 635c5d5570a6c0492be7a924dda3df314bfd13b8 (HEAD -> master) first commit
大きくなりすぎたブランチを作る
大きくなりすぎた(a.txtとb.txtを同時に追加した)ブランチをadd-a-and-b
ブランチとする。
❯ git checkout -b add-a-and-b
a.txt
を追加したcommitと、b.txt
を追加したcommitを行う。
(「2つもcommitあるなんて大きすぎるよ」の状態)
❯ git add a.txt ❯ git commit -m "add a.txt" ❯ git add b.txt ❯ git commit -m "add b.txt"
git cherry-pick
でcommit idを使うので、git log
を確認しておく。
❯ git log --pretty=oneline 451fcd8e75608ca6364fd2ad9f9699adf8a8b3fb (HEAD -> add-a-and-b) add b.txt 41295c0d3043f560a61f57a0f44d4785056b4269 add a.txt 635c5d5570a6c0492be7a924dda3df314bfd13b8 (master) first commit
(本題)ブランチを分割する
a.txtを追加するadd-a
ブランチと、b.txtを追加するadd-b
ブランチに分ける
add-aブランチ
masterブランチからadd-a
ブランチを作成する。
❯ git checkout master
❯ git checkout -b add-a
add a.txt
のcommitをpickする。
# `first commit`から`add a.txt`のcommit idを指定
❯ git cherry-pick 635c5d5570a6c0492be7a924dda3df314bfd13b8..41295c0d3043f560a61f57a0f44d4785056b4269
結果(add-a
のcommitだけpickできた)
❯ git log --pretty=oneline b1abe76c7f481cecf64934a98dcd1971a13496e6 (HEAD -> add-a) add a.txt 635c5d5570a6c0492be7a924dda3df314bfd13b8 (master) first commit
add-bブランチ
masterブランチからadd-b
ブランチを作成する。
❯ git checkout master ❯ git checkout -b add-b Switched to a new branch 'add-b'
add b.txt
のcommitをpickする。
# `add b.txt`のcommi idを指定 ❯ git cherry-pick 451fcd8e75608ca6364fd2ad9f9699adf8a8b3fb
結果(add-b
のcommitだけpickできた)
❯ git log --pretty=oneline bceca8ee93f256fb1d4083798c1aed1e3b1c8c16 (HEAD -> add-b) add b.txt 635c5d5570a6c0492be7a924dda3df314bfd13b8 (master) first commit
masterにマージする4
add-aブランチのマージ
masterブランチに戻る。
❯ git checkout master
masterブランチにadd-aブランチをマージする。実運用ではGitHub上でプルリクを送ることになると思う。
❯ git merge add-a Updating 635c5d5..b1abe76 Fast-forward a.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 a.txt
結果
❯ git log --pretty=oneline b1abe76c7f481cecf64934a98dcd1971a13496e6 (HEAD -> master, add-a) add a.txt 635c5d5570a6c0492be7a924dda3df314bfd13b8 first commit
add-bブランチのマージ
こちらもgit merge
でマージする5。
念のため、事前状態を記載しておく。
❯ git checkout add-b Switched to branch 'add-b' ❯ git log --pretty=oneline bceca8ee93f256fb1d4083798c1aed1e3b1c8c16 (HEAD -> add-b) add b.txt 635c5d5570a6c0492be7a924dda3df314bfd13b8 first commit
マージする。
❯ git checkout master ❯ git merge add-b Merge made by the 'recursive' strategy. b.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 b.txt
結果(add-a
ブランチとadd-b
ブランチを分割できている)
❯ git log --pretty=oneline 298b644f77788e7f2db45f21bfc56731fc46470d (HEAD -> master) Merge branch 'add-b' bceca8ee93f256fb1d4083798c1aed1e3b1c8c16 (add-b) add b.txt b1abe76c7f481cecf64934a98dcd1971a13496e6 (add-a) add a.txt 635c5d5570a6c0492be7a924dda3df314bfd13b8 first commit
「commitをまとめたい」については、以下に書いた。
https://cipepser.hatenablog.com/entry/git-operation-merge-commitcipepser.hatenablog.com
-
打ち消しcommitだったり、そもそもが意味のないcommitだったりも含まれてしまうことも…↩
-
自分でブランチを分割したときにも発生するので、実は対応が必須↩
-
今、考えたいこと以上に複雑な問題にしない)↩
-
実際には、マージ前に
add a.txt
のレビューを行っているはず。↩ -
add-aブランチをmasterにマージしたことで、add-bブランチから見るとmasterが先に進んでしまっている。
git rebase master
だと、一番最初にbranchを分けた時点からのdiffになってしまい、レビュワーの負担が減らなかったため、git merge
を使っている。conflictするパターンも含めて深堀りが必要か。あくまで本記事の対象は、「レビュー負担軽減を目指し、conflictがない範囲でブランチ分割を行う」こととした。↩