git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Junio C Hamano" <gitster@pobox.com>,
	"Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH v2 3/3] checkout: reorder option handling
Date: Wed, 29 Aug 2012 20:55:24 +0700	[thread overview]
Message-ID: <1346248524-11616-3-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1346248524-11616-1-git-send-email-pclouds@gmail.com>

checkout operates in three different modes. On top of that it tries to
be smart by guessing the branch name for switching. This results in
messy option handling code. This patch reorders it so that

 - cmd_checkout() is responsible for parsing, preparing input and
   determinining mode

 - Code of each mode is in cmd_checkout_entry() and cmd_switch(),
   where sanity checks are performed per mode

Another slight improvement is always print branch name (or commit
name) when printing errors related ot them. This helps catch the case
where an option is mistaken as branch/commit.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 I'm not entirely sure about this chunk

 +	if (opts->track != BRANCH_TRACK_UNSPECIFIED) {
 +		if (opts->new_orphan_branch)
 +			die(_("%s cannot be used with %s"), "--orphan", "-t");
 +		if (opts->force_detach)
 +			die(_("%s cannot be used with %s"), "--detach", "-t");
 +	} else
 +		opts->track = git_branch_track;

 If we don't want -t and --orphan/--detach together, then we probably should ignore
 branch.autosetupmerge when --orphan/--detach is specified.

 I did not unify new_branch, new_branch_force and new_orphan_branch.
 They touch other parts of the code and should probably be done
 separately.

 builtin/checkout.c | 169 ++++++++++++++++++++++++++++++++---------------------
 1 file changed, 101 insertions(+), 68 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 78abaeb..8289bcd 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -930,6 +930,81 @@ static int switch_unborn_to_new_branch(const struct checkout_opts *opts)
 	return status;
 }
 
+static int cmd_checkout_entry(const struct checkout_opts *opts,
+			      const struct branch_info *new)
+{
+	if (opts->track != BRANCH_TRACK_UNSPECIFIED)
+		die(_("%s cannot be used with updating paths"), "--track");
+
+	if (opts->new_branch_log)
+		die(_("%s cannot be used with updating paths"), "-l");
+
+	if (opts->force && opts->patch_mode)
+		die(_("%s cannot be used with updating paths"), "-f");
+
+	if (opts->force_detach)
+		die(_("%s cannot be used with updating paths"), "--detach");
+
+	if (opts->merge && opts->patch_mode)
+		die(_("%s cannot be used with %s"), "--merge", "--patch");
+
+	if (opts->force && opts->merge)
+		die(_("%s cannot be used with %s"), "-f", "-m");
+
+	if (opts->new_branch)
+		die(_("Cannot update paths and switch to branch '%s' at the same time."),
+		    opts->new_branch);
+
+	if (opts->patch_mode)
+		return interactive_checkout(new->name, opts->pathspec);
+	else
+		return checkout_paths(opts);
+}
+
+static int cmd_switch(struct checkout_opts *opts,
+		      struct branch_info *new)
+{
+	if (opts->pathspec)
+		die(_("paths cannot be used with switching branches"));
+
+	if (opts->patch_mode)
+		die(_("%s cannot be used with switching branches"),
+		    "--patch");
+
+	if (opts->writeout_stage)
+		die(_("%s cannot be used with switching branches"),
+		    "--ours/--theirs");
+
+	if (opts->force && opts->merge)
+		die(_("%s cannot be used with %s"), "-f", "-m");
+
+	if (opts->force_detach && opts->new_branch)
+		die(_("%s cannot be used with %s"),
+		    "--detach", "-b/-B/--orphan");
+
+	if (opts->track != BRANCH_TRACK_UNSPECIFIED) {
+		if (opts->new_orphan_branch)
+			die(_("%s cannot be used with %s"), "--orphan", "-t");
+		if (opts->force_detach)
+			die(_("%s cannot be used with %s"), "--detach", "-t");
+	} else
+		opts->track = git_branch_track;
+
+	if (new->name && !new->commit)
+		die(_("Cannot switch branch to a non-commit '%s'."),
+		    new->name);
+
+	if (!new->commit && opts->new_branch) {
+		unsigned char rev[20];
+		int flag;
+
+		if (!read_ref_full("HEAD", rev, 0, &flag) &&
+		    (flag & REF_ISSYMREF) && is_null_sha1(rev))
+			return switch_unborn_to_new_branch(opts);
+	}
+	return switch_branches(opts, new);
+}
+
 int cmd_checkout(int argc, const char **argv, const char *prefix)
 {
 	struct checkout_opts opts;
@@ -976,26 +1051,22 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix, options, checkout_usage,
 			     PARSE_OPT_KEEP_DASHDASH);
 
-	/* we can assume from now on new_branch = !new_branch_force */
-	if (opts.new_branch && opts.new_branch_force)
-		die(_("-B cannot be used with -b"));
+	if (conflict_style) {
+		opts.merge = 1; /* implied */
+		git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
+	}
+
+	if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)
+		die(_("-b, -B and --orphan are mutually exclusive"));
 
-	/* copy -B over to -b, so that we can just check the latter */
 	if (opts.new_branch_force)
 		opts.new_branch = opts.new_branch_force;
 
-	if (opts.patch_mode && (opts.track > 0 || opts.new_branch
-			   || opts.new_branch_log || opts.merge || opts.force
-			   || opts.force_detach))
-		die (_("--patch is incompatible with all other options"));
-
-	if (opts.force_detach && (opts.new_branch || opts.new_orphan_branch))
-		die(_("--detach cannot be used with -b/-B/--orphan"));
-	if (opts.force_detach && 0 < opts.track)
-		die(_("--detach cannot be used with -t"));
+	if (opts.new_orphan_branch)
+		opts.new_branch = opts.new_orphan_branch;
 
 	/* --track without -b should DWIM */
-	if (0 < opts.track && !opts.new_branch) {
+	if (opts.track != BRANCH_TRACK_UNSPECIFIED && !opts.new_branch) {
 		const char *argv0 = argv[0];
 		if (!argc || !strcmp(argv0, "--"))
 			die (_("--track needs a branch name"));
@@ -1009,22 +1080,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 		opts.new_branch = argv0 + 1;
 	}
 
-	if (opts.new_orphan_branch) {
-		if (opts.new_branch)
-			die(_("--orphan and -b|-B are mutually exclusive"));
-		if (opts.track > 0)
-			die(_("--orphan cannot be used with -t"));
-		opts.new_branch = opts.new_orphan_branch;
-	}
-
-	if (conflict_style) {
-		opts.merge = 1; /* implied */
-		git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
-	}
-
-	if (opts.force && opts.merge)
-		die(_("git checkout: -f and -m are incompatible"));
-
 	/*
 	 * Extract branch name from command line arguments, so
 	 * all that is left is pathspecs.
@@ -1052,62 +1107,40 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 		argc -= n;
 	}
 
-	if (opts.track == BRANCH_TRACK_UNSPECIFIED)
-		opts.track = git_branch_track;
-
 	if (argc) {
 		opts.pathspec = get_pathspec(prefix, argv);
 
 		if (!opts.pathspec)
 			die(_("invalid path specification"));
 
-		if (opts.patch_mode)
-			return interactive_checkout(new.name, opts.pathspec);
-
-		/* Checkout paths */
-		if (opts.new_branch) {
-			if (argc == 1) {
-				die(_("git checkout: updating paths is incompatible with switching branches.\nDid you intend to checkout '%s' which can not be resolved as commit?"), argv[0]);
-			} else {
-				die(_("git checkout: updating paths is incompatible with switching branches."));
-			}
-		}
+		/* Try to give more helpful suggestion, new_branch &&
+		   argc > 1 will be caught later */
+		if (opts.new_branch && argc == 1)
+			die(_("Cannot update paths and switch to branch '%s' at the same time.\n"
+			      "Did you intend to checkout '%s' which can not be resolved as commit?"),
+			    opts.new_branch, argv[0]);
 
 		if (opts.force_detach)
 			die(_("git checkout: --detach does not take a path argument"));
 
 		if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge)
-			die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index."));
-
-		return checkout_paths(&opts);
+			die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+			      "checking out of the index."));
 	}
 
-	if (opts.patch_mode)
-		return interactive_checkout(new.name, NULL);
-
 	if (opts.new_branch) {
 		struct strbuf buf = STRBUF_INIT;
 
-		opts.branch_exists = validate_new_branchname(opts.new_branch, &buf,
-							     !!opts.new_branch_force,
-							     !!opts.new_branch_force);
+		opts.branch_exists =
+			validate_new_branchname(opts.new_branch, &buf,
+						!!opts.new_branch_force,
+						!!opts.new_branch_force);
 
 		strbuf_release(&buf);
 	}
 
-	if (new.name && !new.commit) {
-		die(_("Cannot switch branch to a non-commit."));
-	}
-	if (opts.writeout_stage)
-		die(_("--ours/--theirs is incompatible with switching branches."));
-
-	if (!new.commit && opts.new_branch) {
-		unsigned char rev[20];
-		int flag;
-
-		if (!read_ref_full("HEAD", rev, 0, &flag) &&
-		    (flag & REF_ISSYMREF) && is_null_sha1(rev))
-			return switch_unborn_to_new_branch(&opts);
-	}
-	return switch_branches(&opts, &new);
+	if (opts.patch_mode || opts.pathspec)
+		return cmd_checkout_entry(&opts, &new);
+	else
+		return cmd_switch(&opts, &new);
 }
-- 
1.7.12.rc2.18.g61b472e

  parent reply	other threads:[~2012-08-29 14:02 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-28  2:29 [PATCH] checkout: verify new branch name's validity early Nguyễn Thái Ngọc Duy
2012-08-28  3:55 ` Junio C Hamano
2012-08-28 13:49   ` [PATCH 0/3] Refactor checkout option handling Nguyễn Thái Ngọc Duy
2012-08-28 13:49     ` [PATCH 1/3] checkout: pass "struct checkout_opts *" as const pointer Nguyễn Thái Ngọc Duy
2012-08-28 13:49     ` [PATCH 2/3] checkout: reorder option handling Nguyễn Thái Ngọc Duy
2012-08-28 20:45       ` Junio C Hamano
2012-08-29 12:16         ` Nguyen Thai Ngoc Duy
2012-08-29 13:55           ` [PATCH v2 1/3] checkout: pass "struct checkout_opts *" as const pointer Nguyễn Thái Ngọc Duy
2012-08-29 13:55             ` [PATCH v2 2/3] checkout: move more parameters to struct checkout_opts Nguyễn Thái Ngọc Duy
2012-08-29 13:55             ` Nguyễn Thái Ngọc Duy [this message]
2012-08-29 18:37               ` [PATCH v2 3/3] checkout: reorder option handling Junio C Hamano
2012-08-29 18:55               ` Junio C Hamano
2012-08-30 12:45               ` [PATCH v3 " Nguyễn Thái Ngọc Duy
2012-08-30 16:10                 ` Junio C Hamano
2012-09-07 20:19                 ` Junio C Hamano
2012-08-28 13:49     ` [PATCH 3/3] checkout: move branch guessing code out as a separate function Nguyễn Thái Ngọc Duy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1346248524-11616-3-git-send-email-pclouds@gmail.com \
    --to=pclouds@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).