Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to split every commit by file?

I know how to manually split a commit using git rebase -i, but how can I automatically split every commit in a branch by file?

For instance, commit A modified 3 files, f1, f2 and f3. After the split, there are 3 commits A-f1, A-f2 and A-f3.

I want to do this to make a major rewriting easier as I will only have to squash some small commits.

like image 613
Julien__ Avatar asked Nov 19 '16 22:11

Julien__


2 Answers

The Script

The following script splits HEAD by file:

#!/usr/bin/env bash
set -e

SHA=$(git rev-parse --short HEAD)

# Change to repo root directory
cd $(git rev-parse --show-toplevel)

git reset HEAD^

git diff-tree --no-commit-id --name-only -r $SHA | while read -r f; do
  git add "$f"
  GIT_EDITOR="echo '0a\n$SHA $f\n\n.\nw' | ed -s" git commit -c $SHA
done

The generated commit messages are of the form:

<original SHA> <file name>

<original commit message>

Usage

The following assumes that you can run above script as git-split.

If you want to split all commits in a range by file, use it like this:

git rebase --interactive --exec git-split <branch>

If you want to split a single commit during an interactive rebase, use it like this:

p Commit to split
x git-split

Any improvements to the script are welcome.

like image 126
raphinesse Avatar answered Oct 12 '22 22:10

raphinesse


For every commit, you would need

  • first to list all files in that commit

    git diff-tree --no-commit-id --name-only -r <SHA1>
    
  • then for each file, extract that file

    git show <SHA1>:/path/within/repo/to/file
    

Do that in a working tree of a dedicated branch, and for every file extracted, add and commit.

Then you can reset your current branch by that new one built commit-file by commit-file.

like image 29
VonC Avatar answered Oct 12 '22 23:10

VonC