That is a correct way to diagnose the mistake and recover from it, but unfortunately it is a rather weak tool to identify the mistake in the first place.
A branch in git, as Randal often used to say on #git, is an illusion---it points only at the top and does not identify the bottom.
But it does _not_ have to stay that way at the Porcelain level.
Here is a rough sketch of one possible solution. It is not fully thought out; the basic idea is probably sound but I did not try to exhaustively cover changes to various tools that are necessary to maintain the invariants this scheme requires.
(0) Define a way to identify the bottom of a branch. One way to do this
is by an extra ref (e.g. refs/branchpoints/frotz). Then the commits
between refs/branchpoints/frotz..refs/heads/frotz identifies the
commits on the branch. None of the additional restrictions below
applies when the branch does not have such bottom defined (i.e.
created by the current git without this extension). (1) At branch creation, the branchpoint is noted. E.g.
$ git branch frotz master~4
would internally become
$ git update-ref refs/heads/frotz master~4
$ git update-ref refs/branchpoints/frotz master~4 You would also need to cover "checkout -b".
(2) You can grow the branch naturally with "commit", "am" and "merge".
The bottom of the branch does not have to move with these operations. (3) Operations that alter histories, e.g. "commit --amend", "rebase",
"reset", while on a branch that records its bottom need to be taught
to pay attention to not break its bottom. Paying attention needs to
take different forms depending on the operation; some probably will
forbid the operation while others would automatically adjust the
bottom. Examples (not exhaustive):
(3-a) "branch -f frotz $commit"
This moves the tip of the branch. Unless $commit is already some
part of the existing frotz branch, we should probably forbid it for
simplicity, when a bottom is defined for the branch. We could later loosen the rule so that $commit is only required to be
a descendant of existing bottom of the branch to support a workflow
like this: $ git checkout -b frotz master~4 ;# records branchpoint
$ edit; git add; git commit; ... ;# builds history
$ git checkout HEAD^ ;# go back somewhere on frotz
$ edit; git add; git commit; ... ;# builds an alternate history
$ git show-branch HEAD frotz ;# check progress
$ git diff frotz HEAD ;# is this one better?
$ git branch -f frotz ;# I prefer this new one better (3-b) "reset $commit" (with or without --hard/--soft/--mixed)
This is similar to (3-a) above; $commit has to be a descendant of
existing bottom. (3-c) "commit --amend"
$ git checkout -b frotz master~4 ;# records branchpoint
$ git commit --amend ;# rewrite the bottom??? would probably be a mistake, as the end result would make the frotz
branch forked from master~5 with the first commit on the branch a
fix-up to what is already in the master branch. However, this is a valid way to work:
$ git checkout -b frotz master~4 ;# records branchpoint
$ edit; git add; git commit ;# builds history
$ git commit --amend ;# fix the tip and it does not have to do anything to the bottom.
(3-d) "rebase"
$ git checkout -b frotz master~4 ;# records branchpoint
$ edit; git add; git commit; ... ;# builds history
$ git rebase --onto master ;# transplants the branch would make the "onto" commit the new bottom. Another interesting
thing to note is that we do not have to compute which commits to
transplant with merge-base with the "onto" commit, because we know
the bottom commit of the branch. (4) Operations that browse histories, e.g. "log", "show-branch", while on
a branch that records its bottom can be taught to pay attention to
the bottom. For example, it is conceivable that $ git log
$ git log -- Documentation/ without an explicit branch name that fell back to the default HEAD
while on branch "frotz" might be better run with an implicit bottom
^refs/branchpoint/frotz.We probably could kill the other bird in the nearby thread that wants to add a description to a branch, if this scheme is fully implemented (no, I am not going to start coding right away, as this message is just a sketch of what we _could_ do), As we will fully know in what operations we need to update the branchpoint ref, we could make the refs/branchpoints/frotz an annotated tag, and store the description for the branch in that tag. Whenever we need to adjust the branchpoint, we update it while carrying the branch description message over to the new tag object.