13

I would like to programmatically determine with of my feature branches would have rebase conflicts if I tried to rebase them. Is there a way I can get git to tell me this information without actually performing the rebase?

Failing that, what is the simplest way to detect if a rebase failed before git rebase --aborting it?

My question is similar to these two, which are the same but for merge instead of rebase

5 Answers 5

17

Is there a way I can get git to tell me this information without actually performing the rebase?

The short answer is "no". The long answer is longer but ends with "no" :-) ... you could get pretty close by writing a lot of code but to get the full correct answer you must do all the commit-copying steps of the rebase, at which point you might as well just run the rebase.

Failing that, what is the simplest way to detect if a rebase failed before git rebase --aborting it?

The git rebase command returns a success (zero) exit code if the rebase completes successfully, and a failure (nonzero) exit code if not. In shell script, you can just use git rebase $args || git rebase --abort.

1
  • Many good answers here. Thanks all. I chose an answer based on age and comprehensiveness.
    – Tom Ellis
    Commented Jul 6, 2017 at 20:45
4

Based on the answer of SVSchmidt, you could extend his first command to revert even in the case of success:

git rebase master && (echo "Success" && git reset --hard ORIG_HEAD) || (echo "Fail" && git rebase --abort)

This will still run the rebase, however in the case of success reset your HEAD back to the old HEAD of before the rebase. Produced commits and changes of the reflog will remain, only the reference of your branch is resetted.

You might want to add redirections for the output of the commands to avoid unneeded output. When doing so keep in mind that the rebase might fail due to other circumstances than merge conflicts, e.g. unstaged changes in the working directory.

2
  • 2
    The reset does not "undo" the rebase. It returns the ref to the previous state; but the rebase also creates new objects and updates reflogs - neither of which are undone Commented Jul 7, 2017 at 12:56
  • Thanks, you are right. I have edited my answer to better describe what the reset will change and what will still remain.
    – lucash
    Commented Jul 8, 2017 at 9:53
2

Failing that, what is the simplest way to detect if a rebase failed before git rebase --aborting it?

git rebase returns a falsy status when it fails, so you could do something like

git rebase feature && echo "Success" || echo "fail" && git rebase --abort

This will, however, perform the actual rebase when it is successful. If you want to test if a rebase would be successful without actually performing it, I'm afraid my only idea is to checkout another branch, check if the rebase is successful and switch back, for example:

branch=$(git branch | grep '* .*' | sed s/..//); git checkout -b $branch-rebase > /dev/null ; git rebase test-2 > /dev/null && result="Success" || result="fail" ; git rebase --abort ; git checkout $branch ; git branch -D $branch-rebase ; echo $result

I first remember the current branch in a variable (if anyone has a better solution for determining the current branch, let me know), switch to branchname-rebase, perform the rebase, checkout the original branch and delete the test branch before I echo the result. Hacky, but depending on your usecase, this might work.

2

The closest thing to a "dry run" of a rebase would be to run the rebase from detached HEAD state (so that no refs are actually modified). So instead of

git rebase develop feature_X

you might do

git rebase develop `git rev-parse feature_x`

and check the exit status. The problems with this approach are:

1) It's time consuming. Basically for any branch that doesn't conflict, the entire rebase will run. (And it's hard to imagine how you could do much less work and still accurately know whether the rebase would succeed anyway.)

2) It creates redundant objects (dangling commits and their dependencies), which won't be visible but will nonetheless hang around taking up space in your local repo until you either knock the dangling commits out of the reflog and run gc, or create a fresh clone. If you do this often, the wasted space could really add up.

I'm also not sure how much utility this has. Just because feature_X and feature_Y would each rebase cleanly onto develop, doesn't mean that the sequence of "rebase featureX then rebase featureY" will necessarily complete cleanly. And while it doesn't seem like it should be the case, after some things I've seen recently I wouldn't be shocked to learn of some edge case where the order of rebases determines whether there's a conflict.

So at best you'll get the "low hanging fruit" - "I know for a fact these have conflicts". But hey, you know, if that's the code you need, then that's the code you need.

-1

You could use a custom pre-rebase hook to do any checks that you need before the rebase begins. There's a sample pre-rebase hook here: https://github.com/git/git/blob/master/templates/hooks--pre-rebase.sample

In the pre-rebase hook code, you could diff the changed files and check for conflicts and stop the rebase.

1
  • 1
    But what are the checks? They are my main question. I don't know what to check or how to check it.
    – Tom Ellis
    Commented Jul 6, 2017 at 15:47

Not the answer you're looking for? Browse other questions tagged or ask your own question.