1

Consider that I have two branches: master and staging. Commit C was made on staging and cherry-picked into master urgently, so it's already there.

-x-x-x-A-B-C-D (staging)
      /     
-x-x-x-C (master)     

Later, another branch feature was merged directly into master, so two commits were added to master, the commit E and the merge commit F.

-x-x-x-A-B-C-D (staging)
      /     
-x-x-x-C-E-F (master)

I need to get what is in master into staging to get a clean merge of staging into master. I end up with duplicate commits because of the cherry-pick if I just use merges. If I rebase instead: git checkout staging && git rebase origin/master I get A, B, and D on top (although, I don't think the merge commit F comes in unless I use --rebase-merges, could be wrong though):

-x-x-x-C-E-F-A-B-D (staging)

But what if I wanted those three commits to be merged in based on when they were actually created and end up with:

-x-x-x-A-B-C-D-E-F (staging)

Is this possible and does it make sense at all to do this? Or am I better off putting A, B, and D on top?

Here are what I believe are the relevant parts of the result for git log --graph master. I added the commit letters I used in the question after each commit hash.

*   commit c0ead31e3f7a7f6e077b2bbb947775dcd2dc3453 (**F**) (HEAD -> master, origin/master, origin/HEAD)
|\  Merge: b943c0fd 07a7dd24
| | Author: Author
| | Date:   Tue Nov 22 03:23:09 2022 +0000
| |
| |     Merge branch 'feature' into 'master'
| |
| |     <commit message for feature>
| |
| |     See merge request company/project!24
| |
| * commit 07a7dd245bec741e1c077d055558b3930c570a3f (**E**)
|/  Author: Author
|   Date:   Tue Nov 22 03:20:57 2022 +0000
|
|       <commit message for feature>
|
* commit b943c0fd70e5ba64b70b03721ab2962facaecbc3 (**C**)
| Author: Author
| Date:   Wed Oct 19 18:49:58 2022 +0000
|
|     <commit message>
|
|
|     (cherry picked from commit e1598f670d0e78e76ee0e54a4a4668e7186adbab)
|
Timothy Fisher
  • 1,001
  • 10
  • 27
  • 1
    Just to get clear: If `feature` was merged into `master` that would cause _one_ commit to be added to `master`, the merge commit F. So where did E come from? – matt Nov 26 '22 at 00:45
  • At least in the GitLab UI, when I merged `feature` into `master`, I got two commits in `master`. The commit that I made on `feature` which was the code for the feature, as well as the merge commit. – Timothy Fisher Nov 26 '22 at 00:50
  • 1
    That doesn't make any sense to me; a move that creates _two_ commits on `master` would not be a merge. Maybe you did a "rebase merge", in which case neither E nor F is a merge commit. Can you show the actual diagram of what the history of `staging` looks like? – matt Nov 26 '22 at 00:54
  • 1
    Another thing to understand is that the same commit cannot be in two places. C is not on both master and staging. The thing you got when you cherry-picked C is a _copy_ of C, which we might call `C'` (pronounced C-prime). – matt Nov 26 '22 at 00:58
  • The merge of `feature` into `master` was done through the GitLab UI via a merge request if that helps. I made a commit `E` on `feature`, then did a merge request of `feature` into `master` without commit squashing, and it shows commit `E` as well as a merge commit `F` in the commit history on `master`. – Timothy Fisher Nov 26 '22 at 00:59
  • Got it, I was wondering what the apostrophe was for in other diagrams. – Timothy Fisher Nov 26 '22 at 01:00
  • As I said, that makes no sense to me. Do you know how to get a graph of the topology and show it to us? – matt Nov 26 '22 at 01:00
  • I do not but I can get it over to you if you could let me know how to! – Timothy Fisher Nov 26 '22 at 01:02
  • Is `staging` a shared branch, or is it effectively another `feature` branch that you alone are using? – TTT Nov 27 '22 at 17:29
  • Regarding the questions around merge commit `F`, the issue is that your graph does not show a merge commit. (A merge commit must have at least two parents and thus at least two lines coming out of it.) The command `git log --graph master` should show you the proper graph and will identify what the other parent commit is. It might even be commit `C` if `feature` was already up to date with `master` at the time of the merge. I don't think this changes your question though, but it could clear up this aspect of the discussion. – TTT Nov 27 '22 at 17:36
  • Thank you @TTT, I've updated the question with the graph result – Timothy Fisher Nov 28 '22 at 23:50
  • What's the problem with "duplicated" commits? As long as your _tree_ looks good, why care? – knittl Jan 14 '23 at 10:23

1 Answers1

0

The phrase git checkout staging && git rebase origin/master rebases staging onto master, which seems to be just the opposite of you want. What you want is more like rebase E and F from master onto staging. Keep in mind that rebase is just cherry-pick, so you could achieve this by cherry-picking E and then F.

If, as you claim, F is a merge commit, then you would have to specify its parent, like this:

git switch staging
git cherry-pick <SHA of E>
git cherry-pick -m1 <SHA of F>

But I am more inclined to think that there was no merge, even though you claim there was, so that all you have to do is say

git switch staging
git cherry-pick <SHA of E>
git cherry-pick <SHA of F>
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Note that you may well get merge conflicts in the course of this. But that's just life; you simply will have to resolve them. – matt Nov 26 '22 at 00:57
  • This does work to get E and F commits on top of my staging branch, but, the only problem I find is that when I do a merge request for staging into master after cherry-picking, I get duplicated E and F commits in master. The ones that are already there in master, and then the ones that I cherry-picked into staging. – Timothy Fisher Nov 26 '22 at 01:22
  • Did you also want to delete E and F from master? `git switch master && reset --hard ` – matt Nov 26 '22 at 02:54
  • I need E and F in master for sure but I suppose I could just remove them from master right before the merge. – Timothy Fisher Nov 26 '22 at 03:29