過去コミットを分割してたら、知らないファイル変更が現れた

はじめに

topic-a ブランチで新たに作成した ComponentX を topic-b ブランチでも使いたくなったので、

topic-a からコンポーネントXを作成したコミットだけ cherry-pick して別PRにしたいが、

コンポーネントXを作成したコミットには他の変更(コンポーネントXの適用)も入っているため単純に cherry-pick するだけでは無理なので

コンポーネントXを作成したコミットを分割しようとしてハマった話をします。

ハマりどころ

「git 過去コミット 分割」でググるとこんな記事を見つけました。

cha-shu00.hatenablog.com

先人に感謝しつつ、なるほど 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 をしたら過去コミットの分割ができました!

さいごに

そういえば前にもこんなことあったなーと思ったので備忘録として残しておきます。

というか、適切な粒度でコミットしましょう。

弊社では適切な粒度でコミットできるエンジニアを絶賛大募集中です!

カジュアル面談も有りますのでご興味あればぜひお気軽に下記リンクからお願いします!

ingage.co.jp

後日談

コンポーネント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 ファイルは生成されました。

綺麗な歴史にこだわりがないなら、これで十分だなーと思いました。

ではまた!