8

I want to selectively promote a number of commits from one branch to another with a PR review.

Imagine I have on my master branch the following commits:

8b08096 - mod4
97eff67 - mod3
b64891f - mod2
fa6e804 - mod1
956e388 - initial

On my staging branch I have only the following:

956e388 - initial

I now want to "promote" the commits for mod1, mod2 & mod3 from master to the staging branch. So, from staging I create a new temporary branch and merge the commits up until mod3:

git checkout staging
git checkout -b promote
git merge 97eff67

Doing a git log now shows me all the commits including mod3 on my promote branch:

git log --pretty=oneline

97eff67 (HEAD -> promote) mod3
b64891f mod2
fa6e804 mod1
956e388 (origin/staging, staging) initial

git push origin promote

I can now create my PR for the team to review the changes.

However, when it comes to merging this into the staging branch, GitHub gives me 3 options; Merge, Squash & Merge and Rebase & Merge. I don't want to do Merge since that gives me a merge commit. I don't want to do Squash & Merge since that will squash all my commits into a single commit so I'm left with Rebase & Merge.

When I do a Rebase & Merge, all the changes are applied to the staging branch. However, all the commits have now been given new hashes (except of course for the "initial" commit):

2d7177a - mod3
2831f46 - mod2
a8a2e15 - mod1
956e388 - initial

How can I merge the commits from my promote branch into my staging branch while keeping the commit hashes intact?

Luke
  • 20,878
  • 35
  • 119
  • 178
  • 1
    It seems they should give a `rebase` option when the commit history allows a clean rebase. If you don't absolutely need the GH PR, you could rebase manually :/ – JScoobyCed Aug 22 '21 at 04:47
  • 2
    @JScoobyCed Or they could just automatically copy the commits when possible during a rebase instead of *always* replacing them. If I have tags on my commits or I've GPG-signed my commits, GitHub's broken rebase option always orphans those tags and signed commits so they're only on my PR branch without going into main. The only way to get GitHub to copy your commits as-is (preserving the commit hash so the GPG-signing and tags remain) is to use the merge-commit option that adds a redundant commit. – LinuxDisciple Dec 31 '21 at 21:03

1 Answers1

9

That's perfectly normal:1 rebase copies commits to new and (supposedly) improved commits, which means they will have different hash IDs.

How can I merge the commits from my promote branch into my staging branch while keeping the commit hashes intact?

Do not use REBASE AND MERGE.

GitHub do not provide a button that would do what I wish they allowed. This means that if you wish to merge a branch on GitHub, you must use the MERGE button.

To merge without a "merge bubble" (i.e., sans merge commit) as a fast-forward instead, you will have to do the fast-forward on your own machine, and then use git push to send the updated commit hash ID to GitHub. That is:

git fetch

(so that you have everything on your laptop or wherever—this step is often unnecessary, but never hurts), then:

git checkout staging
git merge --ff-only origin/staging   # if needed

git merge --ff-only origin/promote   # whatever fast forward you want here
git push origin staging

The checkout-and-fast-forward for staging is only needed if your own staging is behind origin/staging after the git fetch step. The git merge --ff-only commands achieve the fast-forward-instead-of-merge operation.


1Normal for GitHub, anyway. Some systems allow a fast-forward merge operation here, where this would not occur. GitHub is not one of these. REBASE AND MERGE does a forced rebase, making it "normal".

torek
  • 448,244
  • 59
  • 642
  • 775
  • 2
    As for the "[Github] copies commits to new and (supposedly) improved commits", I wonder why they think the commits are improved. I chatted with support, but they had no reason. – Garrett Apr 19 '22 at 20:51
  • 2
    @Garrett: they have a different committer field (as configured by whoever is doing the rebase) and time-stamp. Not much of an improvement, as far as I'm concerned. They *may* also have different parent hash IDs, in which case the copying is forced, but they may not, in which case I just find it annoying. – torek Apr 19 '22 at 20:55
  • 1
    @torek I would say it's not "perfectly normal", since gitlab for instance does it differently and allows to not change any commit-hash when doing a fast-forward merge. This github feature is quite broken in my opinion. The "rebase and merge" is doing the equivalent of "git rebase --force" in the background, instead of doing a simple "git rebase" which would be a NO-OP for a fast-forward merge. – Étienne Sep 06 '22 at 13:31
  • 1
    See also https://stackoverflow.com/questions/60597400/how-to-do-a-fast-forward-merge-on-github – Étienne Sep 06 '22 at 13:32
  • 2
    @Étienne: I've added a footnote. It's normal for GitHub because GitHub are annoying. :-) Note that GitLab's action here is what I meant by "GitHub do not provide a button that would do what I wish they allowed". – torek Sep 06 '22 at 13:50
  • First it was the fact that GitHub merges `base` into `head` (when resolving merge conflicts in a pull request), when attempting to merge `head` into `base` (it literally does the exact opposite of what you want). And now it's "rebase and merge doesn't give the expected outcome." Even as a 20 year veteran of the software industry, I have found working with GitHub UI to be a very painful experience! Thanks for the insights, Torek, Étienne, and Garrett – Brian FitzGerald Apr 14 '23 at 21:06