Re: [RFC/PATCH Second draft] Fast forward strategies allow, never, and only

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

 



"Sverre Hvammen Johansen" <hvammen@xxxxxxxxx> writes:

> New fast forward strategies, only, is introduced.  This new fast
> forward strategy prevents real merges.
>
> FF strategy "only" fails if the specified heads and HEAD can not
> be reduced down to only one real parent.  The only allowed
> outcome is a fast forward unless HEAD is up to date with
> the specified heads.
>
> This patch also uses the real heads found instead of those
> specified for real merges.  This means that merge startegies
> that only take two heads can now accept more than two heads
> if they can be reduced down to only two real heads.  However,
> fast-forward of head in combination with a real merge is
> handled as before.

This might be easier to review if split into two parts.  Code suffling to
do --ff/--no-ff => ff={allow,never} and documentation updates to improve
the description of these two options in the first patch, and addition of
"only" to code and the updated docuemntation in the second.

> +If your workflow is always to branch from the special branch
> +("master") when working on a topic and merge that back to "master", if
> +you happen to have worked only on a single topic and the "master" was
> +never advanced during the time you worked on that topic, merging the
> +topic back to "master" will result in a fast-forward.  When you look
> +back that history, you will not be able to tell where the topic
> +started and ended by following the ancestry chain of the "master"
> +branch.
> +
> +Using "never fast forward" policy on such a special branch will be a
> +way to make sure that all commits on the first-parent ancestry of that
> +special branch will be merges from something else.  From the history
> +you can determine where the topic started and ended.
> +
> +The following shows two branches forked off from "master".  The branch
> +"master" have merged in changes from branch "topicA" twice and
> +"topicB" once:
> +
> +------------
> +         o---o---o---o---o  topicA
> +        /     \           \
> +    ---*-------*-------*---*  master
> +      /         \     /
> +                 o---o  topicB
> +------------
> +
> +The first merge of topicA or the only merge of topicB would have
> +resulted in a fast forward without '--ff=never'.  The last merge of
> +topicA would have failed with '--ff=only'.  Topic A consist of those
> +commits that can be reached from master^2 without passing through any
> +of the first-parent ancestries of master.

If you remove one sentence "The last merge ... =only'." from it, this part
is a very good write-up on how "never fast forward" could be useful, and
might even be a worthy addition to the current documentation.  However it
lacks a crucial bit of information: it is _not enough_ to just use --no-ff
to maintain the "special status" of "master".  You also need to prevent
direct committing to it.  So while --no-ff is an ingredient you can
construct such a workflow out of, it by itself is not the whole solution.
You need additional discipline.

> +However, if your workflow require a linear history for the special
> +branch ("master"), topic branches must be rebased before merging them
> +back to "master".  A pull or a merge from the "master branch of a
> +topic branch may accidentally introduce a merge commit that was not
> +already in the topic branch if the topic that were merged was not
> +properly rebased.  This will creating a none linear history.

This,...

> +Using "only fast forward" policy ensures that whenever a pull or a
> +merge is performed it will fail unless the merge can be resolved as a
> +fast forward.  This will however not guarantee a linear history since
> +the topic branches that are merged in may have merge commits recorded.
>
> +You may therefor need to use this policy on the topic branches as
> +well.

combined with the above, would make "only" an incomplete implementation of
the goal you stated earlier, i.e. "to force a completely linear history",
but I think you can trivially fix this by making sure that there is no
merge commit in ORIG_HEAD..MERGE_HEAD and refusing if you find one.  And
by fixing the implementation, you do not have to make excuses like the
above two and half paragraphs.

Having said that, I doubt what you are trying to achieve is to force a
totally linear history, as that is quite useless policy unless you are
talking about a one-man project.

When your project has gained meaningful number of developers, there will
always be more than one nontrivial changes outstanding.  Forcing a linear
history everywhere means whenever somebody wants his changes accepted, he
needs to fetch + rebase whenever anybody else's change is accepted to the
special "master".  The more developers you have, the narrower window
between acceptance of changes to the "master" becomes, and eventually the
window will become shorter than the time needed to rebase and retest any
nontrivial change on top of the tip of "master".  At that point, nobody
can get anything but a trivially rebasable and untested series accepted.
Such a policy would encourage people to merge only "early half" of their
series (because they do not have enough time to rebase the full series) in
a poorly tested shape.  So in that sense it is not just "practicaly
useless", but can be actively harmful by encouraging a bad workflow.

But your "merge has to fast-forward, but the merged branch can have
nonlinear history itself" semantics is different from "require linear
history".  For example, if you want the top-level integrator to do
absolutely _nothing_ (not even a trivial merge), in order to shift the
burden of integration testing to contributors, then use of such semantics
(which is _different_ from "completely linear") by the top-level
integrator could achieve that.  Nobody can ask the top-level to pull which
would result in a tree that he built and tested himself.  The top-level
integrator would say "Your tree is not a fast-forward from mine, because I
merged with somebody else between the time you prepared your tree and I
learned about it.  Please try again", and in response, the contributor can
pull from the top-level integrator and re-test the merge result and ask
again.  With luck, the top-level integrator may not have merged with
anybody else and a pull from that contributor would fast-forward.

So if that is what you are trying to achieve, you need to update your
description.  If you aim for "Totally linear", I think many people will
find it is practically useless, but if you are aiming for something
different, you should advertise it as such.

I think the scaling issue (iow "narrowing window") is the same either way,
and the documentaion should warn about it to the users.  Unclueful people
may think, without really thinking ;-), that it is a good thing in any
occassions to require totally linear history, unless downsides are also
explained.

> diff --git a/git-merge.sh b/git-merge.sh
> index 7dbbb1d..a98cd77 100755
> --- a/git-merge.sh
> +++ b/git-merge.sh
> @@ -12,7 +12,7 @@ summary              show a diffstat at the end of the merge
>  n,no-summary         don't show a diffstat at the end of the merge
>  squash               create a single commit instead of doing a merge
>  commit               perform a commit if the merge sucesses (default)
> -ff                   allow fast forward (default)
> +ff?                  fast forward options
>  s,strategy=          merge strategy to use
>  m,message=           message to be used for the merge commit (if any)
>  "
> @@ -35,7 +35,7 @@ no_fast_forward_strategies='subtree ours'
>  no_trivial_strategies='recursive recur subtree ours'
>  use_strategies=
>
> -allow_fast_forward=t
> +fast_forward=allow
>  allow_trivial_merge=t
>  squash= no_commit=
>
> @@ -153,8 +153,6 @@ parse_config () {
>                 --summary)
>                         show_diffstat=t ;;
>                 --squash)
> -                       test "$allow_fast_forward" = t ||
> -                               die "You cannot combine --squash with --no-ff."

I do not think you defended why it is good idea to drop this sanity check.

>                         squash=t no_commit=t ;;
>                 --no-squash)
>                         squash= no_commit= ;;
> @@ -163,18 +161,33 @@ parse_config () {
>                 --no-commit)
>                         no_commit=t ;;
>                 --ff)
> -                       allow_fast_forward=t ;;
> +                       case "$2" in
> +                       allow|never|only)
> +                               fast_forward=$2; shift ;;
> +                       -*)
> +                               fast_forward=allow ;;
> +                       *)
> +                               die "Available fast-forward strategies
> are: allow, newer, and only" ;;

Strategies?  "fast forward options" you used in the option description is
a reasonable one, and it would be better to keep it consistent.

I didn't look at the rest of the patch (yet).

--
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]

  Powered by Linux