Skip to content
David Sherrill edited this page Jun 11, 2015 · 2 revisions

Tangled Rebasing

When greatcode is significantly behind and ahead of master (long left and right lines in https://github.com/psi4/psi4public/branches) or people have made mistakes in checking in code, rebasing may not be straightforward. Here's a few commands that can help.

If you do a rebase (within a branch or from master), and you want to discard the whole thing, examine reflog::

>>> git reflog --all
0012758 refs/heads/efp@{0}: commit: Add back changes that got lost in the rebase and slight tweaks for proper running.
6001c28 refs/heads/efp@{1}: rebase finished: refs/heads/efp onto 6d40a1c06fc5af6f4e983ac8d95b28121a2b78b1
0d45649 refs/heads/efp@{2}: commit: Repeat commit of libefp interface that had been lost in merge commit
b4b25c4 refs/heads/efp@{3}: reset: moving to b4b25c4
89ae8fc refs/heads/efp@{4}: rebase -i (finish): refs/heads/efp onto 6a145ef
b4b25c4 refs/heads/efp@{5}: rebase -i (finish): refs/heads/efp onto 6a145ef
d096b42 refs/heads/efp@{6}: branch: Created from refs/remotes/origin/efp

The above shows an interactive rebase of the efp branch that's good (b4b25c4), followed by one that's bad (89ac8fc), so we reset the code base to the end of the good changeset::

>>> git reset --hard b4b25c4

There's a commit atop the good changeset (0d45649), then a final (non-interactive) git rebase master that finishes at 6001c28, and a last commit (0012758). For a within-branch rebase that you want to make sure didn't alter the final state of the code, reflog's useful again. For example, to make sure after rebase b4b25c4 above that code wasn't lost, one could run the following and hope for a clean output::

>>> git diff HEAD d096b42

One reason why the above might not have given a clean output is if someone pulled, was prompted to resolved conflicts and make a merge commit, did resolve those conflicts but didn't commit, added good new code, and committed, still as a merge commit. Rebasing ignores merge commits so that good code would be lost when the branch is rebased to master. A strategy to find and correct such problems internally within the branch before involving master is to find out how many commits are unique to the greatcode branch.

One way to find how many greatcode commits are going to replay on top of master is by::

>>> git merge-base greatcode master

>>> git merge-base efp master
6d40a1c06fc5af6f4e983ac8d95b28121a2b78b1
>>> git show     6d40a1c06fc5af6f4e983ac8d95b28121a2b78b1
commit 6d40a1c06fc5af6f4e983ac8d95b28121a2b78b1
Merge: 6db5dae d9eb4dd
Author: Eugene DePrince <deprince@Eugenes-MacBook-Pro.local>
Date:   Mon Mar 11 19:46:55 2013 -0400

    Merge branch 'master' of github.com:psi4/psi4

Then do an interactive rebase back that far::

>>> git rebase -i HEAD~24

Change nothing in the resulting script. This skips all the merge commits, and prompts you to do new conflict resolutions. At the end, diff the current state of the code with the pre-rebase state (the git diff HEAD d096b42 example above). If there are any changes, apply and re-commit them, before proceeding with git rebase master.

The general course of a git rebase master is to issue the command, wait for it to stop when it can't apply changesets, run git status to see what files are under contention, resolve the conflicts in each file and git add or git rm file as appropriate. Adding is sufficient, there's no need to commit unless it prompts you with a vi window. Issue git rebase --continue and repeat the process until all changesets have been applied. If upon continuing it asks if you forgot to git add and mentions skipping the commit, if git status shows nothing to change, it's fine to take the advice and issue git rebase --skip.

Since the above shouldn't have been nearly so complicated if you were working on a solo branch, greatcode was probably a shared branch, and you had better have warned all your collaborators to check in their code before the whole rebasing process started (in fact, everywhere on the internet you will be advised not to issue the following command because you're rewriting a shared history). Issue the following and advise your collaborators that the branch is open for check-in again, and they should probably re-clone. ::

>>> git push --force origin greatcode