4

I find myself running into a workflow where I do the following:

  • Create a feature branch ("foo") off of our develop ("master") branch
  • Work, work , work...
  • Submit a pull request for foo
  • While waiting for approval, start work on a related feature...:
  • Create another feature branch ("bar") off of my previous foo branch
  • ...because the work is so closely tied that I couldn't progress directly from develop + I can't wait for reviews -- they sometimes take over a week
  • Submit a pull request for bar
  • Get approval for foo and merge it into develop
  • [we use squash-merges]
  • People are reviewing bar, there are comments, maybe bar is even approved by now
  • Now I rebase bar as follows:
  • git checkout bar
  • git rebase --onto develop foo
  • git push --force origin bar
  • Get approval for bar if not already approved by now, and merge it into develop

This works as expected, but it re-writes history, and is frowned upon because people have already been looking at bar, and there's no way to really know what I did when I force-pushed.

If I try to merge without rebasing, I get all kinds of merge conflicts. It's like develop is trying to "undo" my changes in bar.

My question is:

Is there an equivalent git merge workflow to git rebase --onto??? Something like:

  • git checkout bar
  • git merge ??? develop ??? foo

Is there some trick like... maybe I merge foo back onto bar, or some trick with setting the upstream? I'm fishing here...

Thanks!

EDIT: Another thing... even this process can be a PITA if I have multiple commits in bar. I'll usually merge-in foo to bar at the end, so there's definitely no conflicts between them. But there might be a conflict between an early commit in bar and the latest foo. So I have to do a git rebase -i bar on bar and squash it down to one commit before I do the git rebase --onto develop foo... Not great for preserving history... because now I'm squashing out comment commits, and such. So sometimes I use another alternative:

  • git checkout bar
  • git reset foo
  • git add stuff
  • git commit -m "One commit of foo-bar delta"

Again, grimy -- all the comment commit history is lost...

Sean
  • 393
  • 2
  • 11

2 Answers2

2

This works as expected, but it re-writes history, and is frowned upon because people have already been looking at bar, and there's no way to really know what I did when I force-pushed.

GitHub would clearly mark the previous commits referenced in the PR page as obsolete, but you are correct: it is cumbersome to detect the changes you had to make during your rebase onto develop before force pushing bar.

I would consider and pushing it as "bar2", and make a new PR from bar2, with a reference to the original bar PR.
That would allow a reviewer to compare those two PR branches and quickly determine if anything significant has changed between:

  • the original bar PR, which was already approved
  • the new bar2 PR, which has to be rebased onto develop in order to facilitate its PR merge to develop.
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • I'd consider using that in an extreme scenario where the below `git merge -X ours develop` failed to work. And I included a method to verify whether it works or not. I've seen really really weird merge-conflict choices before, so it wouldn't surprise me if there are cases where a failure could actually happen...??? So +1 for a backup option, but I'm going with the `merge -X ours` option for now. – Sean Sep 03 '20 at 08:14
2

Here's what I went with...:

git merge -X ours develop

And then since git is sometimes not-so-smart about the options it gives when there's a merge conflict, I verified the result with:

diff <(git diff Foo origin/Bar) <(git diff develop Bar)

Luckily, I hadn't pruned (I rarely do). If there's a better way, I'm still open to other answers - going to keep this unanswered for a bit.

It would be nice if there were a solution that preserved the history of Bar, did not show the commit history for Foo (like git rebase --onto does), and required no intervention on merging the individual commits in Bar as they're re-played onto develop... But the more I think about it, I'm not sure that's theoretically possible. So I think I can live with having the extraneous commits in Foo shown in Bar's history. The above meets all the other requirements.

EDIT: Haven't had an opportunity to try it yet, but I think this is what rerere is for.

Sean
  • 393
  • 2
  • 11
  • I think they both preserve the history of `Bar` -- I just checked my PR, and it looks like everything is there to me. I hope I'm not missing something...? – Sean Sep 03 '20 at 08:41
  • I just tested it, you are correct, that should work. – VonC Sep 03 '20 at 08:56