0

currently I'm in trouble using rebase.

feat           E(PR1) ---------> H(merge commit)
              /                /              \ (on trouble!)
master A-B - C  - - - - - - -> F
          \ /(merged)        /(merged)
tmp   ...  G - - - - - - - -K


so the case is, I'd made a 'feat' branch on period C and did some devs and made pull request on period E(my first PR).

Then from my director, I've got a request that master branch currently accepted another PR, so pls sync branch and make a rebase to discard merge commits and resend PR.

So, What I did is,

  1. git fetch origin

  2. git pull master

  3. fix conflicts

  4. git add .

  5. git commit -m "merge commit" ---- where problem happens ----

  6. git log (find the period to rebase : hash of period 'C' (alias 0x05) (p.s the log order is : H - F(merge pull request from branch tmp) - E - K , ....)

  7. git rebase -i 0x05 : go back to C to squash E , H

  8. then I get odd result than my expected result that commits for 'H' isn't presented, only E is presented..

(e.g) pick E (I need log pick H as well)

any ideas on this?

Justin Seo
  • 59
  • 8
  • What are you calling a "period" here? – Romain Valeri Dec 19 '22 at 09:12
  • @RomainValeri sorry for the term, pls think as commit – Justin Seo Dec 19 '22 at 09:14
  • *I get strange error* Which error? Copy-and-paste the error message into the question. – j6t Dec 19 '22 at 09:25
  • @j6t sorry, not error, but not expected result. what I want to squash is commit E,H so when I type 'git rebase -i xxx' I want result like " pick E , pick H" but it only shows "pick E" – Justin Seo Dec 19 '22 at 09:31
  • 1
    This is normal. `rebase` omits merge commits. Just continue. You will very likely be presented with the same conflicts that you have already resolved earlier. If you have the rerere database enabled, the resolutions should be applied automatically. If not, it shouldn't be a big problem, either, as you already know how to resolve the conflicts. – j6t Dec 19 '22 at 09:34
  • @j6t thanks for your help :), your answer truly helped me understand what kind of issue what I was facing :) – Justin Seo Dec 21 '22 at 07:47

1 Answers1

1

What you're trying to do doesn't make much sense, and git is assuming you actually mean something else.

The primary purpose of a merge commit is to record the fact that you've merged something. As a side effect of resolving conflicts, the commit may introduce novel changes, but git doesn't store changes, it stores results, so it doesn't actually know the difference between "the code looks like this because of a merge conflict" and "the code looks like this because of a clean merge".

The purpose of a rebase, on the other hand, is to replay changes; again, these changes aren't actually stored, they're reconstructed by comparing commits with their parents. In most circumstances, merge commits don't have changes that you want to replay in this way, so git rebase simply ignores merge commits by default.

Your actual problem is that you're rebasing onto the wrong base.

As a good habit, let's draw the history more like git's view - branches point to recent commits, commits point to parents:

            E <------------- H <-(feat)
           /                /             
A <- B <- C <- - - - - - - F <-(master)
      \  /(merged)        /
        G <- - - - - - - K <-(tmp)

Rebasing onto C, even if you could keep the result of the merge, will give you this:

          /<- E2 <-(feat)
          |
          | E <------------- H (unreachable from any branch)
          |/                /             
A <- B <- C <- - - - - - - F <-(master)
      \  /(merged)        /
        G <- - - - - - - K <-(tmp)

Note that E2, regardless of what code it contains, doesn't claim to be related to commit F in any way.

What you actually wanted was to checkout branch feat, and then:

git rebase master

Which means "find all commits on the current branch but not master; then reset to master, and replay those changes". The result is something like this:

                               /<- E2 <-(feat)
                              /
            E <------------H / (H is unreachable)
           /               |/             
A <- B <- C <- - - - - - - F <-(master)
      \  /(merged)        /
        G <- - - - - - - K <-(tmp)

Pruning out the unreachable commits (git will "garbage collect" them in the background):

                             /<- E2 <-(feat)
                            /        
A <- B <- C <- - - - - - - F <-(master)
      \  /(merged)        /
        G <- - - - - - - K <-(tmp)

Now not only does E2 have the changes of both the original E plus the changes of master up to F; it also records its relationship to F.

IMSoP
  • 89,526
  • 13
  • 117
  • 169
  • So much thanks for your reply, I'd realized I've been just passivly using git, should understand what I were using :(. Thanks again for your kind answer:) – Justin Seo Dec 21 '22 at 07:46