[PATCH v2] merge: handle --ff/--no-ff/--ff-only as a tri-state option

2013-07-02 Thread Miklos Vajna
This has multiple benefits: with more than one of {--ff, --no-ff,
--ff-only} respects the last option; also the command-line option to
always take precedence over the config file option.

Signed-off-by: Miklos Vajna vmik...@suse.cz
---
 builtin/merge.c  | 55 +--
 t/t7600-merge.sh | 12 +---
 2 files changed, 42 insertions(+), 25 deletions(-)

On Tue, Jul 02, 2013 at 10:42:39AM +0200, Michael Haggerty 
mhag...@alum.mit.edu wrote:
 You allow --no-ff-only but ignore it, which I think is incorrect.  In
 
 git merge --ff-only --no-ff-only [...]
 
 , the --no-ff-only should presumably cancel the effect of the previous
 --ff-only (i.e., be equivalent to --ff).  But it is a little bit
 subtle because
 
 git merge --no-ff --no-ff-only
 
 should presumably be equivalent to --no-ff.  So I think that
 --no-ff-only should do something like
 
 if (fast_forward == FF_ONLY)
 fast_forward = FF_ALLOW;

Do we really want --no-ff-only? I would rather just disable it, see the
updated patch.

 I'm no options guru, but I think it would be possible to implement --ff
 and --no-ff without callbacks if you choose constants such that
 FF_NO==0, something like:

Indeed, done.

 Should these do the same as the versions with the option order reversed?
  Or should the command line option that appears later take precedence?
 The latter implies that {--ff, --no-ff, --ff-only, --squash} actually
 constitute a single *quad-state* option, representing how the results
 of the merge should be handled, and, for example,
 
 git merge --squash --ff-only
 
 ignores the --squash option, and
 
 git merge --ff-only --squash
 
 ignores the --ff-only option.
 
 I'm not sure.

Actually there is also --no-squash, used by e.g. git-pull internally.
You definitely don't want a five-state option. :-) So for now I would
rather let --squash/--no-squash alone.

diff --git a/builtin/merge.c b/builtin/merge.c
index 2ebe732..149f32a 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -47,8 +47,8 @@ static const char * const builtin_merge_usage[] = {
 };
 
 static int show_diffstat = 1, shortlog_len = -1, squash;
-static int option_commit = 1, allow_fast_forward = 1;
-static int fast_forward_only, option_edit = -1;
+static int option_commit = 1;
+static int option_edit = -1;
 static int allow_trivial = 1, have_message, verify_signatures;
 static int overwrite_ignore = 1;
 static struct strbuf merge_msg = STRBUF_INIT;
@@ -76,6 +76,14 @@ static struct strategy all_strategy[] = {
 
 static const char *pull_twohead, *pull_octopus;
 
+enum ff_type {
+   FF_NO,
+   FF_ALLOW,
+   FF_ONLY
+};
+
+static enum ff_type fast_forward = FF_ALLOW;
+
 static int option_parse_message(const struct option *opt,
const char *arg, int unset)
 {
@@ -178,6 +186,13 @@ static int option_parse_n(const struct option *opt,
return 0;
 }
 
+static int option_parse_ff_only(const struct option *opt,
+ const char *arg, int unset)
+{
+   fast_forward = FF_ONLY;
+   return 0;
+}
+
 static struct option builtin_merge_options[] = {
{ OPTION_CALLBACK, 'n', NULL, NULL, NULL,
N_(do not show a diffstat at the end of the merge),
@@ -194,10 +209,10 @@ static struct option builtin_merge_options[] = {
N_(perform a commit if the merge succeeds (default))),
OPT_BOOL('e', edit, option_edit,
N_(edit message before committing)),
-   OPT_BOOLEAN(0, ff, allow_fast_forward,
-   N_(allow fast-forward (default))),
-   OPT_BOOLEAN(0, ff-only, fast_forward_only,
-   N_(abort if fast-forward is not possible)),
+   OPT_SET_INT(0, ff, fast_forward, N_(allow fast-forward (default)), 
FF_ALLOW),
+   { OPTION_CALLBACK, 0, ff-only, NULL, NULL,
+   N_(abort if fast-forward is not possible),
+   PARSE_OPT_NOARG | PARSE_OPT_NONEG, option_parse_ff_only },
OPT_RERERE_AUTOUPDATE(allow_rerere_auto),
OPT_BOOL(0, verify-signatures, verify_signatures,
N_(Verify that the named commit has a valid GPG signature)),
@@ -581,10 +596,9 @@ static int git_merge_config(const char *k, const char *v, 
void *cb)
else if (!strcmp(k, merge.ff)) {
int boolval = git_config_maybe_bool(k, v);
if (0 = boolval) {
-   allow_fast_forward = boolval;
+   fast_forward = boolval ? FF_ALLOW : FF_NO;
} else if (v  !strcmp(v, only)) {
-   allow_fast_forward = 1;
-   fast_forward_only = 1;
+   fast_forward = FF_ONLY;
} /* do not barf on values from future versions of git */
return 0;
} else if (!strcmp(k, merge.defaulttoupstream)) {
@@ -863,7 +877,7 @@ static int finish_automerge(struct commit *head,
 
free_commit_list(common);
parents 

Re: [PATCH v2] merge: handle --ff/--no-ff/--ff-only as a tri-state option

2013-07-02 Thread Junio C Hamano
Miklos Vajna vmik...@suse.cz writes:

 if (fast_forward == FF_ONLY)
 fast_forward = FF_ALLOW;

 Do we really want --no-ff-only? I would rather just disable it, see the
 updated patch.

Sounds sane.

 I'm no options guru, but I think it would be possible to implement --ff
 and --no-ff without callbacks if you choose constants such that
 FF_NO==0, something like:

 Indeed, done.

Yup, looks good.

 Actually there is also --no-squash, used by e.g. git-pull internally.
 You definitely don't want a five-state option. :-) So for now I would
 rather let --squash/--no-squash alone.

Sensible for this patch.

Will replace what was queued.  Thanks.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html