git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Bring together merge and rebase

From
Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Date
Dec 23, 2017, 18:59 UTC
Message-ID
<877etds220.fsf@evledraar.gmail.com>
In-Reply-To
<CALiLy7pBvyqA+NjTZHOK9t0AFGYbwqwRVD3sZjUg0ZLx5y1h3A@mail.gmail.com>
On Sat, Dec 23 2017, Carl Baldwin jotted:
Show 64 quoted lines
> The big contention among git users is whether to rebase or to merge
> changes [2][3] while iterating. I used to firmly believe that merging
> was the way to go and rebase was harmful. More recently, I have worked
> in some environments where I saw rebase used very effectively while
> iterating on changes and I relaxed my stance a lot. Now, I'm on the
> fence. I appreciate the strengths and weaknesses of both approaches. I
> waffle between the two depending on the situation, the tools being
> used, and I guess, to some extent, my mood.
>
> I think what git needs is something brand new that brings the two
> together and has all of the advantages of both approaches. Let me
> explain what I've got in mind...
>
> I've been calling this proposal `git replay` or `git replace` but I'd
> like to hear other suggestions for what to name it. It works like
> rebase except with one very important difference. Instead of orphaning
> the original commit, it keeps a pointer to it in the commit just like
> a `parent` entry but calls it `replaces` instead to distinguish it
> from regular history. In the resulting commit history, following
> `parent` pointers shows exactly the same history as if the commit had
> been rebased. Meanwhile, the history of iterating on the change itself
> is available by following `replaces` pointers. The new commit replaces
> the old one but keeps it around to record how the change evolved.
>
> The git history now has two dimensions. The first shows a cleaned up
> history where fix ups and code review feedback have been rolled into
> the original changes and changes can possibly be ordered in a nice
> linear progression that is much easier to understand. The second
> drills into the history of a change. There is no loss and you don't
> change history in a way that will cause problems for others who have
> the older commits.
>
> Replay handles collaboration between multiple authors on a single
> change. This is difficult and prone to accidental loss when using
> rebase and it results in a complex history when done with merge. With
> replay, collaborators could merge while collaborating on a single
> change and a record of each one's contributions can be preserved.
> Attempting this level of collaboration caused me many headaches when I
> worked with the gerrit workflow (which in many ways, I like a lot).
>
> I blogged about this proposal earlier this year when I first thought
> of it [1]. I got busy and didn't think about it for a while. Now with
> a little time off of work, I've come back to revisit it. The blog
> entry has a few examples showing how it works and how the history will
> look in a few examples. Take a look.
>
> Various git commands will have to learn how to handle this kind of
> history. For example, things like fetch, push, gc, and others that
> move history around and clean out orphaned history should treat
> anything reachable through `replaces` pointers as precious. Log and
> related history commands may need new switches to traverse the history
> differently in different situations. Bisect is a interesting one. I
> tend to think that bisect should prefer the regular commit history but
> have the ability to drill into the change history if necessary.
>
> In my opinion, this proposal would bring together rebase and merge in
> a powerful way and could end the contention. Thanks for your
> consideration.
>
> Carl Baldwin
>
> [1] http://blog.episodicgenius.com/post/merge-or-rebase--neither/
> [2] https://git-scm.com/book/en/v2/Git-Branching-Rebasing
> [3] http://changelog.complete.org/archives/586-rebase-considered-harmful

I think this is a worthwhile thing to implement, there are certainly use-cases where you'd like to have your cake & eat it too as it were, i.e. have a nice rebased history in "git log", but also have the "raw" history for all the reasons the fossil people like to talk about, or for some compliance reasons.

But I don't see why you think this needs a new "replaces" parent pointer orthagonal to parent pointers, i.e. something that would need to be a new field in the commit object (I may have misread the proposal, it's not heavy on technical details).

Consider a merge use case like this:
          A---B---C topic
         /         \
    D---E---F---G---H master

Here we worked on a topic with commits A,B & C, maybe we regret not squashing B into A, but it gives us the "raw" history. Instead we might rebase it like this:

          A+B---C topic
         /
    G---H master

Now we can push "topic" to master, but as you've noted this loses the raw history, but now consider doing this instead:

          A---B---C   A2+B2---C2 topic
         /         \ /
    D---E---F---G---G master

I.e. you could have started working on commit A/B/C, now you "git replace" them (which would be some fancy rebase alias), and what it'll do is create a merge commit that entirely resolves the conflict so that hte tree is equivalent to what "master" was already at. Then you rewrite them and re-apply them on top.

If you run "git log" it will already ignore A,B,C unless you specify --full-history, so git already knows to ignore these sort of side histories that result in no changes on the branch they got merged into. I don't know about bisect, but if it's not doing something similar already it would be easy to make it do so.

You could even add a new field to the commit object of A2+B2 & C2 which would be one or more of "replaces <sha1 of A/B/C>", commit objects support adding arbitrary new fields without anything breaking.

But most importantly, while I think this gives you the same things from a UX level, it doesn't need any changes to fetch, push, gc or whatever, since it's all stuff we support today, someone just needs to hack "rebase" to create this sort of no-op merge commit to take advantage of it.

Previous: Carl BaldwinNext: Carl Baldwin
Message 2 of 44 in “Bring together merge and rebase”
  1. Carl BaldwinDec 23, 2017
  2. Ævar Arnfjörð BjarmasonDec 23, 2017
  3. Carl BaldwinDec 23, 2017
  4. Ævar Arnfjörð BjarmasonDec 23, 2017
  5. Carl BaldwinDec 26, 2017
  6. Jacob KellerDec 26, 2017
  7. Igor DjordjevicDec 26, 2017
  8. Ævar Arnfjörð BjarmasonDec 26, 2017
  9. Carl BaldwinDec 26, 2017
  10. Paul SmithDec 26, 2017
  11. Carl BaldwinDec 26, 2017
  12. Randall S. BeckerDec 23, 2017
  13. Carl BaldwinDec 25, 2017
  14. Johannes SchindelinDec 23, 2017
  15. Alexei LozovskyDec 24, 2017
  16. Johannes SchindelinJan 4, 2018
  17. Carl BaldwinDec 25, 2017
  18. Randall S. BeckerDec 26, 2017
  19. Martin FickJan 4, 2018
  20. Johannes SchindelinDec 23, 2017
  21. Theodore Ts'oDec 25, 2017
  22. Carl BaldwinDec 26, 2017
  23. Jacob KellerDec 26, 2017
  24. Carl BaldwinDec 26, 2017
  25. Jacob KellerDec 26, 2017
  26. Martin FickJan 4, 2018
  27. Martin FickJan 5, 2018
  28. Carl BaldwinJan 5, 2018
  29. Carl BaldwinJan 5, 2018
  30. Theodore Ts'oDec 26, 2017
  31. Carl BaldwinDec 26, 2017
  32. Martin FickJan 4, 2018
  33. Carl BaldwinJan 5, 2018
  34. Martin FickJan 4, 2018
  35. Carl BaldwinJan 5, 2018
  36. Junio C HamanoJan 5, 2018
  37. Carl BaldwinJan 6, 2018
  38. Carl BaldwinJan 6, 2018
  39. Theodore Ts'oJan 6, 2018
  40. Carl BaldwinDec 27, 2017
  41. Alexei LozovskyDec 27, 2017
  42. Carl BaldwinDec 28, 2017
  43. Mike HommeyDec 26, 2017
  44. Carl BaldwinDec 27, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.