Re: rebase-with-history -- a technique for rebasing without trashing your repo history

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2009.08.13 14:46:07 +0200, Michael Haggerty wrote:
> Sorry to cross-post, but I think this might be interesting to all three
> projects...
> 
> I've been thinking a lot about the problems of tracking upstream changes
> while developing a feature branch.  As I think everybody knows, both
> rebasing and merging have serious disadvantages for this use case.
> Rebasing discards history and makes it difficult to share
> work-in-progress with others, whereas merging makes it difficult to
> prepare a clean patch series that is suitable for submission upstream.
> 
> I've written some articles describing another possibility, which
> combines the advantages of both methods.  The key idea is to retain
> rebase history correctly, on a patch-by-patch level.  The resulting DAG
> retains enough history to prevent problems with merge conflicts
> downstream, while also allowing the patch series to be kept tidy.
> 
> (Please note that this technique only works for the typical "tracking
> upstream" type of rebase; it doesn't help with rebases whose goals are
> changing the order of commits, moving only part of a branch, rewriting
> commits, etc.)

Hm, so that pretty much doesn't work at all for creating a clean patch
series, which usually involves rewriting commits, squasing bug fixes
into the original commits that introduced the bug etc.

And even for just continously forward porting a series of commits, a
common case might be that upstream applied some patches, but not all.
Can you deal with that?

Example:

A---B---C (upstream)
     \
      H---I---J---K (yours)

Upstream takes some changes:

A---B---C---I'--K'--D (upstream)
     \
      H---I---J---K (yours)

rebase leads to:

A---B---C---I'--K'--D (upstream)
                     \
                      H'--J' (yours)

What would your approach generate in that case?

> For more information, please see the full articles:
> 
> * Upstream rebase Just Works™ if history is retained [2]

In this one you have two DAGs:
(I fixed the second one to also have the merge commit in "subsystem"
instead of "topic", so they only differ WRT to the rebased stuff)

A)
m---N---m---m---m---m---m---M  (master)
     \                       \
      o---o---O---o---o       o'--o'--o'--o'--o'--S  (subsystem)
                       \                         /
                        *---*---*-..........-*--T (topic)


B)
m---N---m---m---m---m---m---M  (master)
     \                       \
      \                       o'--o'--o'--o'--o'----------S  (subsystem)
       \                     /   /   /   /   /           /
        --------------------o---o---O---o---o---*---*---T (topic)


And you say that the former creates problems when you want to merge
again. How so?

Merging "master" to "subsystem" is a no-op in both cases.
Merging "subsystem" to "master" is a fast-forward in both cases.
Merging "subsystem" to "topic" is a fast-forward in both cases.
Merging "topic" to "subsystem" is a no-op in both cases.

Merging "topic" and "master" (in either direction) has merge base N in
both cases.

Let's assume that there's another dev, having his own history based on
the old "O" commit. So:

A)
m---N---m---m---m---m---m---M  (master)
     \                       \
      o---o---O---o---o       o'--o'--o'--o'--o'--S  (subsystem)
               \       \                         /
                \       *---*---*-..........-*--T (topic)
                 \
                  X---Y---Z (outsider)

B)
m---N---m---m---m---m---m---M  (master)
     \                       \
      \                       o'--o'--o'--o'--o'----------S  (subsystem)
       \                     /   /   /   /   /           /
        --------------------o---o---O---o---o---*---*---T (topic)
                                     \
                                      X---Y---Z (outsider)

Merging "master" and "outsider" has merge base N in both cases.
Merging "subsystem" and "outsider" has merge base O in both cases.
Merging "topic" and "outsider" has merge base O in both cases.

The only thing that really makes a difference is when you have another
dev having based his history upon one of the o' commits. If that history
is merged with "topic", then you get merge base N in A) and one of the
o's in B).

But, in that case, merging "topic" is basically just a complicated way
of merging "subsystem". Both contain the full series of "o" commits, and
all the "topic" commits (due to the merge). So you could just trivially
merge "subsystem" instead, which leads the o' commit as the merge base
in both cases.

And, that merge of "topic" to "subsystem" was wrong to begin with. If
you rewrite history, that has to trickle down. So A) should really have
been:

m---m---m---m-...--m---m (master)
                        \
                         o'--o'-...-o'--*'--*'--*' (topic) (subsystem)

(topic was rebased, and subsystem fast-forwarded)

So AFAICT, what your system achieves WRT ease of rebasing is that it
obsoletes the need to use "--onto" with git's rebase.

Instead of "git rebase --onto subsystem old_subsystem", you can just say
"git rebase subsystem", at the cost of a very complicated DAG.

Björn
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]