Git Cherry-Pick VS Rebase

Introduction

When we are working on some large projects in the company, it is often inevitable to have our CL to be dependent on others’ CLs which have not been merged. Although it is usually unambiguous what dependencies we want, running Git cooperatively sometimes is error-prone, causing push failures and even unwanted changes to CLs.

In this blog post, I would like quickly discuss how to run Git using cherry-pick and rebase in cooperative projects.

Cooperative Git

Here is a common scenario that we will encounter in a cooperative project.

Tom and Jerry are enabling two different features in their own CLs. It turns out that Jerry’s feature is dependent on Tom’s. Although Tom’s implementation of the new feature seems successful in his CL, it still has to go through the code review which can take a very long time. Jerry does not want to wait until Tom’s CL gets merged and decide to work based on Tom’s unmerged CL.

Suppose the commit history of Tom’s CL, Jerry’s CL and the main branch are as follows.

  • Tom’s CL: base commit 1 –> Tom’s commit

  • Jerry’s CL: base commit 2 –> Jerry’s commit

  • Main: base commit 1 –(X commits)–> base commit 2 –(Y commits)–> main tip commit

Now if Jerry wants to use Tom’s commit in Jerry’s CL, what should Jerry do? Suppose Jerry can push code to Tom’s CL (by --reset-author).

Cherry-Pick

One of the common ways to incorporate others’ WIP CLs is cherry-pick. We could have two methods to cherry-pick for our problem.

Method 1

  • Checkout Jerry’s CL.

  • Rebase Jerry’s CL onto the main tip and resolve all conflicts if there is any so that
    Jerry’s CL: main tip commit –> Jerry’s commit

  • Push. This goes to Jerry’s CL.

  • Checkout Tom’s CL.

  • Rebase Tom’s CL onto the main tip and resolve all conflicts if there is any so that
    Tom’s CL: main tip commit –> Tom’s commit

  • Push (using --reset-author). This goes to Tom’s CL.

  • (Now still in Tom’s CL branch) Cherry-pick Jerry’s CL and resolve all the conflicts between Tom’s CL and Jerry’s CL if there is any so that

  • Tom’s CL: main tip commit –> Tom’s commit –> Jerry’s commit

  • Push. This goes to Jerry’s CL.

  • Git will catch the relation chain:
    Tom’s CL –> Jerry’s CL

  • Jerry’s CL cannot merge to the main branch until Tom’s CL gets merged.

Method 2

  • Checkout Tom’s CL.

  • Cherry-pick Jerry’s CL and resolve all the conflicts between Tom’s CL and Jerry’s CL if there is any so that
    Tom’s CL: base commit 1 –> Tom’s commit –> Jerry’s commit

  • Push. This goes to Jerry’s CL and this does not require changing Tom’s CL or reset the author for Tom’s CL.

  • Git will catch the relation chain:
    Tom’s CL –> Jerry’s CL

  • Jerry’s CL cannot merge to the main branch until Tom’s CL gets merged.

If base commit 1 is a “good” base, i.e., there is no conflict to resolve when Tom’s commit is rebased on the main tip., this is a very straightforward way to work since we don’t have to push to Tom’s CL.

However, the major problem is Tom’s base commit 1 is much behind Jerry’s base commit 2 and therefore Jerry’s CL might not work (probably due to missing lots of code).

  • To make Jerry’s CL work, Jerry might still have to rebase Tom’s CL after checking out Tom’s CL so that
    Tom’s CL: main tip commit –> Tom’s commit

  • Push (using --reset-author). This goes to Tom’s CL.

  • (Now still in Tom’s CL branch) Cherry-pick Jerry’s CL and resolve all the conflicts between Tom’s CL and Jerry’s CL if there is any so that
    Tom’s CL: main tip commit –> Tom’s commit –> Jerry’s commit

  • Push. This goes to Jerry’s CL.

  • Git will catch the relation chain:
    Tom’s CL –> Jerry’s CL

  • Jerry’s CL cannot merge to the main branch until Tom’s CL gets merged.

Therefore, if base commit 1 is a “bad” base, i.e., there is conflict to resolve when Tom’s commit is rebased on the main tip., it makes almost no difference between method 1 and method 2.

Rebase

An alternative way to incorporate others’ WIP CLs is rebase. It is different from cherry-pick and in some scenarios can be more difficult to work with than cherry-pick. We also could have two methods to rebase for our problem.

Method 1

  • Checkout Tom’s CL.

  • Rebase Tom’s CL onto the main tip and resolve all conflicts if there is any so that
    Tom’s CL: main tip commit –> Tom’s commit

  • Push (using --reset-author). This goes to Tom’s CL.

  • Checkout Jerry’s CL.

  • Rebase Jerry’s CL onto the main tip and resolve all conflicts if there is any so that

  • Jerry’s CL: main tip commit –> Jerry’s commit

  • Push. This goes to Jerry’s CL.

  • (Now still in Jerry’s CL branch) Rebase Jerry’s CL on top of Tom’s CL and resolve all the conflicts between Tom’s CL and Jerry’s CL if there is any so that

  • Jerry’s CL: main tip commit –> Tom’s commit –> Jerry’s commit

  • Push. This goes to Jerry’s CL.

  • Git will catch the relation chain:
    Tom’s CL –> Jerry’s CL

  • Jerry’s CL cannot merge to the main branch until Tom’s CL gets merged.

Method 2

  • Checkout Jerry’s CL.

  • Rebase Jerry’s CL onto Tom’s CL so that

  • Jerry’s CL: base commit 1 –> Tom’s commit –(X commits)–> base commit 2 –> Jerry’s commit

Pushing Jerry’s CL is problematic, because we will push X commits, base commit 2, and Jerry’s commit but Jerry is (usually) not the author for the X commits and base commit 2. Unless Jerry is the administrator of Git, this push will be prevented.

So instead of rebase entirely, we could do rebase interactively which allows the user to pick the commits and reset the author for each commit. In this way, Jerry can become the author of the X commits and base commit 2, or skip rebasing those commits, and the push will be successful.

The major problem is that if X is very large, there will be too many steps for Jerry to rebase interactively. If this is the case, we would rather use the method 1 instead.

Conclusions

It seems that no matter whether we use cherry-pick or rebase, rebase the two CLs to the main branch is very critical for setting up a correct relation chain and pushing.

References

Author

Lei Mao

Posted on

07-18-2022

Updated on

07-18-2022

Licensed under


Comments