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,
git fetch origin
git pull master
fix conflicts
git add .
git commit -m "merge commit" ---- where problem happens ----
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 , ....)
git rebase -i 0x05 : go back to C to squash E , H
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?
CodePudding user response:
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.