DWIM "git checkout frotz" to "git checkout -b frotz origin/frotz"
When 'frotz' is not a valid object name and not a tracked filename, we used to complain and failed this command. When there is only one remote that has 'frotz' as one of its tracking branches, we can DWIM it as a request to create a local branch 'frotz' forking from the matching remote tracking branch. Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									c6e8c8005a
								
							
						
					
					
						commit
						70c9ac2f19
					
				|  | @ -572,6 +572,40 @@ static int interactive_checkout(const char *revision, const char **pathspec, | |||
| 	return run_add_interactive(revision, "--patch=checkout", pathspec); | ||||
| } | ||||
|  | ||||
| struct tracking_name_data { | ||||
| 	const char *name; | ||||
| 	char *remote; | ||||
| 	int unique; | ||||
| }; | ||||
|  | ||||
| static int check_tracking_name(const char *refname, const unsigned char *sha1, | ||||
| 			       int flags, void *cb_data) | ||||
| { | ||||
| 	struct tracking_name_data *cb = cb_data; | ||||
| 	const char *slash; | ||||
|  | ||||
| 	if (prefixcmp(refname, "refs/remotes/")) | ||||
| 		return 0; | ||||
| 	slash = strchr(refname + 13, '/'); | ||||
| 	if (!slash || strcmp(slash + 1, cb->name)) | ||||
| 		return 0; | ||||
| 	if (cb->remote) { | ||||
| 		cb->unique = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	cb->remote = xstrdup(refname); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static const char *unique_tracking_name(const char *name) | ||||
| { | ||||
| 	struct tracking_name_data cb_data = { name, NULL, 1 }; | ||||
| 	for_each_ref(check_tracking_name, &cb_data); | ||||
| 	if (cb_data.unique) | ||||
| 		return cb_data.remote; | ||||
| 	free(cb_data.remote); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| int cmd_checkout(int argc, const char **argv, const char *prefix) | ||||
| { | ||||
|  | @ -630,8 +664,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) | |||
| 		opts.new_branch = argv0 + 1; | ||||
| 	} | ||||
|  | ||||
| 	if (opts.track == BRANCH_TRACK_UNSPECIFIED) | ||||
| 		opts.track = git_branch_track; | ||||
| 	if (conflict_style) { | ||||
| 		opts.merge = 1; /* implied */ | ||||
| 		git_xmerge_config("merge.conflictstyle", conflict_style, NULL); | ||||
|  | @ -655,6 +687,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) | |||
| 	 *   With no paths, if <something> is a commit, that is to | ||||
| 	 *   switch to the branch or detach HEAD at it. | ||||
| 	 * | ||||
| 	 *   With no paths, if <something> is _not_ a commit, no -t nor -b | ||||
| 	 *   was given, and there is a tracking branch whose name is | ||||
| 	 *   <something> in one and only one remote, then this is a short-hand | ||||
| 	 *   to fork local <something> from that remote tracking branch. | ||||
| 	 * | ||||
| 	 *   Otherwise <something> shall not be ambiguous. | ||||
| 	 *   - If it's *only* a reference, treat it like case (1). | ||||
| 	 *   - If it's only a path, treat it like case (2). | ||||
|  | @ -677,7 +714,20 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) | |||
| 		if (get_sha1(arg, rev)) { | ||||
| 			if (has_dash_dash)          /* case (1) */ | ||||
| 				die("invalid reference: %s", arg); | ||||
| 			goto no_reference;          /* case (3 -> 2) */ | ||||
| 			if (!patch_mode && | ||||
| 			    opts.track == BRANCH_TRACK_UNSPECIFIED && | ||||
| 			    !opts.new_branch && | ||||
| 			    !check_filename(NULL, arg) && | ||||
| 			    argc == 1) { | ||||
| 				const char *remote = unique_tracking_name(arg); | ||||
| 				if (!remote || get_sha1(remote, rev)) | ||||
| 					goto no_reference; | ||||
| 				opts.new_branch = arg; | ||||
| 				arg = remote; | ||||
| 				/* DWIMmed to create local branch */ | ||||
| 			} | ||||
| 			else | ||||
| 				goto no_reference; | ||||
| 		} | ||||
|  | ||||
| 		/* we can't end up being in (2) anymore, eat the argument */ | ||||
|  | @ -715,6 +765,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) | |||
| 	} | ||||
|  | ||||
| no_reference: | ||||
|  | ||||
| 	if (opts.track == BRANCH_TRACK_UNSPECIFIED) | ||||
| 		opts.track = git_branch_track; | ||||
|  | ||||
| 	if (argc) { | ||||
| 		const char **pathspec = get_pathspec(prefix, argv); | ||||
|  | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano