はじめに
topic-a ブランチで新たに作成した ComponentX を topic-b ブランチでも使いたくなったので、
topic-a からコンポーネントXを作成したコミットだけ cherry-pick して別PRにしたいが、
コンポーネントXを作成したコミットには他の変更(コンポーネントXの適用)も入っているため単純に cherry-pick するだけでは無理なので
コンポーネントXを作成したコミットを分割しようとしてハマった話をします。
ハマりどころ
「git 過去コミット 分割」でググるとこんな記事を見つけました。
先人に感謝しつつ、なるほど git rebase -i で edit して git reset HEAD^ して、別々に commit したらいいのか・・
やってみます。
$ git log * ccccccc (HEAD -> topic-a) fix typo * bbbbbbb add ComponentX * aaaaaaa fix style
git rebase -i して
$ git rebase -i aaaaaaa pick bbbbbbb add ComponentX pick ccccccc fix typo # Rebase aaaaaaa..ccccccc onto aaaaaaa (2 commands) # # Commands: # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit ....(omitted)
分割したいコミットを pick → edit に変更
- pick bbbbbbb add ComponentX + edit bbbbbbb add ComponentX
git status
$ git status interactive rebase in progress; onto aaaaaaa Last command done (1 command done): edit bbbbbbb add ComponentX Next commands to do (105 remaining commands): pick ccccccc fix typo (use "git rebase --edit-todo" to view and edit) You are currently editing a commit while rebasing branch 'topic-a' on 'aaaaaaa'. (use "git commit --amend" to amend the current commit) (use "git rebase --continue" once you are satisfied with your changes)
コミットを一つ戻して、git status すると
$ git reset --soft HEAD^ $ git status interactive rebase in progress; onto aaaaaaa (省略) Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: foo/common/elements/CoponentX.vue modified: foo/views/settings/pages/UseComponentXPage.vue modified: foo/models/A.ts modified: foo/models/B.ts modified: foo/models/C.ts . . .
ん?!??
コミット bbbbbb での変更以外のファイルまで modified になっている。
Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: foo/common/elements/CoponentX.vue # <- コミット bbbbbb での変更 modified: foo/views/settings/pages/UseComponentXPage.vue # <- コミット bbbbbb での変更 # 以下、知らない子たち modified: foo/models/A.ts modified: foo/models/B.ts modified: foo/models/C.ts . . .
なぜこんなことに・・・・
解決
ESLint 君の autofix の仕業でした。
webpack コンテナを落として再度同じことをやると
$ git status interactive rebase in progress; onto aaaaaaa (省略) Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: foo/common/elements/CoponentX.vue modified: foo/views/settings/pages/UseComponentXPage.vue
今度はコミット bbbbbb での変更だけが表示されました!
あとは個別にファイルをコミットして rebase --continue をしたら過去コミットの分割ができました!
さいごに
そういえば前にもこんなことあったなーと思ったので備忘録として残しておきます。
というか、適切な粒度でコミットしましょう。
弊社では適切な粒度でコミットできるエンジニアを絶賛大募集中です!
カジュアル面談も有りますのでご興味あればぜひお気軽に下記リンクからお願いします!
後日談
コンポーネントXを作成したコミットには他の変更(コンポーネントXの適用)も入っているため単純に cherry-pick するだけでは無理なので
勝手に無理だと思い込んでいたんですが、実際やってみると
$ git log * ccccccc (HEAD -> topic-a) fix typo * bbbbbbb add ComponentX * aaaaaaa fix style $ git switch main $ git switch -c cherry-pick-component-x Switched to a new branch 'cherry-pick-component-x' $ git cherry-pick bbbbbbb error: The following untracked working tree files would be overwritten by merge: foo/common/elements/CoponentX.vue Please move or remove them before you merge. Aborting fatal: cherry-pick failed $ git status On branch cherry-pick-component-x Untracked files: (use "git add <file>..." to include in what will be committed) foo/common/elements/CoponentX.vue nothing added to commit but untracked files present (use "git add" to track)
と cherry-pick 自体は失敗するんですが、untracked な ComponentX.vue ファイルは生成されました。
綺麗な歴史にこだわりがないなら、これで十分だなーと思いました。
ではまた!