From: Junio C Hamano Date: Wed, 29 May 2013 21:23:10 +0000 (-0700) Subject: Merge branch 'jh/checkout-auto-tracking' X-Git-Tag: v1.8.4-rc0~253 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/77eb44b8ed601a17a5ec9b1fb8c4c53ba10aaa56?hp=-c Merge branch 'jh/checkout-auto-tracking' Update "git checkout foo" that DWIMs the intended "upstream" and turns it into "git checkout -t -b foo remotes/origin/foo" to correctly take existing remote definitions into account. The remote "origin" may be what uniquely map its own branch to remotes/some/where/foo but that some/where may not be "origin". * jh/checkout-auto-tracking: glossary: Update and rephrase the definition of a remote-tracking branch branch.c: Validate tracking branches with refspecs instead of refs/remotes/* t9114.2: Don't use --track option against "svn-remote"-tracking branches t7201.24: Add refspec to keep --track working t3200.39: tracking setup should fail if there is no matching refspec. checkout: Use remote refspecs when DWIMming tracking branches t2024: Show failure to use refspec when DWIMming remote branch names t2024: Add tests verifying current DWIM behavior of 'git checkout ' --- 77eb44b8ed601a17a5ec9b1fb8c4c53ba10aaa56 diff --combined Documentation/git-checkout.txt index 23a9413525,bf0c99c539..ca118ac6bf --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@@ -131,9 -131,9 +131,9 @@@ entries; instead, unmerged entries are "--track" in linkgit:git-branch[1] for details. + If no '-b' option is given, the name of the new branch will be - derived from the remote-tracking branch. If "remotes/" or "refs/remotes/" - is prefixed it is stripped away, and then the part up to the - next slash (which would be the nickname of the remote) is removed. + derived from the remote-tracking branch, by looking at the local part of + the refspec configured for the corresponding remote, and then stripping + the initial part up to the "*". This would tell us to use "hack" as the local branch when branching off of "origin/hack" (or "remotes/origin/hack", or even "refs/remotes/origin/hack"). If the given name has no slash, or the above @@@ -180,12 -180,6 +180,12 @@@ branch by running "git rm -rf ." from t Afterwards you will be ready to prepare your new files, repopulating the working tree, by copying them from elsewhere, extracting a tarball, etc. +--ignore-skip-worktree-bits:: + In sparse checkout mode, `git checkout -- ` would + update only entries matched by and sparse patterns + in $GIT_DIR/info/sparse-checkout. This option ignores + the sparse patterns and adds back any files in . + -m:: --merge:: When switching branches, diff --combined Documentation/glossary-content.txt index 68a18e1497,7a79f26231..db2a74df93 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@@ -117,6 -117,9 +117,6 @@@ branch --set-upstream-to` that sets wha current branch integrates with) obviously do not work, as there is no (real) current branch to ask about in this state. -[[def_dircache]]dircache:: - You are *waaaaay* behind. See <>. - [[def_directory]]directory:: The list you get with "ls" :-) @@@ -125,6 -128,11 +125,6 @@@ it contains modifications which have not been <> to the current <>. -[[def_ent]]ent:: - Favorite synonym to "<>" by some total geeks. See - http://en.wikipedia.org/wiki/Ent_(Middle-earth) for an in-depth - explanation. Avoid this term, not to confuse people. - [[def_evil_merge]]evil merge:: An evil merge is a <> that introduces changes that do not appear in any <>. @@@ -166,7 -174,7 +166,7 @@@ created. Configured via the `.git/info/grafts` file. [[def_hash]]hash:: - In Git's context, synonym to <>. + In Git's context, synonym for <>. [[def_head]]head:: A <> to the <> at the tip of a @@@ -238,7 -246,7 +238,7 @@@ This commit is referred to as a "merge [[def_object]]object:: The unit of storage in Git. It is uniquely identified by the - <> of its contents. Consequently, an + <> of its contents. Consequently, an object can not be changed. [[def_object_database]]object database:: @@@ -250,9 -258,10 +250,9 @@@ Synonym for <>. [[def_object_name]]object name:: - The unique identifier of an <>. The <> - of the object's contents using the Secure Hash Algorithm - 1 and usually represented by the 40 character hexadecimal encoding of - the <> of the object. + The unique identifier of an <>. The + object name is usually represented by a 40 character + hexadecimal string. Also colloquially called <>. [[def_object_type]]object type:: One of the identifiers "<>", @@@ -261,7 -270,8 +261,7 @@@ <>. [[def_octopus]]octopus:: - To <> more than two <>. Also denotes an - intelligent predator. + To <> more than two <>. [[def_origin]]origin:: The default upstream <>. Most projects have @@@ -281,7 -291,7 +281,7 @@@ pack. [[def_pathspec]]pathspec:: - Pattern used to specify paths. + Pattern used to limit paths in Git commands. + Pathspecs are used on the command line of "git ls-files", "git ls-tree", "git add", "git grep", "git diff", "git checkout", @@@ -290,8 -300,6 +290,8 @@@ limit the scope of operations to some s worktree. See the documentation of each command for whether paths are relative to the current directory or toplevel. The pathspec syntax is as follows: ++ +-- * any path matches itself * the pathspec up to the last slash represents a @@@ -301,12 -309,11 +301,12 @@@ of the pathname. Paths relative to the directory prefix will be matched against that pattern using fnmatch(3); in particular, '*' and '?' _can_ match directory separators. + +-- + For example, Documentation/*.jpg will match all .jpg files in the Documentation subtree, including Documentation/chapter_1/figure_1.jpg. - + A pathspec that begins with a colon `:` has special meaning. In the short form, the leading colon `:` is followed by zero or more "magic @@@ -322,10 -329,18 +322,10 @@@ and a close parentheses `)`, and the re against the path. + The "magic signature" consists of an ASCII symbol that is not -alphanumeric. -+ --- -top `/`;; - The magic word `top` (mnemonic: `/`) makes the pattern match - from the root of the working tree, even when you are running - the command from inside a subdirectory. --- -+ -Currently only the slash `/` is recognized as the "magic signature", -but it is envisioned that we will support more types of magic in later -versions of Git. +alphanumeric. Currently only the slash `/` is recognized as a +"magic signature": it makes the pattern match from the root of +the working tree, even when you are running the command from +inside a subdirectory. + A pathspec with only a colon means "there is no pathspec". This form should not be combined with other pathspec. @@@ -383,7 -398,7 +383,7 @@@ to the result. [[def_ref]]ref:: - A 40-byte hex representation of a <> or a name that + A 40-byte hex representation of a <> or a name that denotes a particular <>. They may be stored in a file under `$GIT_DIR/refs/` directory, or in the `$GIT_DIR/packed-refs` file. @@@ -397,15 -412,24 +397,16 @@@ [[def_refspec]]refspec:: A "refspec" is used by <> and <> to describe the mapping between remote - <> and local ref. They are combined with a colon in - the format :, preceded by an optional plus sign, +. - For example: `git fetch $URL - refs/heads/master:refs/heads/origin` means "grab the master - <> <> from the $URL and store - it as my origin branch head". And `git push - $URL refs/heads/master:refs/heads/to-upstream` means "publish my - master branch head as to-upstream branch at $URL". See also - linkgit:git-push[1]. + <> and local ref. [[def_remote_tracking_branch]]remote-tracking branch:: - A regular Git <> that is used to follow changes from - another <>. A remote-tracking - branch should not contain direct modifications or have local commits - made to it. A remote-tracking branch can usually be - identified as the right-hand-side <> in a Pull: - <>. + A <> that is used to follow changes from another + <>. It typically looks like + 'refs/remotes/foo/bar' (indicating that it tracks a branch named + 'bar' in a remote named 'foo'), and matches the right-hand-side of + a configured fetch <>. A remote-tracking + branch should not contain direct modifications or have local + commits made to it. [[def_repository]]repository:: A collection of <> together with an @@@ -420,7 -444,9 +421,7 @@@ <> left behind. [[def_revision]]revision:: - A particular state of files and directories which was stored in the - <>. It is referenced by a - <>. + Synonym for <> (the noun). [[def_rewind]]rewind:: To throw away part of the development, i.e. to assign the @@@ -429,9 -455,8 +430,9 @@@ [[def_SCM]]SCM:: Source code management (tool). -[[def_SHA1]]SHA1:: - Synonym for <>. +[[def_SHA1]]SHA-1:: + "Secure Hash Algorithm 1"; a cryptographic hash function. + In the context of Git used as a synonym for <>. [[def_shallow_repository]]shallow repository:: A shallow <> has an incomplete @@@ -445,7 -470,7 +446,7 @@@ its history can be later deepened with linkgit:git-fetch[1]. [[def_symref]]symref:: - Symbolic reference: instead of containing the <> + Symbolic reference: instead of containing the <> id itself, it is of the format 'ref: refs/some/thing' and when referenced, it recursively dereferences to this reference. '<>' is a prime example of a symref. Symbolic diff --combined branch.c index 97c72bfe70,beaf11d97c..c5c6984cb5 --- a/branch.c +++ b/branch.c @@@ -57,7 -57,7 +57,7 @@@ void install_branch_config(int flag, co if (remote_is_branch && !strcmp(local, shortname) && !origin) { - warning("Not setting branch %s as its own upstream.", + warning(_("Not setting branch %s as its own upstream."), local); return; } @@@ -78,25 -78,25 +78,25 @@@ if (flag & BRANCH_CONFIG_VERBOSE) { if (remote_is_branch && origin) - printf(rebasing ? - "Branch %s set up to track remote branch %s from %s by rebasing.\n" : - "Branch %s set up to track remote branch %s from %s.\n", - local, shortname, origin); + printf_ln(rebasing ? + _("Branch %s set up to track remote branch %s from %s by rebasing.") : + _("Branch %s set up to track remote branch %s from %s."), + local, shortname, origin); else if (remote_is_branch && !origin) - printf(rebasing ? - "Branch %s set up to track local branch %s by rebasing.\n" : - "Branch %s set up to track local branch %s.\n", - local, shortname); + printf_ln(rebasing ? + _("Branch %s set up to track local branch %s by rebasing.") : + _("Branch %s set up to track local branch %s."), + local, shortname); else if (!remote_is_branch && origin) - printf(rebasing ? - "Branch %s set up to track remote ref %s by rebasing.\n" : - "Branch %s set up to track remote ref %s.\n", - local, remote); + printf_ln(rebasing ? + _("Branch %s set up to track remote ref %s by rebasing.") : + _("Branch %s set up to track remote ref %s."), + local, remote); else if (!remote_is_branch && !origin) - printf(rebasing ? - "Branch %s set up to track local ref %s by rebasing.\n" : - "Branch %s set up to track local ref %s.\n", - local, remote); + printf_ln(rebasing ? + _("Branch %s set up to track local ref %s by rebasing.") : + _("Branch %s set up to track local ref %s."), + local, remote); else die("BUG: impossible combination of %d and %p", remote_is_branch, origin); @@@ -115,7 -115,7 +115,7 @@@ static int setup_tracking(const char *n int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE; if (strlen(new_ref) > 1024 - 7 - 7 - 1) - return error("Tracking not set up: name too long: %s", + return error(_("Tracking not set up: name too long: %s"), new_ref); memset(&tracking, 0, sizeof(tracking)); @@@ -134,7 -134,7 +134,7 @@@ } if (tracking.matches > 1) - return error("Not tracking: ambiguous information for ref %s", + return error(_("Not tracking: ambiguous information for ref %s"), orig_ref); install_branch_config(config_flags, new_ref, tracking.remote, @@@ -179,12 -179,12 +179,12 @@@ int validate_new_branchname(const char int force, int attr_only) { if (strbuf_check_branch_ref(ref, name)) - die("'%s' is not a valid branch name.", name); + die(_("'%s' is not a valid branch name."), name); if (!ref_exists(ref->buf)) return 0; else if (!force && !attr_only) - die("A branch named '%s' already exists.", ref->buf + strlen("refs/heads/")); + die(_("A branch named '%s' already exists."), ref->buf + strlen("refs/heads/")); if (!attr_only) { const char *head; @@@ -192,11 -192,26 +192,26 @@@ head = resolve_ref_unsafe("HEAD", sha1, 0, NULL); if (!is_bare_repository() && head && !strcmp(head, ref->buf)) - die("Cannot force update the current branch."); + die(_("Cannot force update the current branch.")); } return 1; } + static int check_tracking_branch(struct remote *remote, void *cb_data) + { + char *tracking_branch = cb_data; + struct refspec query; + memset(&query, 0, sizeof(struct refspec)); + query.dst = tracking_branch; + return !(remote_find_tracking(remote, &query) || + prefixcmp(query.src, "refs/heads/")); + } + + static int validate_remote_tracking_branch(char *ref) + { + return !for_each_remote(check_tracking_branch, ref); + } + static const char upstream_not_branch[] = N_("Cannot setup tracking information; starting point '%s' is not a branch."); static const char upstream_missing[] = @@@ -247,7 -262,7 +262,7 @@@ void create_branch(const char *head } die(_(upstream_missing), start_name); } - die("Not a valid object name: '%s'.", start_name); + die(_("Not a valid object name: '%s'."), start_name); } switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) { @@@ -259,7 -274,7 +274,7 @@@ case 1: /* Unique completion -- good, only if it is a real branch */ if (prefixcmp(real_ref, "refs/heads/") && - prefixcmp(real_ref, "refs/remotes/")) { + validate_remote_tracking_branch(real_ref)) { if (explicit_tracking) die(_(upstream_not_branch), start_name); else @@@ -267,18 -282,18 +282,18 @@@ } break; default: - die("Ambiguous object name: '%s'.", start_name); + die(_("Ambiguous object name: '%s'."), start_name); break; } if ((commit = lookup_commit_reference(sha1)) == NULL) - die("Not a valid branch point: '%s'.", start_name); + die(_("Not a valid branch point: '%s'."), start_name); hashcpy(sha1, commit->object.sha1); if (!dont_change_ref) { lock = lock_any_ref_for_update(ref.buf, NULL, 0); if (!lock) - die_errno("Failed to lock ref for update"); + die_errno(_("Failed to lock ref for update")); } if (reflog) @@@ -296,7 -311,7 +311,7 @@@ if (!dont_change_ref) if (write_ref_sha1(lock, sha1, msg) < 0) - die_errno("Failed to write ref"); + die_errno(_("Failed to write ref")); strbuf_release(&ref); free(real_ref); diff --combined builtin/checkout.c index 81b4419da5,bcb18c8d20..f5b50e520f --- a/builtin/checkout.c +++ b/builtin/checkout.c @@@ -35,7 -35,6 +35,7 @@@ struct checkout_opts int force_detach; int writeout_stage; int overwrite_ignore; + int ignore_skipworktree; const char *new_branch; const char *new_branch_force; @@@ -279,8 -278,6 +279,8 @@@ static int checkout_paths(const struct for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; ce->ce_flags &= ~CE_MATCHED; + if (!opts->ignore_skipworktree && ce_skip_worktree(ce)) + continue; if (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) /* * "git checkout tree-ish -- path", but this entry @@@ -825,38 -822,40 +825,40 @@@ static int git_checkout_config(const ch } struct tracking_name_data { - const char *name; - char *remote; + /* const */ char *src_ref; + char *dst_ref; + unsigned char *dst_sha1; int unique; }; - static int check_tracking_name(const char *refname, const unsigned char *sha1, - int flags, void *cb_data) + static int check_tracking_name(struct remote *remote, 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)) + struct refspec query; + memset(&query, 0, sizeof(struct refspec)); + query.src = cb->src_ref; + if (remote_find_tracking(remote, &query) || + get_sha1(query.dst, cb->dst_sha1)) return 0; - if (cb->remote) { + if (cb->dst_ref) { cb->unique = 0; return 0; } - cb->remote = xstrdup(refname); + cb->dst_ref = xstrdup(query.dst); return 0; } - static const char *unique_tracking_name(const char *name) + static const char *unique_tracking_name(const char *name, unsigned char *sha1) { - struct tracking_name_data cb_data = { NULL, NULL, 1 }; - cb_data.name = name; - for_each_ref(check_tracking_name, &cb_data); + struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 }; + char src_ref[PATH_MAX]; + snprintf(src_ref, PATH_MAX, "refs/heads/%s", name); + cb_data.src_ref = src_ref; + cb_data.dst_sha1 = sha1; + for_each_remote(check_tracking_name, &cb_data); if (cb_data.unique) - return cb_data.remote; - free(cb_data.remote); + return cb_data.dst_ref; + free(cb_data.dst_ref); return NULL; } @@@ -919,8 -918,8 +921,8 @@@ static int parse_branchname_arg(int arg if (dwim_new_local_branch_ok && !check_filename(NULL, arg) && argc == 1) { - const char *remote = unique_tracking_name(arg); - if (!remote || get_sha1(remote, rev)) + const char *remote = unique_tracking_name(arg, rev); + if (!remote) return argcount; *new_branch = arg; arg = remote; @@@ -1061,8 -1060,6 +1063,8 @@@ int cmd_checkout(int argc, const char * OPT_STRING(0, "conflict", &conflict_style, N_("style"), N_("conflict style (merge or diff3)")), OPT_BOOLEAN('p', "patch", &opts.patch_mode, N_("select hunks interactively")), + OPT_BOOL(0, "ignore-skip-worktree-bits", &opts.ignore_skipworktree, + N_("do not limit pathspecs to sparse entries only")), { OPTION_BOOLEAN, 0, "guess", &dwim_new_local_branch, NULL, N_("second guess 'git checkout no-such-branch'"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },