{"thread":{"id":"11950","subject":"[PATCH v2 07/11] Move create_branch into a library file","startedAt":"2008-02-07T16:40:08Z","lastAt":"2008-02-07T16:40:08Z","messageCount":1,"participants":["Daniel Barkalow"],"isPatch":true,"patchVersion":2,"patchTotal":11},"messages":[{"id":"67830","messageId":"alpine.LNX.1.00.0802071131100.13593@iabervon.org","threadId":"11950","inReplyTo":null,"subject":"[PATCH v2 07/11] Move create_branch into a library file","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2008-02-07T16:40:08Z","receivedAt":"2008-02-07T16:40:08Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"You can also create branches, in exactly the same way, with checkout -b.\n\nThis introduces branch.{c,h} library files for doing porcelain-level \noperations on branches (such as creating them with their appropriate \ndefault configuration).\n\nSigned-off-by: Daniel Barkalow <barkalow@iabervon.org>\n---\n Makefile         |    2 +-\n branch.c         |  140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n branch.h         |    8 +++\n builtin-branch.c |  138 +----------------------------------------------------\n 4 files changed, 151 insertions(+), 137 deletions(-)\n create mode 100644 branch.c\n create mode 100644 branch.h\n\ndiff --git a/Makefile b/Makefile\nindex 27a8b1b..cc0643e 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -323,7 +323,7 @@ LIB_OBJS = \\\n \talloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \\\n \tcolor.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \\\n \tconvert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o \\\n-\ttransport.o bundle.o walker.o parse-options.o ws.o archive.o\n+\ttransport.o bundle.o walker.o parse-options.o ws.o archive.o branch.o\n \n BUILTIN_OBJS = \\\n \tbuiltin-add.o \\\ndiff --git a/branch.c b/branch.c\nnew file mode 100644\nindex 0000000..45ab820\n--- /dev/null\n+++ b/branch.c\n@@ -0,0 +1,140 @@\n+#include \"cache.h\"\n+#include \"branch.h\"\n+#include \"refs.h\"\n+#include \"remote.h\"\n+#include \"commit.h\"\n+\n+struct tracking {\n+\tstruct refspec spec;\n+\tchar *src;\n+\tconst char *remote;\n+\tint matches;\n+};\n+\n+static int find_tracked_branch(struct remote *remote, void *priv)\n+{\n+\tstruct tracking *tracking = priv;\n+\n+\tif (!remote_find_tracking(remote, &tracking->spec)) {\n+\t\tif (++tracking->matches == 1) {\n+\t\t\ttracking->src = tracking->spec.src;\n+\t\t\ttracking->remote = remote->name;\n+\t\t} else {\n+\t\t\tfree(tracking->spec.src);\n+\t\t\tif (tracking->src) {\n+\t\t\t\tfree(tracking->src);\n+\t\t\t\ttracking->src = NULL;\n+\t\t\t}\n+\t\t}\n+\t\ttracking->spec.src = NULL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * This is called when new_ref is branched off of orig_ref, and tries\n+ * to infer the settings for branch.<new_ref>.{remote,merge} from the\n+ * config.\n+ */\n+static int setup_tracking(const char *new_ref, const char *orig_ref)\n+{\n+\tchar key[1024];\n+\tstruct tracking tracking;\n+\n+\tif (strlen(new_ref) > 1024 - 7 - 7 - 1)\n+\t\treturn error(\"Tracking not set up: name too long: %s\",\n+\t\t\t\tnew_ref);\n+\n+\tmemset(&tracking, 0, sizeof(tracking));\n+\ttracking.spec.dst = (char *)orig_ref;\n+\tif (for_each_remote(find_tracked_branch, &tracking) ||\n+\t\t\t!tracking.matches)\n+\t\treturn 1;\n+\n+\tif (tracking.matches > 1)\n+\t\treturn error(\"Not tracking: ambiguous information for ref %s\",\n+\t\t\t\torig_ref);\n+\n+\tif (tracking.matches == 1) {\n+\t\tsprintf(key, \"branch.%s.remote\", new_ref);\n+\t\tgit_config_set(key, tracking.remote ?  tracking.remote : \".\");\n+\t\tsprintf(key, \"branch.%s.merge\", new_ref);\n+\t\tgit_config_set(key, tracking.src);\n+\t\tfree(tracking.src);\n+\t\tprintf(\"Branch %s set up to track remote branch %s.\\n\",\n+\t\t\t       new_ref, orig_ref);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void create_branch(const char *head,\n+\t\t   const char *name, const char *start_name,\n+\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 *real_ref, ref[PATH_MAX], msg[PATH_MAX + 20];\n+\tint forcing = 0;\n+\n+\tsnprintf(ref, sizeof ref, \"refs/heads/%s\", name);\n+\tif (check_ref_format(ref))\n+\t\tdie(\"'%s' is not a valid branch name.\", name);\n+\n+\tif (resolve_ref(ref, sha1, 1, NULL)) {\n+\t\tif (!force)\n+\t\t\tdie(\"A branch named '%s' already exists.\", name);\n+\t\telse if (!is_bare_repository() && !strcmp(head, name))\n+\t\t\tdie(\"Cannot force update the current branch.\");\n+\t\tforcing = 1;\n+\t}\n+\n+\treal_ref = NULL;\n+\tif (get_sha1(start_name, sha1))\n+\t\tdie(\"Not a valid object name: '%s'.\", start_name);\n+\n+\tswitch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {\n+\tcase 0:\n+\t\t/* Not branching from any existing branch */\n+\t\treal_ref = NULL;\n+\t\tbreak;\n+\tcase 1:\n+\t\t/* Unique completion -- good */\n+\t\tbreak;\n+\tdefault:\n+\t\tdie(\"Ambiguous object name: '%s'.\", start_name);\n+\t\tbreak;\n+\t}\n+\n+\tif ((commit = lookup_commit_reference(sha1)) == NULL)\n+\t\tdie(\"Not a valid branch point: '%s'.\", start_name);\n+\thashcpy(sha1, commit->object.sha1);\n+\n+\tlock = lock_any_ref_for_update(ref, NULL, 0);\n+\tif (!lock)\n+\t\tdie(\"Failed to lock ref for update: %s.\", strerror(errno));\n+\n+\tif (reflog)\n+\t\tlog_all_ref_updates = 1;\n+\n+\tif (forcing)\n+\t\tsnprintf(msg, sizeof msg, \"branch: Reset from %s\",\n+\t\t\t start_name);\n+\telse\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   remotes registered via .git/config.  */\n+\tif (real_ref && track)\n+\t\tsetup_tracking(name, real_ref);\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+}\ndiff --git a/branch.h b/branch.h\nnew file mode 100644\nindex 0000000..8bcd9dc\n--- /dev/null\n+++ b/branch.h\n@@ -0,0 +1,8 @@\n+#ifndef BRANCH_H\n+#define BRANCH_H\n+\n+void create_branch(const char *head,\n+\t\t   const char *name, const char *start_name,\n+\t\t   int force, int reflog, int track);\n+\n+#endif\ndiff --git a/builtin-branch.c b/builtin-branch.c\nindex 089cae5..1e0c9de 100644\n--- a/builtin-branch.c\n+++ b/builtin-branch.c\n@@ -12,6 +12,7 @@\n #include \"builtin.h\"\n #include \"remote.h\"\n #include \"parse-options.h\"\n+#include \"branch.h\"\n \n static const char * const builtin_branch_usage[] = {\n \t\"git-branch [options] [-r | -a]\",\n@@ -356,141 +357,6 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str\n \tfree_ref_list(&ref_list);\n }\n \n-struct tracking {\n-\tstruct refspec spec;\n-\tchar *src;\n-\tconst char *remote;\n-\tint matches;\n-};\n-\n-static int find_tracked_branch(struct remote *remote, void *priv)\n-{\n-\tstruct tracking *tracking = priv;\n-\n-\tif (!remote_find_tracking(remote, &tracking->spec)) {\n-\t\tif (++tracking->matches == 1) {\n-\t\t\ttracking->src = tracking->spec.src;\n-\t\t\ttracking->remote = remote->name;\n-\t\t} else {\n-\t\t\tfree(tracking->spec.src);\n-\t\t\tif (tracking->src) {\n-\t\t\t\tfree(tracking->src);\n-\t\t\t\ttracking->src = NULL;\n-\t\t\t}\n-\t\t}\n-\t\ttracking->spec.src = NULL;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-\n-/*\n- * This is called when new_ref is branched off of orig_ref, and tries\n- * to infer the settings for branch.<new_ref>.{remote,merge} from the\n- * config.\n- */\n-static int setup_tracking(const char *new_ref, const char *orig_ref)\n-{\n-\tchar key[1024];\n-\tstruct tracking tracking;\n-\n-\tif (strlen(new_ref) > 1024 - 7 - 7 - 1)\n-\t\treturn error(\"Tracking not set up: name too long: %s\",\n-\t\t\t\tnew_ref);\n-\n-\tmemset(&tracking, 0, sizeof(tracking));\n-\ttracking.spec.dst = (char *)orig_ref;\n-\tif (for_each_remote(find_tracked_branch, &tracking) ||\n-\t\t\t!tracking.matches)\n-\t\treturn 1;\n-\n-\tif (tracking.matches > 1)\n-\t\treturn error(\"Not tracking: ambiguous information for ref %s\",\n-\t\t\t\torig_ref);\n-\n-\tif (tracking.matches == 1) {\n-\t\tsprintf(key, \"branch.%s.remote\", new_ref);\n-\t\tgit_config_set(key, tracking.remote ?  tracking.remote : \".\");\n-\t\tsprintf(key, \"branch.%s.merge\", new_ref);\n-\t\tgit_config_set(key, tracking.src);\n-\t\tfree(tracking.src);\n-\t\tprintf(\"Branch %s set up to track remote branch %s.\\n\",\n-\t\t\t       new_ref, orig_ref);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static void create_branch(const char *name, const char *start_name,\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 *real_ref, ref[PATH_MAX], msg[PATH_MAX + 20];\n-\tint forcing = 0;\n-\n-\tsnprintf(ref, sizeof ref, \"refs/heads/%s\", name);\n-\tif (check_ref_format(ref))\n-\t\tdie(\"'%s' is not a valid branch name.\", name);\n-\n-\tif (resolve_ref(ref, sha1, 1, NULL)) {\n-\t\tif (!force)\n-\t\t\tdie(\"A branch named '%s' already exists.\", name);\n-\t\telse if (!is_bare_repository() && !strcmp(head, name))\n-\t\t\tdie(\"Cannot force update the current branch.\");\n-\t\tforcing = 1;\n-\t}\n-\n-\treal_ref = NULL;\n-\tif (get_sha1(start_name, sha1))\n-\t\tdie(\"Not a valid object name: '%s'.\", start_name);\n-\n-\tswitch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {\n-\tcase 0:\n-\t\t/* Not branching from any existing branch */\n-\t\treal_ref = NULL;\n-\t\tbreak;\n-\tcase 1:\n-\t\t/* Unique completion -- good */\n-\t\tbreak;\n-\tdefault:\n-\t\tdie(\"Ambiguous object name: '%s'.\", start_name);\n-\t\tbreak;\n-\t}\n-\n-\tif ((commit = lookup_commit_reference(sha1)) == NULL)\n-\t\tdie(\"Not a valid branch point: '%s'.\", start_name);\n-\thashcpy(sha1, commit->object.sha1);\n-\n-\tlock = lock_any_ref_for_update(ref, NULL, 0);\n-\tif (!lock)\n-\t\tdie(\"Failed to lock ref for update: %s.\", strerror(errno));\n-\n-\tif (reflog)\n-\t\tlog_all_ref_updates = 1;\n-\n-\tif (forcing)\n-\t\tsnprintf(msg, sizeof msg, \"branch: Reset from %s\",\n-\t\t\t start_name);\n-\telse\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   remotes registered via .git/config.  */\n-\tif (real_ref && track)\n-\t\tsetup_tracking(name, real_ref);\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 {\n \tchar oldref[PATH_MAX], newref[PATH_MAX], logmsg[PATH_MAX*2 + 100];\n@@ -611,7 +477,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \telse if (rename && (argc == 2))\n \t\trename_branch(argv[0], argv[1], rename > 1);\n \telse if (argc <= 2)\n-\t\tcreate_branch(argv[0], (argc == 2) ? argv[1] : head,\n+\t\tcreate_branch(head, argv[0], (argc == 2) ? argv[1] : head,\n \t\t\t      force_create, reflog, track);\n \telse\n \t\tusage_with_options(builtin_branch_usage, options);\n-- \n1.5.4\n"}]}