On Thu, 17 Dec 2015 13:16:43 +0100
Joerg Sonnenberger <jo...@britannica.bec.de> wrote:

> > [...]
> > > I realize that 'get rebase -i' gives a lot more tools, but
> > > couldn't 99% of rebase use cases be handled with private branches?
> > 
> > `git rebase` is about rewriting history.  It has several modes of
> > operation (that is, it can be used for tasks different from its
> > original intent -- rebasing -- such as squashing several commits
> > together, editing a commit, splitting commits, deleting commit etc)
> > but no matter what mode `git rebase` is being used in, it rewrites
> > (recreates) commits.
> 
> The important point here is rewrite vs recreate. That's quite a
> different, both practically and semantically. It would be useful to
> have a "linearise" command, however you want to call it, which
> performs *one* part of what rebase does: I'm writing a bunch of
> changes in disconnected mode and want to push them back. Someone else
> has committed a change in the mean time and I don't want to merge.
> "No merge on the main branch" is a pretty useful property for things
> like bisect and the like.
>
> Now the tricky part is this can be done *without rewriting history*.
> Essentially, you can (semi-automatically) reapply all changes on top
> of the new commit and record which commit they were originally. This
> allows three things:
> (1) Tight main line with keeping incremental stages.
> (2) Preservation of what commits originally happened in case you need
> the full audit trail because there was a subtil merge fault or the
> like.
> (3) It allows automated follow-up rebases for 3rd parties that already
> got the initial changes. I.e. you can safe push your work-in-progress
> and still transplant it later.
> 
> "git rebase" only really allows the first point.

Not quite.  Well, `git rebase` does indeed replace the tip of the
branch it operated on with a set of changed commits, but this counts as
a so-called "drastic head movement" in the Git parlance.  Such
movements are recorded in the so-called "reflog" ("reference log" --
with refs or references being heads (branches) and tags), so as soon as
a rebase operation completes successfully (as opposed to having been
aborted using `git rebase --abort` where the branch being operated on
is left intact), you can retreive the previous tip of the affected
branch from the reflog.  The reflog keeps about 30 days worth of such
changes by default which is more than enough to cover the "oops!"
situations.

As to "without rewriting history" bit, this might be a terminological
issue but in a (typical) DVCS you simply cannot cherry-pick or
otherwise (re-)apply an existing commit to some tip to produce another
commit without essentially rewriting it because the commit hash includes
the commit creation date.  And once you've changed a commit's hash, the
next commit being applied on top of this one will have its hash changed
also because it will refer to the changed hash-name of its parent
commit, and this "link" is hashed as well.

Another point is that when you rebase (or "linearize"), the new upstream
tip might actually contain changes which will make some or all of the
commits in the series being rebased/linearized be apply with some
fuzz, and in complicated cases they might even fail to apply.  In this
case, even "the contents" (as opposed to metadata) of the
rebased/linearized commits will be re-written quite literally.  In the
sense that if you had a commit A on top of upstream's U, and then
rebased A on top of the updated U' to produce A', the differences A':U'
and A:U might be substantial.

I hence insist on that you can't rebase and not re-write commits at the
same time.  Even your specific "linearization" case still requires
commit re-writing.
_______________________________________________
fossil-users mailing list
fossil-users@lists.fossil-scm.org
http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users

Reply via email to