Skip to content

Instantly share code, notes, and snippets.

@Pierstoval
Last active September 22, 2025 18:14
Show Gist options
  • Save Pierstoval/92dd994bdbe2d4daf7d55b6c242672be to your computer and use it in GitHub Desktop.
Save Pierstoval/92dd994bdbe2d4daf7d55b6c242672be to your computer and use it in GitHub Desktop.
I've got a lot of issues when rebasing tons of branches...

Issue when rebasing lots of branches with conflicts

Working context

Let's imagine I have this git graph:

(fig 1)

* 9e5d9b3 - (HEAD -> branch10) Commit 10
* 3e0a94e - (branch9) Commit 9
* 8ff2ab4 - (branch8) Commit 8
* 2a4b9ec - (branch7) Commit 7
* f075e86 - (branch6) Commit 6
* 2960e5a - (branch5) Commit 5
* 61bf766 - (branch4) Commit 4
* adb8403 - (branch3) Commit 3
* 1539f24 - (branch2) Commit 2
* fa81942 - (branch1) init

Now, imagine a messed up tree of the repository.

Basically, on this kind of tree, every branch has a new commit, but there is zero conflict (like, for example, it's only about adding new files).

(sorry, hard to read, but definitely what I might end up with sometimes)

(fig 2)

* b6336ed - (HEAD -> branch10) New file on branch10
* 9e5d9b3 - Commit 10
| * 26cc916 - (branch2) New file on branch2
| | * c0a3bdb - (branch3) New file on branch3
| | | * 147b2b3 - (branch4) New file on branch4
| | | | * f8d8009 - (branch5) New file on branch5
| | | | | * 707f527 - (branch6) New file on branch6
| | | | | | * b43c03a - (branch7) New file on branch7
| | | | | | | * 859801b - (branch8) New file on branch8
| | | | | | | | * 731e7a3 - (branch9) New file on branch9
| |_|_|_|_|_|_|/
|/| | | | | | |
* | | | | | | | 3e0a94e - Commit 9
| |_|_|_|_|_|/
|/| | | | | |
* | | | | | | 8ff2ab4 - Commit 8
| |_|_|_|_|/
|/| | | | |
* | | | | | 2a4b9ec - Commit 7
| |_|_|_|/
|/| | | |
* | | | | f075e86 - Commit 6
| |_|_|/
|/| | |
* | | | 2960e5a - Commit 5
| |_|/
|/| |
* | | 61bf766 - Commit 4
| |/
|/|
* | adb8403 - Commit 3
|/
* 1539f24 - Commit 2
* fa81942 - (branch1) init

I need to loop over all these branches by their order, and rebase everything.

I do something like this:

for i in {2..10}
do
  prev=$((i-1))
  git switch "branch${i}"
  GIT_EDITOR=true git rebase "branch${prev}"
done

And then, I end up with a beautiful tree of everything rebased onto each previous branch:

(fig 3)

* cf3f06f - (HEAD -> branch10) New file on branch10
* 46bf70b - Commit 10
* b4b33b7 - (branch9) New file on branch9
* 25d40f0 - Commit 9
* a776a3e - (branch8) New file on branch8
* 2b8a707 - Commit 8
* 318010a - (branch7) New file on branch7
* 1dddc07 - Commit 7
* f26fe68 - (branch6) New file on branch6
* fba3235 - Commit 6
* ce4d5db - (branch5) New file on branch5
* b00a618 - Commit 5
* 2ba7ac1 - (branch4) New file on branch4
* 59d1d1d - Commit 4
* 105f4fa - (branch3) New file on branch3
* 7e1e4d0 - Commit 3
* ab12590 - (branch2) New file on branch2
* 3a23697 - Commit 2
* 6c7d585 - (branch1) init

The problem

Whenever I update one branch anywhere in the git tree, and the changes have conflicts, and I re-run the "rebase everything" command, I can end up with strange trees like that, especially when conflicts are solved in a way that I have to "rewrite" some things based on new information:

(fig 4)

* 4ec68c0 - (HEAD -> branch10) New file on branch10
* 126ef9b - Commit 10
* 95273fb - (branch9) New file on branch9
* b053b3b - Commit 9
* 9af7554 - (branch8) New file on branch8
* 9c9dbf4 - Commit 8
* a9656bb - (branch7) New file on branch7
* 71c8535 - Commit 7
* 7e763e0 - (branch6) New file on branch6
* 430a784 - Commit 6
* 8f224b6 - (branch5) New file on branch5
* 84c4439 - Commit 5
* a932c79 - Commit 4
* b521576 - Commit 3
* 4fd71bb - Commit 2
* 8eb2d76 - (branch4) New file on branch4
* e09c8bd - Commit 4
* a060b2c - (branch3) New file on branch3
* 1153c70 - Commit 3
* ceb580a - (branch2) New file on branch2
* 46b6902 - Commit 2
* 6c7d585 - (branch1) init

See the list of "Commit X" in branch5: they correspond to a rebase on a previous branch where everytime I had to manually fix something, and it created a new commit in the tree.

The expected result

What I'd like is to keep the "working case" where remnants of old commits references are squashed together with the first commit of the branch.

So in here, I'd like the tree to stay exactly the same as in fig 3.

The only "workaround" I currently have is the following:

git switch branch5
git rebase --interactive branch4
# The "Interactive rebase" opens, and I do this:
#  > Change "pick" into "squash" for commits that reference commits from previous branches, in this case, a932c79, b521576 and 4fd71bb
#  > Save & exit
# Then the "Commit" editor opens, and I do this:
#  > Remove the commit lines from the "old commits"
#  > Save & exit

# Then sometimes, in case of conflicts:
git rebase --continue

# And if no conflicts, rebase is done 

Once I run this workaround, I have to re-run the "rebase everything" command, and usually, the branches "after the problematic one" will suffer the exact same thing, so I have to do it by hand to ALL upcoming branches.

Question

So, how can I make sure to run a proper chain-rebase like this, resolve conflicts manually if I need (I already have some code that "waits until conflict resolution is done" so it can run git rebase --continue by itself), and end up with only the commits from the specific branches?

What I thought about (and haven't tried yet):

  • Using git reset && git cherry-pick at some point, but the point is, this is quite annoying because I need to fetch the list of all commits that differ between the base and the current head, do it, check for conflicts manually like I'm doing now. Not impossible, but quite tricky too.
  • I also thought about using git merge all over the place, but the graph will be totally unreadable then, and debugging this will be a definite PITA.

(Oh, and side-note: I don't care about commit hashes, it's meant to be exactly like that)

What are your recommendations? Any tips on fixing the rebase process? Should I change and use reset & pick? Should I give up and use git merge, and say goodbye to the nice tree?

Appendix

I just tested with merge-ing everything when having conflicts.

Conflicts are still extremely annoying to handle, but there's less of them: maximum one per branch, compared to rebasing where there can be multiple commits impacted by the conflicting change.

And it turns out it's as ugly as I expected.

Here's an example with the "new file" thing from before, and afterwards, I introduced a conflicting commit in branch5.

*   4be3807 - (HEAD -> branch10) Merge branch 'branch9' into branch10
|\
| *   b7c9304 - (branch9) Merge branch 'branch8' into branch9
| |\
| | *   f1a5d51 - (branch8) Merge branch 'branch7' into branch8
| | |\
| | | *   3cd0392 - (branch7) Merge branch 'branch6' into branch7
| | | |\
| | | | *   6aca8c5 - (branch6) Merge branch 'branch5' into branch6
| | | | |\
| | | | | * cfbb51d - (branch5) conflict with branch 5
* | | | | | 2965de0 - Merge branch 'branch9' into branch10
|\| | | | |
| * | | | | dd861d1 - Merge branch 'branch8' into branch9
| |\| | | |
| | * | | | c3cf079 - Merge branch 'branch7' into branch8
| | |\| | |
| | | * | | a432a77 - Merge branch 'branch6' into branch7
| | | |\| |
| | | | * | f8e6478 - Merge branch 'branch5' into branch6
| | | | |\|
| | | | | *   0e5a170 - Merge branch 'branch4' into branch5
| | | | | |\
| | | | | | *   acc8d0b - (branch4) Merge branch 'branch3' into branch4
| | | | | | |\
| | | | | | | *   4a08149 - (branch3) Merge branch 'branch2' into branch3
| | | | | | | |\
| | | | | | | | * 8dde879 - (branch2) New file on branch2
| | | | | | | * | efad1d7 - New file on branch3
| | | | | | * | | 84e093b - New file on branch4
| | | | | * | | | 94291f6 - New file on branch5
| | | | * | | | | 2563af8 - New file on branch6
| | | * | | | | | 3ff40bf - New file on branch7
| | * | | | | | | fd5874d - New file on branch8
| * | | | | | | | f27bbe0 - New file on branch9
* | | | | | | | | afe9778 - New file on branch10
* | | | | | | | | e2f29df - Commit 10
|/ / / / / / / /
* / / / / / / / 3c37942 - Commit 9
|/ / / / / / /
* / / / / / / 9410c9d - Commit 8
|/ / / / / /
* / / / / / 1c45e66 - Commit 7
|/ / / / /
* / / / / 8a85594 - Commit 6
|/ / / /
* / / / 07083ff - Commit 5
|/ / /
* / / f0e50ea - Commit 4
|/ /
* / e6e5545 - Commit 3
|/
* 926b51f - Commit 2
* 332af2f - (branch1) init
#!/usr/bin/env bash
set -e
gitlog() {
git log --graph --all --pretty=format:'%Cred%h -%C(yellow)%d%Creset %s'
}
rm -rf testgit/
mkdir testgit/
cd testgit/
git init
echo "init" > content.txt
git add content.txt
git cm -m "init"
git branch -m branch1
for i in {2..10}
do
prev=$((i-1))
git checkout -b "branch${i}" "branch${prev}"
echo "branch${i}" >> content.txt
git add content.txt
git cm -m "Commit ${i}"
done
git switch branch10
gitlog
git switch branch1
for i in {2..10}
do
prev=$((i-1))
git switch "branch${i}"
echo "new content ${i}" > "content${i}.txt"
git add "content${i}.txt"
git cm -m "New file on branch${i}"
done
# Commented, because it doesn't reproduce all the time for some sick strange reason 😡
#git switch branch7
#echo "Conflicting changes" >> content.txt
#git add content.txt
#git cm -m "Conflicting changes"
git switch branch1
gitlog
for i in {2..10}
do
prev=$((i-1))
git switch "branch${i}"
GIT_EDITOR=true git rebase "branch${prev}"
done
git switch branch10
gitlog
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment