1

Suppose we had (Z is a merge commit):

...--o--A--C            <-- master
        |\
        | --B           <-- branch
         \   \   
          ----Z         <-- develop

After git checkout branch; git rebase master and some commiting

             B¹-D       <-- branch            
            /         
...--o--A--C            <-- master
        |\
        | --B           
         \   \   
          ----Z         <-- develop

Then develop need to be updated: git checkout develop; git rebase master --rebase-merges

             B¹-D       <-- branch            
            /         
...--o--A--C            <-- master
        |\ |\
        || | --B²
        ||  \   \
        ||   ----Z²     <-- develop
        | \
        |  -B
         \   \   
          ----Z         [abandoned]

If I merge "branch" into "develop", history will contain both B¹ and B². Is it possible to ask git to detect that equal to B² commit already exists in non-abandoned branch "branch" and to re-use it?

  • 1
    Ah, the velocyraptor graph... we meet again (https://stackoverflow.com/a/3162929/6309 from 2010) – VonC Feb 26 '20 at 05:32
  • No. `B¹` and `B²` are not equal, they're different because their parents are different. `git` calculates commit's IDs using a lot of information including parents' IDs. – phd Feb 26 '20 at 05:32
  • @phd A is a parent of B but C is a parent of both B¹ and B². – Lichtgestalt Feb 26 '20 at 06:35
  • @Lichtgestalt Then there're other differences — author/committer names and dates. – phd Feb 26 '20 at 06:44
  • @phd Both B¹ and B² were made from B by `git rebase master` but in different branches ("branch" and "develop"). They have the same comment, author, date, body - everything except of sha1 (at least properties shown by `git log --graph`). – Lichtgestalt Feb 26 '20 at 12:12
  • 1
    @Lichtgestalt `git rebase` changes committer date. Compare `git show -s --format=fuller` for B¹ and B². – phd Feb 26 '20 at 12:25

1 Answers1

0

First, make sure to add any option like --rebase-merges before the branch you are rebasing onto.

git rebase --rebase-merges master 

Then consider rebasing develop onto branch instead of master: branch already include B1, and B2 won't be repeated.
In an interactive rebase (-i option), you will have the opportunity to drop D (a commit from branch you do not want in develop): that might work if there is just one of two commits specific to branch and not on develop. If the history is more complex, that would be cumbersome.
The end result would be B1-Z' on your new rebased develop, reusing B1 as requested.

The key idea is, as torek explains:

That is:

Note that any commits in HEAD which introduce the same textual changes as a commit in HEAD..<upstream> are omitted (i.e., a patch already accepted upstream with a different commit message or timestamp will be skipped).

That is why B would not be repeated as B2, and B1 would be preserved/reused, even though their parent commits (of B and B1) and timestamps differ.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250