フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

Merge Commit を含んだブランチの変更を Squash して綺麗にする

f:id:lirlia:20211209183300p:plain

*   0917e6be 2021-12-09 自分 Merge remote-tracking branch 'xxx/main' into 自分のブランチ
|\  
| *   03234646 2021-12-09 GitHub Merge pull request #xxx 
| |\  
| | *   2514bd4a 2021-12-09 GitHub Merge main into 別の人の作業用ブランチ
| | |\  
| | |/  
| |/|   
| | *   d7a09ced 2021-12-09 GitHub Merge main into 別の人の作業用ブランチ
| | |\  
| | * \   928f9d02 2021-12-09 GitHub Merge branch 'main' into 別の人の作業用ブランチ
| | |\ \  
| | * \ \   25fe9bf7 2021-12-09 GitHub Merge main into 別の人の作業用ブランチ
| | |\ \ \  
| | * | | | b66a0291 2021-12-08 別の人 なんかの修正
* | | | | | f1cd6deb 2021-12-09 自分 これをした
* | | | | | baad9a52 2021-12-09 自分 あれをした

上記のように Merge Commit が連なっているときに、後でコミットを綺麗にしようと思うと 非常に面倒 ですよね。

reset したり rebase したりすると、Merge Commit に含まれる差分も出てきたり・・・。かといって別ブランチつくって cherry-pick も Commit が多いと辛いです。

ということでこのコマンド

# まとめたい Commit がつまれたブランチ名を指定
TARGET_BRANCH=xxxx

git checkout -b sagyo $(git merge-base main "$TARGET_BRANCH")
git diff sagyo...${TARGET_BRANCH} | patch -p1

※base ブランチが main でない場合は適宜変更してください

このコマンドを実行すると、自分が積んだ Commit の差分が Unstaged 状態となります!

ワンライナーにするなら

function gsquash() {
    local target_branch=${1:-$(git rev-parse --abbrev-ref HEAD)}
    local working_branch=${2:-work-$(date +%s)}
    local base_branch=${3:-main}
    git checkout -b "${working_branch}" $(git merge-base "$base_branch" "$target_branch")
    git diff "${working_branch}"..."${target_branch}" | patch -p1
}

をログインシェルなどに貼り付けておけば、gsquash と叩くだけで実行されます。