Subject: Re: request for documentation about branch surgery

From: Bruno Haible <[email-masked]>
Date: Tue, 7 Jul 2009 12:13:24 +0200

Hi Junio,

> You learn new things every day, and today is such a day ;-)
> 
> >   If you want to add a commit in the middle of a branch:
> >
> >             A---C---...---Z    master
> >
> >   =>
> >
> >             A---B---C---...---Z    master
> >
> >   it is achieved by
> 
>         $ git checkout master~25 ;# detach HEAD at A
>         $ edit edit edit
>         $ git commit ;# creates B
> 
> which makes
> 
>                B              HEAD (detached)
>               /
>              A---C---...---Z    master
> 
> and then
> 
>         $ git rebase HEAD master
> 
> which reshapes the history into
> 
> 
>                B---C'--...---Z' master
>               /
>              A---C---...---Z    master@{1}
> 
> and you are done.

Cool! I wouldn't have guessed that. Now you wrote it into the mailing list
archives. It would be even better if it were mentioned in the user's manual,
chapter "Rewriting history and maintaining patch series"

> > 3) When do I need "git merge", and when do I need "git rebase", in the
> >    context of branch surgery?
> >
> >    The simple answer, that I would find worth mentioning, is:
> >      - "git merge" copies commits from one branch to another.
> >      - "git rebase" only moves commits around to make history more linear.
> 
> If you think "git merge" _copies_, you will never understand what "merge"
> does. ... There is no copying involved anywhere .  It only creates a new
> commit 

There are two cases of "git merge" operation: the one that creates a diamond
commit, and the one that doesn't (the "simple" case of "git merge"). The latter
operation I found useful in achieving this surgery:

            C---D---E              topic
           /
      A---B                        master

  =>

            C---D---E              topic
           /
      A---B---C---D---E            master

How do I do this, if not by using "git merge"? Is there a way to do it with
"git rebase" only?

If I have a certain task at hand, what rule of thumb would you give me,
when can I do it with "git rebase", and when can I do it with the simple case
of "git merge"?

> > 4) It would be good to have a section "Cutting branches"
> >
> >    How do I remove the N most recent commits from a branch?
> >
> >                D---E---F---G---H---.........---Y---Z master
> >
> >   =>
> >                D---E master
> 
> And it is not even cutting.  It merely makes this:
> 
>                       F---G---H---.........---Y---Z master@{1}
>                      /
>                 D---E
>                     ^master

I regularly use "git repack -a -d", so that branches like that
master@{1} get garbage collected. So from the point of view of someone
who considers only the contents of the commits that sit on branches,
it *does* cut the branch.

I know that all commits are still present and reachable by their ID,
as long as they have not been garbage collected. But when doing
branch surgery, only the contents of the labelled branches matters to me.

> I think your confusion is primarily coming from not understanding what a
> branch in git is.  A branch in git does not have its own identity per-se,
> and a commit does _not_ belong to a branch, in the sense that a commit
> object does not record anywhere on which branch it was created on.  A
> branch is just a pointer into a dag and the pointer can be moved.

Oh, I do and did know all this. There is no confusion about that. My problem
was that
  - I had a couple of "how do I ..." questions regarding branch surgery,
  - the mapping between such a task and the git command to use is not clear
    (combinations of "git checkout", "git branch", "git rebase", "git merge",
    "git reset", "git cherry-pick" - enough complicated commands to get
    confused),
  - the user's manual answered only half of my questions.

Bruno