git: Moving a feature branch up the main-line until it has a conflict

So you all know the drill: You are hacking away on a pet feature and all around you the work goes on. Sometimes you yourself are changing the master branch, sometimes its your colleagues and your feature branch sits a few hundred commits behind. Rebasing it onto the master fails and you do not know which commit is the top-most one you can actually automatically rebase to.

Enter the following script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$target_branch=$1

echo Rebasing onto $target_branch
# Find the first commit that is common between the target branch and the current branch
branch_point=$(diff --old-line-format='' --new-line-format='' <(git rev-list --first-parent "${target_branch}") <(git rev-list --first-parent "HEAD") | head -n 1)

# Just try a rebase
echo Trying the easy way...
if git rebase $target_branch > /dev/null 2>&1; then
    echo that was easy!
    exit 0
fi

# If the simple rebase failed, roll it back
git rebase --abort > /dev/null 2>&1
echo that did not work.

# Find the number of commits which are candidates to rebase your branch to
number_of_commits=$(git rev-list $branch_point..$target_branch | wc -l)
if [ $number_of_commits == 1 ]; then
    # There is one single commit left and that one failed...
    echo There is no way to go further.
    exit 1
fi
echo There are $number_of_commits left!
# Find the middle commit
middle_commit_nr=$(($number_of_commits/2 + 1))
middle_commit=$(git rev-list $branch_point..$target_branch | awk -ne "NR==${middle_commit_nr}p")

# And recursivly rebase onto the middle commit
if $0 $middle_commit; then
    # If that succeeded, we moved the current branch further up the tree;
    # Recursivly retry rebasing onto the real target branch
    $0 $target_branch
else
    # If it failed, it will have tried every possible branching point. Return an error
    exit 1
fi

That’s it!