{"thread":{"id":"7090","subject":"[PATCH 1/3] git-branch: add --track and --no-track options","startedAt":"2007-03-05T08:57:26Z","lastAt":"2007-03-06T08:22:03Z","messageCount":20,"participants":["Paolo Bonzini","Johannes Schindelin","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"36306","messageId":"esgm1m$33f$1@sea.gmane.org","threadId":"7090","inReplyTo":null,"subject":"[PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Paolo Bonzini","fromEmail":"bonzini@gnu.org","sentAt":"2007-03-05T08:57:26Z","receivedAt":"2007-03-05T08:57:26Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"In order to track and build on top of a branch 'topic' you track from\nyour upstream repository, you often would end up doing this sequence:\n\n  git checkout -b mytopic origin/topic\n  git config --add branch.mytopic.remote origin\n  git config --add branch.mytopic.merge refs/heads/topic\n\nThis would first fork your own 'mytopic' branch from the 'topic'\nbranch you track from the 'origin' repository; then it would set up two\nconfiguration variables so that 'git pull' without parameters does the\nright thing while you are on your own 'mytopic' branch.\n\nThis commit adds a --track option to git-branch, so that \"git\nbranch --track topic origin/topic\" performs the latter two actions\nwhen creating your 'topic' branch.  By setting configuration variable\n'remote.REMOTENAME.trackintolocalbranches' to true, you do not have to\npass the --track option explicitly (the configuration variable is off\nby default, and there is a --no-track option to countermand it even if\nthe variable is set).\n\nSigned-off-by: Paolo Bonzini  <bonzini@gnu.org>\n---\n Documentation/git-branch.txt |    9 ++-\n builtin-branch.c             |  126 ++++++++++++++++++++++++++++++++++++++++---\n 2 files changed, 127 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex 3ea3b80..bd65b98 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n [verse]\n 'git-branch' [--color | --no-color] [-r | -a]\n \t   [-v [--abbrev=<length> | --no-abbrev]]\n-'git-branch' [-l] [-f] <branchname> [<start-point>]\n+'git-branch' [--track | --no-track] [-l] [-f] <branchname> [<start-point>]\n 'git-branch' (-m | -M) [<oldbranch>] <newbranch>\n 'git-branch' (-d | -D) [-r] <branchname>...\n \n@@ -26,6 +26,13 @@ It will start out with a head equal to the one given as <start-point>.\n If no <start-point> is given, the branch will be created with a head\n equal to that of the currently checked out branch.\n \n+When a local branch is started off a remote branch, git can setup the\n+branch so that gitlink:git-pull[1] will appropriately merge from that\n+remote branch.  If this behavior is desired, it is possible to make it\n+the default using the `trackintolocalbranches` option of the\n+corresponding remote.  Otherwise, it can be chosen per-branch using\n+the `--track` and `--no-track` options.\n+\n With a '-m' or '-M' option, <oldbranch> will be renamed to <newbranch>.\n If <oldbranch> had a corresponding reflog, it is renamed to match\n <newbranch>, and a reflog entry is created to remember the branch\ndiff --git a/builtin-branch.c b/builtin-branch.c\nindex d371849..f39759b 100644\n--- a/builtin-branch.c\n+++ b/builtin-branch.c\n@@ -12,7 +12,7 @@\n #include \"builtin.h\"\n \n static const char builtin_branch_usage[] =\n-  \"git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]\";\n+  \"git-branch [-r] (-d | -D) <branchname> | [--track | --no-track] [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]\";\n \n #define REF_UNKNOWN_TYPE    0x00\n #define REF_LOCAL_BRANCH    0x01\n@@ -308,14 +308,105 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev)\n \tfree_ref_list(&ref_list);\n }\n \n+\n+static int config_track;\n+static char *config_repo;\n+static const char *start_ref;\n+static int start_len;\n+static int remote_len;\n+\n+static void get_remote_branch_name(const char* value)\n+{\n+\tint len_first = -1, len_second = -1;\n+\tif (*value == '+')\n+\t\tvalue++;\n+\n+\t/* Try an exact match first.  */\n+\tsscanf(value, \"refs/%*[^:]:%n\", &len_first);\n+\tif (len_first != -1\n+\t    && !strcmp(value + len_first, start_ref)) {\n+\t\t/* Truncate the value before the colon.  */\n+\t\tasprintf(&config_repo, \"%.*s\", len_first - 1, value);\n+\t\treturn;\n+\t}\n+\n+\t/* Try with a wildcard match now.  */\n+\tsscanf(value, \"refs/%*[^/]/*:%nrefs/remotes/%*[^/]/*%n\",\n+\t       &len_first, &len_second);\n+\tif (len_first != -1 && len_second != -1\n+\t    && (len_second - 2) - len_first == remote_len + 13\n+\t    && !strncmp(value + len_first, start_ref, remote_len + 13)) {\n+\t\t/* Replace the star with the remote branch name.  */\n+\t\tasprintf(&config_repo, \"%.*s%s\",\n+\t\t\t len_first - 3, value,\n+\t\t\t start_ref + remote_len + 13);\n+\t}\n+}\n+\n+static int get_remote_config(const char* key, const char* value)\n+{\n+        if (!prefixcmp(key, \"remote.\") &&\n+            !strncmp(key + 7, start_ref + 13, remote_len)) {\n+\t\tif (config_track == -1\n+\t\t    && !strcmp(key + 7 + remote_len, \".trackintolocalbranches\"))\n+\t\t\tconfig_track = git_config_bool(key, value);\n+\n+\t\telse if (!strcmp(key + 7 + remote_len, \".fetch\"))\n+\t\t\tget_remote_branch_name(value);\n+        }\n+        return 0;\n+}\n+\n+static void register_pull(const char *name, const char *real_ref, int track)\n+{\n+\tchar key[1024], value[1024];\n+\tconst char *remote_name = real_ref + 13;\n+\tconst char *slash = strchr(remote_name, '/');\n+\n+\tif (!slash)\n+\t\treturn;\n+\n+\tstart_ref = real_ref;\n+\tstart_len = strlen(real_ref);\n+\tremote_len = slash - remote_name;\n+\tconfig_track = track;\n+\tgit_config(get_remote_config);\n+\n+\t/* Change to != 0 to enable this feature by default.  */\n+\tif (config_track == 1 && config_repo) {\n+\t\tif (snprintf(key, sizeof(key), \"branch.%s.remote\", name)\n+\t\t    > sizeof(key)) {\n+\t\t\tdie(\"what a long branch name you have!\");\n+\t\t\tgoto out;\n+\t\t}\n+\t\tif (snprintf(value, sizeof(value), \"%.*s\", remote_len, remote_name)\n+\t\t    > sizeof(value)) {\n+\t\t\tdie(\"what a long branch name you have!\");\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tgit_config_set(key, value);\n+\n+\t\tsnprintf(key, sizeof(key), \"branch.%s.merge\", name);\n+\t\tgit_config_set(key, config_repo);\n+\n+\t\tprintf(\"Branch %s set up to track remote branch %s.\\n\",\n+\t\t       name, real_ref);\n+\t}\n+\n+ out:\n+\tif (config_repo)\n+\t\tfree(config_repo);\n+}\n+\n static void create_branch(const char *name, const char *start_name,\n \t\t\t  unsigned char *start_sha1,\n-\t\t\t  int force, int reflog)\n+\t\t\t  int force, int reflog, int track)\n {\n \tstruct ref_lock *lock;\n \tstruct commit *commit;\n \tunsigned char sha1[20];\n-\tchar ref[PATH_MAX], msg[PATH_MAX + 20];\n+\tchar *real_ref = NULL, ref[PATH_MAX], msg[PATH_MAX + 20];\n \tint forcing = 0;\n \n \tsnprintf(ref, sizeof ref, \"refs/heads/%s\", name);\n@@ -333,7 +424,9 @@ static void create_branch(const char *name, const char *start_name,\n \tif (start_sha1)\n \t\t/* detached HEAD */\n \t\thashcpy(sha1, start_sha1);\n-\telse if (get_sha1(start_name, sha1))\n+\telse if (dwim_ref(start_name, strlen(start_name), sha1, &real_ref) > 1)\n+\t\tdie(\"Ambiguous object name: '%s'.\", start_name);\n+\telse if (real_ref == NULL)\n \t\tdie(\"Not a valid object name: '%s'.\", start_name);\n \n \tif ((commit = lookup_commit_reference(sha1)) == NULL)\n@@ -354,8 +447,17 @@ static void create_branch(const char *name, const char *start_name,\n \t\tsnprintf(msg, sizeof msg, \"branch: Created from %s\",\n \t\t\t start_name);\n \n+\t/* When branching off a remote branch, set up so that git-pull\n+\t   automatically merges from there.  So far, this is only done for\n+\t   branches registered using git-remote.  */\n+\tif (!prefixcmp(real_ref, \"refs/remotes/\"))\n+\t\tregister_pull(name, real_ref, track);\n+\n \tif (write_ref_sha1(lock, sha1, msg) < 0)\n \t\tdie(\"Failed to write ref: %s.\", strerror(errno));\n+\n+\tif (real_ref)\n+\t\tfree(real_ref);\n }\n \n static void rename_branch(const char *oldname, const char *newname, int force)\n@@ -397,7 +499,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \tint delete = 0, force_delete = 0, force_create = 0;\n \tint rename = 0, force_rename = 0;\n \tint verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;\n-\tint reflog = 0;\n+\tint reflog = 0, track = -1;\n \tint kinds = REF_LOCAL_BRANCH;\n \tint i;\n \n@@ -412,6 +514,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\t\ti++;\n \t\t\tbreak;\n \t\t}\n+\t\tif (!strcmp(arg, \"--track\")) {\n+\t\t\ttrack = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"--no-track\")) {\n+\t\t\ttrack = 0;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"-d\")) {\n \t\t\tdelete = 1;\n \t\t\tcontinue;\n@@ -498,9 +608,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \telse if (rename && (i == argc - 2))\n \t\trename_branch(argv[i], argv[i + 1], force_rename);\n \telse if (i == argc - 1)\n-\t\tcreate_branch(argv[i], head, head_sha1, force_create, reflog);\n+\t\tcreate_branch(argv[i], head, head_sha1, force_create, reflog,\n+\t\t\t      track);\n \telse if (i == argc - 2)\n-\t\tcreate_branch(argv[i], argv[i+1], NULL, force_create, reflog);\n+\t\tcreate_branch(argv[i], argv[i+1], NULL, force_create, reflog,\n+\t\t\t      track);\n \telse\n \t\tusage(builtin_branch_usage);\n \n"},{"id":"36324","messageId":"Pine.LNX.4.63.0703051520340.22628@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"7090","inReplyTo":"esgm1m$33f$1@sea.gmane.org","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-03-05T14:50:17Z","receivedAt":"2007-03-05T14:50:17Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nit is a very good idea to read the information which remote tracks which \nbranch from the config, i.e. if you branch \"refs/remotes/hallo\", to look \nif there is any remote information for that local ref.\n\nOn Mon, 5 Mar 2007, Paolo Bonzini wrote:\n\n> diff --git a/builtin-branch.c b/builtin-branch.c\n> index d371849..f39759b 100644\n> --- a/builtin-branch.c\n> +++ b/builtin-branch.c\n> @@ -12,7 +12,7 @@\n>  #include \"builtin.h\"\n>  \n>  static const char builtin_branch_usage[] =\n> -  \"git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]\";\n> +  \"git-branch [-r] (-d | -D) <branchname> | [--track | --no-track] [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]\";\n>  \n>  #define REF_UNKNOWN_TYPE    0x00\n>  #define REF_LOCAL_BRANCH    0x01\n> @@ -308,14 +308,105 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev)\n>  \tfree_ref_list(&ref_list);\n>  }\n>  \n> +\n\nextra empty line.\n\n> +static void get_remote_branch_name(const char* value)\n> +{\n> +\tint len_first = -1, len_second = -1;\n> +\tif (*value == '+')\n> +\t\tvalue++;\n> +\n\n> +\t/* Try an exact match first.  */\n> +\tsscanf(value, \"refs/%*[^:]:%n\", &len_first);\n\nThis is the first time I saw that sscanf format type. How portable is it?\n\n> +\tif (len_first != -1\n> +\t    && !strcmp(value + len_first, start_ref)) {\n\nI really would rather do\n\n\tconst char *p;\n\tif (!prefixcmp(value, \"refs/\") && (p = strchr(value, ':')) &&\n\t\t\t!strcmp(p + 1, start_ref)) {\n\n> +\t\t/* Truncate the value before the colon.  */\n> +\t\tasprintf(&config_repo, \"%.*s\", len_first - 1, value);\n\nasprintf() is a GNU extension. I guess it is better to just\n\n\tconfig_repo = xstrdup(value);\n\tconfig_repo[p - value] = '\\0';\n\n\n> +\t\treturn;\n> +\t}\n> +\n> +\t/* Try with a wildcard match now.  */\n> +\tsscanf(value, \"refs/%*[^/]/*:%nrefs/remotes/%*[^/]/*%n\",\n> +\t       &len_first, &len_second);\n> +\tif (len_first != -1 && len_second != -1\n> +\t    && (len_second - 2) - len_first == remote_len + 13\n> +\t    && !strncmp(value + len_first, start_ref, remote_len + 13)) {\n> +\t\t/* Replace the star with the remote branch name.  */\n> +\t\tasprintf(&config_repo, \"%.*s%s\",\n> +\t\t\t len_first - 3, value,\n> +\t\t\t start_ref + remote_len + 13);\n\nSame here:\n\n\telse if (!prefixcmp(value, \"refs/\") && (p = strchr(value, ':')) &&\n\t\t\t!memcmp(p + 1, start_ref, remote_len) &&\n\t\t\t!strcmp(p + 1 + remote_len, \"/*\")) {\n\t\tconfig_repo = xstrdup(value);\n\t\tconfig_repo[p - value] = '\\0';\n\t}\n\nBTW I prefer to skip the curly brackets when there is only one statement \nin the block.\n\nJust to be on the safe side, you might want to check here if there are \nmore than one remotes \"tracking\" into start_ref. However, it might not be \nrelevant in practice.\n\n> +\t}\n> +}\n> +\n> +static int get_remote_config(const char* key, const char* value)\n> +{\n> +        if (!prefixcmp(key, \"remote.\") &&\n> +            !strncmp(key + 7, start_ref + 13, remote_len)) {\n> +\t\tif (config_track == -1\n> +\t\t    && !strcmp(key + 7 + remote_len, \".trackintolocalbranches\"))\n\nFWIW I don't think .trackIntoLocalBranches\" is needed. Opinions?\n\n> +static void register_pull(const char *name, const char *real_ref, int track)\n\nMaybe call it \"set_branch_defaults()\"?\n\n> +\t\t\tdie(\"what a long branch name you have!\");\n> +\t\t\tgoto out;\n\ndie() does not return, so no need to \"goto out;\"... But then, it might be \nnicer to return -1, i.e.\n\n\t\t\tret = error(\"what a long branch name you have!\");\n\nand saying\n\t\tif (!ret) {\n\t\t\tgit_config_set(key, value);\n\t\t\t...\n\t\t\tprintf(\"Branch %s setup...\n\t\t}\n\t}\n\tif (repo_config)\n\t\tfree(repo_config);\n\treturn ret;\n\nBut I see you made it return \"void\", so you can skip the \"return ret;\".\n\n> @@ -333,7 +424,9 @@ static void create_branch(const char *name, const char *start_name,\n>  \tif (start_sha1)\n>  \t\t/* detached HEAD */\n>  \t\thashcpy(sha1, start_sha1);\n> -\telse if (get_sha1(start_name, sha1))\n> +\telse if (dwim_ref(start_name, strlen(start_name), sha1, &real_ref) > 1)\n> +\t\tdie(\"Ambiguous object name: '%s'.\", start_name);\n\nI know, I should have said that earlier, but I just found out myself: We \nhave a config variable core.warnambiguousrefs, and maybe we should _not_ \ncomplain and set the defaults when the global variable warn_ambiguous_refs \nis 0.\n\nCiao,\nDscho\n"},{"id":"36329","messageId":"45EC35B2.2070808@lu.unisi.ch","threadId":"7090","inReplyTo":"Pine.LNX.4.63.0703051520340.22628@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Paolo Bonzini","fromEmail":"paolo.bonzini@lu.unisi.ch","sentAt":"2007-03-05T15:22:26Z","receivedAt":"2007-03-05T15:22:26Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"\n>> +\t/* Try an exact match first.  */\n>> +\tsscanf(value, \"refs/%*[^:]:%n\", &len_first);\n> \n> This is the first time I saw that sscanf format type. How portable is it?\n\nIt is.  At the very least it is in OpenGroup.\n\n>> +\t\t/* Truncate the value before the colon.  */\n>> +\t\tasprintf(&config_repo, \"%.*s\", len_first - 1, value);\n> \n> asprintf() is a GNU extension. I guess it is better to just\n> \n> \tconfig_repo = xstrdup(value);\n> \tconfig_repo[p - value] = '\\0';\n\ngit has nfvasprintf -- I'll just use that one.\n\n> FWIW I don't think .trackIntoLocalBranches\" is needed. Opinions?\n\nThat's because I'd like to make it the default for me...  Also, look at patch 3/3.\n\n>> @@ -333,7 +424,9 @@ static void create_branch(const char *name, const char *start_name,\n>>  \tif (start_sha1)\n>>  \t\t/* detached HEAD */\n>>  \t\thashcpy(sha1, start_sha1);\n>> -\telse if (get_sha1(start_name, sha1))\n>> +\telse if (dwim_ref(start_name, strlen(start_name), sha1, &real_ref) > 1)\n>> +\t\tdie(\"Ambiguous object name: '%s'.\", start_name);\n> \n> I know, I should have said that earlier, but I just found out myself: We \n> have a config variable core.warnambiguousrefs, and maybe we should _not_ \n> complain and set the defaults when the global variable warn_ambiguous_refs \n> is 0.\n\nIf warn_ambiguous_ref == 0, dwim_ref is never going to answer anything > 1...\n\nPaolo\n"},{"id":"36330","messageId":"45EC3905.7070406@lu.unisi.ch","threadId":"7090","inReplyTo":"Pine.LNX.4.63.0703051520340.22628@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Paolo Bonzini","fromEmail":"paolo.bonzini@lu.unisi.ch","sentAt":"2007-03-05T15:36:37Z","receivedAt":"2007-03-05T15:36:37Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"\n>> +\t/* Try with a wildcard match now.  */\n>> +\tsscanf(value, \"refs/%*[^/]/*:%nrefs/remotes/%*[^/]/*%n\",\n>> +\t       &len_first, &len_second);\n>> +\tif (len_first != -1 && len_second != -1\n>> +\t    && (len_second - 2) - len_first == remote_len + 13\n>> +\t    && !strncmp(value + len_first, start_ref, remote_len + 13)) {\n>> +\t\t/* Replace the star with the remote branch name.  */\n>> +\t\tasprintf(&config_repo, \"%.*s%s\",\n>> +\t\t\t len_first - 3, value,\n>> +\t\t\t start_ref + remote_len + 13);\n> \n> Same here:\n> \n> \telse if (!prefixcmp(value, \"refs/\") && (p = strchr(value, ':')) &&\n> \t\t\t!memcmp(p + 1, start_ref, remote_len) &&\n> \t\t\t!strcmp(p + 1 + remote_len, \"/*\")) {\n> \t\tconfig_repo = xstrdup(value);\n> \t\tconfig_repo[p - value] = '\\0';\n> \t}\n\nThis is not what my code does.  Are you saying that yours is correct, or that it should actually be the same in practice, or just that I should avoid sscanf/asprintf (which I won't do, since I got mildly insane after writing half of the function without sscanf -- and then decided that the C library is there to be used).\n\nPaolo\n"},{"id":"36333","messageId":"Pine.LNX.4.63.0703051648330.22628@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"7090","inReplyTo":"45EC3905.7070406@lu.unisi.ch","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-03-05T15:58:05Z","receivedAt":"2007-03-05T15:58:05Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 5 Mar 2007, Paolo Bonzini wrote:\n\n> >> +\t/* Try with a wildcard match now.  */\n> >> +\tsscanf(value, \"refs/%*[^/]/*:%nrefs/remotes/%*[^/]/*%n\",\n> >> +\t       &len_first, &len_second);\n> >> +\tif (len_first != -1 && len_second != -1\n> >> +\t    && (len_second - 2) - len_first == remote_len + 13\n> >> +\t    && !strncmp(value + len_first, start_ref, remote_len + 13)) {\n> >> +\t\t/* Replace the star with the remote branch name.  */\n> >> +\t\tasprintf(&config_repo, \"%.*s%s\",\n> >> +\t\t\t len_first - 3, value,\n> >> +\t\t\t start_ref + remote_len + 13);\n> > \n> > Same here:\n> > \n> > \telse if (!prefixcmp(value, \"refs/\") && (p = strchr(value, ':')) &&\n> > \t\t\t!memcmp(p + 1, start_ref, remote_len) &&\n> > \t\t\t!strcmp(p + 1 + remote_len, \"/*\")) {\n> > \t\tconfig_repo = xstrdup(value);\n> > \t\tconfig_repo[p - value] = '\\0';\n> > \t}\n> \n> This is not what my code does.\n\nYou are completely correct. I overlooked the need to check for \"/*\" \nin the first part. So, this should go before the memcmp() line:\n\n\t\t\t!prefixcmp(p - 2, \"/*\") &&\n\nI also forgot to replace \"*\" by the branch name. The if block should look \nlike this, then:\n\n\t\tconfig_repo = xmalloc(p - value + start_len - remote_len);\n\t\tstrncpy(config_repo, value, p - 1 - value);\n\t\tstrcat(config_repo, start_ref + remote_len);\n\nAs usual, completely untested.\n\n> Are you saying that yours is correct, or that it should actually be the \n> same in practice, or just that I should avoid sscanf/asprintf (which I \n> won't do, since I got mildly insane after writing half of the function \n> without sscanf -- and then decided that the C library is there to be \n> used).\n\nWell, you make a good case there. I am only mildly concerned that this \nmight not work on some obscure platforms (including Windows and SunOS), \nand that we are not even realizing that because you do not check the \nreturn value of sscanf().\n\nCiao,\nDscho\n"},{"id":"36335","messageId":"Pine.LNX.4.63.0703051701331.22628@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"7090","inReplyTo":"45EC35B2.2070808@lu.unisi.ch","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-03-05T16:09:30Z","receivedAt":"2007-03-05T16:09:30Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 5 Mar 2007, Paolo Bonzini wrote:\n\n> >> +\t/* Try an exact match first.  */\n> >> +\tsscanf(value, \"refs/%*[^:]:%n\", &len_first);\n> > \n> > This is the first time I saw that sscanf format type. How portable is it?\n> \n> It is.  At the very least it is in OpenGroup.\n\nThat is not very reassuring for me. However, I learnt something new about \nsscanf(), so it was not lost on me.\n\n> >> +\t\t/* Truncate the value before the colon.  */\n> >> +\t\tasprintf(&config_repo, \"%.*s\", len_first - 1, value);\n> > \n> > asprintf() is a GNU extension. I guess it is better to just\n> > \n> > \tconfig_repo = xstrdup(value);\n> > \tconfig_repo[p - value] = '\\0';\n> \n> git has nfvasprintf -- I'll just use that one.\n\nWhich forces you to build a va_list first, and which is horribly \ninefficient. Not that it matters for git-branch...\n\n> > FWIW I don't think .trackIntoLocalBranches\" is needed. Opinions?\n> \n> That's because I'd like to make it the default for me...  Also, look at \n> patch 3/3.\n\nI am not only mildly opposed to switching trackIntoLocalBranches off. It \nis a _very_ useful feature for new Git users, as it will (I am sure) \nreduce the number of \"Huh?\" moments dramatically.\n\nAlso, I am opposed to make this a remote.<name>.trackIntoLocalBranches \nvariable.\n\nIMHO a global flag should be enough, if you really need it at all. Your \ncode now makes sure that the defaults will be set only if there is a \nproper fetch entry for the corresponding remote name, so it is safe. \nPeople wanting to prevent that behaviour can use \"--no-track\", and those \nwho don't know about \"--no-track\" are probably better off _with_ DWIM \ndefaults for the new branch.\n\n> >> @@ -333,7 +424,9 @@ static void create_branch(const char *name, const char *start_name,\n> >>  \tif (start_sha1)\n> >>  \t\t/* detached HEAD */\n> >>  \t\thashcpy(sha1, start_sha1);\n> >> -\telse if (get_sha1(start_name, sha1))\n> >> +\telse if (dwim_ref(start_name, strlen(start_name), sha1, &real_ref) > 1)\n> >> +\t\tdie(\"Ambiguous object name: '%s'.\", start_name);\n> > \n> > I know, I should have said that earlier, but I just found out myself: \n> > We have a config variable core.warnambiguousrefs, and maybe we should \n> > _not_ complain and set the defaults when the global variable \n> > warn_ambiguous_refs is 0.\n> \n> If warn_ambiguous_ref == 0, dwim_ref is never going to answer anything > \n> 1...\n\nRight. Thank you!\n\nCiao,\nDscho\n"},{"id":"36339","messageId":"45EC4B55.3090505@lu.unisi.ch","threadId":"7090","inReplyTo":"Pine.LNX.4.63.0703051648330.22628@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Paolo Bonzini","fromEmail":"paolo.bonzini@lu.unisi.ch","sentAt":"2007-03-05T16:54:45Z","receivedAt":"2007-03-05T16:54:45Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"\n> Well, you make a good case there. I am only mildly concerned that this \n> might not work on some obscure platforms (including Windows and SunOS), \n> and that we are not even realizing that because you do not check the \n> return value of sscanf().\n\nI check that the %n's are written to, instead.\n\nPaolo\n"},{"id":"36341","messageId":"Pine.LNX.4.63.0703051812030.22628@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"7090","inReplyTo":"45EC4B55.3090505@lu.unisi.ch","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-03-05T17:16:36Z","receivedAt":"2007-03-05T17:16:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 5 Mar 2007, Paolo Bonzini wrote:\n\n> > Well, you make a good case there. I am only mildly concerned that this \n> > might not work on some obscure platforms (including Windows and \n> > SunOS), and that we are not even realizing that because you do not \n> > check the return value of sscanf().\n> \n> I check that the %n's are written to, instead.\n\nYes, you also check real_ref instead of checking if dwim_ref() returned 0. \nI feel a little bit uneasy about that, since there is no guarantee that \nthese values are left untouched, whereas the return value is guaranteed to \nbehave as expected.\n\nI also feel a little uneasy about having to parse a format in order to \nparse a string, when you know what that string should look like. For \nexample, you could make the code even more compact by asking \n\"(p = strstr(value, \"/*:refs/remotes/\"))\".\n\nBut if other people do not feel as uneasy about these issues as I do, I \ncertainly will not reject your patch.\n\nCiao,\nDscho\n"},{"id":"36342","messageId":"45EC51C6.5080505@lu.unisi.ch","threadId":"7090","inReplyTo":"Pine.LNX.4.63.0703051812030.22628@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Paolo Bonzini","fromEmail":"paolo.bonzini@lu.unisi.ch","sentAt":"2007-03-05T17:22:14Z","receivedAt":"2007-03-05T17:22:14Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"\n> Yes, you also check real_ref instead of checking if dwim_ref() returned 0. \n> I feel a little bit uneasy about that, since there is no guarantee that \n> these values are left untouched, whereas the return value is guaranteed to \n> behave as expected.\n\nThere is.  The man page says \"Scanning stops when an input character does not match such a format character.\"  Scanning includes not processing %n elements, either.\n\nRegarding dwim_ref, dwim_ref says:\n\nint dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)\n{\n        const char **p, *r;\n        int refs_found = 0;\n\n        *ref = NULL;\n\nand since this \"*ref\" is not used anyway in the rest of the routine, I figured out that it's part of the interface to set \"*ref\" to NULL if no ref is found.  Of course it could help (hint hint) if extern functions had a comment stating the interface.\n\nI see however that I also have a \"real_ref = NULL\" that is actually pointless; I can take it away of course.\n\n> I also feel a little uneasy about having to parse a format in order to \n> parse a string, when you know what that string should look like. For \n> example, you could make the code even more compact by asking \n> \"(p = strstr(value, \"/*:refs/remotes/\"))\".\n\nGo down this way and you will say that printf is useless too.\n\nPaolo\n"},{"id":"36343","messageId":"45EC51D0.7000406@lu.unisi.ch","threadId":"7090","inReplyTo":"Pine.LNX.4.63.0703051701331.22628@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Paolo Bonzini","fromEmail":"paolo.bonzini@lu.unisi.ch","sentAt":"2007-03-05T17:22:24Z","receivedAt":"2007-03-05T17:22:24Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":">>>> +\t/* Try an exact match first.  */\n>>>> +\tsscanf(value, \"refs/%*[^:]:%n\", &len_first);\n>>> This is the first time I saw that sscanf format type. How portable is it?\n>> It is.  At the very least it is in OpenGroup.\n> \n> That is not very reassuring for me. However, I learnt something new about \n> sscanf(), so it was not lost on me.\n\nGoogle books reveals that it's called a \"scanset\" (I didn't know that either).  I found it in \"C: The Complete Reference\" by Herb Schildt (2000) and \"POSIX Programmer's Guide\" by D.A. Lewine (1991).  I don't have K&R at hand to check.\n\nPaolo\n"},{"id":"36349","messageId":"Pine.LNX.4.63.0703051930560.22628@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"7090","inReplyTo":"45EC51C6.5080505@lu.unisi.ch","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-03-05T18:37:01Z","receivedAt":"2007-03-05T18:37:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 5 Mar 2007, Paolo Bonzini wrote:\n\n> > Yes, you also check real_ref instead of checking if dwim_ref() \n> > returned 0. I feel a little bit uneasy about that, since there is no \n> > guarantee that these values are left untouched, whereas the return \n> > value is guaranteed to behave as expected.\n> \n> There is.  The man page says \"Scanning stops when an input character \n> does not match such a format character.\"  Scanning includes not \n> processing %n elements, either.\n\nSo, if you want to be that precise, it never says that it does not touch \nthe pointers passed to it. But it states very clearly what the return \nvalue is in case of a failure.\n\n> Regarding dwim_ref, dwim_ref says:\n> \n> int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)\n> {\n>         const char **p, *r;\n>         int refs_found = 0;\n> \n>         *ref = NULL;\n\nYes, this is what the source does. But again, the return value is what you \nshould -- and indeed forever can -- rely on. I am not really happy that \ndwim_ref() touches ref, even if nothing was found, but it is an \n_implementation detail_.\n\n> > I also feel a little uneasy about having to parse a format in order to \n> > parse a string, when you know what that string should look like. For \n> > example, you could make the code even more compact by asking \"(p = \n> > strstr(value, \"/*:refs/remotes/\"))\".\n> \n> Go down this way and you will say that printf is useless too.\n\nNah. You are not fair.\n\nCiao,\nDscho\n"},{"id":"36367","messageId":"45EC8959.1090303@lu.unisi.ch","threadId":"7090","inReplyTo":"Pine.LNX.4.63.0703051930560.22628@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Paolo Bonzini","fromEmail":"paolo.bonzini@lu.unisi.ch","sentAt":"2007-03-05T21:19:21Z","receivedAt":"2007-03-05T21:19:21Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"\n>> There is.  The man page says \"Scanning stops when an input character \n>> does not match such a format character.\"  Scanning includes not \n>> processing %n elements, either.\n> \n> So, if you want to be that precise, it never says that it does not touch \n> the pointers passed to it.\n\nIt cannot know that there *are* any pointers unless it goes on scanning the format string.  Since the function it varargs, it cannot *guess* that there are any without scanning that the documentation says does not happen.  Anyway...\n\n> But it states very clearly what the return \n> value is in case of a failure.\n\nActually ISTR that %n is not counted in the return value and that's why I wrote the code this way.\n\n> Yes, this is what the source does. But again, the return value is what you \n> should -- and indeed forever can -- rely on. I am not really happy that \n> dwim_ref() touches ref, even if nothing was found, but it is an \n> _implementation detail_.\n\nIt's not fair to not have any documentation in the code, force the contributor to reverse engineer the documentation, and say it is relying on an implementation detail.  In otherwise undocumented code, implementation == interface.\n\nPaolo\n"},{"id":"36368","messageId":"7v3b4jxtx8.fsf@assigned-by-dhcp.cox.net","threadId":"7090","inReplyTo":"45EC8959.1090303@lu.unisi.ch","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-05T21:27:31Z","receivedAt":"2007-03-05T21:27:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Paolo Bonzini <paolo.bonzini@lu.unisi.ch> writes:\n\n> Actually ISTR that %n is not counted in the return value and that's why I wrote the code this way.\n\nYes, that is correct.  Some C lib implementations seem to count\n%n and others don't so it is not reliable.  That is one of the\nreasons I personally have stayed away from fancier sscanf()\nconstructs, both inside and outside git project.\n"},{"id":"36379","messageId":"Pine.LNX.4.63.0703052359440.13683@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"7090","inReplyTo":"45EC8959.1090303@lu.unisi.ch","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-03-05T23:09:45Z","receivedAt":"2007-03-05T23:09:45Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 5 Mar 2007, Paolo Bonzini wrote:\n\n> > Yes, this is what the source does. But again, the return value is what \n> > you should -- and indeed forever can -- rely on. I am not really happy \n> > that dwim_ref() touches ref, even if nothing was found, but it is an \n> > _implementation detail_.\n> \n> It's not fair to not have any documentation in the code, force the \n> contributor to reverse engineer the documentation, and say it is relying \n> on an implementation detail.  In otherwise undocumented code, \n> implementation == interface.\n\nAh, sorry. The \"return 0 on success, other values mean different sorts of \nerrors\" concept is so ubiquituous in Unix-like systems, that nobody \nbothered documenting that.\n\nActually, we usually use \"-1\" to mean error, and depending on the function \nhave different meanings for \">0\".\n\nBut the best documentation for a function is actually the code using it, \nand I thought that you had a look at them. Very often, I do \"git grep bla\" \nto see where the function called \"bla()\" was used. For me, examples are \nworth a thousand man pages...\n\nA supplemental remark on the sscanf() thing: when I was forced to work on \nWindows, I made it a habit not to rely on specs. So often, things just did \nnot work as described, and complaining did not help. For example, we had \nto throw out _all_ uses of templates in a certain project, because the C \ncompiler would choke with an internal error.\n\nSo, my hesitation regarding sscanf() stems mainly from the fact that it \nappears rarely used to me, and such constructs are more likely to break \nexpectations when trying to port to different architectures.\n\nAnd _that_ is why I do not hesitate using printf(): it is much more likely \nthat an incompatibility in printf() is fixed, whereas with sscanf() it \nwill likely end up worked-around all the time instead of being fixed.\n\nCiao,\nDscho\n"},{"id":"36421","messageId":"7vejo2uaxs.fsf@assigned-by-dhcp.cox.net","threadId":"7090","inReplyTo":"esgm1m$33f$1@sea.gmane.org","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-06T06:45:51Z","receivedAt":"2007-03-06T06:45:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Paolo Bonzini <bonzini@gnu.org> writes:\n\n> In order to track and build on top of a branch 'topic' you track from\n> your upstream repository, you often would end up doing this sequence:\n>\n>   git checkout -b mytopic origin/topic\n>   git config --add branch.mytopic.remote origin\n>   git config --add branch.mytopic.merge refs/heads/topic\n>\n> This would first fork your own 'mytopic' branch from the 'topic'\n> branch you track from the 'origin' repository; then it would set up two\n> configuration variables so that 'git pull' without parameters does the\n> right thing while you are on your own 'mytopic' branch.\n>\n> This commit adds a --track option to git-branch, so that \"git\n> branch --track topic origin/topic\" performs the latter two actions\n> when creating your 'topic' branch.\n\nHmm. I think your use of 'mytopic' is very good for the purpose\nof illustration. It makes clear which configuration takes name\nfrom what. So I like your first paragraph. However, one reason\npeople like the separate remote layout is that it allows you to\nname your own branch identically with that of the other side, so\nin that sense, the description in your second paragraph matches\nthe real-life usage better. What I am getting at is that (1)\nthese two paragraphs are inconsistent, (2) there is a reason to\nprefer the description in the first paragraph, and (3) there is\nanother reason to prefer the description in the second one.\n\n> By setting configuration variable\n> 'remote.REMOTENAME.trackintolocalbranches' to true, you do not have to\n> pass the --track option explicitly (the configuration variable is off\n> by default, and there is a --no-track option to countermand it even if\n> the variable is set).\n\nAs Johannes already pointed this out, I think allowing this to\nbe controlled per remote is nice but overkill.  A single boolean\nconfiguration, say \"branch.autosetupmerge\", would suffice.\n"},{"id":"36429","messageId":"45ED16EE.8020303@lu.unisi.ch","threadId":"7090","inReplyTo":"7v3b4jxtx8.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Paolo Bonzini","fromEmail":"paolo.bonzini@lu.unisi.ch","sentAt":"2007-03-06T07:23:26Z","receivedAt":"2007-03-06T07:23:26Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"\n> Yes, that is correct.  Some C lib implementations seem to count\n> %n and others don't so it is not reliable.  That is one of the\n> reasons I personally have stayed away from fancier sscanf()\n> constructs, both inside and outside git project.\n\nSo, should I remove it?  As I said, the code using sscanf is already the second try, and the first was utterly illegible, so I'd rather stay with it.\n\nPaolo\n"},{"id":"36430","messageId":"45ED179B.90500@lu.unisi.ch","threadId":"7090","inReplyTo":"7vejo2uaxs.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Paolo Bonzini","fromEmail":"paolo.bonzini@lu.unisi.ch","sentAt":"2007-03-06T07:26:19Z","receivedAt":"2007-03-06T07:26:19Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"\n> Hmm. I think your use of 'mytopic' is very good for the purpose\n> of illustration. It makes clear which configuration takes name\n> from what. So I like your first paragraph. However, one reason\n> people like the separate remote layout is that it allows you to\n> name your own branch identically with that of the other side, so\n> in that sense, the description in your second paragraph matches\n> the real-life usage better. What I am getting at is that (1)\n> these two paragraphs are inconsistent, (2) there is a reason to\n> prefer the description in the first paragraph, and (3) there is\n> another reason to prefer the description in the second one.\n\nOk, I'll prefer using \"mytopic\" anywhere.\n\n> As Johannes already pointed this out, I think allowing this to\n> be controlled per remote is nice but overkill.  A single boolean\n> configuration, say \"branch.autosetupmerge\", would suffice.\n\nIn this case, patch 2/3 should also be withdrawn, right?\n\nPaolo\n"},{"id":"36432","messageId":"7vlkiastu8.fsf@assigned-by-dhcp.cox.net","threadId":"7090","inReplyTo":"45ED179B.90500@lu.unisi.ch","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-06T07:40:31Z","receivedAt":"2007-03-06T07:40:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Paolo Bonzini <paolo.bonzini@lu.unisi.ch> writes:\n\n>> Hmm. I think your use of 'mytopic' is very good for the purpose\n>> of illustration. It makes clear which configuration takes name\n>> from what. So I like your first paragraph. However, one reason\n>> people like the separate remote layout is that it allows you to\n>> name your own branch identically with that of the other side, so\n>> in that sense, the description in your second paragraph matches\n>> the real-life usage better. What I am getting at is that (1)\n>> these two paragraphs are inconsistent, (2) there is a reason to\n>> prefer the description in the first paragraph, and (3) there is\n>> another reason to prefer the description in the second one.\n>\n> Ok, I'll prefer using \"mytopic\" anywhere.\n>\n>> As Johannes already pointed this out, I think allowing this to\n>> be controlled per remote is nice but overkill.  A single boolean\n>> configuration, say \"branch.autosetupmerge\", would suffice.\n>\n> In this case, patch 2/3 should also be withdrawn, right?\n\nDo you mean you would agree that it is overkill?  Just in case;\nyou do not have to necessarily agree with me but convince me\nyour way, if you feel I am wrong.\n\nIf so, yeah, 2/3 needs a minor adjustment since the configuration\nwill not be on remote.* but one configuration variable.\n\nAlso I agree with many points Dscho made.  I understand you\nagreed to avoid asprintf() from portability worries, which I\nthink is a sensible thing to do.\n\nWhile I do not think we should avoid sscanf(\"%n\"), I suspect\nthat the code in your patch is not helped by using it that much.\n"},{"id":"36435","messageId":"45ED1CB9.7060508@lu.unisi.ch","threadId":"7090","inReplyTo":"7vlkiastu8.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Paolo Bonzini","fromEmail":"paolo.bonzini@lu.unisi.ch","sentAt":"2007-03-06T07:48:09Z","receivedAt":"2007-03-06T07:48:09Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"\n> Do you mean you would agree that it is overkill?\n\nIt means I don't have much interest in trying to convince you your way.  I will try just once, and I have two arguments to make:\n\n1) I added it in the first place because it made the design of patch 2/3 obvious.  If the shared configuration variable wins, I would withdraw patch 2/3 completely and just let the user use git-config (or \"vi\"...) to modify the default.\n\n2) Also, I liked per-remote configuration because it gives you a quick view of which remotes you have just because you sometimes cherrypick from them, and which remotes you have because you are basing your work on them.\n\nIf you're convinced, I'll send the updated (final?) patch later today (which means you'll get it tomorrow morning in your timezone).  If you're not, I'm not sure I can update the patch today to use the shared configuration variable, but I'll get to that too.\n\n> Also I agree with many points Dscho made.  I understand you\n> agreed to avoid asprintf() from portability worries, which I\n> think is a sensible thing to do.\n\nSure, I was somehow convinced that git was already providing a portable version of it.\n\n> While I do not think we should avoid sscanf(\"%n\"), I suspect\n> that the code in your patch is not helped by using it that much.\n\nNo, it's not.  But it's helped a lot by using sscanf itself, and \"%n\" is the only way I know to reliably test the return code of sscanf and, in the process, save one strchr and one strlen.\n\nPaolo\n"},{"id":"36439","messageId":"7v1wk2srx0.fsf@assigned-by-dhcp.cox.net","threadId":"7090","inReplyTo":"45ED1CB9.7060508@lu.unisi.ch","subject":"Re: [PATCH 1/3] git-branch: add --track and --no-track options","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-06T08:22:03Z","receivedAt":"2007-03-06T08:22:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Paolo Bonzini <paolo.bonzini@lu.unisi.ch> writes:\n\n> No, it's not.  But it's helped a lot by using sscanf itself,\n> and \"%n\" is the only way I know to reliably test the return\n> code of sscanf and, in the process, save one strchr and one\n> strlen.\n\nOk, let's see if that is true in the next round, then.  I do not\nhave much against sscanf(%n) as long as its return value is not\ndepended upon (the portability issue as you mentioned).\n"}]}