简体   繁体   中英

How do I rebase merge commits while preserving the commit IDs of all the changes

Let's say I maintain a fork of a project.

I want to perdiodically rebase downstream onto upstream while preserving all the commit SHAs of the changes. That is, I want to rebase each individual merge commit , but I want all the change commits to keep their own parent.

Here's a simplified example, with only one downstream patch.

Initial state:

DOWNSTREAM:
*   d9ce4cb Merge branch 'pr1' into downstream   # <- our merge commit for the downstream change
|\
| * dcc0f5e (pr1) Downstream commit 1       # <- our change downstream
|/
* ee6faa1 Upstream commit 2
* c57fe05 Upstream commit 1
UPSTREAM:
* 732985e Upstream commit 3       # <- one NEW COMMIT upstream
* ee6faa1 Upstream commit 2
* c57fe05 Upstream commit 1

Now, I run:

$ git rebase --rebase-merges=no-rebase-cousins upstream

I end up with:

ACTUAL DOWNSTREAM:
*   e7574a0 Merge branch 'pr1' into downstream
|\
| * 2dc0049 (pr1) Downstream commit 1       # <-- BAD: The downstream commit has changed parent
|/
* 732985e Upstream commit 3
* ee6faa1 Upstream commit 2
* c57fe05 Upstream commit 1

Instead, this is I want ( notice that "Downstream commit 1" still has "Upstream commit 2" as a parent , hence it keeps its commit ID):

DESIRED NEW DOWNSTREAM:
*   e7574a0 Merge branch 'pr1' into downstream      # <- The merge commit has moved
|\
* | 732985e Upstream commit 3
| * dcc0f5e (pr1) Downstream commit 1       # <- GOOD: The downstream commit is preserved
|/
* ee6faa1 Upstream commit 2
* c57fe05 Upstream commit 1

Is there a magic trick to end up in the desired state? (one that ideally works when there are N downstream merge commits to rebase)

I want to perdiodically rebase downstream onto upstream while preserving all the commit SHAs of the changes.

This is not possible. The SHA hash of a commit is computed from the contents of the commit which include its parents. If you rebase the downstream branch onto an upstream branch, the parent of the first rebase changes which creates a new commit with a new hash. Then the next commit must be rebased onto this new parent so its hash changes, etc.

 DESIRED NEW DOWNSTREAM: * e7574a0 Merge branch 'pr1' into downstream # <- The merge commit has moved |\ * | 732985e Upstream commit 3 | * dcc0f5e (pr1) Downstream commit 1 # <- GOOD: The downstream commit is preserved |/ * ee6faa1 Upstream commit 2 * c57fe05 Upstream commit 1

From this diagram, it seems like you need to do a merge, not a rebase. For example:

git checkout downstream
git merge 732985e

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM