{"thread":{"id":"40663","subject":"[PATCH v5 00/26] refs backend pre-vtable","startedAt":"2015-10-28T02:14:01Z","lastAt":"2015-11-08T18:23:23Z","messageCount":67,"participants":["David Turner","Michael Haggerty","Junio C Hamano"],"isPatch":true,"patchVersion":5,"patchTotal":26},"messages":[{"id":"272367","messageId":"1445998467-11511-1-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":null,"subject":"[PATCH v5 00/26] refs backend pre-vtable","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:01Z","receivedAt":"2015-10-28T02:14:01Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"This version of the series makes some minor changes from v4:\n\nrefs.c: move refname_is_safe to the common code: clarify a comment\ninitdb: move safe_create_dir into common code: add a caveat on safe_create_dir\nrefs.c: move update_ref to refs.c: update commit message to include write_pseudoref\nrefs.c: move delete_pseudoref and delete_ref to the common code: remove spurious\nadded newline\nrefs: make files_log_ref_write functions public: reword commit message\nrefs.c: move ref iterators to the common code: added my DCO because this patch changed a bunch since Ronnie wrote it\n\nThanks to Michael and Junio for the reviews.\n\nThe rest of the patches:\nDavid Turner (9):\n  refs: make is_branch public\n  refs: move transaction functions into common code\n  refs.c: move refname_is_safe to the common code\n  refs.c: move copy_msg to the common code\n  refs.c: move peel_object to the common code\n  refs.c: move should_autocreate_reflog to common code\n  initdb: move safe_create_dir into common code\n  refs: make files_log_ref_write functions public\n  refs: break out ref conflict checks\n\nJeff King (1):\n  introduce \"extensions\" form of core.repositoryformatversion\n\nRonnie Sahlberg (16):\n  refs.c: create a public version of verify_refname_available\n  refs-be-files.c: rename refs to refs-be-files\n  refs.c: add a new refs.c file to hold all common refs code\n  refs.c: move update_ref to refs.c\n  refs.c: move delete_pseudoref and delete_ref to the common code\n  refs.c: move read_ref_at to the common refs file\n  refs.c: move the hidden refs functions to the common code\n  refs.c: move dwim and friend functions to the common refs code\n  refs.c: move warn_if_dangling_symref* to the common code\n  refs.c: move read_ref, read_ref_full and ref_exists to the common code\n  refs.c: move resolve_refdup to common\n  refs.c: move check_refname_format to the common code\n  refs.c: move is_branch to the common code\n  refs.c: move prettify_refname to the common code\n  refs.c: move ref iterators to the common code\n  refs.c: move head_ref_namespaced to the common code\n\n Documentation/technical/repository-version.txt |   81 +\n Makefile                                       |    1 +\n builtin/init-db.c                              |   12 -\n cache.h                                        |   11 +\n path.c                                         |   12 +\n refs-be-files.c                                | 3512 ++++++++++++++++\n refs.c                                         | 5172 ++++--------------------\n refs.h                                         |  187 +-\n setup.c                                        |   37 +-\n t/t1302-repo-version.sh                        |   38 +\n 10 files changed, 4644 insertions(+), 4419 deletions(-)\n create mode 100644 Documentation/technical/repository-version.txt\n create mode 100644 refs-be-files.c\n\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272369","messageId":"1445998467-11511-2-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 01/26] refs.c: create a public version of verify_refname_available","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:02Z","receivedAt":"2015-10-28T02:14:02Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nCreate a public version of verify_refname_available that backends can\nprovide.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c | 65 ++++++++++++++++++++++++++++++-----------------------------------\n refs.h | 20 ++++++++++++++++++++\n 2 files changed, 50 insertions(+), 35 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 132eff5..fe71ea0 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -279,7 +279,7 @@ struct ref_dir {\n  * presence of an empty subdirectory does not block the creation of a\n  * similarly-named reference.  (The fact that reference names with the\n  * same leading components can conflict *with each other* is a\n- * separate issue that is regulated by verify_refname_available().)\n+ * separate issue that is regulated by verify_refname_available_dir().)\n  *\n  * Please note that the name field contains the fully-qualified\n  * reference (or subdirectory) name.  Space could be saved by only\n@@ -897,25 +897,13 @@ static int nonmatching_ref_fn(struct ref_entry *entry, void *vdata)\n /*\n  * Return 0 if a reference named refname could be created without\n  * conflicting with the name of an existing reference in dir.\n- * Otherwise, return a negative value and write an explanation to err.\n- * If extras is non-NULL, it is a list of additional refnames with\n- * which refname is not allowed to conflict. If skip is non-NULL,\n- * ignore potential conflicts with refs in skip (e.g., because they\n- * are scheduled for deletion in the same operation). Behavior is\n- * undefined if the same name is listed in both extras and skip.\n- *\n- * Two reference names conflict if one of them exactly matches the\n- * leading components of the other; e.g., \"refs/foo/bar\" conflicts\n- * with both \"refs/foo\" and with \"refs/foo/bar/baz\" but not with\n- * \"refs/foo/bar\" or \"refs/foo/barbados\".\n- *\n- * extras and skip must be sorted.\n+ * See verify_refname_available for details.\n  */\n-static int verify_refname_available(const char *refname,\n-\t\t\t\t    const struct string_list *extras,\n-\t\t\t\t    const struct string_list *skip,\n-\t\t\t\t    struct ref_dir *dir,\n-\t\t\t\t    struct strbuf *err)\n+static int verify_refname_available_dir(const char *refname,\n+\t\t\t\t\tconst struct string_list *extras,\n+\t\t\t\t\tconst struct string_list *skip,\n+\t\t\t\t\tstruct ref_dir *dir,\n+\t\t\t\t\tstruct strbuf *err)\n {\n \tconst char *slash;\n \tint pos;\n@@ -2464,9 +2452,12 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \t\t */\n \t\tstrbuf_git_path(&orig_ref_file, \"%s\", orig_refname);\n \t\tif (remove_empty_directories(&orig_ref_file)) {\n+\t\t\tstruct ref_dir *loose_refs;\n+\t\t\tloose_refs = get_loose_refs(&ref_cache);\n \t\t\tlast_errno = errno;\n-\t\t\tif (!verify_refname_available(orig_refname, extras, skip,\n-\t\t\t\t\t\t      get_loose_refs(&ref_cache), err))\n+\t\t\tif (!verify_refname_available_dir(orig_refname, extras,\n+\t\t\t\t\t\t\t  skip, loose_refs,\n+\t\t\t\t\t\t\t  err))\n \t\t\t\tstrbuf_addf(err, \"there are still refs under '%s'\",\n \t\t\t\t\t    orig_refname);\n \t\t\tgoto error_return;\n@@ -2479,8 +2470,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \tif (!refname) {\n \t\tlast_errno = errno;\n \t\tif (last_errno != ENOTDIR ||\n-\t\t    !verify_refname_available(orig_refname, extras, skip,\n-\t\t\t\t\t      get_loose_refs(&ref_cache), err))\n+\t\t    !verify_refname_available_dir(orig_refname, extras, skip,\n+\t\t\t\t\t\t  get_loose_refs(&ref_cache),\n+\t\t\t\t\t\t  err))\n \t\t\tstrbuf_addf(err, \"unable to resolve reference %s: %s\",\n \t\t\t\t    orig_refname, strerror(last_errno));\n \n@@ -2493,8 +2485,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \t * our refname.\n \t */\n \tif (is_null_oid(&lock->old_oid) &&\n-\t    verify_refname_available(refname, extras, skip,\n-\t\t\t\t     get_packed_refs(&ref_cache), err)) {\n+\t    verify_refname_available_dir(refname, extras, skip,\n+\t\t\t\t\t get_packed_refs(&ref_cache), err)) {\n \t\tlast_errno = ENOTDIR;\n \t\tgoto error_return;\n \t}\n@@ -3127,10 +3119,7 @@ static int rename_ref_available(const char *oldname, const char *newname)\n \tint ret;\n \n \tstring_list_insert(&skip, oldname);\n-\tret = !verify_refname_available(newname, NULL, &skip,\n-\t\t\t\t\tget_packed_refs(&ref_cache), &err)\n-\t\t&& !verify_refname_available(newname, NULL, &skip,\n-\t\t\t\t\t     get_loose_refs(&ref_cache), &err);\n+\tret = !verify_refname_available(newname, NULL, &skip, &err);\n \tif (!ret)\n \t\terror(\"%s\", err.buf);\n \n@@ -3299,6 +3288,17 @@ static int should_autocreate_reflog(const char *refname)\n \t\t!strcmp(refname, \"HEAD\");\n }\n \n+int verify_refname_available(const char *newname, struct string_list *extra,\n+\t\t\t     struct string_list *skip, struct strbuf *err)\n+{\n+\tstruct ref_dir *packed_refs = get_packed_refs(&ref_cache);\n+\tstruct ref_dir *loose_refs = get_loose_refs(&ref_cache);\n+\treturn verify_refname_available_dir(newname, extra, skip,\n+\t\t\t\t\t    packed_refs, err) ||\n+\t\tverify_refname_available_dir(newname, extra, skip,\n+\t\t\t\t\t     loose_refs, err);\n+}\n+\n /*\n  * Create a reflog for a ref.  If force_create = 0, the reflog will\n  * only be created for certain refs (those for which\n@@ -4334,8 +4334,6 @@ static int ref_present(const char *refname,\n int initial_ref_transaction_commit(struct ref_transaction *transaction,\n \t\t\t\t   struct strbuf *err)\n {\n-\tstruct ref_dir *loose_refs = get_loose_refs(&ref_cache);\n-\tstruct ref_dir *packed_refs = get_packed_refs(&ref_cache);\n \tint ret = 0, i;\n \tint n = transaction->nr;\n \tstruct ref_update **updates = transaction->updates;\n@@ -4378,10 +4376,7 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,\n \t\t\tdie(\"BUG: initial ref transaction with old_sha1 set\");\n \t\tif (verify_refname_available(update->refname,\n \t\t\t\t\t     &affected_refnames, NULL,\n-\t\t\t\t\t     loose_refs, err) ||\n-\t\t    verify_refname_available(update->refname,\n-\t\t\t\t\t     &affected_refnames, NULL,\n-\t\t\t\t\t     packed_refs, err)) {\n+\t\t\t\t\t     err)) {\n \t\t\tret = TRANSACTION_NAME_CONFLICT;\n \t\t\tgoto cleanup;\n \t\t}\ndiff --git a/refs.h b/refs.h\nindex 6d30c98..7367a7f 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -218,6 +218,26 @@ extern void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct st\n int pack_refs(unsigned int flags);\n \n /*\n+ * Return 0 if a reference named refname could be created without\n+ * conflicting with the name of an existing reference.\n+ * Otherwise, return a negative value and write an explanation to err.\n+ * If extras is non-NULL, it is a list of additional refnames with\n+ * which refname is not allowed to conflict. If skip is non-NULL,\n+ * ignore potential conflicts with refs in skip (e.g., because they\n+ * are scheduled for deletion in the same operation). Behavior is\n+ * undefined if the same name is listed in both extras and skip.\n+ *\n+ * Two reference names conflict if one of them exactly matches the\n+ * leading components of the other; e.g., \"foo/bar\" conflicts with\n+ * both \"foo\" and with \"foo/bar/baz\" but not with \"foo/bar\" or\n+ * \"foo/barbados\".\n+ *\n+ * skip must be sorted.\n+ */\n+int verify_refname_available(const char *newname, struct string_list *extra,\n+\t\t\t     struct string_list *skip, struct strbuf *err);\n+\n+/*\n  * Flags controlling ref_transaction_update(), ref_transaction_create(), etc.\n  * REF_NODEREF: act on the ref directly, instead of dereferencing\n  *              symbolic references.\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272368","messageId":"1445998467-11511-3-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 02/26] refs: make is_branch public","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:03Z","receivedAt":"2015-10-28T02:14:03Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"is_branch was already non-static, but this patch declares it in the\nheader.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.h | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/refs.h b/refs.h\nindex 7367a7f..8408bef 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -237,6 +237,8 @@ int pack_refs(unsigned int flags);\n int verify_refname_available(const char *newname, struct string_list *extra,\n \t\t\t     struct string_list *skip, struct strbuf *err);\n \n+extern int is_branch(const char *refname);\n+\n /*\n  * Flags controlling ref_transaction_update(), ref_transaction_create(), etc.\n  * REF_NODEREF: act on the ref directly, instead of dereferencing\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272370","messageId":"1445998467-11511-4-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 03/26] refs-be-files.c: rename refs to refs-be-files","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:04Z","receivedAt":"2015-10-28T02:14:04Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nRename refs.c to refs-be-files.c to indicate that this file now\nholds the implementation for the files based refs backend.\nA smaller portion of the code in this file is backend agnostic and will\nbe moved to a new refs.c file that will hold all the common refs code\nthat is shared across all backends.\n\nA second reason for first moving all the code to the new file and then\nmove the backend agnostic code back to refs.c instead of the other way\naround is because the code that will eventually remain in this new\nrefs-be-files.c file is so entangled that it would then be very\ndifficult to break the split up into small independent patches/chunks.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Makefile                  | 2 +-\n refs.c => refs-be-files.c | 0\n 2 files changed, 1 insertion(+), 1 deletion(-)\n rename refs.c => refs-be-files.c (100%)\n\ndiff --git a/Makefile b/Makefile\nindex 0d9f5dd..173b9d4 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -762,7 +762,7 @@ LIB_OBJS += quote.o\n LIB_OBJS += reachable.o\n LIB_OBJS += read-cache.o\n LIB_OBJS += reflog-walk.o\n-LIB_OBJS += refs.o\n+LIB_OBJS += refs-be-files.o\n LIB_OBJS += ref-filter.o\n LIB_OBJS += remote.o\n LIB_OBJS += replace_object.o\ndiff --git a/refs.c b/refs-be-files.c\nsimilarity index 100%\nrename from refs.c\nrename to refs-be-files.c\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272371","messageId":"1445998467-11511-5-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 04/26] refs.c: add a new refs.c file to hold all common refs code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:05Z","receivedAt":"2015-10-28T02:14:05Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nCreate a new refs.c file that will be used to hold all the refs\ncode that is backend agnostic and will be shared across all backends.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Makefile | 1 +\n refs.c   | 3 +++\n 2 files changed, 4 insertions(+)\n create mode 100644 refs.c\n\ndiff --git a/Makefile b/Makefile\nindex 173b9d4..b37eae3 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -763,6 +763,7 @@ LIB_OBJS += reachable.o\n LIB_OBJS += read-cache.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += refs-be-files.o\n+LIB_OBJS += refs.o\n LIB_OBJS += ref-filter.o\n LIB_OBJS += remote.o\n LIB_OBJS += replace_object.o\ndiff --git a/refs.c b/refs.c\nnew file mode 100644\nindex 0000000..77492ff\n--- /dev/null\n+++ b/refs.c\n@@ -0,0 +1,3 @@\n+/*\n+ * Common refs code for all backends.\n+ */\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272393","messageId":"1445998467-11511-6-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 05/26] refs.c: move update_ref to refs.c","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:06Z","receivedAt":"2015-10-28T02:14:06Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nMove update_ref() to the refs.c file since this function does not\ncontain any backend specific code.  Move the ref classifier functions\nand write_pseudoref as well, since update_ref depends on them.\n\nBased on Ronnie Sahlberg's patch\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 117 +-------------------------------------------------------\n refs.c          | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 117 insertions(+), 116 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex fe71ea0..f03d68c 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -2675,8 +2675,6 @@ struct pack_refs_cb_data {\n \tstruct ref_to_prune *ref_to_prune;\n };\n \n-static int is_per_worktree_ref(const char *refname);\n-\n /*\n  * An each_ref_entry_fn that is run over loose references only.  If\n  * the loose reference can be packed, add an entry in the packed ref\n@@ -2691,7 +2689,7 @@ static int pack_if_possible_fn(struct ref_entry *entry, void *cb_data)\n \tint is_tag_ref = starts_with(entry->name, \"refs/tags/\");\n \n \t/* Do not pack per-worktree refs: */\n-\tif (is_per_worktree_ref(entry->name))\n+\tif (ref_type(entry->name) == REF_TYPE_PER_WORKTREE)\n \t\treturn 0;\n \n \t/* ALWAYS pack tags */\n@@ -2886,77 +2884,6 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)\n \treturn 0;\n }\n \n-static int is_per_worktree_ref(const char *refname)\n-{\n-\treturn !strcmp(refname, \"HEAD\") ||\n-\t\tstarts_with(refname, \"refs/bisect/\");\n-}\n-\n-static int is_pseudoref_syntax(const char *refname)\n-{\n-\tconst char *c;\n-\n-\tfor (c = refname; *c; c++) {\n-\t\tif (!isupper(*c) && *c != '-' && *c != '_')\n-\t\t\treturn 0;\n-\t}\n-\n-\treturn 1;\n-}\n-\n-enum ref_type ref_type(const char *refname)\n-{\n-\tif (is_per_worktree_ref(refname))\n-\t\treturn REF_TYPE_PER_WORKTREE;\n-\tif (is_pseudoref_syntax(refname))\n-\t\treturn REF_TYPE_PSEUDOREF;\n-       return REF_TYPE_NORMAL;\n-}\n-\n-static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,\n-\t\t\t   const unsigned char *old_sha1, struct strbuf *err)\n-{\n-\tconst char *filename;\n-\tint fd;\n-\tstatic struct lock_file lock;\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tint ret = -1;\n-\n-\tstrbuf_addf(&buf, \"%s\\n\", sha1_to_hex(sha1));\n-\n-\tfilename = git_path(\"%s\", pseudoref);\n-\tfd = hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR);\n-\tif (fd < 0) {\n-\t\tstrbuf_addf(err, \"Could not open '%s' for writing: %s\",\n-\t\t\t    filename, strerror(errno));\n-\t\treturn -1;\n-\t}\n-\n-\tif (old_sha1) {\n-\t\tunsigned char actual_old_sha1[20];\n-\n-\t\tif (read_ref(pseudoref, actual_old_sha1))\n-\t\t\tdie(\"could not read ref '%s'\", pseudoref);\n-\t\tif (hashcmp(actual_old_sha1, old_sha1)) {\n-\t\t\tstrbuf_addf(err, \"Unexpected sha1 when writing %s\", pseudoref);\n-\t\t\trollback_lock_file(&lock);\n-\t\t\tgoto done;\n-\t\t}\n-\t}\n-\n-\tif (write_in_full(fd, buf.buf, buf.len) != buf.len) {\n-\t\tstrbuf_addf(err, \"Could not write to '%s'\", filename);\n-\t\trollback_lock_file(&lock);\n-\t\tgoto done;\n-\t}\n-\n-\tcommit_lock_file(&lock);\n-\tret = 0;\n-done:\n-\tstrbuf_release(&buf);\n-\treturn ret;\n-}\n-\n static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1)\n {\n \tstatic struct lock_file lock;\n@@ -4105,48 +4032,6 @@ int ref_transaction_verify(struct ref_transaction *transaction,\n \t\t\t\t      flags, NULL, err);\n }\n \n-int update_ref(const char *msg, const char *refname,\n-\t       const unsigned char *new_sha1, const unsigned char *old_sha1,\n-\t       unsigned int flags, enum action_on_err onerr)\n-{\n-\tstruct ref_transaction *t = NULL;\n-\tstruct strbuf err = STRBUF_INIT;\n-\tint ret = 0;\n-\n-\tif (ref_type(refname) == REF_TYPE_PSEUDOREF) {\n-\t\tret = write_pseudoref(refname, new_sha1, old_sha1, &err);\n-\t} else {\n-\t\tt = ref_transaction_begin(&err);\n-\t\tif (!t ||\n-\t\t    ref_transaction_update(t, refname, new_sha1, old_sha1,\n-\t\t\t\t\t   flags, msg, &err) ||\n-\t\t    ref_transaction_commit(t, &err)) {\n-\t\t\tret = 1;\n-\t\t\tref_transaction_free(t);\n-\t\t}\n-\t}\n-\tif (ret) {\n-\t\tconst char *str = \"update_ref failed for ref '%s': %s\";\n-\n-\t\tswitch (onerr) {\n-\t\tcase UPDATE_REFS_MSG_ON_ERR:\n-\t\t\terror(str, refname, err.buf);\n-\t\t\tbreak;\n-\t\tcase UPDATE_REFS_DIE_ON_ERR:\n-\t\t\tdie(str, refname, err.buf);\n-\t\t\tbreak;\n-\t\tcase UPDATE_REFS_QUIET_ON_ERR:\n-\t\t\tbreak;\n-\t\t}\n-\t\tstrbuf_release(&err);\n-\t\treturn 1;\n-\t}\n-\tstrbuf_release(&err);\n-\tif (t)\n-\t\tref_transaction_free(t);\n-\treturn 0;\n-}\n-\n static int ref_update_reject_duplicates(struct string_list *refnames,\n \t\t\t\t\tstruct strbuf *err)\n {\ndiff --git a/refs.c b/refs.c\nindex 77492ff..610fab0 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1,3 +1,119 @@\n /*\n  * Common refs code for all backends.\n  */\n+#include \"cache.h\"\n+#include \"refs.h\"\n+#include \"lockfile.h\"\n+\n+static int is_per_worktree_ref(const char *refname)\n+{\n+\treturn !strcmp(refname, \"HEAD\") ||\n+\t\tstarts_with(refname, \"refs/bisect/\");\n+}\n+\n+static int is_pseudoref_syntax(const char *refname)\n+{\n+\tconst char *c;\n+\n+\tfor (c = refname; *c; c++) {\n+\t\tif (!isupper(*c) && *c != '-' && *c != '_')\n+\t\t\treturn 0;\n+\t}\n+\n+\treturn 1;\n+}\n+\n+enum ref_type ref_type(const char *refname)\n+{\n+\tif (is_per_worktree_ref(refname))\n+\t\treturn REF_TYPE_PER_WORKTREE;\n+\tif (is_pseudoref_syntax(refname))\n+\t\treturn REF_TYPE_PSEUDOREF;\n+       return REF_TYPE_NORMAL;\n+}\n+\n+static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,\n+\t\t\t   const unsigned char *old_sha1, struct strbuf *err)\n+{\n+\tconst char *filename;\n+\tint fd;\n+\tstatic struct lock_file lock;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint ret = -1;\n+\n+\tstrbuf_addf(&buf, \"%s\\n\", sha1_to_hex(sha1));\n+\n+\tfilename = git_path(\"%s\", pseudoref);\n+\tfd = hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR);\n+\tif (fd < 0) {\n+\t\tstrbuf_addf(err, \"Could not open '%s' for writing: %s\",\n+\t\t\t    filename, strerror(errno));\n+\t\treturn -1;\n+\t}\n+\n+\tif (old_sha1) {\n+\t\tunsigned char actual_old_sha1[20];\n+\n+\t\tif (read_ref(pseudoref, actual_old_sha1))\n+\t\t\tdie(\"could not read ref '%s'\", pseudoref);\n+\t\tif (hashcmp(actual_old_sha1, old_sha1)) {\n+\t\t\tstrbuf_addf(err, \"Unexpected sha1 when writing %s\", pseudoref);\n+\t\t\trollback_lock_file(&lock);\n+\t\t\tgoto done;\n+\t\t}\n+\t}\n+\n+\tif (write_in_full(fd, buf.buf, buf.len) != buf.len) {\n+\t\tstrbuf_addf(err, \"Could not write to '%s'\", filename);\n+\t\trollback_lock_file(&lock);\n+\t\tgoto done;\n+\t}\n+\n+\tcommit_lock_file(&lock);\n+\tret = 0;\n+done:\n+\tstrbuf_release(&buf);\n+\treturn ret;\n+}\n+\n+int update_ref(const char *msg, const char *refname,\n+\t       const unsigned char *new_sha1, const unsigned char *old_sha1,\n+\t       unsigned int flags, enum action_on_err onerr)\n+{\n+\tstruct ref_transaction *t = NULL;\n+\tstruct strbuf err = STRBUF_INIT;\n+\tint ret = 0;\n+\n+\tif (ref_type(refname) == REF_TYPE_PSEUDOREF) {\n+\t\tret = write_pseudoref(refname, new_sha1, old_sha1, &err);\n+\t} else {\n+\t\tt = ref_transaction_begin(&err);\n+\t\tif (!t ||\n+\t\t    ref_transaction_update(t, refname, new_sha1, old_sha1,\n+\t\t\t\t\t   flags, msg, &err) ||\n+\t\t    ref_transaction_commit(t, &err)) {\n+\t\t\tret = 1;\n+\t\t\tref_transaction_free(t);\n+\t\t}\n+\t}\n+\tif (ret) {\n+\t\tconst char *str = \"update_ref failed for ref '%s': %s\";\n+\n+\t\tswitch (onerr) {\n+\t\tcase UPDATE_REFS_MSG_ON_ERR:\n+\t\t\terror(str, refname, err.buf);\n+\t\t\tbreak;\n+\t\tcase UPDATE_REFS_DIE_ON_ERR:\n+\t\t\tdie(str, refname, err.buf);\n+\t\t\tbreak;\n+\t\tcase UPDATE_REFS_QUIET_ON_ERR:\n+\t\t\tbreak;\n+\t\t}\n+\t\tstrbuf_release(&err);\n+\t\treturn 1;\n+\t}\n+\tstrbuf_release(&err);\n+\tif (t)\n+\t\tref_transaction_free(t);\n+\treturn 0;\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272372","messageId":"1445998467-11511-7-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 06/26] refs.c: move delete_pseudoref and delete_ref to the common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:07Z","receivedAt":"2015-10-28T02:14:07Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nMove delete_pseudoref() and delete_ref() to the refs.c file since\nthese functions do not contain any backend specific code.  We can't\nmove delete_refs yet because it depends on the files-backend-specific\nrepack_without_refs.\n\nBased on a patch by Ronnie Sahlberg.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 56 --------------------------------------------------------\n refs.c          | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 56 insertions(+), 56 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex f03d68c..de99c93 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -2884,62 +2884,6 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)\n \treturn 0;\n }\n \n-static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1)\n-{\n-\tstatic struct lock_file lock;\n-\tconst char *filename;\n-\n-\tfilename = git_path(\"%s\", pseudoref);\n-\n-\tif (old_sha1 && !is_null_sha1(old_sha1)) {\n-\t\tint fd;\n-\t\tunsigned char actual_old_sha1[20];\n-\n-\t\tfd = hold_lock_file_for_update(&lock, filename,\n-\t\t\t\t\t       LOCK_DIE_ON_ERROR);\n-\t\tif (fd < 0)\n-\t\t\tdie_errno(_(\"Could not open '%s' for writing\"), filename);\n-\t\tif (read_ref(pseudoref, actual_old_sha1))\n-\t\t\tdie(\"could not read ref '%s'\", pseudoref);\n-\t\tif (hashcmp(actual_old_sha1, old_sha1)) {\n-\t\t\twarning(\"Unexpected sha1 when deleting %s\", pseudoref);\n-\t\t\trollback_lock_file(&lock);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tunlink(filename);\n-\t\trollback_lock_file(&lock);\n-\t} else {\n-\t\tunlink(filename);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-int delete_ref(const char *refname, const unsigned char *old_sha1,\n-\t       unsigned int flags)\n-{\n-\tstruct ref_transaction *transaction;\n-\tstruct strbuf err = STRBUF_INIT;\n-\n-\tif (ref_type(refname) == REF_TYPE_PSEUDOREF)\n-\t\treturn delete_pseudoref(refname, old_sha1);\n-\n-\ttransaction = ref_transaction_begin(&err);\n-\tif (!transaction ||\n-\t    ref_transaction_delete(transaction, refname, old_sha1,\n-\t\t\t\t   flags, NULL, &err) ||\n-\t    ref_transaction_commit(transaction, &err)) {\n-\t\terror(\"%s\", err.buf);\n-\t\tref_transaction_free(transaction);\n-\t\tstrbuf_release(&err);\n-\t\treturn 1;\n-\t}\n-\tref_transaction_free(transaction);\n-\tstrbuf_release(&err);\n-\treturn 0;\n-}\n-\n int delete_refs(struct string_list *refnames)\n {\n \tstruct strbuf err = STRBUF_INIT;\ndiff --git a/refs.c b/refs.c\nindex 610fab0..d9a713b 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -117,3 +117,59 @@ int update_ref(const char *msg, const char *refname,\n \t\tref_transaction_free(t);\n \treturn 0;\n }\n+\n+static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1)\n+{\n+\tstatic struct lock_file lock;\n+\tconst char *filename;\n+\n+\tfilename = git_path(\"%s\", pseudoref);\n+\n+\tif (old_sha1 && !is_null_sha1(old_sha1)) {\n+\t\tint fd;\n+\t\tunsigned char actual_old_sha1[20];\n+\n+\t\tfd = hold_lock_file_for_update(&lock, filename,\n+\t\t\t\t\t       LOCK_DIE_ON_ERROR);\n+\t\tif (fd < 0)\n+\t\t\tdie_errno(_(\"Could not open '%s' for writing\"), filename);\n+\t\tif (read_ref(pseudoref, actual_old_sha1))\n+\t\t\tdie(\"could not read ref '%s'\", pseudoref);\n+\t\tif (hashcmp(actual_old_sha1, old_sha1)) {\n+\t\t\twarning(\"Unexpected sha1 when deleting %s\", pseudoref);\n+\t\t\trollback_lock_file(&lock);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tunlink(filename);\n+\t\trollback_lock_file(&lock);\n+\t} else {\n+\t\tunlink(filename);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int delete_ref(const char *refname, const unsigned char *old_sha1,\n+\t       unsigned int flags)\n+{\n+\tstruct ref_transaction *transaction;\n+\tstruct strbuf err = STRBUF_INIT;\n+\n+\tif (ref_type(refname) == REF_TYPE_PSEUDOREF)\n+\t\treturn delete_pseudoref(refname, old_sha1);\n+\n+\ttransaction = ref_transaction_begin(&err);\n+\tif (!transaction ||\n+\t    ref_transaction_delete(transaction, refname, old_sha1,\n+\t\t\t\t   flags, NULL, &err) ||\n+\t    ref_transaction_commit(transaction, &err)) {\n+\t\terror(\"%s\", err.buf);\n+\t\tref_transaction_free(transaction);\n+\t\tstrbuf_release(&err);\n+\t\treturn 1;\n+\t}\n+\tref_transaction_free(transaction);\n+\tstrbuf_release(&err);\n+\treturn 0;\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272373","messageId":"1445998467-11511-8-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 07/26] refs.c: move read_ref_at to the common refs file","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:08Z","receivedAt":"2015-10-28T02:14:08Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nMove read_ref_at() to the refs.c file since this function does not\ncontain any backend specific code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 118 --------------------------------------------------------\n refs.c          | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 118 insertions(+), 118 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex de99c93..841fa6d 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -3469,124 +3469,6 @@ int create_symref(const char *ref_target, const char *refs_heads_master,\n \treturn 0;\n }\n \n-struct read_ref_at_cb {\n-\tconst char *refname;\n-\tunsigned long at_time;\n-\tint cnt;\n-\tint reccnt;\n-\tunsigned char *sha1;\n-\tint found_it;\n-\n-\tunsigned char osha1[20];\n-\tunsigned char nsha1[20];\n-\tint tz;\n-\tunsigned long date;\n-\tchar **msg;\n-\tunsigned long *cutoff_time;\n-\tint *cutoff_tz;\n-\tint *cutoff_cnt;\n-};\n-\n-static int read_ref_at_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n-\t\tconst char *message, void *cb_data)\n-{\n-\tstruct read_ref_at_cb *cb = cb_data;\n-\n-\tcb->reccnt++;\n-\tcb->tz = tz;\n-\tcb->date = timestamp;\n-\n-\tif (timestamp <= cb->at_time || cb->cnt == 0) {\n-\t\tif (cb->msg)\n-\t\t\t*cb->msg = xstrdup(message);\n-\t\tif (cb->cutoff_time)\n-\t\t\t*cb->cutoff_time = timestamp;\n-\t\tif (cb->cutoff_tz)\n-\t\t\t*cb->cutoff_tz = tz;\n-\t\tif (cb->cutoff_cnt)\n-\t\t\t*cb->cutoff_cnt = cb->reccnt - 1;\n-\t\t/*\n-\t\t * we have not yet updated cb->[n|o]sha1 so they still\n-\t\t * hold the values for the previous record.\n-\t\t */\n-\t\tif (!is_null_sha1(cb->osha1)) {\n-\t\t\thashcpy(cb->sha1, nsha1);\n-\t\t\tif (hashcmp(cb->osha1, nsha1))\n-\t\t\t\twarning(\"Log for ref %s has gap after %s.\",\n-\t\t\t\t\tcb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));\n-\t\t}\n-\t\telse if (cb->date == cb->at_time)\n-\t\t\thashcpy(cb->sha1, nsha1);\n-\t\telse if (hashcmp(nsha1, cb->sha1))\n-\t\t\twarning(\"Log for ref %s unexpectedly ended on %s.\",\n-\t\t\t\tcb->refname, show_date(cb->date, cb->tz,\n-\t\t\t\t\t\t       DATE_MODE(RFC2822)));\n-\t\thashcpy(cb->osha1, osha1);\n-\t\thashcpy(cb->nsha1, nsha1);\n-\t\tcb->found_it = 1;\n-\t\treturn 1;\n-\t}\n-\thashcpy(cb->osha1, osha1);\n-\thashcpy(cb->nsha1, nsha1);\n-\tif (cb->cnt > 0)\n-\t\tcb->cnt--;\n-\treturn 0;\n-}\n-\n-static int read_ref_at_ent_oldest(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t\t  const char *email, unsigned long timestamp,\n-\t\t\t\t  int tz, const char *message, void *cb_data)\n-{\n-\tstruct read_ref_at_cb *cb = cb_data;\n-\n-\tif (cb->msg)\n-\t\t*cb->msg = xstrdup(message);\n-\tif (cb->cutoff_time)\n-\t\t*cb->cutoff_time = timestamp;\n-\tif (cb->cutoff_tz)\n-\t\t*cb->cutoff_tz = tz;\n-\tif (cb->cutoff_cnt)\n-\t\t*cb->cutoff_cnt = cb->reccnt;\n-\thashcpy(cb->sha1, osha1);\n-\tif (is_null_sha1(cb->sha1))\n-\t\thashcpy(cb->sha1, nsha1);\n-\t/* We just want the first entry */\n-\treturn 1;\n-}\n-\n-int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,\n-\t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n-{\n-\tstruct read_ref_at_cb cb;\n-\n-\tmemset(&cb, 0, sizeof(cb));\n-\tcb.refname = refname;\n-\tcb.at_time = at_time;\n-\tcb.cnt = cnt;\n-\tcb.msg = msg;\n-\tcb.cutoff_time = cutoff_time;\n-\tcb.cutoff_tz = cutoff_tz;\n-\tcb.cutoff_cnt = cutoff_cnt;\n-\tcb.sha1 = sha1;\n-\n-\tfor_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);\n-\n-\tif (!cb.reccnt) {\n-\t\tif (flags & GET_SHA1_QUIETLY)\n-\t\t\texit(128);\n-\t\telse\n-\t\t\tdie(\"Log for %s is empty.\", refname);\n-\t}\n-\tif (cb.found_it)\n-\t\treturn 0;\n-\n-\tfor_each_reflog_ent(refname, read_ref_at_ent_oldest, &cb);\n-\n-\treturn 1;\n-}\n-\n int reflog_exists(const char *refname)\n {\n \tstruct stat st;\ndiff --git a/refs.c b/refs.c\nindex d9a713b..751219c 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -173,3 +173,121 @@ int delete_ref(const char *refname, const unsigned char *old_sha1,\n \tstrbuf_release(&err);\n \treturn 0;\n }\n+\n+struct read_ref_at_cb {\n+\tconst char *refname;\n+\tunsigned long at_time;\n+\tint cnt;\n+\tint reccnt;\n+\tunsigned char *sha1;\n+\tint found_it;\n+\n+\tunsigned char osha1[20];\n+\tunsigned char nsha1[20];\n+\tint tz;\n+\tunsigned long date;\n+\tchar **msg;\n+\tunsigned long *cutoff_time;\n+\tint *cutoff_tz;\n+\tint *cutoff_cnt;\n+};\n+\n+static int read_ref_at_ent(unsigned char *osha1, unsigned char *nsha1,\n+\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *message, void *cb_data)\n+{\n+\tstruct read_ref_at_cb *cb = cb_data;\n+\n+\tcb->reccnt++;\n+\tcb->tz = tz;\n+\tcb->date = timestamp;\n+\n+\tif (timestamp <= cb->at_time || cb->cnt == 0) {\n+\t\tif (cb->msg)\n+\t\t\t*cb->msg = xstrdup(message);\n+\t\tif (cb->cutoff_time)\n+\t\t\t*cb->cutoff_time = timestamp;\n+\t\tif (cb->cutoff_tz)\n+\t\t\t*cb->cutoff_tz = tz;\n+\t\tif (cb->cutoff_cnt)\n+\t\t\t*cb->cutoff_cnt = cb->reccnt - 1;\n+\t\t/*\n+\t\t * we have not yet updated cb->[n|o]sha1 so they still\n+\t\t * hold the values for the previous record.\n+\t\t */\n+\t\tif (!is_null_sha1(cb->osha1)) {\n+\t\t\thashcpy(cb->sha1, nsha1);\n+\t\t\tif (hashcmp(cb->osha1, nsha1))\n+\t\t\t\twarning(\"Log for ref %s has gap after %s.\",\n+\t\t\t\t\tcb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));\n+\t\t}\n+\t\telse if (cb->date == cb->at_time)\n+\t\t\thashcpy(cb->sha1, nsha1);\n+\t\telse if (hashcmp(nsha1, cb->sha1))\n+\t\t\twarning(\"Log for ref %s unexpectedly ended on %s.\",\n+\t\t\t\tcb->refname, show_date(cb->date, cb->tz,\n+\t\t\t\t\t\t       DATE_MODE(RFC2822)));\n+\t\thashcpy(cb->osha1, osha1);\n+\t\thashcpy(cb->nsha1, nsha1);\n+\t\tcb->found_it = 1;\n+\t\treturn 1;\n+\t}\n+\thashcpy(cb->osha1, osha1);\n+\thashcpy(cb->nsha1, nsha1);\n+\tif (cb->cnt > 0)\n+\t\tcb->cnt--;\n+\treturn 0;\n+}\n+\n+static int read_ref_at_ent_oldest(unsigned char *osha1, unsigned char *nsha1,\n+\t\t\t\t  const char *email, unsigned long timestamp,\n+\t\t\t\t  int tz, const char *message, void *cb_data)\n+{\n+\tstruct read_ref_at_cb *cb = cb_data;\n+\n+\tif (cb->msg)\n+\t\t*cb->msg = xstrdup(message);\n+\tif (cb->cutoff_time)\n+\t\t*cb->cutoff_time = timestamp;\n+\tif (cb->cutoff_tz)\n+\t\t*cb->cutoff_tz = tz;\n+\tif (cb->cutoff_cnt)\n+\t\t*cb->cutoff_cnt = cb->reccnt;\n+\thashcpy(cb->sha1, osha1);\n+\tif (is_null_sha1(cb->sha1))\n+\t\thashcpy(cb->sha1, nsha1);\n+\t/* We just want the first entry */\n+\treturn 1;\n+}\n+\n+int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,\n+\t\tunsigned char *sha1, char **msg,\n+\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n+{\n+\tstruct read_ref_at_cb cb;\n+\n+\tmemset(&cb, 0, sizeof(cb));\n+\tcb.refname = refname;\n+\tcb.at_time = at_time;\n+\tcb.cnt = cnt;\n+\tcb.msg = msg;\n+\tcb.cutoff_time = cutoff_time;\n+\tcb.cutoff_tz = cutoff_tz;\n+\tcb.cutoff_cnt = cutoff_cnt;\n+\tcb.sha1 = sha1;\n+\n+\tfor_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);\n+\n+\tif (!cb.reccnt) {\n+\t\tif (flags & GET_SHA1_QUIETLY)\n+\t\t\texit(128);\n+\t\telse\n+\t\t\tdie(\"Log for %s is empty.\", refname);\n+\t}\n+\tif (cb.found_it)\n+\t\treturn 0;\n+\n+\tfor_each_reflog_ent(refname, read_ref_at_ent_oldest, &cb);\n+\n+\treturn 1;\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272392","messageId":"1445998467-11511-9-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 08/26] refs.c: move the hidden refs functions to the common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:09Z","receivedAt":"2015-10-28T02:14:09Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nMove the hidden refs functions to the refs.c file since these\nfunctions do not contain any backend specific code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 51 ---------------------------------------------------\n refs.c          | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 51 insertions(+), 51 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex 841fa6d..8be8405 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -4214,57 +4214,6 @@ char *shorten_unambiguous_ref(const char *refname, int strict)\n \treturn xstrdup(refname);\n }\n \n-static struct string_list *hide_refs;\n-\n-int parse_hide_refs_config(const char *var, const char *value, const char *section)\n-{\n-\tif (!strcmp(\"transfer.hiderefs\", var) ||\n-\t    /* NEEDSWORK: use parse_config_key() once both are merged */\n-\t    (starts_with(var, section) && var[strlen(section)] == '.' &&\n-\t     !strcmp(var + strlen(section), \".hiderefs\"))) {\n-\t\tchar *ref;\n-\t\tint len;\n-\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\tref = xstrdup(value);\n-\t\tlen = strlen(ref);\n-\t\twhile (len && ref[len - 1] == '/')\n-\t\t\tref[--len] = '\\0';\n-\t\tif (!hide_refs) {\n-\t\t\thide_refs = xcalloc(1, sizeof(*hide_refs));\n-\t\t\thide_refs->strdup_strings = 1;\n-\t\t}\n-\t\tstring_list_append(hide_refs, ref);\n-\t}\n-\treturn 0;\n-}\n-\n-int ref_is_hidden(const char *refname)\n-{\n-\tint i;\n-\n-\tif (!hide_refs)\n-\t\treturn 0;\n-\tfor (i = hide_refs->nr - 1; i >= 0; i--) {\n-\t\tconst char *match = hide_refs->items[i].string;\n-\t\tint neg = 0;\n-\t\tint len;\n-\n-\t\tif (*match == '!') {\n-\t\t\tneg = 1;\n-\t\t\tmatch++;\n-\t\t}\n-\n-\t\tif (!starts_with(refname, match))\n-\t\t\tcontinue;\n-\t\tlen = strlen(match);\n-\t\tif (!refname[len] || refname[len] == '/')\n-\t\t\treturn !neg;\n-\t}\n-\treturn 0;\n-}\n-\n struct expire_reflog_cb {\n \tunsigned int flags;\n \treflog_expiry_should_prune_fn *should_prune_fn;\ndiff --git a/refs.c b/refs.c\nindex 751219c..071784c 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -291,3 +291,54 @@ int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time,\n \n \treturn 1;\n }\n+\n+static struct string_list *hide_refs;\n+\n+int parse_hide_refs_config(const char *var, const char *value, const char *section)\n+{\n+\tif (!strcmp(\"transfer.hiderefs\", var) ||\n+\t    /* NEEDSWORK: use parse_config_key() once both are merged */\n+\t    (starts_with(var, section) && var[strlen(section)] == '.' &&\n+\t     !strcmp(var + strlen(section), \".hiderefs\"))) {\n+\t\tchar *ref;\n+\t\tint len;\n+\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tref = xstrdup(value);\n+\t\tlen = strlen(ref);\n+\t\twhile (len && ref[len - 1] == '/')\n+\t\t\tref[--len] = '\\0';\n+\t\tif (!hide_refs) {\n+\t\t\thide_refs = xcalloc(1, sizeof(*hide_refs));\n+\t\t\thide_refs->strdup_strings = 1;\n+\t\t}\n+\t\tstring_list_append(hide_refs, ref);\n+\t}\n+\treturn 0;\n+}\n+\n+int ref_is_hidden(const char *refname)\n+{\n+\tint i;\n+\n+\tif (!hide_refs)\n+\t\treturn 0;\n+\tfor (i = hide_refs->nr - 1; i >= 0; i--) {\n+\t\tconst char *match = hide_refs->items[i].string;\n+\t\tint neg = 0;\n+\t\tint len;\n+\n+\t\tif (*match == '!') {\n+\t\t\tneg = 1;\n+\t\t\tmatch++;\n+\t\t}\n+\n+\t\tif (!starts_with(refname, match))\n+\t\t\tcontinue;\n+\t\tlen = strlen(match);\n+\t\tif (!refname[len] || refname[len] == '/')\n+\t\t\treturn !neg;\n+\t}\n+\treturn 0;\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272374","messageId":"1445998467-11511-10-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 09/26] refs.c: move dwim and friend functions to the common refs code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:10Z","receivedAt":"2015-10-28T02:14:10Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nThese functions do not contain any backend specific code so we move\nthem to the common code and share across all backends.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 203 --------------------------------------------------------\n refs.c          | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 203 insertions(+), 203 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex 8be8405..b74b6cc 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -2247,30 +2247,6 @@ const char *prettify_refname(const char *name)\n \t\t0);\n }\n \n-static const char *ref_rev_parse_rules[] = {\n-\t\"%.*s\",\n-\t\"refs/%.*s\",\n-\t\"refs/tags/%.*s\",\n-\t\"refs/heads/%.*s\",\n-\t\"refs/remotes/%.*s\",\n-\t\"refs/remotes/%.*s/HEAD\",\n-\tNULL\n-};\n-\n-int refname_match(const char *abbrev_name, const char *full_name)\n-{\n-\tconst char **p;\n-\tconst int abbrev_name_len = strlen(abbrev_name);\n-\n-\tfor (p = ref_rev_parse_rules; *p; p++) {\n-\t\tif (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) {\n-\t\t\treturn 1;\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-}\n-\n static void unlock_ref(struct ref_lock *lock)\n {\n \t/* Do not free lock->lk -- atexit() still looks at them */\n@@ -2323,92 +2299,6 @@ static int remove_empty_directories(struct strbuf *path)\n }\n \n /*\n- * *string and *len will only be substituted, and *string returned (for\n- * later free()ing) if the string passed in is a magic short-hand form\n- * to name a branch.\n- */\n-static char *substitute_branch_name(const char **string, int *len)\n-{\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tint ret = interpret_branch_name(*string, *len, &buf);\n-\n-\tif (ret == *len) {\n-\t\tsize_t size;\n-\t\t*string = strbuf_detach(&buf, &size);\n-\t\t*len = size;\n-\t\treturn (char *)*string;\n-\t}\n-\n-\treturn NULL;\n-}\n-\n-int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)\n-{\n-\tchar *last_branch = substitute_branch_name(&str, &len);\n-\tconst char **p, *r;\n-\tint refs_found = 0;\n-\n-\t*ref = NULL;\n-\tfor (p = ref_rev_parse_rules; *p; p++) {\n-\t\tchar fullref[PATH_MAX];\n-\t\tunsigned char sha1_from_ref[20];\n-\t\tunsigned char *this_result;\n-\t\tint flag;\n-\n-\t\tthis_result = refs_found ? sha1_from_ref : sha1;\n-\t\tmksnpath(fullref, sizeof(fullref), *p, len, str);\n-\t\tr = resolve_ref_unsafe(fullref, RESOLVE_REF_READING,\n-\t\t\t\t       this_result, &flag);\n-\t\tif (r) {\n-\t\t\tif (!refs_found++)\n-\t\t\t\t*ref = xstrdup(r);\n-\t\t\tif (!warn_ambiguous_refs)\n-\t\t\t\tbreak;\n-\t\t} else if ((flag & REF_ISSYMREF) && strcmp(fullref, \"HEAD\")) {\n-\t\t\twarning(\"ignoring dangling symref %s.\", fullref);\n-\t\t} else if ((flag & REF_ISBROKEN) && strchr(fullref, '/')) {\n-\t\t\twarning(\"ignoring broken ref %s.\", fullref);\n-\t\t}\n-\t}\n-\tfree(last_branch);\n-\treturn refs_found;\n-}\n-\n-int dwim_log(const char *str, int len, unsigned char *sha1, char **log)\n-{\n-\tchar *last_branch = substitute_branch_name(&str, &len);\n-\tconst char **p;\n-\tint logs_found = 0;\n-\n-\t*log = NULL;\n-\tfor (p = ref_rev_parse_rules; *p; p++) {\n-\t\tunsigned char hash[20];\n-\t\tchar path[PATH_MAX];\n-\t\tconst char *ref, *it;\n-\n-\t\tmksnpath(path, sizeof(path), *p, len, str);\n-\t\tref = resolve_ref_unsafe(path, RESOLVE_REF_READING,\n-\t\t\t\t\t hash, NULL);\n-\t\tif (!ref)\n-\t\t\tcontinue;\n-\t\tif (reflog_exists(path))\n-\t\t\tit = path;\n-\t\telse if (strcmp(ref, path) && reflog_exists(ref))\n-\t\t\tit = ref;\n-\t\telse\n-\t\t\tcontinue;\n-\t\tif (!logs_found++) {\n-\t\t\t*log = xstrdup(it);\n-\t\t\thashcpy(sha1, hash);\n-\t\t}\n-\t\tif (!warn_ambiguous_refs)\n-\t\t\tbreak;\n-\t}\n-\tfree(last_branch);\n-\treturn logs_found;\n-}\n-\n-/*\n  * Locks a ref returning the lock on success and NULL on failure.\n  * On failure errno is set to something meaningful.\n  */\n@@ -4121,99 +4011,6 @@ cleanup:\n \treturn ret;\n }\n \n-char *shorten_unambiguous_ref(const char *refname, int strict)\n-{\n-\tint i;\n-\tstatic char **scanf_fmts;\n-\tstatic int nr_rules;\n-\tchar *short_name;\n-\n-\tif (!nr_rules) {\n-\t\t/*\n-\t\t * Pre-generate scanf formats from ref_rev_parse_rules[].\n-\t\t * Generate a format suitable for scanf from a\n-\t\t * ref_rev_parse_rules rule by interpolating \"%s\" at the\n-\t\t * location of the \"%.*s\".\n-\t\t */\n-\t\tsize_t total_len = 0;\n-\t\tsize_t offset = 0;\n-\n-\t\t/* the rule list is NULL terminated, count them first */\n-\t\tfor (nr_rules = 0; ref_rev_parse_rules[nr_rules]; nr_rules++)\n-\t\t\t/* -2 for strlen(\"%.*s\") - strlen(\"%s\"); +1 for NUL */\n-\t\t\ttotal_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;\n-\n-\t\tscanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);\n-\n-\t\toffset = 0;\n-\t\tfor (i = 0; i < nr_rules; i++) {\n-\t\t\tassert(offset < total_len);\n-\t\t\tscanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset;\n-\t\t\toffset += snprintf(scanf_fmts[i], total_len - offset,\n-\t\t\t\t\t   ref_rev_parse_rules[i], 2, \"%s\") + 1;\n-\t\t}\n-\t}\n-\n-\t/* bail out if there are no rules */\n-\tif (!nr_rules)\n-\t\treturn xstrdup(refname);\n-\n-\t/* buffer for scanf result, at most refname must fit */\n-\tshort_name = xstrdup(refname);\n-\n-\t/* skip first rule, it will always match */\n-\tfor (i = nr_rules - 1; i > 0 ; --i) {\n-\t\tint j;\n-\t\tint rules_to_fail = i;\n-\t\tint short_name_len;\n-\n-\t\tif (1 != sscanf(refname, scanf_fmts[i], short_name))\n-\t\t\tcontinue;\n-\n-\t\tshort_name_len = strlen(short_name);\n-\n-\t\t/*\n-\t\t * in strict mode, all (except the matched one) rules\n-\t\t * must fail to resolve to a valid non-ambiguous ref\n-\t\t */\n-\t\tif (strict)\n-\t\t\trules_to_fail = nr_rules;\n-\n-\t\t/*\n-\t\t * check if the short name resolves to a valid ref,\n-\t\t * but use only rules prior to the matched one\n-\t\t */\n-\t\tfor (j = 0; j < rules_to_fail; j++) {\n-\t\t\tconst char *rule = ref_rev_parse_rules[j];\n-\t\t\tchar refname[PATH_MAX];\n-\n-\t\t\t/* skip matched rule */\n-\t\t\tif (i == j)\n-\t\t\t\tcontinue;\n-\n-\t\t\t/*\n-\t\t\t * the short name is ambiguous, if it resolves\n-\t\t\t * (with this previous rule) to a valid ref\n-\t\t\t * read_ref() returns 0 on success\n-\t\t\t */\n-\t\t\tmksnpath(refname, sizeof(refname),\n-\t\t\t\t rule, short_name_len, short_name);\n-\t\t\tif (ref_exists(refname))\n-\t\t\t\tbreak;\n-\t\t}\n-\n-\t\t/*\n-\t\t * short name is non-ambiguous if all previous rules\n-\t\t * haven't resolved to a valid ref\n-\t\t */\n-\t\tif (j == rules_to_fail)\n-\t\t\treturn short_name;\n-\t}\n-\n-\tfree(short_name);\n-\treturn xstrdup(refname);\n-}\n-\n struct expire_reflog_cb {\n \tunsigned int flags;\n \treflog_expiry_should_prune_fn *should_prune_fn;\ndiff --git a/refs.c b/refs.c\nindex 071784c..e0bc031 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -342,3 +342,206 @@ int ref_is_hidden(const char *refname)\n \t}\n \treturn 0;\n }\n+\n+static const char *ref_rev_parse_rules[] = {\n+\t\"%.*s\",\n+\t\"refs/%.*s\",\n+\t\"refs/tags/%.*s\",\n+\t\"refs/heads/%.*s\",\n+\t\"refs/remotes/%.*s\",\n+\t\"refs/remotes/%.*s/HEAD\",\n+\tNULL\n+};\n+\n+int refname_match(const char *abbrev_name, const char *full_name)\n+{\n+\tconst char **p;\n+\tconst int abbrev_name_len = strlen(abbrev_name);\n+\n+\tfor (p = ref_rev_parse_rules; *p; p++) {\n+\t\tif (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) {\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * *string and *len will only be substituted, and *string returned (for\n+ * later free()ing) if the string passed in is a magic short-hand form\n+ * to name a branch.\n+ */\n+static char *substitute_branch_name(const char **string, int *len)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint ret = interpret_branch_name(*string, *len, &buf);\n+\n+\tif (ret == *len) {\n+\t\tsize_t size;\n+\t\t*string = strbuf_detach(&buf, &size);\n+\t\t*len = size;\n+\t\treturn (char *)*string;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)\n+{\n+\tchar *last_branch = substitute_branch_name(&str, &len);\n+\tconst char **p, *r;\n+\tint refs_found = 0;\n+\n+\t*ref = NULL;\n+\tfor (p = ref_rev_parse_rules; *p; p++) {\n+\t\tchar fullref[PATH_MAX];\n+\t\tunsigned char sha1_from_ref[20];\n+\t\tunsigned char *this_result;\n+\t\tint flag;\n+\n+\t\tthis_result = refs_found ? sha1_from_ref : sha1;\n+\t\tmksnpath(fullref, sizeof(fullref), *p, len, str);\n+\t\tr = resolve_ref_unsafe(fullref, RESOLVE_REF_READING,\n+\t\t\t\t       this_result, &flag);\n+\t\tif (r) {\n+\t\t\tif (!refs_found++)\n+\t\t\t\t*ref = xstrdup(r);\n+\t\t\tif (!warn_ambiguous_refs)\n+\t\t\t\tbreak;\n+\t\t} else if ((flag & REF_ISSYMREF) && strcmp(fullref, \"HEAD\")) {\n+\t\t\twarning(\"ignoring dangling symref %s.\", fullref);\n+\t\t} else if ((flag & REF_ISBROKEN) && strchr(fullref, '/')) {\n+\t\t\twarning(\"ignoring broken ref %s.\", fullref);\n+\t\t}\n+\t}\n+\tfree(last_branch);\n+\treturn refs_found;\n+}\n+\n+int dwim_log(const char *str, int len, unsigned char *sha1, char **log)\n+{\n+\tchar *last_branch = substitute_branch_name(&str, &len);\n+\tconst char **p;\n+\tint logs_found = 0;\n+\n+\t*log = NULL;\n+\tfor (p = ref_rev_parse_rules; *p; p++) {\n+\t\tunsigned char hash[20];\n+\t\tchar path[PATH_MAX];\n+\t\tconst char *ref, *it;\n+\n+\t\tmksnpath(path, sizeof(path), *p, len, str);\n+\t\tref = resolve_ref_unsafe(path, RESOLVE_REF_READING,\n+\t\t\t\t\t hash, NULL);\n+\t\tif (!ref)\n+\t\t\tcontinue;\n+\t\tif (reflog_exists(path))\n+\t\t\tit = path;\n+\t\telse if (strcmp(ref, path) && reflog_exists(ref))\n+\t\t\tit = ref;\n+\t\telse\n+\t\t\tcontinue;\n+\t\tif (!logs_found++) {\n+\t\t\t*log = xstrdup(it);\n+\t\t\thashcpy(sha1, hash);\n+\t\t}\n+\t\tif (!warn_ambiguous_refs)\n+\t\t\tbreak;\n+\t}\n+\tfree(last_branch);\n+\treturn logs_found;\n+}\n+\n+char *shorten_unambiguous_ref(const char *refname, int strict)\n+{\n+\tint i;\n+\tstatic char **scanf_fmts;\n+\tstatic int nr_rules;\n+\tchar *short_name;\n+\n+\tif (!nr_rules) {\n+\t\t/*\n+\t\t * Pre-generate scanf formats from ref_rev_parse_rules[].\n+\t\t * Generate a format suitable for scanf from a\n+\t\t * ref_rev_parse_rules rule by interpolating \"%s\" at the\n+\t\t * location of the \"%.*s\".\n+\t\t */\n+\t\tsize_t total_len = 0;\n+\t\tsize_t offset = 0;\n+\n+\t\t/* the rule list is NULL terminated, count them first */\n+\t\tfor (nr_rules = 0; ref_rev_parse_rules[nr_rules]; nr_rules++)\n+\t\t\t/* -2 for strlen(\"%.*s\") - strlen(\"%s\"); +1 for NUL */\n+\t\t\ttotal_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;\n+\n+\t\tscanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);\n+\n+\t\toffset = 0;\n+\t\tfor (i = 0; i < nr_rules; i++) {\n+\t\t\tassert(offset < total_len);\n+\t\t\tscanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset;\n+\t\t\toffset += snprintf(scanf_fmts[i], total_len - offset,\n+\t\t\t\t\t   ref_rev_parse_rules[i], 2, \"%s\") + 1;\n+\t\t}\n+\t}\n+\n+\t/* bail out if there are no rules */\n+\tif (!nr_rules)\n+\t\treturn xstrdup(refname);\n+\n+\t/* buffer for scanf result, at most refname must fit */\n+\tshort_name = xstrdup(refname);\n+\n+\t/* skip first rule, it will always match */\n+\tfor (i = nr_rules - 1; i > 0 ; --i) {\n+\t\tint j;\n+\t\tint rules_to_fail = i;\n+\t\tint short_name_len;\n+\n+\t\tif (1 != sscanf(refname, scanf_fmts[i], short_name))\n+\t\t\tcontinue;\n+\n+\t\tshort_name_len = strlen(short_name);\n+\n+\t\t/*\n+\t\t * in strict mode, all (except the matched one) rules\n+\t\t * must fail to resolve to a valid non-ambiguous ref\n+\t\t */\n+\t\tif (strict)\n+\t\t\trules_to_fail = nr_rules;\n+\n+\t\t/*\n+\t\t * check if the short name resolves to a valid ref,\n+\t\t * but use only rules prior to the matched one\n+\t\t */\n+\t\tfor (j = 0; j < rules_to_fail; j++) {\n+\t\t\tconst char *rule = ref_rev_parse_rules[j];\n+\t\t\tchar refname[PATH_MAX];\n+\n+\t\t\t/* skip matched rule */\n+\t\t\tif (i == j)\n+\t\t\t\tcontinue;\n+\n+\t\t\t/*\n+\t\t\t * the short name is ambiguous, if it resolves\n+\t\t\t * (with this previous rule) to a valid ref\n+\t\t\t * read_ref() returns 0 on success\n+\t\t\t */\n+\t\t\tmksnpath(refname, sizeof(refname),\n+\t\t\t\t rule, short_name_len, short_name);\n+\t\t\tif (ref_exists(refname))\n+\t\t\t\tbreak;\n+\t\t}\n+\n+\t\t/*\n+\t\t * short name is non-ambiguous if all previous rules\n+\t\t * haven't resolved to a valid ref\n+\t\t */\n+\t\tif (j == rules_to_fail)\n+\t\t\treturn short_name;\n+\t}\n+\n+\tfree(short_name);\n+\treturn xstrdup(refname);\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272379","messageId":"1445998467-11511-11-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 10/26] refs.c: move warn_if_dangling_symref* to the common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:11Z","receivedAt":"2015-10-28T02:14:11Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nThese functions do not use any backend specific code so we move\nthem to the common code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 52 ----------------------------------------------------\n refs.c          | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 52 insertions(+), 52 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex b74b6cc..ab72adf 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -1944,58 +1944,6 @@ int peel_ref(const char *refname, unsigned char *sha1)\n \treturn peel_object(base, sha1);\n }\n \n-struct warn_if_dangling_data {\n-\tFILE *fp;\n-\tconst char *refname;\n-\tconst struct string_list *refnames;\n-\tconst char *msg_fmt;\n-};\n-\n-static int warn_if_dangling_symref(const char *refname, const struct object_id *oid,\n-\t\t\t\t   int flags, void *cb_data)\n-{\n-\tstruct warn_if_dangling_data *d = cb_data;\n-\tconst char *resolves_to;\n-\tstruct object_id junk;\n-\n-\tif (!(flags & REF_ISSYMREF))\n-\t\treturn 0;\n-\n-\tresolves_to = resolve_ref_unsafe(refname, 0, junk.hash, NULL);\n-\tif (!resolves_to\n-\t    || (d->refname\n-\t\t? strcmp(resolves_to, d->refname)\n-\t\t: !string_list_has_string(d->refnames, resolves_to))) {\n-\t\treturn 0;\n-\t}\n-\n-\tfprintf(d->fp, d->msg_fmt, refname);\n-\tfputc('\\n', d->fp);\n-\treturn 0;\n-}\n-\n-void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)\n-{\n-\tstruct warn_if_dangling_data data;\n-\n-\tdata.fp = fp;\n-\tdata.refname = refname;\n-\tdata.refnames = NULL;\n-\tdata.msg_fmt = msg_fmt;\n-\tfor_each_rawref(warn_if_dangling_symref, &data);\n-}\n-\n-void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames)\n-{\n-\tstruct warn_if_dangling_data data;\n-\n-\tdata.fp = fp;\n-\tdata.refname = NULL;\n-\tdata.refnames = refnames;\n-\tdata.msg_fmt = msg_fmt;\n-\tfor_each_rawref(warn_if_dangling_symref, &data);\n-}\n-\n /*\n  * Call fn for each reference in the specified ref_cache, omitting\n  * references not in the containing_dir of base.  fn is called for all\ndiff --git a/refs.c b/refs.c\nindex e0bc031..1f77978 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -545,3 +545,55 @@ char *shorten_unambiguous_ref(const char *refname, int strict)\n \tfree(short_name);\n \treturn xstrdup(refname);\n }\n+\n+struct warn_if_dangling_data {\n+\tFILE *fp;\n+\tconst char *refname;\n+\tconst struct string_list *refnames;\n+\tconst char *msg_fmt;\n+};\n+\n+static int warn_if_dangling_symref(const char *refname, const struct object_id *oid,\n+\t\t\t\t   int flags, void *cb_data)\n+{\n+\tstruct warn_if_dangling_data *d = cb_data;\n+\tconst char *resolves_to;\n+\tstruct object_id junk;\n+\n+\tif (!(flags & REF_ISSYMREF))\n+\t\treturn 0;\n+\n+\tresolves_to = resolve_ref_unsafe(refname, 0, junk.hash, NULL);\n+\tif (!resolves_to\n+\t    || (d->refname\n+\t\t? strcmp(resolves_to, d->refname)\n+\t\t: !string_list_has_string(d->refnames, resolves_to))) {\n+\t\treturn 0;\n+\t}\n+\n+\tfprintf(d->fp, d->msg_fmt, refname);\n+\tfputc('\\n', d->fp);\n+\treturn 0;\n+}\n+\n+void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)\n+{\n+\tstruct warn_if_dangling_data data;\n+\n+\tdata.fp = fp;\n+\tdata.refname = refname;\n+\tdata.refnames = NULL;\n+\tdata.msg_fmt = msg_fmt;\n+\tfor_each_rawref(warn_if_dangling_symref, &data);\n+}\n+\n+void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames)\n+{\n+\tstruct warn_if_dangling_data data;\n+\n+\tdata.fp = fp;\n+\tdata.refname = NULL;\n+\tdata.refnames = refnames;\n+\tdata.msg_fmt = msg_fmt;\n+\tfor_each_rawref(warn_if_dangling_symref, &data);\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272377","messageId":"1445998467-11511-12-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 11/26] refs.c: move read_ref, read_ref_full and ref_exists to the common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:12Z","receivedAt":"2015-10-28T02:14:12Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nThese functions do not depend on the backend implementation so we\nmove them to the common code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 18 ------------------\n refs.c          | 18 ++++++++++++++++++\n 2 files changed, 18 insertions(+), 18 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex ab72adf..7f341bd 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -1791,24 +1791,6 @@ struct ref_filter {\n \tvoid *cb_data;\n };\n \n-int read_ref_full(const char *refname, int resolve_flags, unsigned char *sha1, int *flags)\n-{\n-\tif (resolve_ref_unsafe(refname, resolve_flags, sha1, flags))\n-\t\treturn 0;\n-\treturn -1;\n-}\n-\n-int read_ref(const char *refname, unsigned char *sha1)\n-{\n-\treturn read_ref_full(refname, RESOLVE_REF_READING, sha1, NULL);\n-}\n-\n-int ref_exists(const char *refname)\n-{\n-\tunsigned char sha1[20];\n-\treturn !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, sha1, NULL);\n-}\n-\n static int filter_refs(const char *refname, const struct object_id *oid,\n \t\t\t   int flags, void *data)\n {\ndiff --git a/refs.c b/refs.c\nindex 1f77978..f3241e4 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -597,3 +597,21 @@ void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_li\n \tdata.msg_fmt = msg_fmt;\n \tfor_each_rawref(warn_if_dangling_symref, &data);\n }\n+\n+int read_ref_full(const char *refname, int resolve_flags, unsigned char *sha1, int *flags)\n+{\n+\tif (resolve_ref_unsafe(refname, resolve_flags, sha1, flags))\n+\t\treturn 0;\n+\treturn -1;\n+}\n+\n+int read_ref(const char *refname, unsigned char *sha1)\n+{\n+\treturn read_ref_full(refname, RESOLVE_REF_READING, sha1, NULL);\n+}\n+\n+int ref_exists(const char *refname)\n+{\n+\tunsigned char sha1[20];\n+\treturn !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, sha1, NULL);\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272391","messageId":"1445998467-11511-13-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 12/26] refs.c: move resolve_refdup to common","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:13Z","receivedAt":"2015-10-28T02:14:13Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nThis function can be shared across all refs backends so move it\nto the common code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 7 -------\n refs.c          | 7 +++++++\n 2 files changed, 7 insertions(+), 7 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex 7f341bd..dcb6394 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -1777,13 +1777,6 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \treturn ret;\n }\n \n-char *resolve_refdup(const char *refname, int resolve_flags,\n-\t\t     unsigned char *sha1, int *flags)\n-{\n-\treturn xstrdup_or_null(resolve_ref_unsafe(refname, resolve_flags,\n-\t\t\t\t\t\t  sha1, flags));\n-}\n-\n /* The argument to filter_refs */\n struct ref_filter {\n \tconst char *pattern;\ndiff --git a/refs.c b/refs.c\nindex f3241e4..b605460 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -615,3 +615,10 @@ int ref_exists(const char *refname)\n \tunsigned char sha1[20];\n \treturn !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, sha1, NULL);\n }\n+\n+char *resolve_refdup(const char *refname, int resolve_flags,\n+\t\t     unsigned char *sha1, int *flags)\n+{\n+\treturn xstrdup_or_null(resolve_ref_unsafe(refname, resolve_flags,\n+\t\t\t\t\t\t  sha1, flags));\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272375","messageId":"1445998467-11511-14-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 13/26] refs.c: move check_refname_format to the common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:14Z","receivedAt":"2015-10-28T02:14:14Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nThis function does not contain any backend specific code so we\nmove it to the common code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 109 --------------------------------------------------------\n refs.c          | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 109 insertions(+), 109 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex dcb6394..ec6efd7 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -14,27 +14,6 @@ struct ref_lock {\n };\n \n /*\n- * How to handle various characters in refnames:\n- * 0: An acceptable character for refs\n- * 1: End-of-component\n- * 2: ., look for a preceding . to reject .. in refs\n- * 3: {, look for a preceding @ to reject @{ in refs\n- * 4: A bad character: ASCII control characters, and\n- *    \":\", \"?\", \"[\", \"\\\", \"^\", \"~\", SP, or TAB\n- * 5: *, reject unless REFNAME_REFSPEC_PATTERN is set\n- */\n-static unsigned char refname_disposition[256] = {\n-\t1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n-\t4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n-\t4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 2, 1,\n-\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4,\n-\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n-\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 4, 0,\n-\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n-\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4\n-};\n-\n-/*\n  * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken\n  * refs (i.e., because the reference is about to be deleted anyway).\n  */\n@@ -69,94 +48,6 @@ static unsigned char refname_disposition[256] = {\n  * value to ref_update::flags\n  */\n \n-/*\n- * Try to read one refname component from the front of refname.\n- * Return the length of the component found, or -1 if the component is\n- * not legal.  It is legal if it is something reasonable to have under\n- * \".git/refs/\"; We do not like it if:\n- *\n- * - any path component of it begins with \".\", or\n- * - it has double dots \"..\", or\n- * - it has ASCII control characters, or\n- * - it has \":\", \"?\", \"[\", \"\\\", \"^\", \"~\", SP, or TAB anywhere, or\n- * - it has \"*\" anywhere unless REFNAME_REFSPEC_PATTERN is set, or\n- * - it ends with a \"/\", or\n- * - it ends with \".lock\", or\n- * - it contains a \"@{\" portion\n- */\n-static int check_refname_component(const char *refname, int *flags)\n-{\n-\tconst char *cp;\n-\tchar last = '\\0';\n-\n-\tfor (cp = refname; ; cp++) {\n-\t\tint ch = *cp & 255;\n-\t\tunsigned char disp = refname_disposition[ch];\n-\t\tswitch (disp) {\n-\t\tcase 1:\n-\t\t\tgoto out;\n-\t\tcase 2:\n-\t\t\tif (last == '.')\n-\t\t\t\treturn -1; /* Refname contains \"..\". */\n-\t\t\tbreak;\n-\t\tcase 3:\n-\t\t\tif (last == '@')\n-\t\t\t\treturn -1; /* Refname contains \"@{\". */\n-\t\t\tbreak;\n-\t\tcase 4:\n-\t\t\treturn -1;\n-\t\tcase 5:\n-\t\t\tif (!(*flags & REFNAME_REFSPEC_PATTERN))\n-\t\t\t\treturn -1; /* refspec can't be a pattern */\n-\n-\t\t\t/*\n-\t\t\t * Unset the pattern flag so that we only accept\n-\t\t\t * a single asterisk for one side of refspec.\n-\t\t\t */\n-\t\t\t*flags &= ~ REFNAME_REFSPEC_PATTERN;\n-\t\t\tbreak;\n-\t\t}\n-\t\tlast = ch;\n-\t}\n-out:\n-\tif (cp == refname)\n-\t\treturn 0; /* Component has zero length. */\n-\tif (refname[0] == '.')\n-\t\treturn -1; /* Component starts with '.'. */\n-\tif (cp - refname >= LOCK_SUFFIX_LEN &&\n-\t    !memcmp(cp - LOCK_SUFFIX_LEN, LOCK_SUFFIX, LOCK_SUFFIX_LEN))\n-\t\treturn -1; /* Refname ends with \".lock\". */\n-\treturn cp - refname;\n-}\n-\n-int check_refname_format(const char *refname, int flags)\n-{\n-\tint component_len, component_count = 0;\n-\n-\tif (!strcmp(refname, \"@\"))\n-\t\t/* Refname is a single character '@'. */\n-\t\treturn -1;\n-\n-\twhile (1) {\n-\t\t/* We are at the start of a path component. */\n-\t\tcomponent_len = check_refname_component(refname, &flags);\n-\t\tif (component_len <= 0)\n-\t\t\treturn -1;\n-\n-\t\tcomponent_count++;\n-\t\tif (refname[component_len] == '\\0')\n-\t\t\tbreak;\n-\t\t/* Skip to next component. */\n-\t\trefname += component_len + 1;\n-\t}\n-\n-\tif (refname[component_len - 1] == '.')\n-\t\treturn -1; /* Refname ends with '.'. */\n-\tif (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2)\n-\t\treturn -1; /* Refname has only one component. */\n-\treturn 0;\n-}\n-\n struct ref_entry;\n \n /*\ndiff --git a/refs.c b/refs.c\nindex b605460..58991a0 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -622,3 +622,112 @@ char *resolve_refdup(const char *refname, int resolve_flags,\n \treturn xstrdup_or_null(resolve_ref_unsafe(refname, resolve_flags,\n \t\t\t\t\t\t  sha1, flags));\n }\n+\n+/*\n+ * How to handle various characters in refnames:\n+ * 0: An acceptable character for refs\n+ * 1: End-of-component\n+ * 2: ., look for a preceding . to reject .. in refs\n+ * 3: {, look for a preceding @ to reject @{ in refs\n+ * 4: A bad character: ASCII control characters, and\n+ *    \":\", \"?\", \"[\", \"\\\", \"^\", \"~\", SP, or TAB\n+ * 5: *, reject unless REFNAME_REFSPEC_PATTERN is set\n+ */\n+static unsigned char refname_disposition[256] = {\n+\t1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n+\t4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n+\t4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 2, 1,\n+\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4,\n+\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n+\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 4, 0,\n+\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n+\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4\n+};\n+\n+/*\n+ * Try to read one refname component from the front of refname.\n+ * Return the length of the component found, or -1 if the component is\n+ * not legal.  It is legal if it is something reasonable to have under\n+ * \".git/refs/\"; We do not like it if:\n+ *\n+ * - any path component of it begins with \".\", or\n+ * - it has double dots \"..\", or\n+ * - it has ASCII control characters, or\n+ * - it has \":\", \"?\", \"[\", \"\\\", \"^\", \"~\", SP, or TAB anywhere, or\n+ * - it has \"*\" anywhere unless REFNAME_REFSPEC_PATTERN is set, or\n+ * - it ends with a \"/\", or\n+ * - it ends with \".lock\", or\n+ * - it contains a \"@{\" portion\n+ */\n+static int check_refname_component(const char *refname, int *flags)\n+{\n+\tconst char *cp;\n+\tchar last = '\\0';\n+\n+\tfor (cp = refname; ; cp++) {\n+\t\tint ch = *cp & 255;\n+\t\tunsigned char disp = refname_disposition[ch];\n+\t\tswitch (disp) {\n+\t\tcase 1:\n+\t\t\tgoto out;\n+\t\tcase 2:\n+\t\t\tif (last == '.')\n+\t\t\t\treturn -1; /* Refname contains \"..\". */\n+\t\t\tbreak;\n+\t\tcase 3:\n+\t\t\tif (last == '@')\n+\t\t\t\treturn -1; /* Refname contains \"@{\". */\n+\t\t\tbreak;\n+\t\tcase 4:\n+\t\t\treturn -1;\n+\t\tcase 5:\n+\t\t\tif (!(*flags & REFNAME_REFSPEC_PATTERN))\n+\t\t\t\treturn -1; /* refspec can't be a pattern */\n+\n+\t\t\t/*\n+\t\t\t * Unset the pattern flag so that we only accept\n+\t\t\t * a single asterisk for one side of refspec.\n+\t\t\t */\n+\t\t\t*flags &= ~ REFNAME_REFSPEC_PATTERN;\n+\t\t\tbreak;\n+\t\t}\n+\t\tlast = ch;\n+\t}\n+out:\n+\tif (cp == refname)\n+\t\treturn 0; /* Component has zero length. */\n+\tif (refname[0] == '.')\n+\t\treturn -1; /* Component starts with '.'. */\n+\tif (cp - refname >= LOCK_SUFFIX_LEN &&\n+\t    !memcmp(cp - LOCK_SUFFIX_LEN, LOCK_SUFFIX, LOCK_SUFFIX_LEN))\n+\t\treturn -1; /* Refname ends with \".lock\". */\n+\treturn cp - refname;\n+}\n+\n+int check_refname_format(const char *refname, int flags)\n+{\n+\tint component_len, component_count = 0;\n+\n+\tif (!strcmp(refname, \"@\"))\n+\t\t/* Refname is a single character '@'. */\n+\t\treturn -1;\n+\n+\twhile (1) {\n+\t\t/* We are at the start of a path component. */\n+\t\tcomponent_len = check_refname_component(refname, &flags);\n+\t\tif (component_len <= 0)\n+\t\t\treturn -1;\n+\n+\t\tcomponent_count++;\n+\t\tif (refname[component_len] == '\\0')\n+\t\t\tbreak;\n+\t\t/* Skip to next component. */\n+\t\trefname += component_len + 1;\n+\t}\n+\n+\tif (refname[component_len - 1] == '.')\n+\t\treturn -1; /* Refname ends with '.'. */\n+\tif (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2)\n+\t\treturn -1; /* Refname has only one component. */\n+\treturn 0;\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272376","messageId":"1445998467-11511-15-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 14/26] refs.c: move is_branch to the common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:15Z","receivedAt":"2015-10-28T02:14:15Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 5 -----\n refs.c          | 5 +++++\n 2 files changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex ec6efd7..8eb4b93 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -3002,11 +3002,6 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,\n \treturn ret;\n }\n \n-int is_branch(const char *refname)\n-{\n-\treturn !strcmp(refname, \"HEAD\") || starts_with(refname, \"refs/heads/\");\n-}\n-\n /*\n  * Write sha1 into the open lockfile, then close the lockfile. On\n  * errors, rollback the lockfile, fill in *err and\ndiff --git a/refs.c b/refs.c\nindex 58991a0..2aae268 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -731,3 +731,8 @@ int check_refname_format(const char *refname, int flags)\n \t\treturn -1; /* Refname has only one component. */\n \treturn 0;\n }\n+\n+int is_branch(const char *refname)\n+{\n+\treturn !strcmp(refname, \"HEAD\") || starts_with(refname, \"refs/heads/\");\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272390","messageId":"1445998467-11511-16-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 15/26] refs.c: move prettify_refname to the common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:16Z","receivedAt":"2015-10-28T02:14:16Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 9 ---------\n refs.c          | 9 +++++++++\n 2 files changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex 8eb4b93..c5cc7e7 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -2052,15 +2052,6 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)\n \t\t\t       DO_FOR_EACH_INCLUDE_BROKEN, cb_data);\n }\n \n-const char *prettify_refname(const char *name)\n-{\n-\treturn name + (\n-\t\tstarts_with(name, \"refs/heads/\") ? 11 :\n-\t\tstarts_with(name, \"refs/tags/\") ? 10 :\n-\t\tstarts_with(name, \"refs/remotes/\") ? 13 :\n-\t\t0);\n-}\n-\n static void unlock_ref(struct ref_lock *lock)\n {\n \t/* Do not free lock->lk -- atexit() still looks at them */\ndiff --git a/refs.c b/refs.c\nindex 2aae268..d89a8d3 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -736,3 +736,12 @@ int is_branch(const char *refname)\n {\n \treturn !strcmp(refname, \"HEAD\") || starts_with(refname, \"refs/heads/\");\n }\n+\n+const char *prettify_refname(const char *name)\n+{\n+\treturn name + (\n+\t\tstarts_with(name, \"refs/heads/\") ? 11 :\n+\t\tstarts_with(name, \"refs/tags/\") ? 10 :\n+\t\tstarts_with(name, \"refs/remotes/\") ? 13 :\n+\t\t0);\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272378","messageId":"1445998467-11511-17-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 16/26] refs.c: move ref iterators to the common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:17Z","receivedAt":"2015-10-28T02:14:17Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n refs-be-files.c | 82 ---------------------------------------------------------\n refs.c          | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 81 insertions(+), 82 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex c5cc7e7..d04a9d2 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -1668,23 +1668,6 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \treturn ret;\n }\n \n-/* The argument to filter_refs */\n-struct ref_filter {\n-\tconst char *pattern;\n-\teach_ref_fn *fn;\n-\tvoid *cb_data;\n-};\n-\n-static int filter_refs(const char *refname, const struct object_id *oid,\n-\t\t\t   int flags, void *data)\n-{\n-\tstruct ref_filter *filter = (struct ref_filter *)data;\n-\n-\tif (wildmatch(filter->pattern, refname, 0, NULL))\n-\t\treturn 0;\n-\treturn filter->fn(refname, oid, flags, filter->cb_data);\n-}\n-\n enum peel_status {\n \t/* object was peeled successfully: */\n \tPEEL_PEELED = 0,\n@@ -1950,37 +1933,6 @@ int for_each_ref_in_submodule(const char *submodule, const char *prefix,\n {\n \treturn do_for_each_ref(get_ref_cache(submodule), prefix, fn, strlen(prefix), 0, cb_data);\n }\n-\n-int for_each_tag_ref(each_ref_fn fn, void *cb_data)\n-{\n-\treturn for_each_ref_in(\"refs/tags/\", fn, cb_data);\n-}\n-\n-int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn for_each_ref_in_submodule(submodule, \"refs/tags/\", fn, cb_data);\n-}\n-\n-int for_each_branch_ref(each_ref_fn fn, void *cb_data)\n-{\n-\treturn for_each_ref_in(\"refs/heads/\", fn, cb_data);\n-}\n-\n-int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn for_each_ref_in_submodule(submodule, \"refs/heads/\", fn, cb_data);\n-}\n-\n-int for_each_remote_ref(each_ref_fn fn, void *cb_data)\n-{\n-\treturn for_each_ref_in(\"refs/remotes/\", fn, cb_data);\n-}\n-\n-int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn for_each_ref_in_submodule(submodule, \"refs/remotes/\", fn, cb_data);\n-}\n-\n int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n {\n \treturn do_for_each_ref(&ref_cache, git_replace_ref_base, fn,\n@@ -2012,40 +1964,6 @@ int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)\n \treturn ret;\n }\n \n-int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,\n-\tconst char *prefix, void *cb_data)\n-{\n-\tstruct strbuf real_pattern = STRBUF_INIT;\n-\tstruct ref_filter filter;\n-\tint ret;\n-\n-\tif (!prefix && !starts_with(pattern, \"refs/\"))\n-\t\tstrbuf_addstr(&real_pattern, \"refs/\");\n-\telse if (prefix)\n-\t\tstrbuf_addstr(&real_pattern, prefix);\n-\tstrbuf_addstr(&real_pattern, pattern);\n-\n-\tif (!has_glob_specials(pattern)) {\n-\t\t/* Append implied '/' '*' if not present. */\n-\t\tstrbuf_complete(&real_pattern, '/');\n-\t\t/* No need to check for '*', there is none. */\n-\t\tstrbuf_addch(&real_pattern, '*');\n-\t}\n-\n-\tfilter.pattern = real_pattern.buf;\n-\tfilter.fn = fn;\n-\tfilter.cb_data = cb_data;\n-\tret = for_each_ref(filter_refs, &filter);\n-\n-\tstrbuf_release(&real_pattern);\n-\treturn ret;\n-}\n-\n-int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)\n-{\n-\treturn for_each_glob_ref_in(fn, pattern, NULL, cb_data);\n-}\n-\n int for_each_rawref(each_ref_fn fn, void *cb_data)\n {\n \treturn do_for_each_ref(&ref_cache, \"\", fn, 0,\ndiff --git a/refs.c b/refs.c\nindex d89a8d3..c7778d1 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -745,3 +745,84 @@ const char *prettify_refname(const char *name)\n \t\tstarts_with(name, \"refs/remotes/\") ? 13 :\n \t\t0);\n }\n+\n+/* The argument to filter_refs */\n+struct ref_filter {\n+\tconst char *pattern;\n+\teach_ref_fn *fn;\n+\tvoid *cb_data;\n+};\n+\n+static int filter_refs(const char *refname, const struct object_id *oid, int flags,\n+\t\t       void *data)\n+{\n+\tstruct ref_filter *filter = (struct ref_filter *)data;\n+\n+\tif (wildmatch(filter->pattern, refname, 0, NULL))\n+\t\treturn 0;\n+\treturn filter->fn(refname, oid, flags, filter->cb_data);\n+}\n+\n+int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,\n+\tconst char *prefix, void *cb_data)\n+{\n+\tstruct strbuf real_pattern = STRBUF_INIT;\n+\tstruct ref_filter filter;\n+\tint ret;\n+\n+\tif (!prefix && !starts_with(pattern, \"refs/\"))\n+\t\tstrbuf_addstr(&real_pattern, \"refs/\");\n+\telse if (prefix)\n+\t\tstrbuf_addstr(&real_pattern, prefix);\n+\tstrbuf_addstr(&real_pattern, pattern);\n+\n+\tif (!has_glob_specials(pattern)) {\n+\t\t/* Append implied '/' '*' if not present. */\n+\t\tstrbuf_complete(&real_pattern, '/');\n+\t\t/* No need to check for '*', there is none. */\n+\t\tstrbuf_addch(&real_pattern, '*');\n+\t}\n+\n+\tfilter.pattern = real_pattern.buf;\n+\tfilter.fn = fn;\n+\tfilter.cb_data = cb_data;\n+\tret = for_each_ref(filter_refs, &filter);\n+\n+\tstrbuf_release(&real_pattern);\n+\treturn ret;\n+}\n+\n+int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)\n+{\n+\treturn for_each_glob_ref_in(fn, pattern, NULL, cb_data);\n+}\n+\n+int for_each_tag_ref(each_ref_fn fn, void *cb_data)\n+{\n+\treturn for_each_ref_in(\"refs/tags/\", fn, cb_data);\n+}\n+\n+int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n+{\n+\treturn for_each_ref_in_submodule(submodule, \"refs/tags/\", fn, cb_data);\n+}\n+\n+int for_each_branch_ref(each_ref_fn fn, void *cb_data)\n+{\n+\treturn for_each_ref_in(\"refs/heads/\", fn, cb_data);\n+}\n+\n+int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n+{\n+\treturn for_each_ref_in_submodule(submodule, \"refs/heads/\", fn, cb_data);\n+}\n+\n+int for_each_remote_ref(each_ref_fn fn, void *cb_data)\n+{\n+\treturn for_each_ref_in(\"refs/remotes/\", fn, cb_data);\n+}\n+\n+int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n+{\n+\treturn for_each_ref_in_submodule(submodule, \"refs/remotes/\", fn, cb_data);\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272389","messageId":"1445998467-11511-18-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 17/26] refs.c: move head_ref_namespaced to the common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:18Z","receivedAt":"2015-10-28T02:14:18Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 15 ---------------\n refs.c          | 15 +++++++++++++++\n 2 files changed, 15 insertions(+), 15 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex d04a9d2..18c849c 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -1939,21 +1939,6 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n \t\t\t       strlen(git_replace_ref_base), 0, cb_data);\n }\n \n-int head_ref_namespaced(each_ref_fn fn, void *cb_data)\n-{\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tint ret = 0;\n-\tstruct object_id oid;\n-\tint flag;\n-\n-\tstrbuf_addf(&buf, \"%sHEAD\", get_git_namespace());\n-\tif (!read_ref_full(buf.buf, RESOLVE_REF_READING, oid.hash, &flag))\n-\t\tret = fn(buf.buf, &oid, flag, cb_data);\n-\tstrbuf_release(&buf);\n-\n-\treturn ret;\n-}\n-\n int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/refs.c b/refs.c\nindex c7778d1..61d71d5 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -826,3 +826,18 @@ int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *c\n {\n \treturn for_each_ref_in_submodule(submodule, \"refs/remotes/\", fn, cb_data);\n }\n+\n+int head_ref_namespaced(each_ref_fn fn, void *cb_data)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint ret = 0;\n+\tstruct object_id oid;\n+\tint flag;\n+\n+\tstrbuf_addf(&buf, \"%sHEAD\", get_git_namespace());\n+\tif (!read_ref_full(buf.buf, RESOLVE_REF_READING, oid.hash, &flag))\n+\t\tret = fn(buf.buf, &oid, flag, cb_data);\n+\tstrbuf_release(&buf);\n+\n+\treturn ret;\n+}\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272380","messageId":"1445998467-11511-19-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 18/26] refs: move transaction functions into common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:19Z","receivedAt":"2015-10-28T02:14:19Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"The common ref code will build up a ref transaction.  Backends will\nthen commit it.  So the transaction creation and update functions should\nbe in the common code.  We also need to move the ref structs into\nthe common code so that alternate backends can access them.\n\nLater, we will modify struct ref_update to support alternate backends.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs-be-files.c | 198 --------------------------------------------------------\n refs.c          | 108 +++++++++++++++++++++++++++++++\n refs.h          |  91 +++++++++++++++++++++++++-\n 3 files changed, 198 insertions(+), 199 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex 18c849c..156ab4f 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -13,41 +13,6 @@ struct ref_lock {\n \tstruct object_id old_oid;\n };\n \n-/*\n- * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken\n- * refs (i.e., because the reference is about to be deleted anyway).\n- */\n-#define REF_DELETING\t0x02\n-\n-/*\n- * Used as a flag in ref_update::flags when a loose ref is being\n- * pruned.\n- */\n-#define REF_ISPRUNING\t0x04\n-\n-/*\n- * Used as a flag in ref_update::flags when the reference should be\n- * updated to new_sha1.\n- */\n-#define REF_HAVE_NEW\t0x08\n-\n-/*\n- * Used as a flag in ref_update::flags when old_sha1 should be\n- * checked.\n- */\n-#define REF_HAVE_OLD\t0x10\n-\n-/*\n- * Used as a flag in ref_update::flags when the lockfile needs to be\n- * committed.\n- */\n-#define REF_NEEDS_COMMIT 0x20\n-\n-/*\n- * 0x40 is REF_FORCE_CREATE_REFLOG, so skip it if you're adding a\n- * value to ref_update::flags\n- */\n-\n struct ref_entry;\n \n /*\n@@ -3288,169 +3253,6 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)\n \treturn retval;\n }\n \n-/**\n- * Information needed for a single ref update. Set new_sha1 to the new\n- * value or to null_sha1 to delete the ref. To check the old value\n- * while the ref is locked, set (flags & REF_HAVE_OLD) and set\n- * old_sha1 to the old value, or to null_sha1 to ensure the ref does\n- * not exist before update.\n- */\n-struct ref_update {\n-\t/*\n-\t * If (flags & REF_HAVE_NEW), set the reference to this value:\n-\t */\n-\tunsigned char new_sha1[20];\n-\t/*\n-\t * If (flags & REF_HAVE_OLD), check that the reference\n-\t * previously had this value:\n-\t */\n-\tunsigned char old_sha1[20];\n-\t/*\n-\t * One or more of REF_HAVE_NEW, REF_HAVE_OLD, REF_NODEREF,\n-\t * REF_DELETING, and REF_ISPRUNING:\n-\t */\n-\tunsigned int flags;\n-\tstruct ref_lock *lock;\n-\tint type;\n-\tchar *msg;\n-\tconst char refname[FLEX_ARRAY];\n-};\n-\n-/*\n- * Transaction states.\n- * OPEN:   The transaction is in a valid state and can accept new updates.\n- *         An OPEN transaction can be committed.\n- * CLOSED: A closed transaction is no longer active and no other operations\n- *         than free can be used on it in this state.\n- *         A transaction can either become closed by successfully committing\n- *         an active transaction or if there is a failure while building\n- *         the transaction thus rendering it failed/inactive.\n- */\n-enum ref_transaction_state {\n-\tREF_TRANSACTION_OPEN   = 0,\n-\tREF_TRANSACTION_CLOSED = 1\n-};\n-\n-/*\n- * Data structure for holding a reference transaction, which can\n- * consist of checks and updates to multiple references, carried out\n- * as atomically as possible.  This structure is opaque to callers.\n- */\n-struct ref_transaction {\n-\tstruct ref_update **updates;\n-\tsize_t alloc;\n-\tsize_t nr;\n-\tenum ref_transaction_state state;\n-};\n-\n-struct ref_transaction *ref_transaction_begin(struct strbuf *err)\n-{\n-\tassert(err);\n-\n-\treturn xcalloc(1, sizeof(struct ref_transaction));\n-}\n-\n-void ref_transaction_free(struct ref_transaction *transaction)\n-{\n-\tint i;\n-\n-\tif (!transaction)\n-\t\treturn;\n-\n-\tfor (i = 0; i < transaction->nr; i++) {\n-\t\tfree(transaction->updates[i]->msg);\n-\t\tfree(transaction->updates[i]);\n-\t}\n-\tfree(transaction->updates);\n-\tfree(transaction);\n-}\n-\n-static struct ref_update *add_update(struct ref_transaction *transaction,\n-\t\t\t\t     const char *refname)\n-{\n-\tsize_t len = strlen(refname) + 1;\n-\tstruct ref_update *update = xcalloc(1, sizeof(*update) + len);\n-\n-\tmemcpy((char *)update->refname, refname, len); /* includes NUL */\n-\tALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);\n-\ttransaction->updates[transaction->nr++] = update;\n-\treturn update;\n-}\n-\n-int ref_transaction_update(struct ref_transaction *transaction,\n-\t\t\t   const char *refname,\n-\t\t\t   const unsigned char *new_sha1,\n-\t\t\t   const unsigned char *old_sha1,\n-\t\t\t   unsigned int flags, const char *msg,\n-\t\t\t   struct strbuf *err)\n-{\n-\tstruct ref_update *update;\n-\n-\tassert(err);\n-\n-\tif (transaction->state != REF_TRANSACTION_OPEN)\n-\t\tdie(\"BUG: update called for transaction that is not open\");\n-\n-\tif (new_sha1 && !is_null_sha1(new_sha1) &&\n-\t    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {\n-\t\tstrbuf_addf(err, \"refusing to update ref with bad name %s\",\n-\t\t\t    refname);\n-\t\treturn -1;\n-\t}\n-\n-\tupdate = add_update(transaction, refname);\n-\tif (new_sha1) {\n-\t\thashcpy(update->new_sha1, new_sha1);\n-\t\tflags |= REF_HAVE_NEW;\n-\t}\n-\tif (old_sha1) {\n-\t\thashcpy(update->old_sha1, old_sha1);\n-\t\tflags |= REF_HAVE_OLD;\n-\t}\n-\tupdate->flags = flags;\n-\tif (msg)\n-\t\tupdate->msg = xstrdup(msg);\n-\treturn 0;\n-}\n-\n-int ref_transaction_create(struct ref_transaction *transaction,\n-\t\t\t   const char *refname,\n-\t\t\t   const unsigned char *new_sha1,\n-\t\t\t   unsigned int flags, const char *msg,\n-\t\t\t   struct strbuf *err)\n-{\n-\tif (!new_sha1 || is_null_sha1(new_sha1))\n-\t\tdie(\"BUG: create called without valid new_sha1\");\n-\treturn ref_transaction_update(transaction, refname, new_sha1,\n-\t\t\t\t      null_sha1, flags, msg, err);\n-}\n-\n-int ref_transaction_delete(struct ref_transaction *transaction,\n-\t\t\t   const char *refname,\n-\t\t\t   const unsigned char *old_sha1,\n-\t\t\t   unsigned int flags, const char *msg,\n-\t\t\t   struct strbuf *err)\n-{\n-\tif (old_sha1 && is_null_sha1(old_sha1))\n-\t\tdie(\"BUG: delete called with old_sha1 set to zeros\");\n-\treturn ref_transaction_update(transaction, refname,\n-\t\t\t\t      null_sha1, old_sha1,\n-\t\t\t\t      flags, msg, err);\n-}\n-\n-int ref_transaction_verify(struct ref_transaction *transaction,\n-\t\t\t   const char *refname,\n-\t\t\t   const unsigned char *old_sha1,\n-\t\t\t   unsigned int flags,\n-\t\t\t   struct strbuf *err)\n-{\n-\tif (!old_sha1)\n-\t\tdie(\"BUG: verify called with old_sha1 set to NULL\");\n-\treturn ref_transaction_update(transaction, refname,\n-\t\t\t\t      NULL, old_sha1,\n-\t\t\t\t      flags, NULL, err);\n-}\n-\n static int ref_update_reject_duplicates(struct string_list *refnames,\n \t\t\t\t\tstruct strbuf *err)\n {\ndiff --git a/refs.c b/refs.c\nindex 61d71d5..9cafcc9 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -841,3 +841,111 @@ int head_ref_namespaced(each_ref_fn fn, void *cb_data)\n \n \treturn ret;\n }\n+\n+struct ref_transaction *ref_transaction_begin(struct strbuf *err)\n+{\n+\tassert(err);\n+\n+\treturn xcalloc(1, sizeof(struct ref_transaction));\n+}\n+\n+void ref_transaction_free(struct ref_transaction *transaction)\n+{\n+\tint i;\n+\n+\tif (!transaction)\n+\t\treturn;\n+\n+\tfor (i = 0; i < transaction->nr; i++) {\n+\t\tfree(transaction->updates[i]->msg);\n+\t\tfree(transaction->updates[i]);\n+\t}\n+\tfree(transaction->updates);\n+\tfree(transaction);\n+}\n+\n+static struct ref_update *add_update(struct ref_transaction *transaction,\n+\t\t\t\t     const char *refname)\n+{\n+\tsize_t len = strlen(refname) + 1;\n+\tstruct ref_update *update = xcalloc(1, sizeof(*update) + len);\n+\n+\tmemcpy((char *)update->refname, refname, len); /* includes NUL */\n+\tALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);\n+\ttransaction->updates[transaction->nr++] = update;\n+\treturn update;\n+}\n+\n+int ref_transaction_update(struct ref_transaction *transaction,\n+\t\t\t   const char *refname,\n+\t\t\t   const unsigned char *new_sha1,\n+\t\t\t   const unsigned char *old_sha1,\n+\t\t\t   unsigned int flags, const char *msg,\n+\t\t\t   struct strbuf *err)\n+{\n+\tstruct ref_update *update;\n+\n+\tassert(err);\n+\n+\tif (transaction->state != REF_TRANSACTION_OPEN)\n+\t\tdie(\"BUG: update called for transaction that is not open\");\n+\n+\tif (new_sha1 && !is_null_sha1(new_sha1) &&\n+\t    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {\n+\t\tstrbuf_addf(err, \"refusing to update ref with bad name %s\",\n+\t\t\t    refname);\n+\t\treturn -1;\n+\t}\n+\n+\tupdate = add_update(transaction, refname);\n+\tif (new_sha1) {\n+\t\thashcpy(update->new_sha1, new_sha1);\n+\t\tflags |= REF_HAVE_NEW;\n+\t}\n+\tif (old_sha1) {\n+\t\thashcpy(update->old_sha1, old_sha1);\n+\t\tflags |= REF_HAVE_OLD;\n+\t}\n+\tupdate->flags = flags;\n+\tif (msg)\n+\t\tupdate->msg = xstrdup(msg);\n+\treturn 0;\n+}\n+\n+int ref_transaction_create(struct ref_transaction *transaction,\n+\t\t\t   const char *refname,\n+\t\t\t   const unsigned char *new_sha1,\n+\t\t\t   unsigned int flags, const char *msg,\n+\t\t\t   struct strbuf *err)\n+{\n+\tif (!new_sha1 || is_null_sha1(new_sha1))\n+\t\tdie(\"BUG: create called without valid new_sha1\");\n+\treturn ref_transaction_update(transaction, refname, new_sha1,\n+\t\t\t\t      null_sha1, flags, msg, err);\n+}\n+\n+int ref_transaction_delete(struct ref_transaction *transaction,\n+\t\t\t   const char *refname,\n+\t\t\t   const unsigned char *old_sha1,\n+\t\t\t   unsigned int flags, const char *msg,\n+\t\t\t   struct strbuf *err)\n+{\n+\tif (old_sha1 && is_null_sha1(old_sha1))\n+\t\tdie(\"BUG: delete called with old_sha1 set to zeros\");\n+\treturn ref_transaction_update(transaction, refname,\n+\t\t\t\t      null_sha1, old_sha1,\n+\t\t\t\t      flags, msg, err);\n+}\n+\n+int ref_transaction_verify(struct ref_transaction *transaction,\n+\t\t\t   const char *refname,\n+\t\t\t   const unsigned char *old_sha1,\n+\t\t\t   unsigned int flags,\n+\t\t\t   struct strbuf *err)\n+{\n+\tif (!old_sha1)\n+\t\tdie(\"BUG: verify called with old_sha1 set to NULL\");\n+\treturn ref_transaction_update(transaction, refname,\n+\t\t\t\t      NULL, old_sha1,\n+\t\t\t\t      flags, NULL, err);\n+}\ndiff --git a/refs.h b/refs.h\nindex 8408bef..3d24c79 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -94,6 +94,84 @@ extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);\n extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);\n \n /*\n+ * Transaction states.\n+ * OPEN:   The transaction is in a valid state and can accept new updates.\n+ *         An OPEN transaction can be committed.\n+ * CLOSED: A closed transaction is no longer active and no other operations\n+ *         than free can be used on it in this state.\n+ *         A transaction can either become closed by successfully committing\n+ *         an active transaction or if there is a failure while building\n+ *         the transaction thus rendering it failed/inactive.\n+ */\n+enum ref_transaction_state {\n+\tREF_TRANSACTION_OPEN   = 0,\n+\tREF_TRANSACTION_CLOSED = 1\n+};\n+\n+/*\n+ * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken\n+ * refs (i.e., because the reference is about to be deleted anyway).\n+ */\n+#define REF_DELETING\t0x02\n+\n+/*\n+ * Used as a flag in ref_update::flags when a loose ref is being\n+ * pruned.\n+ */\n+#define REF_ISPRUNING\t0x04\n+\n+/*\n+ * Used as a flag in ref_update::flags when the reference should be\n+ * updated to new_sha1.\n+ */\n+#define REF_HAVE_NEW\t0x08\n+\n+/*\n+ * Used as a flag in ref_update::flags when old_sha1 should be\n+ * checked.\n+ */\n+#define REF_HAVE_OLD\t0x10\n+\n+/*\n+ * Used as a flag in ref_update::flags when the lockfile needs to be\n+ * committed.\n+ */\n+#define REF_NEEDS_COMMIT 0x20\n+\n+/*\n+ * 0x40 is REF_FORCE_CREATE_REFLOG, so skip it if you're adding a\n+ * value to ref_update::flags\n+ */\n+\n+/**\n+ * Information needed for a single ref update. Set new_sha1 to the new\n+ * value or to null_sha1 to delete the ref. To check the old value\n+ * while the ref is locked, set (flags & REF_HAVE_OLD) and set\n+ * old_sha1 to the old value, or to null_sha1 to ensure the ref does\n+ * not exist before update.\n+ */\n+struct ref_update {\n+\t/*\n+\t * If (flags & REF_HAVE_NEW), set the reference to this value:\n+\t */\n+\tunsigned char new_sha1[20];\n+\t/*\n+\t * If (flags & REF_HAVE_OLD), check that the reference\n+\t * previously had this value:\n+\t */\n+\tunsigned char old_sha1[20];\n+\t/*\n+\t * One or more of REF_HAVE_NEW, REF_HAVE_OLD, REF_NODEREF,\n+\t * REF_DELETING, and REF_ISPRUNING:\n+\t */\n+\tunsigned int flags;\n+\tstruct ref_lock *lock;\n+\tint type;\n+\tchar *msg;\n+\tconst char refname[FLEX_ARRAY];\n+};\n+\n+/*\n  * A ref_transaction represents a collection of ref updates\n  * that should succeed or fail together.\n  *\n@@ -125,7 +203,18 @@ extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);\n  * The message is appended to err without first clearing err.\n  * err will not be '\\n' terminated.\n  */\n-struct ref_transaction;\n+\n+/*\n+ * Data structure for holding a reference transaction, which can\n+ * consist of checks and updates to multiple references, carried out\n+ * as atomically as possible.  This structure is opaque to callers.\n+ */\n+struct ref_transaction {\n+\tstruct ref_update **updates;\n+\tsize_t alloc;\n+\tsize_t nr;\n+\tenum ref_transaction_state state;\n+};\n \n /*\n  * Bit values set in the flags argument passed to each_ref_fn():\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272388","messageId":"1445998467-11511-20-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 19/26] refs.c: move refname_is_safe to the common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:20Z","receivedAt":"2015-10-28T02:14:20Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"This function does not contain any backend specific code so we move it\nto the common code. This function might be used by other refs backends.\n\nWhile we are doing so, we improve the comment's grammar and clarify a\nsafety rule.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs-be-files.c | 33 ---------------------------------\n refs.c          | 24 ++++++++++++++++++++++++\n refs.h          | 11 +++++++++++\n 3 files changed, 35 insertions(+), 33 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex 156ab4f..0111282 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -196,39 +196,6 @@ static struct ref_dir *get_ref_dir(struct ref_entry *entry)\n \treturn dir;\n }\n \n-/*\n- * Check if a refname is safe.\n- * For refs that start with \"refs/\" we consider it safe as long they do\n- * not try to resolve to outside of refs/.\n- *\n- * For all other refs we only consider them safe iff they only contain\n- * upper case characters and '_' (like \"HEAD\" AND \"MERGE_HEAD\", and not like\n- * \"config\").\n- */\n-static int refname_is_safe(const char *refname)\n-{\n-\tif (starts_with(refname, \"refs/\")) {\n-\t\tchar *buf;\n-\t\tint result;\n-\n-\t\tbuf = xmalloc(strlen(refname) + 1);\n-\t\t/*\n-\t\t * Does the refname try to escape refs/?\n-\t\t * For example: refs/foo/../bar is safe but refs/foo/../../bar\n-\t\t * is not.\n-\t\t */\n-\t\tresult = !normalize_path_copy(buf, refname + strlen(\"refs/\"));\n-\t\tfree(buf);\n-\t\treturn result;\n-\t}\n-\twhile (*refname) {\n-\t\tif (!isupper(*refname) && *refname != '_')\n-\t\t\treturn 0;\n-\t\trefname++;\n-\t}\n-\treturn 1;\n-}\n-\n static struct ref_entry *create_ref_entry(const char *refname,\n \t\t\t\t\t  const unsigned char *sha1, int flag,\n \t\t\t\t\t  int check_name)\ndiff --git a/refs.c b/refs.c\nindex 9cafcc9..cd0ab21 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -949,3 +949,27 @@ int ref_transaction_verify(struct ref_transaction *transaction,\n \t\t\t\t      NULL, old_sha1,\n \t\t\t\t      flags, NULL, err);\n }\n+\n+int refname_is_safe(const char *refname)\n+{\n+\tif (starts_with(refname, \"refs/\")) {\n+\t\tchar *buf;\n+\t\tint result;\n+\n+\t\tbuf = xmalloc(strlen(refname) + 1);\n+\t\t/*\n+\t\t * Does the refname try to escape refs/?\n+\t\t * For example: refs/foo/../bar is safe but refs/foo/../../bar\n+\t\t * is not.\n+\t\t */\n+\t\tresult = !normalize_path_copy(buf, refname + strlen(\"refs/\"));\n+\t\tfree(buf);\n+\t\treturn result;\n+\t}\n+\twhile (*refname) {\n+\t\tif (!isupper(*refname) && *refname != '_')\n+\t\t\treturn 0;\n+\t\trefname++;\n+\t}\n+\treturn 1;\n+}\ndiff --git a/refs.h b/refs.h\nindex 3d24c79..927b64d 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -396,6 +396,17 @@ extern int for_each_reflog(each_ref_fn, void *);\n  */\n extern int check_refname_format(const char *refname, int flags);\n \n+/*\n+ * Check if a refname is safe.\n+ * For a ref that starts with \"refs/\", we consider it safe as long it does\n+ * not try to resolve to outside of refs/.\n+ *\n+ * For all other refs we only consider them safe iff they only consist of\n+ * upper case characters and '_' (like \"HEAD\" AND \"MERGE_HEAD\", and not like\n+ * \"config\").\n+ */\n+extern int refname_is_safe(const char *refname);\n+\n extern const char *prettify_refname(const char *refname);\n \n extern char *shorten_unambiguous_ref(const char *refname, int strict);\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272381","messageId":"1445998467-11511-21-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 20/26] refs.c: move copy_msg to the common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:21Z","receivedAt":"2015-10-28T02:14:21Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Rename copy_msg to copy_reflog_msg and make it public.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs-be-files.c | 28 +---------------------------\n refs.c          | 21 +++++++++++++++++++++\n refs.h          |  7 +++++++\n 3 files changed, 29 insertions(+), 27 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex 0111282..fc8a0a9 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -2653,32 +2653,6 @@ static int commit_ref(struct ref_lock *lock)\n \treturn 0;\n }\n \n-/*\n- * copy the reflog message msg to buf, which has been allocated sufficiently\n- * large, while cleaning up the whitespaces.  Especially, convert LF to space,\n- * because reflog file is one line per entry.\n- */\n-static int copy_msg(char *buf, const char *msg)\n-{\n-\tchar *cp = buf;\n-\tchar c;\n-\tint wasspace = 1;\n-\n-\t*cp++ = '\\t';\n-\twhile ((c = *msg++)) {\n-\t\tif (wasspace && isspace(c))\n-\t\t\tcontinue;\n-\t\twasspace = isspace(c);\n-\t\tif (wasspace)\n-\t\t\tc = ' ';\n-\t\t*cp++ = c;\n-\t}\n-\twhile (buf < cp && isspace(cp[-1]))\n-\t\tcp--;\n-\t*cp++ = '\\n';\n-\treturn cp - buf;\n-}\n-\n static int should_autocreate_reflog(const char *refname)\n {\n \tif (!log_all_ref_updates)\n@@ -2773,7 +2747,7 @@ static int log_ref_write_fd(int fd, const unsigned char *old_sha1,\n \t\t\tsha1_to_hex(new_sha1),\n \t\t\tcommitter);\n \tif (msglen)\n-\t\tlen += copy_msg(logrec + len - 1, msg) - 1;\n+\t\tlen += copy_reflog_msg(logrec + len - 1, msg) - 1;\n \n \twritten = len <= maxlen ? write_in_full(fd, logrec, len) : -1;\n \tfree(logrec);\ndiff --git a/refs.c b/refs.c\nindex cd0ab21..c31418d 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -827,6 +827,27 @@ int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *c\n \treturn for_each_ref_in_submodule(submodule, \"refs/remotes/\", fn, cb_data);\n }\n \n+int copy_reflog_msg(char *buf, const char *msg)\n+{\n+\tchar *cp = buf;\n+\tchar c;\n+\tint wasspace = 1;\n+\n+\t*cp++ = '\\t';\n+\twhile ((c = *msg++)) {\n+\t\tif (wasspace && isspace(c))\n+\t\t\tcontinue;\n+\t\twasspace = isspace(c);\n+\t\tif (wasspace)\n+\t\t\tc = ' ';\n+\t\t*cp++ = c;\n+\t}\n+\twhile (buf < cp && isspace(cp[-1]))\n+\t\tcp--;\n+\t*cp++ = '\\n';\n+\treturn cp - buf;\n+}\n+\n int head_ref_namespaced(each_ref_fn fn, void *cb_data)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/refs.h b/refs.h\nindex 927b64d..4951141 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -576,6 +576,13 @@ enum ref_type {\n \n enum ref_type ref_type(const char *refname);\n \n+/*\n+ * Copy the reflog message msg to buf, which has been allocated sufficiently\n+ * large, while cleaning up the whitespaces.  Especially, convert LF to space,\n+ * because reflog file is one line per entry.\n+ */\n+int copy_reflog_msg(char *buf, const char *msg);\n+\n enum expire_reflog_flags {\n \tEXPIRE_REFLOGS_DRY_RUN = 1 << 0,\n \tEXPIRE_REFLOGS_UPDATE_REF = 1 << 1,\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272387","messageId":"1445998467-11511-22-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 21/26] refs.c: move peel_object to the common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:22Z","receivedAt":"2015-10-28T02:14:22Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"This function does not contain any backend specific code so we\nmove it to the common code.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs-be-files.c | 53 -----------------------------------------------------\n refs.c          | 23 +++++++++++++++++++++++\n refs.h          | 34 ++++++++++++++++++++++++++++++++++\n 3 files changed, 57 insertions(+), 53 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex fc8a0a9..23c2f78 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -1600,59 +1600,6 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \treturn ret;\n }\n \n-enum peel_status {\n-\t/* object was peeled successfully: */\n-\tPEEL_PEELED = 0,\n-\n-\t/*\n-\t * object cannot be peeled because the named object (or an\n-\t * object referred to by a tag in the peel chain), does not\n-\t * exist.\n-\t */\n-\tPEEL_INVALID = -1,\n-\n-\t/* object cannot be peeled because it is not a tag: */\n-\tPEEL_NON_TAG = -2,\n-\n-\t/* ref_entry contains no peeled value because it is a symref: */\n-\tPEEL_IS_SYMREF = -3,\n-\n-\t/*\n-\t * ref_entry cannot be peeled because it is broken (i.e., the\n-\t * symbolic reference cannot even be resolved to an object\n-\t * name):\n-\t */\n-\tPEEL_BROKEN = -4\n-};\n-\n-/*\n- * Peel the named object; i.e., if the object is a tag, resolve the\n- * tag recursively until a non-tag is found.  If successful, store the\n- * result to sha1 and return PEEL_PEELED.  If the object is not a tag\n- * or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,\n- * and leave sha1 unchanged.\n- */\n-static enum peel_status peel_object(const unsigned char *name, unsigned char *sha1)\n-{\n-\tstruct object *o = lookup_unknown_object(name);\n-\n-\tif (o->type == OBJ_NONE) {\n-\t\tint type = sha1_object_info(name, NULL);\n-\t\tif (type < 0 || !object_as_type(o, type, 0))\n-\t\t\treturn PEEL_INVALID;\n-\t}\n-\n-\tif (o->type != OBJ_TAG)\n-\t\treturn PEEL_NON_TAG;\n-\n-\to = deref_tag_noverify(o);\n-\tif (!o)\n-\t\treturn PEEL_INVALID;\n-\n-\thashcpy(sha1, o->sha1);\n-\treturn PEEL_PEELED;\n-}\n-\n /*\n  * Peel the entry (if possible) and return its new peel_status.  If\n  * repeel is true, re-peel the entry even if there is an old peeled\ndiff --git a/refs.c b/refs.c\nindex c31418d..3867549 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -4,6 +4,8 @@\n #include \"cache.h\"\n #include \"refs.h\"\n #include \"lockfile.h\"\n+#include \"object.h\"\n+#include \"tag.h\"\n \n static int is_per_worktree_ref(const char *refname)\n {\n@@ -994,3 +996,24 @@ int refname_is_safe(const char *refname)\n \t}\n \treturn 1;\n }\n+\n+enum peel_status peel_object(const unsigned char *name, unsigned char *sha1)\n+{\n+\tstruct object *o = lookup_unknown_object(name);\n+\n+\tif (o->type == OBJ_NONE) {\n+\t\tint type = sha1_object_info(name, NULL);\n+\t\tif (type < 0 || !object_as_type(o, type, 0))\n+\t\t\treturn PEEL_INVALID;\n+\t}\n+\n+\tif (o->type != OBJ_TAG)\n+\t\treturn PEEL_NON_TAG;\n+\n+\to = deref_tag_noverify(o);\n+\tif (!o)\n+\t\treturn PEEL_INVALID;\n+\n+\thashcpy(sha1, o->sha1);\n+\treturn PEEL_PEELED;\n+}\ndiff --git a/refs.h b/refs.h\nindex 4951141..ca60de5 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -76,6 +76,40 @@ extern int is_branch(const char *refname);\n  */\n extern int peel_ref(const char *refname, unsigned char *sha1);\n \n+enum peel_status {\n+\t/* object was peeled successfully: */\n+\tPEEL_PEELED = 0,\n+\n+\t/*\n+\t * object cannot be peeled because the named object (or an\n+\t * object referred to by a tag in the peel chain), does not\n+\t * exist.\n+\t */\n+\tPEEL_INVALID = -1,\n+\n+\t/* object cannot be peeled because it is not a tag: */\n+\tPEEL_NON_TAG = -2,\n+\n+\t/* ref_entry contains no peeled value because it is a symref: */\n+\tPEEL_IS_SYMREF = -3,\n+\n+\t/*\n+\t * ref_entry cannot be peeled because it is broken (i.e., the\n+\t * symbolic reference cannot even be resolved to an object\n+\t * name):\n+\t */\n+\tPEEL_BROKEN = -4\n+};\n+\n+/*\n+ * Peel the named object; i.e., if the object is a tag, resolve the\n+ * tag recursively until a non-tag is found.  If successful, store the\n+ * result to sha1 and return PEEL_PEELED.  If the object is not a tag\n+ * or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,\n+ * and leave sha1 unchanged.\n+ */\n+enum peel_status peel_object(const unsigned char *name, unsigned char *sha1);\n+\n /**\n  * Resolve refname in the nested \"gitlink\" repository that is located\n  * at path.  If the resolution is successful, return 0 and set sha1 to\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272382","messageId":"1445998467-11511-23-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 22/26] refs.c: move should_autocreate_reflog to common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:23Z","receivedAt":"2015-10-28T02:14:23Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Signed-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs-be-files.c | 10 ----------\n refs.c          | 10 ++++++++++\n refs.h          |  2 ++\n 3 files changed, 12 insertions(+), 10 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex 23c2f78..680641d 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -2600,16 +2600,6 @@ static int commit_ref(struct ref_lock *lock)\n \treturn 0;\n }\n \n-static int should_autocreate_reflog(const char *refname)\n-{\n-\tif (!log_all_ref_updates)\n-\t\treturn 0;\n-\treturn starts_with(refname, \"refs/heads/\") ||\n-\t\tstarts_with(refname, \"refs/remotes/\") ||\n-\t\tstarts_with(refname, \"refs/notes/\") ||\n-\t\t!strcmp(refname, \"HEAD\");\n-}\n-\n int verify_refname_available(const char *newname, struct string_list *extra,\n \t\t\t     struct string_list *skip, struct strbuf *err)\n {\ndiff --git a/refs.c b/refs.c\nindex 3867549..056c172 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -625,6 +625,16 @@ char *resolve_refdup(const char *refname, int resolve_flags,\n \t\t\t\t\t\t  sha1, flags));\n }\n \n+int should_autocreate_reflog(const char *refname)\n+{\n+\tif (!log_all_ref_updates)\n+\t\treturn 0;\n+\treturn starts_with(refname, \"refs/heads/\") ||\n+\t\tstarts_with(refname, \"refs/remotes/\") ||\n+\t\tstarts_with(refname, \"refs/notes/\") ||\n+\t\t!strcmp(refname, \"HEAD\");\n+}\n+\n /*\n  * How to handle various characters in refnames:\n  * 0: An acceptable character for refs\ndiff --git a/refs.h b/refs.h\nindex ca60de5..ce99aef 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -58,6 +58,8 @@ extern const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n extern char *resolve_refdup(const char *refname, int resolve_flags,\n \t\t\t    unsigned char *sha1, int *flags);\n \n+extern int should_autocreate_reflog(const char *refname);\n+\n extern int read_ref_full(const char *refname, int resolve_flags,\n \t\t\t unsigned char *sha1, int *flags);\n extern int read_ref(const char *refname, unsigned char *sha1);\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272383","messageId":"1445998467-11511-24-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 23/26] initdb: move safe_create_dir into common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:24Z","receivedAt":"2015-10-28T02:14:24Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"In a moment, we'll create initdb functions for ref backends, and code\nfrom initdb that calls this function needs to move into the files\nbackend.  So this function needs to be public.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n builtin/init-db.c | 12 ------------\n cache.h           |  7 +++++++\n path.c            | 12 ++++++++++++\n 3 files changed, 19 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/init-db.c b/builtin/init-db.c\nindex f59f407..07229d6 100644\n--- a/builtin/init-db.c\n+++ b/builtin/init-db.c\n@@ -24,18 +24,6 @@ static int init_shared_repository = -1;\n static const char *init_db_template_dir;\n static const char *git_link;\n \n-static void safe_create_dir(const char *dir, int share)\n-{\n-\tif (mkdir(dir, 0777) < 0) {\n-\t\tif (errno != EEXIST) {\n-\t\t\tperror(dir);\n-\t\t\texit(1);\n-\t\t}\n-\t}\n-\telse if (share && adjust_shared_perm(dir))\n-\t\tdie(_(\"Could not make %s writable by group\"), dir);\n-}\n-\n static void copy_templates_1(struct strbuf *path, struct strbuf *template,\n \t\t\t     DIR *dir)\n {\ndiff --git a/cache.h b/cache.h\nindex 9a905a8..28b9896 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1737,4 +1737,11 @@ void stat_validity_update(struct stat_validity *sv, int fd);\n int versioncmp(const char *s1, const char *s2);\n void sleep_millisec(int millisec);\n \n+/*\n+ * Create a directory and (if share is nonzero) adjust its permissions\n+ * according to the shared_repository setting. Only use this for\n+ * directories under $GIT_DIR.  Don't use it for working tree\n+ * directories.\n+ */\n+void safe_create_dir(const char *dir, int share);\n #endif /* CACHE_H */\ndiff --git a/path.c b/path.c\nindex 212695a..9e0283c 100644\n--- a/path.c\n+++ b/path.c\n@@ -723,6 +723,18 @@ int adjust_shared_perm(const char *path)\n \treturn 0;\n }\n \n+void safe_create_dir(const char *dir, int share)\n+{\n+\tif (mkdir(dir, 0777) < 0) {\n+\t\tif (errno != EEXIST) {\n+\t\t\tperror(dir);\n+\t\t\texit(1);\n+\t\t}\n+\t}\n+\telse if (share && adjust_shared_perm(dir))\n+\t\tdie(_(\"Could not make %s writable by group\"), dir);\n+}\n+\n static int have_same_root(const char *path1, const char *path2)\n {\n \tint is_abs1, is_abs2;\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272384","messageId":"1445998467-11511-25-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 24/26] refs: make files_log_ref_write functions public","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:25Z","receivedAt":"2015-10-28T02:14:25Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Because HEAD and stash are per-worktree, refs.c needs to go through\nthe files backend to write these refs.\n\nIn this patch, we make one files_log_ref_write public. Later, we will\nuse this to handle reflog updates for per-worktree symbolic refs\n(HEAD).\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs-be-files.c | 8 ++++++++\n refs.h          | 5 +++++\n 2 files changed, 13 insertions(+)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex 680641d..0eabea9 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -2732,6 +2732,14 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,\n \t\t\t const unsigned char *new_sha1, const char *msg,\n \t\t\t int flags, struct strbuf *err)\n {\n+\treturn files_log_ref_write(refname, old_sha1, new_sha1, msg, flags,\n+\t\t\t\t   err);\n+}\n+\n+int files_log_ref_write(const char *refname, const unsigned char *old_sha1,\n+\t\t\tconst unsigned char *new_sha1, const char *msg,\n+\t\t\tint flags, struct strbuf *err)\n+{\n \tstruct strbuf sb = STRBUF_INIT;\n \tint ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb, flags,\n \t\t\t\t  err);\ndiff --git a/refs.h b/refs.h\nindex ce99aef..f97a2e4 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -619,6 +619,11 @@ enum ref_type ref_type(const char *refname);\n  */\n int copy_reflog_msg(char *buf, const char *msg);\n \n+int files_log_ref_write(const char *refname, const unsigned char *old_sha1,\n+\t\t\tconst unsigned char *new_sha1, const char *msg,\n+\t\t\tint flags, struct strbuf *err);\n+\n+\n enum expire_reflog_flags {\n \tEXPIRE_REFLOGS_DRY_RUN = 1 << 0,\n \tEXPIRE_REFLOGS_UPDATE_REF = 1 << 1,\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272385","messageId":"1445998467-11511-26-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 25/26] refs: break out ref conflict checks","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:26Z","receivedAt":"2015-10-28T02:14:26Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Create new function verify_no_descendants, to hold one of the ref\nconflict checks used in verify_refname_available.  Multiple backends\nwill need this function, so it goes in the common code.\n\nrename_ref_available also moves to the common code, because alternate\nbackends might need it and it has no files-backend-specific code.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs-be-files.c | 49 ++++++++-----------------------------------------\n refs.c          | 38 ++++++++++++++++++++++++++++++++++++++\n refs.h          | 15 +++++++++++++++\n 3 files changed, 61 insertions(+), 41 deletions(-)\n\ndiff --git a/refs-be-files.c b/refs-be-files.c\nindex 0eabea9..97a5983 100644\n--- a/refs-be-files.c\n+++ b/refs-be-files.c\n@@ -729,6 +729,7 @@ static int verify_refname_available_dir(const char *refname,\n \t\t\t\t\tstruct strbuf *err)\n {\n \tconst char *slash;\n+\tconst char *extra_refname;\n \tint pos;\n \tstruct strbuf dirname = STRBUF_INIT;\n \tint ret = -1;\n@@ -834,33 +835,15 @@ static int verify_refname_available_dir(const char *refname,\n \t\t}\n \t}\n \n-\tif (extras) {\n-\t\t/*\n-\t\t * Check for entries in extras that start with\n-\t\t * \"$refname/\". We do that by looking for the place\n-\t\t * where \"$refname/\" would be inserted in extras. If\n-\t\t * there is an entry at that position that starts with\n-\t\t * \"$refname/\" and is not in skip, then we have a\n-\t\t * conflict.\n-\t\t */\n-\t\tfor (pos = string_list_find_insert_index(extras, dirname.buf, 0);\n-\t\t     pos < extras->nr; pos++) {\n-\t\t\tconst char *extra_refname = extras->items[pos].string;\n-\n-\t\t\tif (!starts_with(extra_refname, dirname.buf))\n-\t\t\t\tbreak;\n-\n-\t\t\tif (!skip || !string_list_has_string(skip, extra_refname)) {\n-\t\t\t\tstrbuf_addf(err, \"cannot process '%s' and '%s' at the same time\",\n-\t\t\t\t\t    refname, extra_refname);\n-\t\t\t\tgoto cleanup;\n-\t\t\t}\n-\t\t}\n+\textra_refname = find_descendant_ref(dirname.buf, extras, skip);\n+\tif (extra_refname) {\n+\t\tstrbuf_addf(err,\n+\t\t\t    \"cannot process '%s' and '%s' at the same time\",\n+\t\t\t    refname, extra_refname);\n+\t} else {\n+\t\tret = 0;\n \t}\n \n-\t/* No conflicts were found */\n-\tret = 0;\n-\n cleanup:\n \tstrbuf_release(&dirname);\n \treturn ret;\n@@ -2460,22 +2443,6 @@ out:\n \treturn ret;\n }\n \n-static int rename_ref_available(const char *oldname, const char *newname)\n-{\n-\tstruct string_list skip = STRING_LIST_INIT_NODUP;\n-\tstruct strbuf err = STRBUF_INIT;\n-\tint ret;\n-\n-\tstring_list_insert(&skip, oldname);\n-\tret = !verify_refname_available(newname, NULL, &skip, &err);\n-\tif (!ret)\n-\t\terror(\"%s\", err.buf);\n-\n-\tstring_list_clear(&skip, 0);\n-\tstrbuf_release(&err);\n-\treturn ret;\n-}\n-\n static int write_ref_to_lockfile(struct ref_lock *lock,\n \t\t\t\t const unsigned char *sha1, struct strbuf *err);\n static int commit_ref_update(struct ref_lock *lock,\ndiff --git a/refs.c b/refs.c\nindex 056c172..5d8b6ea 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1027,3 +1027,41 @@ enum peel_status peel_object(const unsigned char *name, unsigned char *sha1)\n \thashcpy(sha1, o->sha1);\n \treturn PEEL_PEELED;\n }\n+\n+const char *find_descendant_ref(const char *dirname,\n+\t\t\t\tconst struct string_list *extras,\n+\t\t\t\tconst struct string_list *skip)\n+{\n+\tint pos;\n+\tif (!extras)\n+\t\treturn NULL;\n+\n+\t/* Look for the place where dirname would be inserted in extras. */\n+\tfor (pos = string_list_find_insert_index(extras, dirname, 0);\n+\t     pos < extras->nr; pos++) {\n+\t\tconst char *extra_refname = extras->items[pos].string;\n+\n+\t\tif (!starts_with(extra_refname, dirname))\n+\t\t\tbreak;\n+\n+\t\tif (!skip || !string_list_has_string(skip, extra_refname))\n+\t\t\treturn extra_refname;\n+\t}\n+\treturn NULL;\n+}\n+\n+int rename_ref_available(const char *oldname, const char *newname)\n+{\n+\tstruct string_list skip = STRING_LIST_INIT_NODUP;\n+\tstruct strbuf err = STRBUF_INIT;\n+\tint ret;\n+\n+\tstring_list_insert(&skip, oldname);\n+\tret = !verify_refname_available(newname, NULL, &skip, &err);\n+\tif (!ret)\n+\t\terror(\"%s\", err.buf);\n+\n+\tstring_list_clear(&skip, 0);\n+\tstrbuf_release(&err);\n+\treturn ret;\n+}\ndiff --git a/refs.h b/refs.h\nindex f97a2e4..88fea3e 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -362,6 +362,8 @@ int pack_refs(unsigned int flags);\n int verify_refname_available(const char *newname, struct string_list *extra,\n \t\t\t     struct string_list *skip, struct strbuf *err);\n \n+int rename_ref_available(const char *oldname, const char *newname);\n+\n extern int is_branch(const char *refname);\n \n /*\n@@ -623,6 +625,19 @@ int files_log_ref_write(const char *refname, const unsigned char *old_sha1,\n \t\t\tconst unsigned char *new_sha1, const char *msg,\n \t\t\tint flags, struct strbuf *err);\n \n+/*\n+ * Check for entries in extras that are within the specified\n+ * directory, where dirname is a reference directory name including\n+ * the trailing slash (e.g., \"refs/heads/master/\"). Ignore any\n+ * conflicting references that are found in skip. If there is a\n+ * conflicting reference, return its name.\n+ *\n+ * extras and skip must be sorted lists of reference names. skip can\n+ * be NULL; extras cannot.\n+ */\n+const char *find_descendant_ref(const char *dirname,\n+\t\t\t\tconst struct string_list *extras,\n+\t\t\t\tconst struct string_list *skip);\n \n enum expire_reflog_flags {\n \tEXPIRE_REFLOGS_DRY_RUN = 1 << 0,\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272386","messageId":"1445998467-11511-27-git-send-email-dturner@twopensource.com","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v5 26/26] introduce \"extensions\" form of core.repositoryformatversion","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-10-28T02:14:27Z","receivedAt":"2015-10-28T02:14:27Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nNormally we try to avoid bumps of the whole-repository\ncore.repositoryformatversion field. However, it is\nunavoidable if we want to safely change certain aspects of\ngit in a backwards-incompatible way (e.g., modifying the set\nof ref tips that we must traverse to generate a list of\nunreachable, safe-to-prune objects).\n\nIf we were to bump the repository version for every such\nchange, then any implementation understanding version `X`\nwould also have to understand `X-1`, `X-2`, and so forth,\neven though the incompatibilities may be in orthogonal parts\nof the system, and there is otherwise no reason we cannot\nimplement one without the other (or more importantly, that\nthe user cannot choose to use one feature without the other,\nweighing the tradeoff in compatibility only for that\nparticular feature).\n\nThis patch documents the existing repositoryformatversion\nstrategy and introduces a new format, \"1\", which lets a\nrepository specify that it must run with an arbitrary set of\nextensions. This can be used, for example:\n\n - to inform git that the objects should not be pruned based\n   only on the reachability of the ref tips (e.g, because it\n   has \"clone --shared\" children)\n\n - that the refs are stored in a format besides the usual\n   \"refs\" and \"packed-refs\" directories\n\nBecause we bump to format \"1\", and because format \"1\"\nrequires that a running git knows about any extensions\nmentioned, we know that older versions of the code will not\ndo something dangerous when confronted with these new\nformats.\n\nFor example, if the user chooses to use database storage for\nrefs, they may set the \"extensions.refbackend\" config to\n\"db\". Older versions of git will not understand format \"1\"\nand bail. Versions of git which understand \"1\" but do not\nknow about \"refbackend\", or which know about \"refbackend\"\nbut not about the \"db\" backend, will refuse to run. This is\nannoying, of course, but much better than the alternative of\nclaiming that there are no refs in the repository, or\nwriting to a location that other implementations will not\nread.\n\nNote that we are only defining the rules for format 1 here.\nWe do not ever write format 1 ourselves; it is a tool that\nis meant to be used by users and future extensions to\nprovide safety with older implementations.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n Documentation/technical/repository-version.txt | 81 ++++++++++++++++++++++++++\n cache.h                                        |  6 ++\n setup.c                                        | 37 +++++++++++-\n t/t1302-repo-version.sh                        | 38 ++++++++++++\n 4 files changed, 159 insertions(+), 3 deletions(-)\n create mode 100644 Documentation/technical/repository-version.txt\n\ndiff --git a/Documentation/technical/repository-version.txt b/Documentation/technical/repository-version.txt\nnew file mode 100644\nindex 0000000..3d7106d\n--- /dev/null\n+++ b/Documentation/technical/repository-version.txt\n@@ -0,0 +1,81 @@\n+Git Repository Format Versions\n+==============================\n+\n+Every git repository is marked with a numeric version in the\n+`core.repositoryformatversion` key of its `config` file. This version\n+specifies the rules for operating on the on-disk repository data. An\n+implementation of git which does not understand a particular version\n+advertised by an on-disk repository MUST NOT operate on that repository;\n+doing so risks not only producing wrong results, but actually losing\n+data.\n+\n+Because of this rule, version bumps should be kept to an absolute\n+minimum. Instead, we generally prefer these strategies:\n+\n+  - bumping format version numbers of individual data files (e.g.,\n+    index, packfiles, etc). This restricts the incompatibilities only to\n+    those files.\n+\n+  - introducing new data that gracefully degrades when used by older\n+    clients (e.g., pack bitmap files are ignored by older clients, which\n+    simply do not take advantage of the optimization they provide).\n+\n+A whole-repository format version bump should only be part of a change\n+that cannot be independently versioned. For instance, if one were to\n+change the reachability rules for objects, or the rules for locking\n+refs, that would require a bump of the repository format version.\n+\n+Note that this applies only to accessing the repository's disk contents\n+directly. An older client which understands only format `0` may still\n+connect via `git://` to a repository using format `1`, as long as the\n+server process understands format `1`.\n+\n+The preferred strategy for rolling out a version bump (whether whole\n+repository or for a single file) is to teach git to read the new format,\n+and allow writing the new format with a config switch or command line\n+option (for experimentation or for those who do not care about backwards\n+compatibility with older gits). Then after a long period to allow the\n+reading capability to become common, we may switch to writing the new\n+format by default.\n+\n+The currently defined format versions are:\n+\n+Version `0`\n+-----------\n+\n+This is the format defined by the initial version of git, including but\n+not limited to the format of the repository directory, the repository\n+configuration file, and the object and ref storage. Specifying the\n+complete behavior of git is beyond the scope of this document.\n+\n+Version `1`\n+-----------\n+\n+This format is identical to version `0`, with the following exceptions:\n+\n+  1. When reading the `core.repositoryformatversion` variable, a git\n+     implementation which supports version 1 MUST also read any\n+     configuration keys found in the `extensions` section of the\n+     configuration file.\n+\n+  2. If a version-1 repository specifies any `extensions.*` keys that\n+     the running git has not implemented, the operation MUST NOT\n+     proceed. Similarly, if the value of any known key is not understood\n+     by the implementation, the operation MUST NOT proceed.\n+\n+Note that if no extensions are specified in the config file, then\n+`core.repositoryformatversion` SHOULD be set to `0` (setting it to `1`\n+provides no benefit, and makes the repository incompatible with older\n+implementations of git).\n+\n+This document will serve as the master list for extensions. Any\n+implementation wishing to define a new extension should make a note of\n+it here, in order to claim the name.\n+\n+The defined extensions are:\n+\n+`noop`\n+~~~~~~\n+\n+This extension does not change git's behavior at all. It is useful only\n+for testing format-1 compatibility.\ndiff --git a/cache.h b/cache.h\nindex 28b9896..90ec48e 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -696,7 +696,13 @@ extern char *notes_ref_name;\n \n extern int grafts_replace_parents;\n \n+/*\n+ * GIT_REPO_VERSION is the version we write by default. The\n+ * _READ variant is the highest number we know how to\n+ * handle.\n+ */\n #define GIT_REPO_VERSION 0\n+#define GIT_REPO_VERSION_READ 1\n extern int repository_format_version;\n extern int check_repository_format(void);\n \ndiff --git a/setup.c b/setup.c\nindex 2b64cbb..0c29469 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -5,6 +5,7 @@\n static int inside_git_dir = -1;\n static int inside_work_tree = -1;\n static int work_tree_config_is_bogus;\n+static struct string_list unknown_extensions = STRING_LIST_INIT_DUP;\n \n /*\n  * The input parameter must contain an absolute path, and it must already be\n@@ -349,10 +350,23 @@ void setup_work_tree(void)\n \n static int check_repo_format(const char *var, const char *value, void *cb)\n {\n+\tconst char *ext;\n+\n \tif (strcmp(var, \"core.repositoryformatversion\") == 0)\n \t\trepository_format_version = git_config_int(var, value);\n \telse if (strcmp(var, \"core.sharedrepository\") == 0)\n \t\tshared_repository = git_config_perm(var, value);\n+\telse if (skip_prefix(var, \"extensions.\", &ext)) {\n+\t\t/*\n+\t\t * record any known extensions here; otherwise,\n+\t\t * we fall through to recording it as unknown, and\n+\t\t * check_repository_format will complain\n+\t\t */\n+\t\tif (!strcmp(ext, \"noop\"))\n+\t\t\t;\n+\t\telse\n+\t\t\tstring_list_append(&unknown_extensions, ext);\n+\t}\n \treturn 0;\n }\n \n@@ -363,6 +377,8 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n \tconfig_fn_t fn;\n \tint ret = 0;\n \n+\tstring_list_clear(&unknown_extensions, 0);\n+\n \tif (get_common_dir(&sb, gitdir))\n \t\tfn = check_repo_format;\n \telse\n@@ -380,16 +396,31 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n \t * is a good one.\n \t */\n \tgit_config_early(fn, NULL, repo_config);\n-\tif (GIT_REPO_VERSION < repository_format_version) {\n+\tif (GIT_REPO_VERSION_READ < repository_format_version) {\n \t\tif (!nongit_ok)\n \t\t\tdie (\"Expected git repo version <= %d, found %d\",\n-\t\t\t     GIT_REPO_VERSION, repository_format_version);\n+\t\t\t     GIT_REPO_VERSION_READ, repository_format_version);\n \t\twarning(\"Expected git repo version <= %d, found %d\",\n-\t\t\tGIT_REPO_VERSION, repository_format_version);\n+\t\t\tGIT_REPO_VERSION_READ, repository_format_version);\n \t\twarning(\"Please upgrade Git\");\n \t\t*nongit_ok = -1;\n \t\tret = -1;\n \t}\n+\n+\tif (repository_format_version >= 1 && unknown_extensions.nr) {\n+\t\tint i;\n+\n+\t\tif (!nongit_ok)\n+\t\t\tdie(\"unknown repository extension: %s\",\n+\t\t\t    unknown_extensions.items[0].string);\n+\n+\t\tfor (i = 0; i < unknown_extensions.nr; i++)\n+\t\t\twarning(\"unknown repository extension: %s\",\n+\t\t\t\tunknown_extensions.items[i].string);\n+\t\t*nongit_ok = -1;\n+\t\tret = -1;\n+\t}\n+\n \tstrbuf_release(&sb);\n \treturn ret;\n }\ndiff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh\nindex 0d9388a..8dd6fd7 100755\n--- a/t/t1302-repo-version.sh\n+++ b/t/t1302-repo-version.sh\n@@ -67,4 +67,42 @@ test_expect_success 'gitdir required mode' '\n \t)\n '\n \n+check_allow () {\n+\tgit rev-parse --git-dir >actual &&\n+\techo .git >expect &&\n+\ttest_cmp expect actual\n+}\n+\n+check_abort () {\n+\ttest_must_fail git rev-parse --git-dir\n+}\n+\n+# avoid git-config, since it cannot be trusted to run\n+# in a repository with a broken version\n+mkconfig () {\n+\techo '[core]' &&\n+\techo \"repositoryformatversion = $1\" &&\n+\tshift &&\n+\n+\tif test $# -gt 0; then\n+\t\techo '[extensions]' &&\n+\t\tfor i in \"$@\"; do\n+\t\t\techo \"$i\"\n+\t\tdone\n+\tfi\n+}\n+\n+while read outcome version extensions; do\n+\ttest_expect_success \"$outcome version=$version $extensions\" \"\n+\t\tmkconfig $version $extensions >.git/config &&\n+\t\tcheck_${outcome}\n+\t\"\n+done <<\\EOF\n+allow 0\n+allow 1\n+allow 1 noop\n+abort 1 no-such-extension\n+allow 0 no-such-extension\n+EOF\n+\n test_done\n-- \n2.4.2.658.g6d8523e-twtrsrc\n"},{"id":"272643","messageId":"56359784.2060606@alum.mit.edu","threadId":"40663","inReplyTo":"1445998467-11511-17-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v5 16/26] refs.c: move ref iterators to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-01T04:39:32Z","receivedAt":"2015-11-01T04:39:32Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 10/28/2015 03:14 AM, David Turner wrote:\n> From: Ronnie Sahlberg <sahlberg@google.com>\n> \n> Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> ---\n>  refs-be-files.c | 82 ---------------------------------------------------------\n>  refs.c          | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n>  2 files changed, 81 insertions(+), 82 deletions(-)\n> \n> diff --git a/refs-be-files.c b/refs-be-files.c\n> index c5cc7e7..d04a9d2 100644\n> --- a/refs-be-files.c\n> +++ b/refs-be-files.c\n> [...]\n> @@ -1950,37 +1933,6 @@ int for_each_ref_in_submodule(const char *submodule, const char *prefix,\n>  {\n>  \treturn do_for_each_ref(get_ref_cache(submodule), prefix, fn, strlen(prefix), 0, cb_data);\n>  }\n> -\n> -int for_each_tag_ref(each_ref_fn fn, void *cb_data)\n> -{\n> -\treturn for_each_ref_in(\"refs/tags/\", fn, cb_data);\n> -}\n> -\n> -int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n> -{\n> -\treturn for_each_ref_in_submodule(submodule, \"refs/tags/\", fn, cb_data);\n> -}\n> -\n> -int for_each_branch_ref(each_ref_fn fn, void *cb_data)\n> -{\n> -\treturn for_each_ref_in(\"refs/heads/\", fn, cb_data);\n> -}\n> -\n> -int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n> -{\n> -\treturn for_each_ref_in_submodule(submodule, \"refs/heads/\", fn, cb_data);\n> -}\n> -\n> -int for_each_remote_ref(each_ref_fn fn, void *cb_data)\n> -{\n> -\treturn for_each_ref_in(\"refs/remotes/\", fn, cb_data);\n> -}\n> -\n> -int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n> -{\n> -\treturn for_each_ref_in_submodule(submodule, \"refs/remotes/\", fn, cb_data);\n> -}\n> -\n>  int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n>  {\n>  \treturn do_for_each_ref(&ref_cache, git_replace_ref_base, fn,\n\nNit: you deleted one LF too many in the above hunk, leaving no blank\nline between the function definitions.\n\n> [...]\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"272650","messageId":"5635CA8A.2080505@alum.mit.edu","threadId":"40663","inReplyTo":"1445998467-11511-19-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v5 18/26] refs: move transaction functions into common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-01T08:17:14Z","receivedAt":"2015-11-01T08:17:14Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 10/28/2015 03:14 AM, David Turner wrote:\n> The common ref code will build up a ref transaction.  Backends will\n> then commit it.  So the transaction creation and update functions should\n> be in the common code.  We also need to move the ref structs into\n> the common code so that alternate backends can access them.\n> \n> Later, we will modify struct ref_update to support alternate backends.\n\nI would prefer that this and later patches *not* add declarations to the\npublic API in refs.h for functions and data that are only meant to be\nused by other reference backends.\n\nSo I'm working on a modified version of your series that declares such\nfunctions in refs-internal.h [1] instead. I hope to submit it tomorrow.\n\nActually, I have half a mind to move all of the refs-related files to a\nsubdirectory, like\n\n    refs.h\n    refs/refs.c\n    refs/refs-internal.h\n    refs/refs-be-files.c\n    refs/refs-be-lmdb.c       <- still to come\n\nWhat would you think of that?\n\nMichael\n\n[1] We've discussed this idea earlier, using the tentative names\nrefs-shared.h or refs-common.h.\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"272736","messageId":"563794B1.5000002@alum.mit.edu","threadId":"40663","inReplyTo":"1445998467-11511-26-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v5 25/26] refs: break out ref conflict checks","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-02T16:52:01Z","receivedAt":"2015-11-02T16:52:01Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 10/28/2015 03:14 AM, David Turner wrote:\n> Create new function verify_no_descendants, to hold one of the ref\n> conflict checks used in verify_refname_available.  Multiple backends\n> will need this function, so it goes in the common code.\n> \n> rename_ref_available also moves to the common code, because alternate\n> backends might need it and it has no files-backend-specific code.\n\nIt is preferred that log messages be written in the imperative voice:\n\n    ... so move it to the common code.\n\n    Also move rename_ref_available ...\n\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n> ---\n>  refs-be-files.c | 49 ++++++++-----------------------------------------\n>  refs.c          | 38 ++++++++++++++++++++++++++++++++++++++\n>  refs.h          | 15 +++++++++++++++\n>  3 files changed, 61 insertions(+), 41 deletions(-)\n> \n> diff --git a/refs-be-files.c b/refs-be-files.c\n> index 0eabea9..97a5983 100644\n> --- a/refs-be-files.c\n> +++ b/refs-be-files.c\n> @@ -729,6 +729,7 @@ static int verify_refname_available_dir(const char *refname,\n>  \t\t\t\t\tstruct strbuf *err)\n>  {\n>  \tconst char *slash;\n> +\tconst char *extra_refname;\n>  \tint pos;\n>  \tstruct strbuf dirname = STRBUF_INIT;\n>  \tint ret = -1;\n> @@ -834,33 +835,15 @@ static int verify_refname_available_dir(const char *refname,\n>  \t\t}\n>  \t}\n>  \n> -\tif (extras) {\n> -\t\t/*\n> -\t\t * Check for entries in extras that start with\n> -\t\t * \"$refname/\". We do that by looking for the place\n> -\t\t * where \"$refname/\" would be inserted in extras. If\n> -\t\t * there is an entry at that position that starts with\n> -\t\t * \"$refname/\" and is not in skip, then we have a\n> -\t\t * conflict.\n> -\t\t */\n\nIn your version, the above comment is replaced with\n\n    /* Look for the place where dirname would be inserted in extras. */\n\nwhich is pretty obvious, I think, from the following line. It's\ndebatable whether the long-winded old comment was worthwhile, but I\nthink the new comment is clearly not. I suggest either restoring a\nlonger explanation or eliminating the comment altogether.\n\n> -\t\tfor (pos = string_list_find_insert_index(extras, dirname.buf, 0);\n> -\t\t     pos < extras->nr; pos++) {\n> -\t\t\tconst char *extra_refname = extras->items[pos].string;\n> -\n> -\t\t\tif (!starts_with(extra_refname, dirname.buf))\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tif (!skip || !string_list_has_string(skip, extra_refname)) {\n> -\t\t\t\tstrbuf_addf(err, \"cannot process '%s' and '%s' at the same time\",\n> -\t\t\t\t\t    refname, extra_refname);\n> -\t\t\t\tgoto cleanup;\n> -\t\t\t}\n> -\t\t}\n> +\textra_refname = find_descendant_ref(dirname.buf, extras, skip);\n> +\tif (extra_refname) {\n> +\t\tstrbuf_addf(err,\n> +\t\t\t    \"cannot process '%s' and '%s' at the same time\",\n> +\t\t\t    refname, extra_refname);\n> +\t} else {\n> +\t\tret = 0;\n>  \t}\n\nProject practice is to leave out unnecessary braces.\n\n>  \n> -\t/* No conflicts were found */\n> -\tret = 0;\n> -\n>  cleanup:\n>  \tstrbuf_release(&dirname);\n>  \treturn ret;\n> @@ -2460,22 +2443,6 @@ out:\n> [...]\n> diff --git a/refs.c b/refs.c\n> index 056c172..5d8b6ea 100644\n> --- a/refs.c\n> +++ b/refs.c\n> [...]\n> diff --git a/refs.h b/refs.h\n> index f97a2e4..88fea3e 100644\n> --- a/refs.h\n> +++ b/refs.h\n> [...]\n> @@ -623,6 +625,19 @@ int files_log_ref_write(const char *refname, const unsigned char *old_sha1,\n>  \t\t\tconst unsigned char *new_sha1, const char *msg,\n>  \t\t\tint flags, struct strbuf *err);\n>  \n> +/*\n> + * Check for entries in extras that are within the specified\n> + * directory, where dirname is a reference directory name including\n> + * the trailing slash (e.g., \"refs/heads/master/\"). Ignore any\n> + * conflicting references that are found in skip. If there is a\n> + * conflicting reference, return its name.\n> + *\n> + * extras and skip must be sorted lists of reference names. skip can\n> + * be NULL; extras cannot.\n\nThe last sentence is incorrect; the function can handle extras == NULL.\n\n> + */\n> +const char *find_descendant_ref(const char *dirname,\n> +\t\t\t\tconst struct string_list *extras,\n> +\t\t\t\tconst struct string_list *skip);\n>  \n>  enum expire_reflog_flags {\n>  \tEXPIRE_REFLOGS_DRY_RUN = 1 << 0,\n> \n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"272767","messageId":"1446502776.4131.30.camel@twopensource.com","threadId":"40663","inReplyTo":"5635CA8A.2080505@alum.mit.edu","subject":"Re: [PATCH v5 18/26] refs: move transaction functions into common code","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-11-02T22:19:36Z","receivedAt":"2015-11-02T22:19:36Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"On Sun, 2015-11-01 at 09:17 +0100, Michael Haggerty wrote:\n> On 10/28/2015 03:14 AM, David Turner wrote:\n> > The common ref code will build up a ref transaction.  Backends will\n> > then commit it.  So the transaction creation and update functions should\n> > be in the common code.  We also need to move the ref structs into\n> > the common code so that alternate backends can access them.\n> > \n> > Later, we will modify struct ref_update to support alternate backends.\n> \n> I would prefer that this and later patches *not* add declarations to the\n> public API in refs.h for functions and data that are only meant to be\n> used by other reference backends.\n> \n> So I'm working on a modified version of your series that declares such\n> functions in refs-internal.h [1] instead. I hope to submit it tomorrow.\n\nOK, I will fix up your other two issues and then wait for that series.\n\n> Actually, I have half a mind to move all of the refs-related files to a\n> subdirectory, like\n> \n>     refs.h\n>     refs/refs.c\n>     refs/refs-internal.h\n>     refs/refs-be-files.c\n>     refs/refs-be-lmdb.c       <- still to come\n> \n> What would you think of that?\n\nSince we're moving stuff around anyway, we might as well introduce a\nlittle more hierarchy.  \n"},{"id":"272789","messageId":"56386406.302@alum.mit.edu","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v5 00/26] refs backend pre-vtable","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:36:38Z","receivedAt":"2015-11-03T07:36:38Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 10/28/2015 03:14 AM, David Turner wrote:\n> This version of the series makes some minor changes from v4:\n> \n> refs.c: move refname_is_safe to the common code: clarify a comment\n> initdb: move safe_create_dir into common code: add a caveat on safe_create_dir\n> refs.c: move update_ref to refs.c: update commit message to include write_pseudoref\n> refs.c: move delete_pseudoref and delete_ref to the common code: remove spurious\n> added newline\n> refs: make files_log_ref_write functions public: reword commit message\n> refs.c: move ref iterators to the common code: added my DCO because this patch changed a bunch since Ronnie wrote it\n\nThanks for your re-roll. I think this series is almost ready. I already\nsent a couple of minor comments about it, plus one bigger one: wouldn't\nit be better to have a header file for declarations intended to be used\ninternally by the various refs backends but not be exposed to non-refs\ncode? I also think we agreed that the refs code could be moved to a\nrefs/ subdirectory.\n\nSo I revised your patch series, including a suggested new file naming\nscheme and addressing my other comments. I will submit that version\nshortly as v6.\n\nOtherwise it all looks good. I've checked everything rather carefully\nand didn't find any problems.\n\nThanks for your patience!\n\nMichael\n\n[1] https://github.com/mhagger/git\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"272790","messageId":"cover.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"1445998467-11511-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v6 00/25] refs backend pre-vtable","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:44Z","receivedAt":"2015-11-03T07:39:44Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"This is a proposed revision of David Turner's refs-backend-pre-vtable\nv5 [1]. It incorporates all of the changes I suggested when reviewing\nthat series, plus it moves the refs-related code to a subdirectory and\ncreates a new header file refs/refs-internal.h for declarations meant\nto be used within the refs module but not by other code. I've retained\nthe authors of the original patches because most of what I've done is\njust shift things around and adjust some includes and comments\naccordingly.\n\nThis branch proposes the following file layout for the refs module:\n\n    refs.h\n    refs/refs.c\n    refs/refs-internal.h\n    refs/files-backend.c\n    refs/lmdb-backend.c   <- suggested name for the upcoming LMDB code\n\nI changed the name of \"refs-be-files.c\" to \"refs/files-backend.c\"\nbecause otherwise the \"refs\" would have been redundant with the\nsubdirectory name, and now there is room in the filename to spell out\n\"backend\".\n\nSummary of changes in my branch vs. your v5:\n\n* Rename refs-be-files.c to refs/files-backend.c\n* Rename refs.c to refs/refs.c\n* Introduce a new header file, refs/refs-internal.h, to hold\n  declarations that are needed by other refs backends but shouldn't\n  be used by non-refs code. The end result is that refs.h is almost\n  unchanged by this series.\n* Adjust commit messages for the new file locations.\n* Instead of making verify_refname_available() public, move it to\n  refs/refs-internal.h. (I think this function will only be needed\n  by other refs backends and not by other code.) This change\n  required your patch 03/26 to be moved later in the series.\n* Add a missing LF in your patch 18/26.\n* Touch up the log message and comments in your patch 25/26.\n* Drop patch 26/26, Peff's \"introduce \"extensions\" form of\n  core.repositoryformatversion\", as that patch is already in master.\n\nThese patches are also available as the `refs-backend-pre-vtable`\nbranch in my GitHub repo [2].\n\nI don't want to hijack this patch series or anything, but it seemed\nsimpler to express my suggestions as code. Feel free to pick and\nchoose what you like and submit a v7 if that is your preference.\n\nMichael\n\n[1] http://thread.gmane.org/gmane.comp.version-control.git/280325\n[2] https://github.com/mhagger/git\n\nDavid Turner (9):\n  refs: make is_branch public\n  refs: move transaction functions to the common code\n  refs: move refname_is_safe to the common code\n  refs: move copy_msg to the common code\n  refs: move peel_object to the common code\n  refs: move should_autocreate_reflog to common code\n  initdb: make safe_create_dir public\n  files_log_ref_write: new function\n  refs: break out ref conflict checks\n\nRonnie Sahlberg (16):\n  refs/files-backend.c: new file, renamed from refs.c\n  refs: add a new file, refs/refs.c, to hold common refs code\n  refs: move update_ref to refs/refs.c\n  refs: move delete_pseudoref and delete_ref to the common code\n  refs: move read_ref_at to the common refs file\n  refs: move the hidden refs functions to the common code\n  refs: move dwim and friend functions to the common refs code\n  refs: move warn_if_dangling_symref* to the common code\n  refs: move read_ref, read_ref_full and ref_exists to the common code\n  refs: move resolve_refdup to common\n  refs: move check_refname_format to the common code\n  refs: move is_branch to the common code\n  refs: move prettify_refname to the common code\n  refs: move ref iterators to the common code\n  refs: move head_ref_namespaced to the common code\n  refs: create a shared version of verify_refname_available\n\n Makefile                       |    5 +-\n builtin/init-db.c              |   12 -\n cache.h                        |    8 +\n path.c                         |   12 +\n refs.h                         |    2 +\n refs.c => refs/files-backend.c | 1291 ++--------------------------------------\n refs/refs-internal.h           |  200 +++++++\n refs/refs.c                    | 1073 +++++++++++++++++++++++++++++++++\n 8 files changed, 1348 insertions(+), 1255 deletions(-)\n rename refs.c => refs/files-backend.c (75%)\n create mode 100644 refs/refs-internal.h\n create mode 100644 refs/refs.c\n\n-- \n2.6.2\n"},{"id":"272792","messageId":"39e0a2a708fb1a42b69e45bc5c0b17d565d3662e.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 01/25] refs: make is_branch public","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:45Z","receivedAt":"2015-11-03T07:39:45Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nis_branch was already non-static, but this patch declares it in the\nheader.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.h | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/refs.h b/refs.h\nindex 6d30c98..39b8edc 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -217,6 +217,8 @@ extern void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct st\n  */\n int pack_refs(unsigned int flags);\n \n+int is_branch(const char *refname);\n+\n /*\n  * Flags controlling ref_transaction_update(), ref_transaction_create(), etc.\n  * REF_NODEREF: act on the ref directly, instead of dereferencing\n-- \n2.6.2\n"},{"id":"272791","messageId":"5910b009877933ad63ca376a904f5003fcd3e627.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 02/25] refs/files-backend.c: new file, renamed from refs.c","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:46Z","receivedAt":"2015-11-03T07:39:46Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nWe are about to split up the reference code into multiple source\nfiles, to separate the generic code from the code that is specific to\nthe current files-based backend. To keep things organized, we will\nmove the reference-related code to a subdirectory, \"refs/\". Over time,\nmore files will appear in this subdirectory.\n\nAs the first step, rename refs.c to refs/files-backend.c. This file\nwill eventually contain only the code specific to the files-based\nbackend. In subsequent commits we will move backend-agnostic code to a\nnew refs/refs.c file that will hold the common refs code that is\nshared across backends.\n\nThe reason for first moving all the code to refs/files-backend.c and\nthen moving the backend agnostic code back to refs/refs.c instead of\nmoving refs.c to refs/refs.c first is because the code that will\neventually remain in this new files-backend.c file is so entangled\nthat it would then be very difficult to break the split up into small\nindependent patches/chunks.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n Makefile                       |  4 ++--\n refs.c => refs/files-backend.c | 14 +++++++-------\n 2 files changed, 9 insertions(+), 9 deletions(-)\n rename refs.c => refs/files-backend.c (99%)\n\ndiff --git a/Makefile b/Makefile\nindex 0d9f5dd..1a63383 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -762,8 +762,8 @@ LIB_OBJS += quote.o\n LIB_OBJS += reachable.o\n LIB_OBJS += read-cache.o\n LIB_OBJS += reflog-walk.o\n-LIB_OBJS += refs.o\n LIB_OBJS += ref-filter.o\n+LIB_OBJS += refs/files-backend.o\n LIB_OBJS += remote.o\n LIB_OBJS += replace_object.o\n LIB_OBJS += rerere.o\n@@ -2412,7 +2412,7 @@ profile-clean:\n \t$(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))\n \n clean: profile-clean coverage-clean\n-\t$(RM) *.o *.res block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o\n+\t$(RM) *.o *.res refs/*.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o\n \t$(RM) xdiff/*.o vcs-svn/*.o ewah/*.o builtin/*.o\n \t$(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)\n \t$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X\ndiff --git a/refs.c b/refs/files-backend.c\nsimilarity index 99%\nrename from refs.c\nrename to refs/files-backend.c\nindex 132eff5..dc39b36 100644\n--- a/refs.c\n+++ b/refs/files-backend.c\n@@ -1,10 +1,10 @@\n-#include \"cache.h\"\n-#include \"lockfile.h\"\n-#include \"refs.h\"\n-#include \"object.h\"\n-#include \"tag.h\"\n-#include \"dir.h\"\n-#include \"string-list.h\"\n+#include \"../cache.h\"\n+#include \"../refs.h\"\n+#include \"../lockfile.h\"\n+#include \"../object.h\"\n+#include \"../tag.h\"\n+#include \"../dir.h\"\n+#include \"../string-list.h\"\n \n struct ref_lock {\n \tchar *ref_name;\n-- \n2.6.2\n"},{"id":"272801","messageId":"8cd6d2158e8e4512eae6f8c17e8fe2245b37e3dc.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 03/25] refs: add a new file, refs/refs.c, to hold common refs code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:47Z","receivedAt":"2015-11-03T07:39:47Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nCreate a new file, refs/refs.c, that will be used to hold all the refs\ncode that is backend agnostic and can be used across all backends.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n Makefile    | 1 +\n refs/refs.c | 3 +++\n 2 files changed, 4 insertions(+)\n create mode 100644 refs/refs.c\n\ndiff --git a/Makefile b/Makefile\nindex 1a63383..be45704 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -764,6 +764,7 @@ LIB_OBJS += read-cache.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += ref-filter.o\n LIB_OBJS += refs/files-backend.o\n+LIB_OBJS += refs/refs.o\n LIB_OBJS += remote.o\n LIB_OBJS += replace_object.o\n LIB_OBJS += rerere.o\ndiff --git a/refs/refs.c b/refs/refs.c\nnew file mode 100644\nindex 0000000..77492ff\n--- /dev/null\n+++ b/refs/refs.c\n@@ -0,0 +1,3 @@\n+/*\n+ * Common refs code for all backends.\n+ */\n-- \n2.6.2\n"},{"id":"272802","messageId":"c57c5d140bfb905aa00bc86a35e8f580b3334e10.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 04/25] refs: move update_ref to refs/refs.c","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:48Z","receivedAt":"2015-11-03T07:39:48Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nMove update_ref() to refs/refs.c since this function does not contain\nany backend specific code. Move the ref classifier functions and\nwrite_pseudoref as well, since update_ref depends on them.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 117 +--------------------------------------------------\n refs/refs.c          | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 117 insertions(+), 116 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex dc39b36..e8c592a 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2683,8 +2683,6 @@ struct pack_refs_cb_data {\n \tstruct ref_to_prune *ref_to_prune;\n };\n \n-static int is_per_worktree_ref(const char *refname);\n-\n /*\n  * An each_ref_entry_fn that is run over loose references only.  If\n  * the loose reference can be packed, add an entry in the packed ref\n@@ -2699,7 +2697,7 @@ static int pack_if_possible_fn(struct ref_entry *entry, void *cb_data)\n \tint is_tag_ref = starts_with(entry->name, \"refs/tags/\");\n \n \t/* Do not pack per-worktree refs: */\n-\tif (is_per_worktree_ref(entry->name))\n+\tif (ref_type(entry->name) == REF_TYPE_PER_WORKTREE)\n \t\treturn 0;\n \n \t/* ALWAYS pack tags */\n@@ -2894,77 +2892,6 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)\n \treturn 0;\n }\n \n-static int is_per_worktree_ref(const char *refname)\n-{\n-\treturn !strcmp(refname, \"HEAD\") ||\n-\t\tstarts_with(refname, \"refs/bisect/\");\n-}\n-\n-static int is_pseudoref_syntax(const char *refname)\n-{\n-\tconst char *c;\n-\n-\tfor (c = refname; *c; c++) {\n-\t\tif (!isupper(*c) && *c != '-' && *c != '_')\n-\t\t\treturn 0;\n-\t}\n-\n-\treturn 1;\n-}\n-\n-enum ref_type ref_type(const char *refname)\n-{\n-\tif (is_per_worktree_ref(refname))\n-\t\treturn REF_TYPE_PER_WORKTREE;\n-\tif (is_pseudoref_syntax(refname))\n-\t\treturn REF_TYPE_PSEUDOREF;\n-       return REF_TYPE_NORMAL;\n-}\n-\n-static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,\n-\t\t\t   const unsigned char *old_sha1, struct strbuf *err)\n-{\n-\tconst char *filename;\n-\tint fd;\n-\tstatic struct lock_file lock;\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tint ret = -1;\n-\n-\tstrbuf_addf(&buf, \"%s\\n\", sha1_to_hex(sha1));\n-\n-\tfilename = git_path(\"%s\", pseudoref);\n-\tfd = hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR);\n-\tif (fd < 0) {\n-\t\tstrbuf_addf(err, \"Could not open '%s' for writing: %s\",\n-\t\t\t    filename, strerror(errno));\n-\t\treturn -1;\n-\t}\n-\n-\tif (old_sha1) {\n-\t\tunsigned char actual_old_sha1[20];\n-\n-\t\tif (read_ref(pseudoref, actual_old_sha1))\n-\t\t\tdie(\"could not read ref '%s'\", pseudoref);\n-\t\tif (hashcmp(actual_old_sha1, old_sha1)) {\n-\t\t\tstrbuf_addf(err, \"Unexpected sha1 when writing %s\", pseudoref);\n-\t\t\trollback_lock_file(&lock);\n-\t\t\tgoto done;\n-\t\t}\n-\t}\n-\n-\tif (write_in_full(fd, buf.buf, buf.len) != buf.len) {\n-\t\tstrbuf_addf(err, \"Could not write to '%s'\", filename);\n-\t\trollback_lock_file(&lock);\n-\t\tgoto done;\n-\t}\n-\n-\tcommit_lock_file(&lock);\n-\tret = 0;\n-done:\n-\tstrbuf_release(&buf);\n-\treturn ret;\n-}\n-\n static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1)\n {\n \tstatic struct lock_file lock;\n@@ -4105,48 +4032,6 @@ int ref_transaction_verify(struct ref_transaction *transaction,\n \t\t\t\t      flags, NULL, err);\n }\n \n-int update_ref(const char *msg, const char *refname,\n-\t       const unsigned char *new_sha1, const unsigned char *old_sha1,\n-\t       unsigned int flags, enum action_on_err onerr)\n-{\n-\tstruct ref_transaction *t = NULL;\n-\tstruct strbuf err = STRBUF_INIT;\n-\tint ret = 0;\n-\n-\tif (ref_type(refname) == REF_TYPE_PSEUDOREF) {\n-\t\tret = write_pseudoref(refname, new_sha1, old_sha1, &err);\n-\t} else {\n-\t\tt = ref_transaction_begin(&err);\n-\t\tif (!t ||\n-\t\t    ref_transaction_update(t, refname, new_sha1, old_sha1,\n-\t\t\t\t\t   flags, msg, &err) ||\n-\t\t    ref_transaction_commit(t, &err)) {\n-\t\t\tret = 1;\n-\t\t\tref_transaction_free(t);\n-\t\t}\n-\t}\n-\tif (ret) {\n-\t\tconst char *str = \"update_ref failed for ref '%s': %s\";\n-\n-\t\tswitch (onerr) {\n-\t\tcase UPDATE_REFS_MSG_ON_ERR:\n-\t\t\terror(str, refname, err.buf);\n-\t\t\tbreak;\n-\t\tcase UPDATE_REFS_DIE_ON_ERR:\n-\t\t\tdie(str, refname, err.buf);\n-\t\t\tbreak;\n-\t\tcase UPDATE_REFS_QUIET_ON_ERR:\n-\t\t\tbreak;\n-\t\t}\n-\t\tstrbuf_release(&err);\n-\t\treturn 1;\n-\t}\n-\tstrbuf_release(&err);\n-\tif (t)\n-\t\tref_transaction_free(t);\n-\treturn 0;\n-}\n-\n static int ref_update_reject_duplicates(struct string_list *refnames,\n \t\t\t\t\tstruct strbuf *err)\n {\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 77492ff..a63a58d 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -1,3 +1,119 @@\n /*\n  * Common refs code for all backends.\n  */\n+#include \"../cache.h\"\n+#include \"../refs.h\"\n+#include \"../lockfile.h\"\n+\n+static int is_per_worktree_ref(const char *refname)\n+{\n+\treturn !strcmp(refname, \"HEAD\") ||\n+\t\tstarts_with(refname, \"refs/bisect/\");\n+}\n+\n+static int is_pseudoref_syntax(const char *refname)\n+{\n+\tconst char *c;\n+\n+\tfor (c = refname; *c; c++) {\n+\t\tif (!isupper(*c) && *c != '-' && *c != '_')\n+\t\t\treturn 0;\n+\t}\n+\n+\treturn 1;\n+}\n+\n+enum ref_type ref_type(const char *refname)\n+{\n+\tif (is_per_worktree_ref(refname))\n+\t\treturn REF_TYPE_PER_WORKTREE;\n+\tif (is_pseudoref_syntax(refname))\n+\t\treturn REF_TYPE_PSEUDOREF;\n+       return REF_TYPE_NORMAL;\n+}\n+\n+static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,\n+\t\t\t   const unsigned char *old_sha1, struct strbuf *err)\n+{\n+\tconst char *filename;\n+\tint fd;\n+\tstatic struct lock_file lock;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint ret = -1;\n+\n+\tstrbuf_addf(&buf, \"%s\\n\", sha1_to_hex(sha1));\n+\n+\tfilename = git_path(\"%s\", pseudoref);\n+\tfd = hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR);\n+\tif (fd < 0) {\n+\t\tstrbuf_addf(err, \"Could not open '%s' for writing: %s\",\n+\t\t\t    filename, strerror(errno));\n+\t\treturn -1;\n+\t}\n+\n+\tif (old_sha1) {\n+\t\tunsigned char actual_old_sha1[20];\n+\n+\t\tif (read_ref(pseudoref, actual_old_sha1))\n+\t\t\tdie(\"could not read ref '%s'\", pseudoref);\n+\t\tif (hashcmp(actual_old_sha1, old_sha1)) {\n+\t\t\tstrbuf_addf(err, \"Unexpected sha1 when writing %s\", pseudoref);\n+\t\t\trollback_lock_file(&lock);\n+\t\t\tgoto done;\n+\t\t}\n+\t}\n+\n+\tif (write_in_full(fd, buf.buf, buf.len) != buf.len) {\n+\t\tstrbuf_addf(err, \"Could not write to '%s'\", filename);\n+\t\trollback_lock_file(&lock);\n+\t\tgoto done;\n+\t}\n+\n+\tcommit_lock_file(&lock);\n+\tret = 0;\n+done:\n+\tstrbuf_release(&buf);\n+\treturn ret;\n+}\n+\n+int update_ref(const char *msg, const char *refname,\n+\t       const unsigned char *new_sha1, const unsigned char *old_sha1,\n+\t       unsigned int flags, enum action_on_err onerr)\n+{\n+\tstruct ref_transaction *t = NULL;\n+\tstruct strbuf err = STRBUF_INIT;\n+\tint ret = 0;\n+\n+\tif (ref_type(refname) == REF_TYPE_PSEUDOREF) {\n+\t\tret = write_pseudoref(refname, new_sha1, old_sha1, &err);\n+\t} else {\n+\t\tt = ref_transaction_begin(&err);\n+\t\tif (!t ||\n+\t\t    ref_transaction_update(t, refname, new_sha1, old_sha1,\n+\t\t\t\t\t   flags, msg, &err) ||\n+\t\t    ref_transaction_commit(t, &err)) {\n+\t\t\tret = 1;\n+\t\t\tref_transaction_free(t);\n+\t\t}\n+\t}\n+\tif (ret) {\n+\t\tconst char *str = \"update_ref failed for ref '%s': %s\";\n+\n+\t\tswitch (onerr) {\n+\t\tcase UPDATE_REFS_MSG_ON_ERR:\n+\t\t\terror(str, refname, err.buf);\n+\t\t\tbreak;\n+\t\tcase UPDATE_REFS_DIE_ON_ERR:\n+\t\t\tdie(str, refname, err.buf);\n+\t\t\tbreak;\n+\t\tcase UPDATE_REFS_QUIET_ON_ERR:\n+\t\t\tbreak;\n+\t\t}\n+\t\tstrbuf_release(&err);\n+\t\treturn 1;\n+\t}\n+\tstrbuf_release(&err);\n+\tif (t)\n+\t\tref_transaction_free(t);\n+\treturn 0;\n+}\n-- \n2.6.2\n"},{"id":"272806","messageId":"66b3ecccedd5eac095e8e165a363a3a3d1a2a920.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 05/25] refs: move delete_pseudoref and delete_ref to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:49Z","receivedAt":"2015-11-03T07:39:49Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nMove delete_pseudoref() and delete_ref() to refs/refs.c since these\nfunctions do not contain any backend specific code. We can't move\ndelete_refs yet because it depends on the files-backend-specific\nrepack_without_refs.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 56 ----------------------------------------------------\n refs/refs.c          | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 56 insertions(+), 56 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex e8c592a..6d502ac 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2892,62 +2892,6 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)\n \treturn 0;\n }\n \n-static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1)\n-{\n-\tstatic struct lock_file lock;\n-\tconst char *filename;\n-\n-\tfilename = git_path(\"%s\", pseudoref);\n-\n-\tif (old_sha1 && !is_null_sha1(old_sha1)) {\n-\t\tint fd;\n-\t\tunsigned char actual_old_sha1[20];\n-\n-\t\tfd = hold_lock_file_for_update(&lock, filename,\n-\t\t\t\t\t       LOCK_DIE_ON_ERROR);\n-\t\tif (fd < 0)\n-\t\t\tdie_errno(_(\"Could not open '%s' for writing\"), filename);\n-\t\tif (read_ref(pseudoref, actual_old_sha1))\n-\t\t\tdie(\"could not read ref '%s'\", pseudoref);\n-\t\tif (hashcmp(actual_old_sha1, old_sha1)) {\n-\t\t\twarning(\"Unexpected sha1 when deleting %s\", pseudoref);\n-\t\t\trollback_lock_file(&lock);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tunlink(filename);\n-\t\trollback_lock_file(&lock);\n-\t} else {\n-\t\tunlink(filename);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-int delete_ref(const char *refname, const unsigned char *old_sha1,\n-\t       unsigned int flags)\n-{\n-\tstruct ref_transaction *transaction;\n-\tstruct strbuf err = STRBUF_INIT;\n-\n-\tif (ref_type(refname) == REF_TYPE_PSEUDOREF)\n-\t\treturn delete_pseudoref(refname, old_sha1);\n-\n-\ttransaction = ref_transaction_begin(&err);\n-\tif (!transaction ||\n-\t    ref_transaction_delete(transaction, refname, old_sha1,\n-\t\t\t\t   flags, NULL, &err) ||\n-\t    ref_transaction_commit(transaction, &err)) {\n-\t\terror(\"%s\", err.buf);\n-\t\tref_transaction_free(transaction);\n-\t\tstrbuf_release(&err);\n-\t\treturn 1;\n-\t}\n-\tref_transaction_free(transaction);\n-\tstrbuf_release(&err);\n-\treturn 0;\n-}\n-\n int delete_refs(struct string_list *refnames)\n {\n \tstruct strbuf err = STRBUF_INIT;\ndiff --git a/refs/refs.c b/refs/refs.c\nindex a63a58d..96d5c6d 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -117,3 +117,59 @@ int update_ref(const char *msg, const char *refname,\n \t\tref_transaction_free(t);\n \treturn 0;\n }\n+\n+static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1)\n+{\n+\tstatic struct lock_file lock;\n+\tconst char *filename;\n+\n+\tfilename = git_path(\"%s\", pseudoref);\n+\n+\tif (old_sha1 && !is_null_sha1(old_sha1)) {\n+\t\tint fd;\n+\t\tunsigned char actual_old_sha1[20];\n+\n+\t\tfd = hold_lock_file_for_update(&lock, filename,\n+\t\t\t\t\t       LOCK_DIE_ON_ERROR);\n+\t\tif (fd < 0)\n+\t\t\tdie_errno(_(\"Could not open '%s' for writing\"), filename);\n+\t\tif (read_ref(pseudoref, actual_old_sha1))\n+\t\t\tdie(\"could not read ref '%s'\", pseudoref);\n+\t\tif (hashcmp(actual_old_sha1, old_sha1)) {\n+\t\t\twarning(\"Unexpected sha1 when deleting %s\", pseudoref);\n+\t\t\trollback_lock_file(&lock);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tunlink(filename);\n+\t\trollback_lock_file(&lock);\n+\t} else {\n+\t\tunlink(filename);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int delete_ref(const char *refname, const unsigned char *old_sha1,\n+\t       unsigned int flags)\n+{\n+\tstruct ref_transaction *transaction;\n+\tstruct strbuf err = STRBUF_INIT;\n+\n+\tif (ref_type(refname) == REF_TYPE_PSEUDOREF)\n+\t\treturn delete_pseudoref(refname, old_sha1);\n+\n+\ttransaction = ref_transaction_begin(&err);\n+\tif (!transaction ||\n+\t    ref_transaction_delete(transaction, refname, old_sha1,\n+\t\t\t\t   flags, NULL, &err) ||\n+\t    ref_transaction_commit(transaction, &err)) {\n+\t\terror(\"%s\", err.buf);\n+\t\tref_transaction_free(transaction);\n+\t\tstrbuf_release(&err);\n+\t\treturn 1;\n+\t}\n+\tref_transaction_free(transaction);\n+\tstrbuf_release(&err);\n+\treturn 0;\n+}\n-- \n2.6.2\n"},{"id":"272803","messageId":"d7a4044eab7dc4d56172bb43c2e68dba0d40037b.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 06/25] refs: move read_ref_at to the common refs file","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:50Z","receivedAt":"2015-11-03T07:39:50Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nMove read_ref_at() to refs/refs.c since this function does not contain\nany backend specific code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 118 ---------------------------------------------------\n refs/refs.c          | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 118 insertions(+), 118 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 6d502ac..8eba347 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3469,124 +3469,6 @@ int create_symref(const char *ref_target, const char *refs_heads_master,\n \treturn 0;\n }\n \n-struct read_ref_at_cb {\n-\tconst char *refname;\n-\tunsigned long at_time;\n-\tint cnt;\n-\tint reccnt;\n-\tunsigned char *sha1;\n-\tint found_it;\n-\n-\tunsigned char osha1[20];\n-\tunsigned char nsha1[20];\n-\tint tz;\n-\tunsigned long date;\n-\tchar **msg;\n-\tunsigned long *cutoff_time;\n-\tint *cutoff_tz;\n-\tint *cutoff_cnt;\n-};\n-\n-static int read_ref_at_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n-\t\tconst char *message, void *cb_data)\n-{\n-\tstruct read_ref_at_cb *cb = cb_data;\n-\n-\tcb->reccnt++;\n-\tcb->tz = tz;\n-\tcb->date = timestamp;\n-\n-\tif (timestamp <= cb->at_time || cb->cnt == 0) {\n-\t\tif (cb->msg)\n-\t\t\t*cb->msg = xstrdup(message);\n-\t\tif (cb->cutoff_time)\n-\t\t\t*cb->cutoff_time = timestamp;\n-\t\tif (cb->cutoff_tz)\n-\t\t\t*cb->cutoff_tz = tz;\n-\t\tif (cb->cutoff_cnt)\n-\t\t\t*cb->cutoff_cnt = cb->reccnt - 1;\n-\t\t/*\n-\t\t * we have not yet updated cb->[n|o]sha1 so they still\n-\t\t * hold the values for the previous record.\n-\t\t */\n-\t\tif (!is_null_sha1(cb->osha1)) {\n-\t\t\thashcpy(cb->sha1, nsha1);\n-\t\t\tif (hashcmp(cb->osha1, nsha1))\n-\t\t\t\twarning(\"Log for ref %s has gap after %s.\",\n-\t\t\t\t\tcb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));\n-\t\t}\n-\t\telse if (cb->date == cb->at_time)\n-\t\t\thashcpy(cb->sha1, nsha1);\n-\t\telse if (hashcmp(nsha1, cb->sha1))\n-\t\t\twarning(\"Log for ref %s unexpectedly ended on %s.\",\n-\t\t\t\tcb->refname, show_date(cb->date, cb->tz,\n-\t\t\t\t\t\t       DATE_MODE(RFC2822)));\n-\t\thashcpy(cb->osha1, osha1);\n-\t\thashcpy(cb->nsha1, nsha1);\n-\t\tcb->found_it = 1;\n-\t\treturn 1;\n-\t}\n-\thashcpy(cb->osha1, osha1);\n-\thashcpy(cb->nsha1, nsha1);\n-\tif (cb->cnt > 0)\n-\t\tcb->cnt--;\n-\treturn 0;\n-}\n-\n-static int read_ref_at_ent_oldest(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t\t  const char *email, unsigned long timestamp,\n-\t\t\t\t  int tz, const char *message, void *cb_data)\n-{\n-\tstruct read_ref_at_cb *cb = cb_data;\n-\n-\tif (cb->msg)\n-\t\t*cb->msg = xstrdup(message);\n-\tif (cb->cutoff_time)\n-\t\t*cb->cutoff_time = timestamp;\n-\tif (cb->cutoff_tz)\n-\t\t*cb->cutoff_tz = tz;\n-\tif (cb->cutoff_cnt)\n-\t\t*cb->cutoff_cnt = cb->reccnt;\n-\thashcpy(cb->sha1, osha1);\n-\tif (is_null_sha1(cb->sha1))\n-\t\thashcpy(cb->sha1, nsha1);\n-\t/* We just want the first entry */\n-\treturn 1;\n-}\n-\n-int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,\n-\t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n-{\n-\tstruct read_ref_at_cb cb;\n-\n-\tmemset(&cb, 0, sizeof(cb));\n-\tcb.refname = refname;\n-\tcb.at_time = at_time;\n-\tcb.cnt = cnt;\n-\tcb.msg = msg;\n-\tcb.cutoff_time = cutoff_time;\n-\tcb.cutoff_tz = cutoff_tz;\n-\tcb.cutoff_cnt = cutoff_cnt;\n-\tcb.sha1 = sha1;\n-\n-\tfor_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);\n-\n-\tif (!cb.reccnt) {\n-\t\tif (flags & GET_SHA1_QUIETLY)\n-\t\t\texit(128);\n-\t\telse\n-\t\t\tdie(\"Log for %s is empty.\", refname);\n-\t}\n-\tif (cb.found_it)\n-\t\treturn 0;\n-\n-\tfor_each_reflog_ent(refname, read_ref_at_ent_oldest, &cb);\n-\n-\treturn 1;\n-}\n-\n int reflog_exists(const char *refname)\n {\n \tstruct stat st;\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 96d5c6d..99221a3 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -173,3 +173,121 @@ int delete_ref(const char *refname, const unsigned char *old_sha1,\n \tstrbuf_release(&err);\n \treturn 0;\n }\n+\n+struct read_ref_at_cb {\n+\tconst char *refname;\n+\tunsigned long at_time;\n+\tint cnt;\n+\tint reccnt;\n+\tunsigned char *sha1;\n+\tint found_it;\n+\n+\tunsigned char osha1[20];\n+\tunsigned char nsha1[20];\n+\tint tz;\n+\tunsigned long date;\n+\tchar **msg;\n+\tunsigned long *cutoff_time;\n+\tint *cutoff_tz;\n+\tint *cutoff_cnt;\n+};\n+\n+static int read_ref_at_ent(unsigned char *osha1, unsigned char *nsha1,\n+\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *message, void *cb_data)\n+{\n+\tstruct read_ref_at_cb *cb = cb_data;\n+\n+\tcb->reccnt++;\n+\tcb->tz = tz;\n+\tcb->date = timestamp;\n+\n+\tif (timestamp <= cb->at_time || cb->cnt == 0) {\n+\t\tif (cb->msg)\n+\t\t\t*cb->msg = xstrdup(message);\n+\t\tif (cb->cutoff_time)\n+\t\t\t*cb->cutoff_time = timestamp;\n+\t\tif (cb->cutoff_tz)\n+\t\t\t*cb->cutoff_tz = tz;\n+\t\tif (cb->cutoff_cnt)\n+\t\t\t*cb->cutoff_cnt = cb->reccnt - 1;\n+\t\t/*\n+\t\t * we have not yet updated cb->[n|o]sha1 so they still\n+\t\t * hold the values for the previous record.\n+\t\t */\n+\t\tif (!is_null_sha1(cb->osha1)) {\n+\t\t\thashcpy(cb->sha1, nsha1);\n+\t\t\tif (hashcmp(cb->osha1, nsha1))\n+\t\t\t\twarning(\"Log for ref %s has gap after %s.\",\n+\t\t\t\t\tcb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));\n+\t\t}\n+\t\telse if (cb->date == cb->at_time)\n+\t\t\thashcpy(cb->sha1, nsha1);\n+\t\telse if (hashcmp(nsha1, cb->sha1))\n+\t\t\twarning(\"Log for ref %s unexpectedly ended on %s.\",\n+\t\t\t\tcb->refname, show_date(cb->date, cb->tz,\n+\t\t\t\t\t\t       DATE_MODE(RFC2822)));\n+\t\thashcpy(cb->osha1, osha1);\n+\t\thashcpy(cb->nsha1, nsha1);\n+\t\tcb->found_it = 1;\n+\t\treturn 1;\n+\t}\n+\thashcpy(cb->osha1, osha1);\n+\thashcpy(cb->nsha1, nsha1);\n+\tif (cb->cnt > 0)\n+\t\tcb->cnt--;\n+\treturn 0;\n+}\n+\n+static int read_ref_at_ent_oldest(unsigned char *osha1, unsigned char *nsha1,\n+\t\t\t\t  const char *email, unsigned long timestamp,\n+\t\t\t\t  int tz, const char *message, void *cb_data)\n+{\n+\tstruct read_ref_at_cb *cb = cb_data;\n+\n+\tif (cb->msg)\n+\t\t*cb->msg = xstrdup(message);\n+\tif (cb->cutoff_time)\n+\t\t*cb->cutoff_time = timestamp;\n+\tif (cb->cutoff_tz)\n+\t\t*cb->cutoff_tz = tz;\n+\tif (cb->cutoff_cnt)\n+\t\t*cb->cutoff_cnt = cb->reccnt;\n+\thashcpy(cb->sha1, osha1);\n+\tif (is_null_sha1(cb->sha1))\n+\t\thashcpy(cb->sha1, nsha1);\n+\t/* We just want the first entry */\n+\treturn 1;\n+}\n+\n+int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,\n+\t\tunsigned char *sha1, char **msg,\n+\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n+{\n+\tstruct read_ref_at_cb cb;\n+\n+\tmemset(&cb, 0, sizeof(cb));\n+\tcb.refname = refname;\n+\tcb.at_time = at_time;\n+\tcb.cnt = cnt;\n+\tcb.msg = msg;\n+\tcb.cutoff_time = cutoff_time;\n+\tcb.cutoff_tz = cutoff_tz;\n+\tcb.cutoff_cnt = cutoff_cnt;\n+\tcb.sha1 = sha1;\n+\n+\tfor_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);\n+\n+\tif (!cb.reccnt) {\n+\t\tif (flags & GET_SHA1_QUIETLY)\n+\t\t\texit(128);\n+\t\telse\n+\t\t\tdie(\"Log for %s is empty.\", refname);\n+\t}\n+\tif (cb.found_it)\n+\t\treturn 0;\n+\n+\tfor_each_reflog_ent(refname, read_ref_at_ent_oldest, &cb);\n+\n+\treturn 1;\n+}\n-- \n2.6.2\n"},{"id":"272810","messageId":"41fe017e6d9ae1348de1838b80af70b8bf7db947.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 07/25] refs: move the hidden refs functions to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:51Z","receivedAt":"2015-11-03T07:39:51Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nMove the hidden refs functions to refs/refs.c since these functions do\nnot contain any backend specific code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 51 ---------------------------------------------------\n refs/refs.c          | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 51 insertions(+), 51 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 8eba347..8f1e486 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -4219,57 +4219,6 @@ char *shorten_unambiguous_ref(const char *refname, int strict)\n \treturn xstrdup(refname);\n }\n \n-static struct string_list *hide_refs;\n-\n-int parse_hide_refs_config(const char *var, const char *value, const char *section)\n-{\n-\tif (!strcmp(\"transfer.hiderefs\", var) ||\n-\t    /* NEEDSWORK: use parse_config_key() once both are merged */\n-\t    (starts_with(var, section) && var[strlen(section)] == '.' &&\n-\t     !strcmp(var + strlen(section), \".hiderefs\"))) {\n-\t\tchar *ref;\n-\t\tint len;\n-\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\tref = xstrdup(value);\n-\t\tlen = strlen(ref);\n-\t\twhile (len && ref[len - 1] == '/')\n-\t\t\tref[--len] = '\\0';\n-\t\tif (!hide_refs) {\n-\t\t\thide_refs = xcalloc(1, sizeof(*hide_refs));\n-\t\t\thide_refs->strdup_strings = 1;\n-\t\t}\n-\t\tstring_list_append(hide_refs, ref);\n-\t}\n-\treturn 0;\n-}\n-\n-int ref_is_hidden(const char *refname)\n-{\n-\tint i;\n-\n-\tif (!hide_refs)\n-\t\treturn 0;\n-\tfor (i = hide_refs->nr - 1; i >= 0; i--) {\n-\t\tconst char *match = hide_refs->items[i].string;\n-\t\tint neg = 0;\n-\t\tint len;\n-\n-\t\tif (*match == '!') {\n-\t\t\tneg = 1;\n-\t\t\tmatch++;\n-\t\t}\n-\n-\t\tif (!starts_with(refname, match))\n-\t\t\tcontinue;\n-\t\tlen = strlen(match);\n-\t\tif (!refname[len] || refname[len] == '/')\n-\t\t\treturn !neg;\n-\t}\n-\treturn 0;\n-}\n-\n struct expire_reflog_cb {\n \tunsigned int flags;\n \treflog_expiry_should_prune_fn *should_prune_fn;\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 99221a3..0620ba3 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -291,3 +291,54 @@ int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time,\n \n \treturn 1;\n }\n+\n+static struct string_list *hide_refs;\n+\n+int parse_hide_refs_config(const char *var, const char *value, const char *section)\n+{\n+\tif (!strcmp(\"transfer.hiderefs\", var) ||\n+\t    /* NEEDSWORK: use parse_config_key() once both are merged */\n+\t    (starts_with(var, section) && var[strlen(section)] == '.' &&\n+\t     !strcmp(var + strlen(section), \".hiderefs\"))) {\n+\t\tchar *ref;\n+\t\tint len;\n+\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tref = xstrdup(value);\n+\t\tlen = strlen(ref);\n+\t\twhile (len && ref[len - 1] == '/')\n+\t\t\tref[--len] = '\\0';\n+\t\tif (!hide_refs) {\n+\t\t\thide_refs = xcalloc(1, sizeof(*hide_refs));\n+\t\t\thide_refs->strdup_strings = 1;\n+\t\t}\n+\t\tstring_list_append(hide_refs, ref);\n+\t}\n+\treturn 0;\n+}\n+\n+int ref_is_hidden(const char *refname)\n+{\n+\tint i;\n+\n+\tif (!hide_refs)\n+\t\treturn 0;\n+\tfor (i = hide_refs->nr - 1; i >= 0; i--) {\n+\t\tconst char *match = hide_refs->items[i].string;\n+\t\tint neg = 0;\n+\t\tint len;\n+\n+\t\tif (*match == '!') {\n+\t\t\tneg = 1;\n+\t\t\tmatch++;\n+\t\t}\n+\n+\t\tif (!starts_with(refname, match))\n+\t\t\tcontinue;\n+\t\tlen = strlen(match);\n+\t\tif (!refname[len] || refname[len] == '/')\n+\t\t\treturn !neg;\n+\t}\n+\treturn 0;\n+}\n-- \n2.6.2\n"},{"id":"272809","messageId":"51d5134027518b62c3bdf82fe1ee2dce9708f62b.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 08/25] refs: move dwim and friend functions to the common refs code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:52Z","receivedAt":"2015-11-03T07:39:52Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nThese functions do not contain any backend specific code so move them\nto the common code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 203 ---------------------------------------------------\n refs/refs.c          | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 203 insertions(+), 203 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 8f1e486..8809595 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2259,30 +2259,6 @@ const char *prettify_refname(const char *name)\n \t\t0);\n }\n \n-static const char *ref_rev_parse_rules[] = {\n-\t\"%.*s\",\n-\t\"refs/%.*s\",\n-\t\"refs/tags/%.*s\",\n-\t\"refs/heads/%.*s\",\n-\t\"refs/remotes/%.*s\",\n-\t\"refs/remotes/%.*s/HEAD\",\n-\tNULL\n-};\n-\n-int refname_match(const char *abbrev_name, const char *full_name)\n-{\n-\tconst char **p;\n-\tconst int abbrev_name_len = strlen(abbrev_name);\n-\n-\tfor (p = ref_rev_parse_rules; *p; p++) {\n-\t\tif (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) {\n-\t\t\treturn 1;\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-}\n-\n static void unlock_ref(struct ref_lock *lock)\n {\n \t/* Do not free lock->lk -- atexit() still looks at them */\n@@ -2335,92 +2311,6 @@ static int remove_empty_directories(struct strbuf *path)\n }\n \n /*\n- * *string and *len will only be substituted, and *string returned (for\n- * later free()ing) if the string passed in is a magic short-hand form\n- * to name a branch.\n- */\n-static char *substitute_branch_name(const char **string, int *len)\n-{\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tint ret = interpret_branch_name(*string, *len, &buf);\n-\n-\tif (ret == *len) {\n-\t\tsize_t size;\n-\t\t*string = strbuf_detach(&buf, &size);\n-\t\t*len = size;\n-\t\treturn (char *)*string;\n-\t}\n-\n-\treturn NULL;\n-}\n-\n-int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)\n-{\n-\tchar *last_branch = substitute_branch_name(&str, &len);\n-\tconst char **p, *r;\n-\tint refs_found = 0;\n-\n-\t*ref = NULL;\n-\tfor (p = ref_rev_parse_rules; *p; p++) {\n-\t\tchar fullref[PATH_MAX];\n-\t\tunsigned char sha1_from_ref[20];\n-\t\tunsigned char *this_result;\n-\t\tint flag;\n-\n-\t\tthis_result = refs_found ? sha1_from_ref : sha1;\n-\t\tmksnpath(fullref, sizeof(fullref), *p, len, str);\n-\t\tr = resolve_ref_unsafe(fullref, RESOLVE_REF_READING,\n-\t\t\t\t       this_result, &flag);\n-\t\tif (r) {\n-\t\t\tif (!refs_found++)\n-\t\t\t\t*ref = xstrdup(r);\n-\t\t\tif (!warn_ambiguous_refs)\n-\t\t\t\tbreak;\n-\t\t} else if ((flag & REF_ISSYMREF) && strcmp(fullref, \"HEAD\")) {\n-\t\t\twarning(\"ignoring dangling symref %s.\", fullref);\n-\t\t} else if ((flag & REF_ISBROKEN) && strchr(fullref, '/')) {\n-\t\t\twarning(\"ignoring broken ref %s.\", fullref);\n-\t\t}\n-\t}\n-\tfree(last_branch);\n-\treturn refs_found;\n-}\n-\n-int dwim_log(const char *str, int len, unsigned char *sha1, char **log)\n-{\n-\tchar *last_branch = substitute_branch_name(&str, &len);\n-\tconst char **p;\n-\tint logs_found = 0;\n-\n-\t*log = NULL;\n-\tfor (p = ref_rev_parse_rules; *p; p++) {\n-\t\tunsigned char hash[20];\n-\t\tchar path[PATH_MAX];\n-\t\tconst char *ref, *it;\n-\n-\t\tmksnpath(path, sizeof(path), *p, len, str);\n-\t\tref = resolve_ref_unsafe(path, RESOLVE_REF_READING,\n-\t\t\t\t\t hash, NULL);\n-\t\tif (!ref)\n-\t\t\tcontinue;\n-\t\tif (reflog_exists(path))\n-\t\t\tit = path;\n-\t\telse if (strcmp(ref, path) && reflog_exists(ref))\n-\t\t\tit = ref;\n-\t\telse\n-\t\t\tcontinue;\n-\t\tif (!logs_found++) {\n-\t\t\t*log = xstrdup(it);\n-\t\t\thashcpy(sha1, hash);\n-\t\t}\n-\t\tif (!warn_ambiguous_refs)\n-\t\t\tbreak;\n-\t}\n-\tfree(last_branch);\n-\treturn logs_found;\n-}\n-\n-/*\n  * Locks a ref returning the lock on success and NULL on failure.\n  * On failure errno is set to something meaningful.\n  */\n@@ -4126,99 +4016,6 @@ cleanup:\n \treturn ret;\n }\n \n-char *shorten_unambiguous_ref(const char *refname, int strict)\n-{\n-\tint i;\n-\tstatic char **scanf_fmts;\n-\tstatic int nr_rules;\n-\tchar *short_name;\n-\n-\tif (!nr_rules) {\n-\t\t/*\n-\t\t * Pre-generate scanf formats from ref_rev_parse_rules[].\n-\t\t * Generate a format suitable for scanf from a\n-\t\t * ref_rev_parse_rules rule by interpolating \"%s\" at the\n-\t\t * location of the \"%.*s\".\n-\t\t */\n-\t\tsize_t total_len = 0;\n-\t\tsize_t offset = 0;\n-\n-\t\t/* the rule list is NULL terminated, count them first */\n-\t\tfor (nr_rules = 0; ref_rev_parse_rules[nr_rules]; nr_rules++)\n-\t\t\t/* -2 for strlen(\"%.*s\") - strlen(\"%s\"); +1 for NUL */\n-\t\t\ttotal_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;\n-\n-\t\tscanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);\n-\n-\t\toffset = 0;\n-\t\tfor (i = 0; i < nr_rules; i++) {\n-\t\t\tassert(offset < total_len);\n-\t\t\tscanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset;\n-\t\t\toffset += snprintf(scanf_fmts[i], total_len - offset,\n-\t\t\t\t\t   ref_rev_parse_rules[i], 2, \"%s\") + 1;\n-\t\t}\n-\t}\n-\n-\t/* bail out if there are no rules */\n-\tif (!nr_rules)\n-\t\treturn xstrdup(refname);\n-\n-\t/* buffer for scanf result, at most refname must fit */\n-\tshort_name = xstrdup(refname);\n-\n-\t/* skip first rule, it will always match */\n-\tfor (i = nr_rules - 1; i > 0 ; --i) {\n-\t\tint j;\n-\t\tint rules_to_fail = i;\n-\t\tint short_name_len;\n-\n-\t\tif (1 != sscanf(refname, scanf_fmts[i], short_name))\n-\t\t\tcontinue;\n-\n-\t\tshort_name_len = strlen(short_name);\n-\n-\t\t/*\n-\t\t * in strict mode, all (except the matched one) rules\n-\t\t * must fail to resolve to a valid non-ambiguous ref\n-\t\t */\n-\t\tif (strict)\n-\t\t\trules_to_fail = nr_rules;\n-\n-\t\t/*\n-\t\t * check if the short name resolves to a valid ref,\n-\t\t * but use only rules prior to the matched one\n-\t\t */\n-\t\tfor (j = 0; j < rules_to_fail; j++) {\n-\t\t\tconst char *rule = ref_rev_parse_rules[j];\n-\t\t\tchar refname[PATH_MAX];\n-\n-\t\t\t/* skip matched rule */\n-\t\t\tif (i == j)\n-\t\t\t\tcontinue;\n-\n-\t\t\t/*\n-\t\t\t * the short name is ambiguous, if it resolves\n-\t\t\t * (with this previous rule) to a valid ref\n-\t\t\t * read_ref() returns 0 on success\n-\t\t\t */\n-\t\t\tmksnpath(refname, sizeof(refname),\n-\t\t\t\t rule, short_name_len, short_name);\n-\t\t\tif (ref_exists(refname))\n-\t\t\t\tbreak;\n-\t\t}\n-\n-\t\t/*\n-\t\t * short name is non-ambiguous if all previous rules\n-\t\t * haven't resolved to a valid ref\n-\t\t */\n-\t\tif (j == rules_to_fail)\n-\t\t\treturn short_name;\n-\t}\n-\n-\tfree(short_name);\n-\treturn xstrdup(refname);\n-}\n-\n struct expire_reflog_cb {\n \tunsigned int flags;\n \treflog_expiry_should_prune_fn *should_prune_fn;\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 0620ba3..40d7831 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -342,3 +342,206 @@ int ref_is_hidden(const char *refname)\n \t}\n \treturn 0;\n }\n+\n+static const char *ref_rev_parse_rules[] = {\n+\t\"%.*s\",\n+\t\"refs/%.*s\",\n+\t\"refs/tags/%.*s\",\n+\t\"refs/heads/%.*s\",\n+\t\"refs/remotes/%.*s\",\n+\t\"refs/remotes/%.*s/HEAD\",\n+\tNULL\n+};\n+\n+int refname_match(const char *abbrev_name, const char *full_name)\n+{\n+\tconst char **p;\n+\tconst int abbrev_name_len = strlen(abbrev_name);\n+\n+\tfor (p = ref_rev_parse_rules; *p; p++) {\n+\t\tif (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) {\n+\t\t\treturn 1;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * *string and *len will only be substituted, and *string returned (for\n+ * later free()ing) if the string passed in is a magic short-hand form\n+ * to name a branch.\n+ */\n+static char *substitute_branch_name(const char **string, int *len)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint ret = interpret_branch_name(*string, *len, &buf);\n+\n+\tif (ret == *len) {\n+\t\tsize_t size;\n+\t\t*string = strbuf_detach(&buf, &size);\n+\t\t*len = size;\n+\t\treturn (char *)*string;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)\n+{\n+\tchar *last_branch = substitute_branch_name(&str, &len);\n+\tconst char **p, *r;\n+\tint refs_found = 0;\n+\n+\t*ref = NULL;\n+\tfor (p = ref_rev_parse_rules; *p; p++) {\n+\t\tchar fullref[PATH_MAX];\n+\t\tunsigned char sha1_from_ref[20];\n+\t\tunsigned char *this_result;\n+\t\tint flag;\n+\n+\t\tthis_result = refs_found ? sha1_from_ref : sha1;\n+\t\tmksnpath(fullref, sizeof(fullref), *p, len, str);\n+\t\tr = resolve_ref_unsafe(fullref, RESOLVE_REF_READING,\n+\t\t\t\t       this_result, &flag);\n+\t\tif (r) {\n+\t\t\tif (!refs_found++)\n+\t\t\t\t*ref = xstrdup(r);\n+\t\t\tif (!warn_ambiguous_refs)\n+\t\t\t\tbreak;\n+\t\t} else if ((flag & REF_ISSYMREF) && strcmp(fullref, \"HEAD\")) {\n+\t\t\twarning(\"ignoring dangling symref %s.\", fullref);\n+\t\t} else if ((flag & REF_ISBROKEN) && strchr(fullref, '/')) {\n+\t\t\twarning(\"ignoring broken ref %s.\", fullref);\n+\t\t}\n+\t}\n+\tfree(last_branch);\n+\treturn refs_found;\n+}\n+\n+int dwim_log(const char *str, int len, unsigned char *sha1, char **log)\n+{\n+\tchar *last_branch = substitute_branch_name(&str, &len);\n+\tconst char **p;\n+\tint logs_found = 0;\n+\n+\t*log = NULL;\n+\tfor (p = ref_rev_parse_rules; *p; p++) {\n+\t\tunsigned char hash[20];\n+\t\tchar path[PATH_MAX];\n+\t\tconst char *ref, *it;\n+\n+\t\tmksnpath(path, sizeof(path), *p, len, str);\n+\t\tref = resolve_ref_unsafe(path, RESOLVE_REF_READING,\n+\t\t\t\t\t hash, NULL);\n+\t\tif (!ref)\n+\t\t\tcontinue;\n+\t\tif (reflog_exists(path))\n+\t\t\tit = path;\n+\t\telse if (strcmp(ref, path) && reflog_exists(ref))\n+\t\t\tit = ref;\n+\t\telse\n+\t\t\tcontinue;\n+\t\tif (!logs_found++) {\n+\t\t\t*log = xstrdup(it);\n+\t\t\thashcpy(sha1, hash);\n+\t\t}\n+\t\tif (!warn_ambiguous_refs)\n+\t\t\tbreak;\n+\t}\n+\tfree(last_branch);\n+\treturn logs_found;\n+}\n+\n+char *shorten_unambiguous_ref(const char *refname, int strict)\n+{\n+\tint i;\n+\tstatic char **scanf_fmts;\n+\tstatic int nr_rules;\n+\tchar *short_name;\n+\n+\tif (!nr_rules) {\n+\t\t/*\n+\t\t * Pre-generate scanf formats from ref_rev_parse_rules[].\n+\t\t * Generate a format suitable for scanf from a\n+\t\t * ref_rev_parse_rules rule by interpolating \"%s\" at the\n+\t\t * location of the \"%.*s\".\n+\t\t */\n+\t\tsize_t total_len = 0;\n+\t\tsize_t offset = 0;\n+\n+\t\t/* the rule list is NULL terminated, count them first */\n+\t\tfor (nr_rules = 0; ref_rev_parse_rules[nr_rules]; nr_rules++)\n+\t\t\t/* -2 for strlen(\"%.*s\") - strlen(\"%s\"); +1 for NUL */\n+\t\t\ttotal_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;\n+\n+\t\tscanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);\n+\n+\t\toffset = 0;\n+\t\tfor (i = 0; i < nr_rules; i++) {\n+\t\t\tassert(offset < total_len);\n+\t\t\tscanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset;\n+\t\t\toffset += snprintf(scanf_fmts[i], total_len - offset,\n+\t\t\t\t\t   ref_rev_parse_rules[i], 2, \"%s\") + 1;\n+\t\t}\n+\t}\n+\n+\t/* bail out if there are no rules */\n+\tif (!nr_rules)\n+\t\treturn xstrdup(refname);\n+\n+\t/* buffer for scanf result, at most refname must fit */\n+\tshort_name = xstrdup(refname);\n+\n+\t/* skip first rule, it will always match */\n+\tfor (i = nr_rules - 1; i > 0 ; --i) {\n+\t\tint j;\n+\t\tint rules_to_fail = i;\n+\t\tint short_name_len;\n+\n+\t\tif (1 != sscanf(refname, scanf_fmts[i], short_name))\n+\t\t\tcontinue;\n+\n+\t\tshort_name_len = strlen(short_name);\n+\n+\t\t/*\n+\t\t * in strict mode, all (except the matched one) rules\n+\t\t * must fail to resolve to a valid non-ambiguous ref\n+\t\t */\n+\t\tif (strict)\n+\t\t\trules_to_fail = nr_rules;\n+\n+\t\t/*\n+\t\t * check if the short name resolves to a valid ref,\n+\t\t * but use only rules prior to the matched one\n+\t\t */\n+\t\tfor (j = 0; j < rules_to_fail; j++) {\n+\t\t\tconst char *rule = ref_rev_parse_rules[j];\n+\t\t\tchar refname[PATH_MAX];\n+\n+\t\t\t/* skip matched rule */\n+\t\t\tif (i == j)\n+\t\t\t\tcontinue;\n+\n+\t\t\t/*\n+\t\t\t * the short name is ambiguous, if it resolves\n+\t\t\t * (with this previous rule) to a valid ref\n+\t\t\t * read_ref() returns 0 on success\n+\t\t\t */\n+\t\t\tmksnpath(refname, sizeof(refname),\n+\t\t\t\t rule, short_name_len, short_name);\n+\t\t\tif (ref_exists(refname))\n+\t\t\t\tbreak;\n+\t\t}\n+\n+\t\t/*\n+\t\t * short name is non-ambiguous if all previous rules\n+\t\t * haven't resolved to a valid ref\n+\t\t */\n+\t\tif (j == rules_to_fail)\n+\t\t\treturn short_name;\n+\t}\n+\n+\tfree(short_name);\n+\treturn xstrdup(refname);\n+}\n-- \n2.6.2\n"},{"id":"272811","messageId":"4b1de143c01feee0d9195820196c3d350c809b14.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 09/25] refs: move warn_if_dangling_symref* to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:53Z","receivedAt":"2015-11-03T07:39:53Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nThese functions do not use any backend specific code so move them to\nthe common code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 52 ----------------------------------------------------\n refs/refs.c          | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 52 insertions(+), 52 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 8809595..9fb77c2 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1956,58 +1956,6 @@ int peel_ref(const char *refname, unsigned char *sha1)\n \treturn peel_object(base, sha1);\n }\n \n-struct warn_if_dangling_data {\n-\tFILE *fp;\n-\tconst char *refname;\n-\tconst struct string_list *refnames;\n-\tconst char *msg_fmt;\n-};\n-\n-static int warn_if_dangling_symref(const char *refname, const struct object_id *oid,\n-\t\t\t\t   int flags, void *cb_data)\n-{\n-\tstruct warn_if_dangling_data *d = cb_data;\n-\tconst char *resolves_to;\n-\tstruct object_id junk;\n-\n-\tif (!(flags & REF_ISSYMREF))\n-\t\treturn 0;\n-\n-\tresolves_to = resolve_ref_unsafe(refname, 0, junk.hash, NULL);\n-\tif (!resolves_to\n-\t    || (d->refname\n-\t\t? strcmp(resolves_to, d->refname)\n-\t\t: !string_list_has_string(d->refnames, resolves_to))) {\n-\t\treturn 0;\n-\t}\n-\n-\tfprintf(d->fp, d->msg_fmt, refname);\n-\tfputc('\\n', d->fp);\n-\treturn 0;\n-}\n-\n-void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)\n-{\n-\tstruct warn_if_dangling_data data;\n-\n-\tdata.fp = fp;\n-\tdata.refname = refname;\n-\tdata.refnames = NULL;\n-\tdata.msg_fmt = msg_fmt;\n-\tfor_each_rawref(warn_if_dangling_symref, &data);\n-}\n-\n-void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames)\n-{\n-\tstruct warn_if_dangling_data data;\n-\n-\tdata.fp = fp;\n-\tdata.refname = NULL;\n-\tdata.refnames = refnames;\n-\tdata.msg_fmt = msg_fmt;\n-\tfor_each_rawref(warn_if_dangling_symref, &data);\n-}\n-\n /*\n  * Call fn for each reference in the specified ref_cache, omitting\n  * references not in the containing_dir of base.  fn is called for all\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 40d7831..6d9ea7c 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -545,3 +545,55 @@ char *shorten_unambiguous_ref(const char *refname, int strict)\n \tfree(short_name);\n \treturn xstrdup(refname);\n }\n+\n+struct warn_if_dangling_data {\n+\tFILE *fp;\n+\tconst char *refname;\n+\tconst struct string_list *refnames;\n+\tconst char *msg_fmt;\n+};\n+\n+static int warn_if_dangling_symref(const char *refname, const struct object_id *oid,\n+\t\t\t\t   int flags, void *cb_data)\n+{\n+\tstruct warn_if_dangling_data *d = cb_data;\n+\tconst char *resolves_to;\n+\tstruct object_id junk;\n+\n+\tif (!(flags & REF_ISSYMREF))\n+\t\treturn 0;\n+\n+\tresolves_to = resolve_ref_unsafe(refname, 0, junk.hash, NULL);\n+\tif (!resolves_to\n+\t    || (d->refname\n+\t\t? strcmp(resolves_to, d->refname)\n+\t\t: !string_list_has_string(d->refnames, resolves_to))) {\n+\t\treturn 0;\n+\t}\n+\n+\tfprintf(d->fp, d->msg_fmt, refname);\n+\tfputc('\\n', d->fp);\n+\treturn 0;\n+}\n+\n+void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)\n+{\n+\tstruct warn_if_dangling_data data;\n+\n+\tdata.fp = fp;\n+\tdata.refname = refname;\n+\tdata.refnames = NULL;\n+\tdata.msg_fmt = msg_fmt;\n+\tfor_each_rawref(warn_if_dangling_symref, &data);\n+}\n+\n+void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames)\n+{\n+\tstruct warn_if_dangling_data data;\n+\n+\tdata.fp = fp;\n+\tdata.refname = NULL;\n+\tdata.refnames = refnames;\n+\tdata.msg_fmt = msg_fmt;\n+\tfor_each_rawref(warn_if_dangling_symref, &data);\n+}\n-- \n2.6.2\n"},{"id":"272805","messageId":"467939ca5f0943f8e776ee236a24d7d991c54d70.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 10/25] refs: move read_ref, read_ref_full and ref_exists to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:54Z","receivedAt":"2015-11-03T07:39:54Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nThese functions do not depend on the backend implementation so move\nthem to the common code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 18 ------------------\n refs/refs.c          | 18 ++++++++++++++++++\n 2 files changed, 18 insertions(+), 18 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 9fb77c2..6940d54 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1803,24 +1803,6 @@ struct ref_filter {\n \tvoid *cb_data;\n };\n \n-int read_ref_full(const char *refname, int resolve_flags, unsigned char *sha1, int *flags)\n-{\n-\tif (resolve_ref_unsafe(refname, resolve_flags, sha1, flags))\n-\t\treturn 0;\n-\treturn -1;\n-}\n-\n-int read_ref(const char *refname, unsigned char *sha1)\n-{\n-\treturn read_ref_full(refname, RESOLVE_REF_READING, sha1, NULL);\n-}\n-\n-int ref_exists(const char *refname)\n-{\n-\tunsigned char sha1[20];\n-\treturn !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, sha1, NULL);\n-}\n-\n static int filter_refs(const char *refname, const struct object_id *oid,\n \t\t\t   int flags, void *data)\n {\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 6d9ea7c..ae55d85 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -597,3 +597,21 @@ void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_li\n \tdata.msg_fmt = msg_fmt;\n \tfor_each_rawref(warn_if_dangling_symref, &data);\n }\n+\n+int read_ref_full(const char *refname, int resolve_flags, unsigned char *sha1, int *flags)\n+{\n+\tif (resolve_ref_unsafe(refname, resolve_flags, sha1, flags))\n+\t\treturn 0;\n+\treturn -1;\n+}\n+\n+int read_ref(const char *refname, unsigned char *sha1)\n+{\n+\treturn read_ref_full(refname, RESOLVE_REF_READING, sha1, NULL);\n+}\n+\n+int ref_exists(const char *refname)\n+{\n+\tunsigned char sha1[20];\n+\treturn !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, sha1, NULL);\n+}\n-- \n2.6.2\n"},{"id":"272793","messageId":"4d1782ce2943a543e38999c0abb01a314231494a.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 11/25] refs: move resolve_refdup to common","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:55Z","receivedAt":"2015-11-03T07:39:55Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nThis function can be shared across all refs backends so move it\nto the common code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 7 -------\n refs/refs.c          | 7 +++++++\n 2 files changed, 7 insertions(+), 7 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 6940d54..f84fa9e 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1789,13 +1789,6 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \treturn ret;\n }\n \n-char *resolve_refdup(const char *refname, int resolve_flags,\n-\t\t     unsigned char *sha1, int *flags)\n-{\n-\treturn xstrdup_or_null(resolve_ref_unsafe(refname, resolve_flags,\n-\t\t\t\t\t\t  sha1, flags));\n-}\n-\n /* The argument to filter_refs */\n struct ref_filter {\n \tconst char *pattern;\ndiff --git a/refs/refs.c b/refs/refs.c\nindex ae55d85..56dee05 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -615,3 +615,10 @@ int ref_exists(const char *refname)\n \tunsigned char sha1[20];\n \treturn !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, sha1, NULL);\n }\n+\n+char *resolve_refdup(const char *refname, int resolve_flags,\n+\t\t     unsigned char *sha1, int *flags)\n+{\n+\treturn xstrdup_or_null(resolve_ref_unsafe(refname, resolve_flags,\n+\t\t\t\t\t\t  sha1, flags));\n+}\n-- \n2.6.2\n"},{"id":"272794","messageId":"4dad486935e0752408c29ab20ec4acd74a35d1e4.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 12/25] refs: move check_refname_format to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:56Z","receivedAt":"2015-11-03T07:39:56Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nThis function does not contain any backend specific code so move it to\nthe common code.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 109 ---------------------------------------------------\n refs/refs.c          | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 109 insertions(+), 109 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex f84fa9e..545075f 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -14,27 +14,6 @@ struct ref_lock {\n };\n \n /*\n- * How to handle various characters in refnames:\n- * 0: An acceptable character for refs\n- * 1: End-of-component\n- * 2: ., look for a preceding . to reject .. in refs\n- * 3: {, look for a preceding @ to reject @{ in refs\n- * 4: A bad character: ASCII control characters, and\n- *    \":\", \"?\", \"[\", \"\\\", \"^\", \"~\", SP, or TAB\n- * 5: *, reject unless REFNAME_REFSPEC_PATTERN is set\n- */\n-static unsigned char refname_disposition[256] = {\n-\t1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n-\t4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n-\t4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 2, 1,\n-\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4,\n-\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n-\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 4, 0,\n-\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n-\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4\n-};\n-\n-/*\n  * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken\n  * refs (i.e., because the reference is about to be deleted anyway).\n  */\n@@ -69,94 +48,6 @@ static unsigned char refname_disposition[256] = {\n  * value to ref_update::flags\n  */\n \n-/*\n- * Try to read one refname component from the front of refname.\n- * Return the length of the component found, or -1 if the component is\n- * not legal.  It is legal if it is something reasonable to have under\n- * \".git/refs/\"; We do not like it if:\n- *\n- * - any path component of it begins with \".\", or\n- * - it has double dots \"..\", or\n- * - it has ASCII control characters, or\n- * - it has \":\", \"?\", \"[\", \"\\\", \"^\", \"~\", SP, or TAB anywhere, or\n- * - it has \"*\" anywhere unless REFNAME_REFSPEC_PATTERN is set, or\n- * - it ends with a \"/\", or\n- * - it ends with \".lock\", or\n- * - it contains a \"@{\" portion\n- */\n-static int check_refname_component(const char *refname, int *flags)\n-{\n-\tconst char *cp;\n-\tchar last = '\\0';\n-\n-\tfor (cp = refname; ; cp++) {\n-\t\tint ch = *cp & 255;\n-\t\tunsigned char disp = refname_disposition[ch];\n-\t\tswitch (disp) {\n-\t\tcase 1:\n-\t\t\tgoto out;\n-\t\tcase 2:\n-\t\t\tif (last == '.')\n-\t\t\t\treturn -1; /* Refname contains \"..\". */\n-\t\t\tbreak;\n-\t\tcase 3:\n-\t\t\tif (last == '@')\n-\t\t\t\treturn -1; /* Refname contains \"@{\". */\n-\t\t\tbreak;\n-\t\tcase 4:\n-\t\t\treturn -1;\n-\t\tcase 5:\n-\t\t\tif (!(*flags & REFNAME_REFSPEC_PATTERN))\n-\t\t\t\treturn -1; /* refspec can't be a pattern */\n-\n-\t\t\t/*\n-\t\t\t * Unset the pattern flag so that we only accept\n-\t\t\t * a single asterisk for one side of refspec.\n-\t\t\t */\n-\t\t\t*flags &= ~ REFNAME_REFSPEC_PATTERN;\n-\t\t\tbreak;\n-\t\t}\n-\t\tlast = ch;\n-\t}\n-out:\n-\tif (cp == refname)\n-\t\treturn 0; /* Component has zero length. */\n-\tif (refname[0] == '.')\n-\t\treturn -1; /* Component starts with '.'. */\n-\tif (cp - refname >= LOCK_SUFFIX_LEN &&\n-\t    !memcmp(cp - LOCK_SUFFIX_LEN, LOCK_SUFFIX, LOCK_SUFFIX_LEN))\n-\t\treturn -1; /* Refname ends with \".lock\". */\n-\treturn cp - refname;\n-}\n-\n-int check_refname_format(const char *refname, int flags)\n-{\n-\tint component_len, component_count = 0;\n-\n-\tif (!strcmp(refname, \"@\"))\n-\t\t/* Refname is a single character '@'. */\n-\t\treturn -1;\n-\n-\twhile (1) {\n-\t\t/* We are at the start of a path component. */\n-\t\tcomponent_len = check_refname_component(refname, &flags);\n-\t\tif (component_len <= 0)\n-\t\t\treturn -1;\n-\n-\t\tcomponent_count++;\n-\t\tif (refname[component_len] == '\\0')\n-\t\t\tbreak;\n-\t\t/* Skip to next component. */\n-\t\trefname += component_len + 1;\n-\t}\n-\n-\tif (refname[component_len - 1] == '.')\n-\t\treturn -1; /* Refname ends with '.'. */\n-\tif (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2)\n-\t\treturn -1; /* Refname has only one component. */\n-\treturn 0;\n-}\n-\n struct ref_entry;\n \n /*\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 56dee05..bc7e159 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -622,3 +622,112 @@ char *resolve_refdup(const char *refname, int resolve_flags,\n \treturn xstrdup_or_null(resolve_ref_unsafe(refname, resolve_flags,\n \t\t\t\t\t\t  sha1, flags));\n }\n+\n+/*\n+ * How to handle various characters in refnames:\n+ * 0: An acceptable character for refs\n+ * 1: End-of-component\n+ * 2: ., look for a preceding . to reject .. in refs\n+ * 3: {, look for a preceding @ to reject @{ in refs\n+ * 4: A bad character: ASCII control characters, and\n+ *    \":\", \"?\", \"[\", \"\\\", \"^\", \"~\", SP, or TAB\n+ * 5: *, reject unless REFNAME_REFSPEC_PATTERN is set\n+ */\n+static unsigned char refname_disposition[256] = {\n+\t1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n+\t4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n+\t4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 2, 1,\n+\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4,\n+\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n+\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 4, 0,\n+\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n+\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4\n+};\n+\n+/*\n+ * Try to read one refname component from the front of refname.\n+ * Return the length of the component found, or -1 if the component is\n+ * not legal.  It is legal if it is something reasonable to have under\n+ * \".git/refs/\"; We do not like it if:\n+ *\n+ * - any path component of it begins with \".\", or\n+ * - it has double dots \"..\", or\n+ * - it has ASCII control characters, or\n+ * - it has \":\", \"?\", \"[\", \"\\\", \"^\", \"~\", SP, or TAB anywhere, or\n+ * - it has \"*\" anywhere unless REFNAME_REFSPEC_PATTERN is set, or\n+ * - it ends with a \"/\", or\n+ * - it ends with \".lock\", or\n+ * - it contains a \"@{\" portion\n+ */\n+static int check_refname_component(const char *refname, int *flags)\n+{\n+\tconst char *cp;\n+\tchar last = '\\0';\n+\n+\tfor (cp = refname; ; cp++) {\n+\t\tint ch = *cp & 255;\n+\t\tunsigned char disp = refname_disposition[ch];\n+\t\tswitch (disp) {\n+\t\tcase 1:\n+\t\t\tgoto out;\n+\t\tcase 2:\n+\t\t\tif (last == '.')\n+\t\t\t\treturn -1; /* Refname contains \"..\". */\n+\t\t\tbreak;\n+\t\tcase 3:\n+\t\t\tif (last == '@')\n+\t\t\t\treturn -1; /* Refname contains \"@{\". */\n+\t\t\tbreak;\n+\t\tcase 4:\n+\t\t\treturn -1;\n+\t\tcase 5:\n+\t\t\tif (!(*flags & REFNAME_REFSPEC_PATTERN))\n+\t\t\t\treturn -1; /* refspec can't be a pattern */\n+\n+\t\t\t/*\n+\t\t\t * Unset the pattern flag so that we only accept\n+\t\t\t * a single asterisk for one side of refspec.\n+\t\t\t */\n+\t\t\t*flags &= ~ REFNAME_REFSPEC_PATTERN;\n+\t\t\tbreak;\n+\t\t}\n+\t\tlast = ch;\n+\t}\n+out:\n+\tif (cp == refname)\n+\t\treturn 0; /* Component has zero length. */\n+\tif (refname[0] == '.')\n+\t\treturn -1; /* Component starts with '.'. */\n+\tif (cp - refname >= LOCK_SUFFIX_LEN &&\n+\t    !memcmp(cp - LOCK_SUFFIX_LEN, LOCK_SUFFIX, LOCK_SUFFIX_LEN))\n+\t\treturn -1; /* Refname ends with \".lock\". */\n+\treturn cp - refname;\n+}\n+\n+int check_refname_format(const char *refname, int flags)\n+{\n+\tint component_len, component_count = 0;\n+\n+\tif (!strcmp(refname, \"@\"))\n+\t\t/* Refname is a single character '@'. */\n+\t\treturn -1;\n+\n+\twhile (1) {\n+\t\t/* We are at the start of a path component. */\n+\t\tcomponent_len = check_refname_component(refname, &flags);\n+\t\tif (component_len <= 0)\n+\t\t\treturn -1;\n+\n+\t\tcomponent_count++;\n+\t\tif (refname[component_len] == '\\0')\n+\t\t\tbreak;\n+\t\t/* Skip to next component. */\n+\t\trefname += component_len + 1;\n+\t}\n+\n+\tif (refname[component_len - 1] == '.')\n+\t\treturn -1; /* Refname ends with '.'. */\n+\tif (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2)\n+\t\treturn -1; /* Refname has only one component. */\n+\treturn 0;\n+}\n-- \n2.6.2\n"},{"id":"272795","messageId":"ec95aecb12255f1382c22fac0012856a275ec3b5.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 13/25] refs: move is_branch to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:57Z","receivedAt":"2015-11-03T07:39:57Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 5 -----\n refs/refs.c          | 5 +++++\n 2 files changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 545075f..468758a 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3002,11 +3002,6 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,\n \treturn ret;\n }\n \n-int is_branch(const char *refname)\n-{\n-\treturn !strcmp(refname, \"HEAD\") || starts_with(refname, \"refs/heads/\");\n-}\n-\n /*\n  * Write sha1 into the open lockfile, then close the lockfile. On\n  * errors, rollback the lockfile, fill in *err and\ndiff --git a/refs/refs.c b/refs/refs.c\nindex bc7e159..fb0e5df 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -731,3 +731,8 @@ int check_refname_format(const char *refname, int flags)\n \t\treturn -1; /* Refname has only one component. */\n \treturn 0;\n }\n+\n+int is_branch(const char *refname)\n+{\n+\treturn !strcmp(refname, \"HEAD\") || starts_with(refname, \"refs/heads/\");\n+}\n-- \n2.6.2\n"},{"id":"272796","messageId":"2dbbc21d1aad46a7422070299451e1aff89df50c.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 14/25] refs: move prettify_refname to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:58Z","receivedAt":"2015-11-03T07:39:58Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 9 ---------\n refs/refs.c          | 9 +++++++++\n 2 files changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 468758a..89410a7 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2064,15 +2064,6 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)\n \t\t\t       DO_FOR_EACH_INCLUDE_BROKEN, cb_data);\n }\n \n-const char *prettify_refname(const char *name)\n-{\n-\treturn name + (\n-\t\tstarts_with(name, \"refs/heads/\") ? 11 :\n-\t\tstarts_with(name, \"refs/tags/\") ? 10 :\n-\t\tstarts_with(name, \"refs/remotes/\") ? 13 :\n-\t\t0);\n-}\n-\n static void unlock_ref(struct ref_lock *lock)\n {\n \t/* Do not free lock->lk -- atexit() still looks at them */\ndiff --git a/refs/refs.c b/refs/refs.c\nindex fb0e5df..3dd8e91 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -736,3 +736,12 @@ int is_branch(const char *refname)\n {\n \treturn !strcmp(refname, \"HEAD\") || starts_with(refname, \"refs/heads/\");\n }\n+\n+const char *prettify_refname(const char *name)\n+{\n+\treturn name + (\n+\t\tstarts_with(name, \"refs/heads/\") ? 11 :\n+\t\tstarts_with(name, \"refs/tags/\") ? 10 :\n+\t\tstarts_with(name, \"refs/remotes/\") ? 13 :\n+\t\t0);\n+}\n-- \n2.6.2\n"},{"id":"272799","messageId":"e1eebbf63a9e097b662d6aabcac337c837844193.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 15/25] refs: move ref iterators to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:39:59Z","receivedAt":"2015-11-03T07:39:59Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 81 ----------------------------------------------------\n refs/refs.c          | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 81 insertions(+), 81 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 89410a7..53f69f3 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1680,23 +1680,6 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \treturn ret;\n }\n \n-/* The argument to filter_refs */\n-struct ref_filter {\n-\tconst char *pattern;\n-\teach_ref_fn *fn;\n-\tvoid *cb_data;\n-};\n-\n-static int filter_refs(const char *refname, const struct object_id *oid,\n-\t\t\t   int flags, void *data)\n-{\n-\tstruct ref_filter *filter = (struct ref_filter *)data;\n-\n-\tif (wildmatch(filter->pattern, refname, 0, NULL))\n-\t\treturn 0;\n-\treturn filter->fn(refname, oid, flags, filter->cb_data);\n-}\n-\n enum peel_status {\n \t/* object was peeled successfully: */\n \tPEEL_PEELED = 0,\n@@ -1963,36 +1946,6 @@ int for_each_ref_in_submodule(const char *submodule, const char *prefix,\n \treturn do_for_each_ref(get_ref_cache(submodule), prefix, fn, strlen(prefix), 0, cb_data);\n }\n \n-int for_each_tag_ref(each_ref_fn fn, void *cb_data)\n-{\n-\treturn for_each_ref_in(\"refs/tags/\", fn, cb_data);\n-}\n-\n-int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn for_each_ref_in_submodule(submodule, \"refs/tags/\", fn, cb_data);\n-}\n-\n-int for_each_branch_ref(each_ref_fn fn, void *cb_data)\n-{\n-\treturn for_each_ref_in(\"refs/heads/\", fn, cb_data);\n-}\n-\n-int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn for_each_ref_in_submodule(submodule, \"refs/heads/\", fn, cb_data);\n-}\n-\n-int for_each_remote_ref(each_ref_fn fn, void *cb_data)\n-{\n-\treturn for_each_ref_in(\"refs/remotes/\", fn, cb_data);\n-}\n-\n-int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn for_each_ref_in_submodule(submodule, \"refs/remotes/\", fn, cb_data);\n-}\n-\n int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n {\n \treturn do_for_each_ref(&ref_cache, git_replace_ref_base, fn,\n@@ -2024,40 +1977,6 @@ int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)\n \treturn ret;\n }\n \n-int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,\n-\tconst char *prefix, void *cb_data)\n-{\n-\tstruct strbuf real_pattern = STRBUF_INIT;\n-\tstruct ref_filter filter;\n-\tint ret;\n-\n-\tif (!prefix && !starts_with(pattern, \"refs/\"))\n-\t\tstrbuf_addstr(&real_pattern, \"refs/\");\n-\telse if (prefix)\n-\t\tstrbuf_addstr(&real_pattern, prefix);\n-\tstrbuf_addstr(&real_pattern, pattern);\n-\n-\tif (!has_glob_specials(pattern)) {\n-\t\t/* Append implied '/' '*' if not present. */\n-\t\tstrbuf_complete(&real_pattern, '/');\n-\t\t/* No need to check for '*', there is none. */\n-\t\tstrbuf_addch(&real_pattern, '*');\n-\t}\n-\n-\tfilter.pattern = real_pattern.buf;\n-\tfilter.fn = fn;\n-\tfilter.cb_data = cb_data;\n-\tret = for_each_ref(filter_refs, &filter);\n-\n-\tstrbuf_release(&real_pattern);\n-\treturn ret;\n-}\n-\n-int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)\n-{\n-\treturn for_each_glob_ref_in(fn, pattern, NULL, cb_data);\n-}\n-\n int for_each_rawref(each_ref_fn fn, void *cb_data)\n {\n \treturn do_for_each_ref(&ref_cache, \"\", fn, 0,\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 3dd8e91..9644df6 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -745,3 +745,84 @@ const char *prettify_refname(const char *name)\n \t\tstarts_with(name, \"refs/remotes/\") ? 13 :\n \t\t0);\n }\n+\n+/* The argument to filter_refs */\n+struct ref_filter {\n+\tconst char *pattern;\n+\teach_ref_fn *fn;\n+\tvoid *cb_data;\n+};\n+\n+static int filter_refs(const char *refname, const struct object_id *oid, int flags,\n+\t\t       void *data)\n+{\n+\tstruct ref_filter *filter = (struct ref_filter *)data;\n+\n+\tif (wildmatch(filter->pattern, refname, 0, NULL))\n+\t\treturn 0;\n+\treturn filter->fn(refname, oid, flags, filter->cb_data);\n+}\n+\n+int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,\n+\tconst char *prefix, void *cb_data)\n+{\n+\tstruct strbuf real_pattern = STRBUF_INIT;\n+\tstruct ref_filter filter;\n+\tint ret;\n+\n+\tif (!prefix && !starts_with(pattern, \"refs/\"))\n+\t\tstrbuf_addstr(&real_pattern, \"refs/\");\n+\telse if (prefix)\n+\t\tstrbuf_addstr(&real_pattern, prefix);\n+\tstrbuf_addstr(&real_pattern, pattern);\n+\n+\tif (!has_glob_specials(pattern)) {\n+\t\t/* Append implied '/' '*' if not present. */\n+\t\tstrbuf_complete(&real_pattern, '/');\n+\t\t/* No need to check for '*', there is none. */\n+\t\tstrbuf_addch(&real_pattern, '*');\n+\t}\n+\n+\tfilter.pattern = real_pattern.buf;\n+\tfilter.fn = fn;\n+\tfilter.cb_data = cb_data;\n+\tret = for_each_ref(filter_refs, &filter);\n+\n+\tstrbuf_release(&real_pattern);\n+\treturn ret;\n+}\n+\n+int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)\n+{\n+\treturn for_each_glob_ref_in(fn, pattern, NULL, cb_data);\n+}\n+\n+int for_each_tag_ref(each_ref_fn fn, void *cb_data)\n+{\n+\treturn for_each_ref_in(\"refs/tags/\", fn, cb_data);\n+}\n+\n+int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n+{\n+\treturn for_each_ref_in_submodule(submodule, \"refs/tags/\", fn, cb_data);\n+}\n+\n+int for_each_branch_ref(each_ref_fn fn, void *cb_data)\n+{\n+\treturn for_each_ref_in(\"refs/heads/\", fn, cb_data);\n+}\n+\n+int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n+{\n+\treturn for_each_ref_in_submodule(submodule, \"refs/heads/\", fn, cb_data);\n+}\n+\n+int for_each_remote_ref(each_ref_fn fn, void *cb_data)\n+{\n+\treturn for_each_ref_in(\"refs/remotes/\", fn, cb_data);\n+}\n+\n+int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n+{\n+\treturn for_each_ref_in_submodule(submodule, \"refs/remotes/\", fn, cb_data);\n+}\n-- \n2.6.2\n"},{"id":"272797","messageId":"49cf53c5dc2bc96a79bf07203ddeb01836c8a937.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 16/25] refs: move head_ref_namespaced to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:40:00Z","receivedAt":"2015-11-03T07:40:00Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 15 ---------------\n refs/refs.c          | 15 +++++++++++++++\n 2 files changed, 15 insertions(+), 15 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 53f69f3..728e646 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1952,21 +1952,6 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n \t\t\t       strlen(git_replace_ref_base), 0, cb_data);\n }\n \n-int head_ref_namespaced(each_ref_fn fn, void *cb_data)\n-{\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tint ret = 0;\n-\tstruct object_id oid;\n-\tint flag;\n-\n-\tstrbuf_addf(&buf, \"%sHEAD\", get_git_namespace());\n-\tif (!read_ref_full(buf.buf, RESOLVE_REF_READING, oid.hash, &flag))\n-\t\tret = fn(buf.buf, &oid, flag, cb_data);\n-\tstrbuf_release(&buf);\n-\n-\treturn ret;\n-}\n-\n int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 9644df6..6af5fd6 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -826,3 +826,18 @@ int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *c\n {\n \treturn for_each_ref_in_submodule(submodule, \"refs/remotes/\", fn, cb_data);\n }\n+\n+int head_ref_namespaced(each_ref_fn fn, void *cb_data)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint ret = 0;\n+\tstruct object_id oid;\n+\tint flag;\n+\n+\tstrbuf_addf(&buf, \"%sHEAD\", get_git_namespace());\n+\tif (!read_ref_full(buf.buf, RESOLVE_REF_READING, oid.hash, &flag))\n+\t\tret = fn(buf.buf, &oid, flag, cb_data);\n+\tstrbuf_release(&buf);\n+\n+\treturn ret;\n+}\n-- \n2.6.2\n"},{"id":"272813","messageId":"69658d718bd300009c5ae17388b548937b9751fb.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 17/25] refs: move transaction functions to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:40:01Z","receivedAt":"2015-11-03T07:40:01Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nThe common ref code will build up a ref transaction. Backends will\nthen commit it. So the transaction creation and update functions\nshould be in the common code.\n\nThe backends will also need access to some constants and structs that,\nuntil now, were defined within refs.c and treated as private. So move\nthose into a new header file, refs/refs-internal.h, that is intended\nfor internal use only within the refs module.\n\nLater, we will modify struct ref_update to support alternate backends.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 200 +--------------------------------------------------\n refs/refs-internal.h | 102 ++++++++++++++++++++++++++\n refs/refs.c          | 110 +++++++++++++++++++++++++++-\n 3 files changed, 212 insertions(+), 200 deletions(-)\n create mode 100644 refs/refs-internal.h\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 728e646..1719720 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1,5 +1,5 @@\n #include \"../cache.h\"\n-#include \"../refs.h\"\n+#include \"refs-internal.h\"\n #include \"../lockfile.h\"\n #include \"../object.h\"\n #include \"../tag.h\"\n@@ -13,41 +13,6 @@ struct ref_lock {\n \tstruct object_id old_oid;\n };\n \n-/*\n- * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken\n- * refs (i.e., because the reference is about to be deleted anyway).\n- */\n-#define REF_DELETING\t0x02\n-\n-/*\n- * Used as a flag in ref_update::flags when a loose ref is being\n- * pruned.\n- */\n-#define REF_ISPRUNING\t0x04\n-\n-/*\n- * Used as a flag in ref_update::flags when the reference should be\n- * updated to new_sha1.\n- */\n-#define REF_HAVE_NEW\t0x08\n-\n-/*\n- * Used as a flag in ref_update::flags when old_sha1 should be\n- * checked.\n- */\n-#define REF_HAVE_OLD\t0x10\n-\n-/*\n- * Used as a flag in ref_update::flags when the lockfile needs to be\n- * committed.\n- */\n-#define REF_NEEDS_COMMIT 0x20\n-\n-/*\n- * 0x40 is REF_FORCE_CREATE_REFLOG, so skip it if you're adding a\n- * value to ref_update::flags\n- */\n-\n struct ref_entry;\n \n /*\n@@ -3289,169 +3254,6 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)\n \treturn retval;\n }\n \n-/**\n- * Information needed for a single ref update. Set new_sha1 to the new\n- * value or to null_sha1 to delete the ref. To check the old value\n- * while the ref is locked, set (flags & REF_HAVE_OLD) and set\n- * old_sha1 to the old value, or to null_sha1 to ensure the ref does\n- * not exist before update.\n- */\n-struct ref_update {\n-\t/*\n-\t * If (flags & REF_HAVE_NEW), set the reference to this value:\n-\t */\n-\tunsigned char new_sha1[20];\n-\t/*\n-\t * If (flags & REF_HAVE_OLD), check that the reference\n-\t * previously had this value:\n-\t */\n-\tunsigned char old_sha1[20];\n-\t/*\n-\t * One or more of REF_HAVE_NEW, REF_HAVE_OLD, REF_NODEREF,\n-\t * REF_DELETING, and REF_ISPRUNING:\n-\t */\n-\tunsigned int flags;\n-\tstruct ref_lock *lock;\n-\tint type;\n-\tchar *msg;\n-\tconst char refname[FLEX_ARRAY];\n-};\n-\n-/*\n- * Transaction states.\n- * OPEN:   The transaction is in a valid state and can accept new updates.\n- *         An OPEN transaction can be committed.\n- * CLOSED: A closed transaction is no longer active and no other operations\n- *         than free can be used on it in this state.\n- *         A transaction can either become closed by successfully committing\n- *         an active transaction or if there is a failure while building\n- *         the transaction thus rendering it failed/inactive.\n- */\n-enum ref_transaction_state {\n-\tREF_TRANSACTION_OPEN   = 0,\n-\tREF_TRANSACTION_CLOSED = 1\n-};\n-\n-/*\n- * Data structure for holding a reference transaction, which can\n- * consist of checks and updates to multiple references, carried out\n- * as atomically as possible.  This structure is opaque to callers.\n- */\n-struct ref_transaction {\n-\tstruct ref_update **updates;\n-\tsize_t alloc;\n-\tsize_t nr;\n-\tenum ref_transaction_state state;\n-};\n-\n-struct ref_transaction *ref_transaction_begin(struct strbuf *err)\n-{\n-\tassert(err);\n-\n-\treturn xcalloc(1, sizeof(struct ref_transaction));\n-}\n-\n-void ref_transaction_free(struct ref_transaction *transaction)\n-{\n-\tint i;\n-\n-\tif (!transaction)\n-\t\treturn;\n-\n-\tfor (i = 0; i < transaction->nr; i++) {\n-\t\tfree(transaction->updates[i]->msg);\n-\t\tfree(transaction->updates[i]);\n-\t}\n-\tfree(transaction->updates);\n-\tfree(transaction);\n-}\n-\n-static struct ref_update *add_update(struct ref_transaction *transaction,\n-\t\t\t\t     const char *refname)\n-{\n-\tsize_t len = strlen(refname) + 1;\n-\tstruct ref_update *update = xcalloc(1, sizeof(*update) + len);\n-\n-\tmemcpy((char *)update->refname, refname, len); /* includes NUL */\n-\tALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);\n-\ttransaction->updates[transaction->nr++] = update;\n-\treturn update;\n-}\n-\n-int ref_transaction_update(struct ref_transaction *transaction,\n-\t\t\t   const char *refname,\n-\t\t\t   const unsigned char *new_sha1,\n-\t\t\t   const unsigned char *old_sha1,\n-\t\t\t   unsigned int flags, const char *msg,\n-\t\t\t   struct strbuf *err)\n-{\n-\tstruct ref_update *update;\n-\n-\tassert(err);\n-\n-\tif (transaction->state != REF_TRANSACTION_OPEN)\n-\t\tdie(\"BUG: update called for transaction that is not open\");\n-\n-\tif (new_sha1 && !is_null_sha1(new_sha1) &&\n-\t    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {\n-\t\tstrbuf_addf(err, \"refusing to update ref with bad name %s\",\n-\t\t\t    refname);\n-\t\treturn -1;\n-\t}\n-\n-\tupdate = add_update(transaction, refname);\n-\tif (new_sha1) {\n-\t\thashcpy(update->new_sha1, new_sha1);\n-\t\tflags |= REF_HAVE_NEW;\n-\t}\n-\tif (old_sha1) {\n-\t\thashcpy(update->old_sha1, old_sha1);\n-\t\tflags |= REF_HAVE_OLD;\n-\t}\n-\tupdate->flags = flags;\n-\tif (msg)\n-\t\tupdate->msg = xstrdup(msg);\n-\treturn 0;\n-}\n-\n-int ref_transaction_create(struct ref_transaction *transaction,\n-\t\t\t   const char *refname,\n-\t\t\t   const unsigned char *new_sha1,\n-\t\t\t   unsigned int flags, const char *msg,\n-\t\t\t   struct strbuf *err)\n-{\n-\tif (!new_sha1 || is_null_sha1(new_sha1))\n-\t\tdie(\"BUG: create called without valid new_sha1\");\n-\treturn ref_transaction_update(transaction, refname, new_sha1,\n-\t\t\t\t      null_sha1, flags, msg, err);\n-}\n-\n-int ref_transaction_delete(struct ref_transaction *transaction,\n-\t\t\t   const char *refname,\n-\t\t\t   const unsigned char *old_sha1,\n-\t\t\t   unsigned int flags, const char *msg,\n-\t\t\t   struct strbuf *err)\n-{\n-\tif (old_sha1 && is_null_sha1(old_sha1))\n-\t\tdie(\"BUG: delete called with old_sha1 set to zeros\");\n-\treturn ref_transaction_update(transaction, refname,\n-\t\t\t\t      null_sha1, old_sha1,\n-\t\t\t\t      flags, msg, err);\n-}\n-\n-int ref_transaction_verify(struct ref_transaction *transaction,\n-\t\t\t   const char *refname,\n-\t\t\t   const unsigned char *old_sha1,\n-\t\t\t   unsigned int flags,\n-\t\t\t   struct strbuf *err)\n-{\n-\tif (!old_sha1)\n-\t\tdie(\"BUG: verify called with old_sha1 set to NULL\");\n-\treturn ref_transaction_update(transaction, refname,\n-\t\t\t\t      NULL, old_sha1,\n-\t\t\t\t      flags, NULL, err);\n-}\n-\n static int ref_update_reject_duplicates(struct string_list *refnames,\n \t\t\t\t\tstruct strbuf *err)\n {\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nnew file mode 100644\nindex 0000000..94f5dde\n--- /dev/null\n+++ b/refs/refs-internal.h\n@@ -0,0 +1,102 @@\n+#ifndef REFS_REFS_INTERNAL_H\n+#define REFS_REFS_INTERNAL_H\n+\n+/*\n+ * Data structures and functions for the internal use of the refs\n+ * module. Code outside of the refs module should use only the public\n+ * functions defined in \"refs.h\", and should *not* include this file.\n+ */\n+\n+#include \"../refs.h\"\n+\n+/*\n+ * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken\n+ * refs (i.e., because the reference is about to be deleted anyway).\n+ */\n+#define REF_DELETING\t0x02\n+\n+/*\n+ * Used as a flag in ref_update::flags when a loose ref is being\n+ * pruned.\n+ */\n+#define REF_ISPRUNING\t0x04\n+\n+/*\n+ * Used as a flag in ref_update::flags when the reference should be\n+ * updated to new_sha1.\n+ */\n+#define REF_HAVE_NEW\t0x08\n+\n+/*\n+ * Used as a flag in ref_update::flags when old_sha1 should be\n+ * checked.\n+ */\n+#define REF_HAVE_OLD\t0x10\n+\n+/*\n+ * Used as a flag in ref_update::flags when the lockfile needs to be\n+ * committed.\n+ */\n+#define REF_NEEDS_COMMIT 0x20\n+\n+/*\n+ * 0x40 is REF_FORCE_CREATE_REFLOG, so skip it if you're adding a\n+ * value to ref_update::flags\n+ */\n+\n+/**\n+ * Information needed for a single ref update. Set new_sha1 to the new\n+ * value or to null_sha1 to delete the ref. To check the old value\n+ * while the ref is locked, set (flags & REF_HAVE_OLD) and set\n+ * old_sha1 to the old value, or to null_sha1 to ensure the ref does\n+ * not exist before update.\n+ */\n+struct ref_update {\n+\t/*\n+\t * If (flags & REF_HAVE_NEW), set the reference to this value:\n+\t */\n+\tunsigned char new_sha1[20];\n+\t/*\n+\t * If (flags & REF_HAVE_OLD), check that the reference\n+\t * previously had this value:\n+\t */\n+\tunsigned char old_sha1[20];\n+\t/*\n+\t * One or more of REF_HAVE_NEW, REF_HAVE_OLD, REF_NODEREF,\n+\t * REF_DELETING, and REF_ISPRUNING:\n+\t */\n+\tunsigned int flags;\n+\tstruct ref_lock *lock;\n+\tint type;\n+\tchar *msg;\n+\tconst char refname[FLEX_ARRAY];\n+};\n+\n+/*\n+ * Transaction states.\n+ * OPEN:   The transaction is in a valid state and can accept new updates.\n+ *         An OPEN transaction can be committed.\n+ * CLOSED: A closed transaction is no longer active and no other operations\n+ *         than free can be used on it in this state.\n+ *         A transaction can either become closed by successfully committing\n+ *         an active transaction or if there is a failure while building\n+ *         the transaction thus rendering it failed/inactive.\n+ */\n+enum ref_transaction_state {\n+\tREF_TRANSACTION_OPEN   = 0,\n+\tREF_TRANSACTION_CLOSED = 1\n+};\n+\n+/*\n+ * Data structure for holding a reference transaction, which can\n+ * consist of checks and updates to multiple references, carried out\n+ * as atomically as possible.  This structure is opaque to callers.\n+ */\n+struct ref_transaction {\n+\tstruct ref_update **updates;\n+\tsize_t alloc;\n+\tsize_t nr;\n+\tenum ref_transaction_state state;\n+};\n+\n+#endif /* REFS_REFS_INTERNAL_H */\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 6af5fd6..0d0579f 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -2,7 +2,7 @@\n  * Common refs code for all backends.\n  */\n #include \"../cache.h\"\n-#include \"../refs.h\"\n+#include \"refs-internal.h\"\n #include \"../lockfile.h\"\n \n static int is_per_worktree_ref(const char *refname)\n@@ -841,3 +841,111 @@ int head_ref_namespaced(each_ref_fn fn, void *cb_data)\n \n \treturn ret;\n }\n+\n+struct ref_transaction *ref_transaction_begin(struct strbuf *err)\n+{\n+\tassert(err);\n+\n+\treturn xcalloc(1, sizeof(struct ref_transaction));\n+}\n+\n+void ref_transaction_free(struct ref_transaction *transaction)\n+{\n+\tint i;\n+\n+\tif (!transaction)\n+\t\treturn;\n+\n+\tfor (i = 0; i < transaction->nr; i++) {\n+\t\tfree(transaction->updates[i]->msg);\n+\t\tfree(transaction->updates[i]);\n+\t}\n+\tfree(transaction->updates);\n+\tfree(transaction);\n+}\n+\n+static struct ref_update *add_update(struct ref_transaction *transaction,\n+\t\t\t\t     const char *refname)\n+{\n+\tsize_t len = strlen(refname) + 1;\n+\tstruct ref_update *update = xcalloc(1, sizeof(*update) + len);\n+\n+\tmemcpy((char *)update->refname, refname, len); /* includes NUL */\n+\tALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);\n+\ttransaction->updates[transaction->nr++] = update;\n+\treturn update;\n+}\n+\n+int ref_transaction_update(struct ref_transaction *transaction,\n+\t\t\t   const char *refname,\n+\t\t\t   const unsigned char *new_sha1,\n+\t\t\t   const unsigned char *old_sha1,\n+\t\t\t   unsigned int flags, const char *msg,\n+\t\t\t   struct strbuf *err)\n+{\n+\tstruct ref_update *update;\n+\n+\tassert(err);\n+\n+\tif (transaction->state != REF_TRANSACTION_OPEN)\n+\t\tdie(\"BUG: update called for transaction that is not open\");\n+\n+\tif (new_sha1 && !is_null_sha1(new_sha1) &&\n+\t    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {\n+\t\tstrbuf_addf(err, \"refusing to update ref with bad name %s\",\n+\t\t\t    refname);\n+\t\treturn -1;\n+\t}\n+\n+\tupdate = add_update(transaction, refname);\n+\tif (new_sha1) {\n+\t\thashcpy(update->new_sha1, new_sha1);\n+\t\tflags |= REF_HAVE_NEW;\n+\t}\n+\tif (old_sha1) {\n+\t\thashcpy(update->old_sha1, old_sha1);\n+\t\tflags |= REF_HAVE_OLD;\n+\t}\n+\tupdate->flags = flags;\n+\tif (msg)\n+\t\tupdate->msg = xstrdup(msg);\n+\treturn 0;\n+}\n+\n+int ref_transaction_create(struct ref_transaction *transaction,\n+\t\t\t   const char *refname,\n+\t\t\t   const unsigned char *new_sha1,\n+\t\t\t   unsigned int flags, const char *msg,\n+\t\t\t   struct strbuf *err)\n+{\n+\tif (!new_sha1 || is_null_sha1(new_sha1))\n+\t\tdie(\"BUG: create called without valid new_sha1\");\n+\treturn ref_transaction_update(transaction, refname, new_sha1,\n+\t\t\t\t      null_sha1, flags, msg, err);\n+}\n+\n+int ref_transaction_delete(struct ref_transaction *transaction,\n+\t\t\t   const char *refname,\n+\t\t\t   const unsigned char *old_sha1,\n+\t\t\t   unsigned int flags, const char *msg,\n+\t\t\t   struct strbuf *err)\n+{\n+\tif (old_sha1 && is_null_sha1(old_sha1))\n+\t\tdie(\"BUG: delete called with old_sha1 set to zeros\");\n+\treturn ref_transaction_update(transaction, refname,\n+\t\t\t\t      null_sha1, old_sha1,\n+\t\t\t\t      flags, msg, err);\n+}\n+\n+int ref_transaction_verify(struct ref_transaction *transaction,\n+\t\t\t   const char *refname,\n+\t\t\t   const unsigned char *old_sha1,\n+\t\t\t   unsigned int flags,\n+\t\t\t   struct strbuf *err)\n+{\n+\tif (!old_sha1)\n+\t\tdie(\"BUG: verify called with old_sha1 set to NULL\");\n+\treturn ref_transaction_update(transaction, refname,\n+\t\t\t\t      NULL, old_sha1,\n+\t\t\t\t      flags, NULL, err);\n+}\n-- \n2.6.2\n"},{"id":"272798","messageId":"0ceed2b4f61fd896995994690ae2dcd06d602ee2.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 18/25] refs: move refname_is_safe to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:40:02Z","receivedAt":"2015-11-03T07:40:02Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nThis function does not contain any backend specific code, so move it\nto the common code. This function might be used by other refs\nbackends.\n\nWhile we are doing so, improve the comment's grammar and clarify a\nsafety rule.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 33 ---------------------------------\n refs/refs-internal.h | 15 +++++++++++++++\n refs/refs.c          | 24 ++++++++++++++++++++++++\n 3 files changed, 39 insertions(+), 33 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 1719720..3a4aff6 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -196,39 +196,6 @@ static struct ref_dir *get_ref_dir(struct ref_entry *entry)\n \treturn dir;\n }\n \n-/*\n- * Check if a refname is safe.\n- * For refs that start with \"refs/\" we consider it safe as long they do\n- * not try to resolve to outside of refs/.\n- *\n- * For all other refs we only consider them safe iff they only contain\n- * upper case characters and '_' (like \"HEAD\" AND \"MERGE_HEAD\", and not like\n- * \"config\").\n- */\n-static int refname_is_safe(const char *refname)\n-{\n-\tif (starts_with(refname, \"refs/\")) {\n-\t\tchar *buf;\n-\t\tint result;\n-\n-\t\tbuf = xmalloc(strlen(refname) + 1);\n-\t\t/*\n-\t\t * Does the refname try to escape refs/?\n-\t\t * For example: refs/foo/../bar is safe but refs/foo/../../bar\n-\t\t * is not.\n-\t\t */\n-\t\tresult = !normalize_path_copy(buf, refname + strlen(\"refs/\"));\n-\t\tfree(buf);\n-\t\treturn result;\n-\t}\n-\twhile (*refname) {\n-\t\tif (!isupper(*refname) && *refname != '_')\n-\t\t\treturn 0;\n-\t\trefname++;\n-\t}\n-\treturn 1;\n-}\n-\n static struct ref_entry *create_ref_entry(const char *refname,\n \t\t\t\t\t  const unsigned char *sha1, int flag,\n \t\t\t\t\t  int check_name)\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 94f5dde..5ae084b 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -10,6 +10,21 @@\n #include \"../refs.h\"\n \n /*\n+ * Return true iff refname is minimally safe. \"Safe\" here means that\n+ * deleting a loose reference by this name will not do any damage, for\n+ * example by causing a file that is not a reference to be deleted.\n+ * This function does not check that the reference name is legal; for\n+ * that, use check_refname_format().\n+ *\n+ * We consider a refname that starts with \"refs/\" to be safe as long\n+ * as any \"..\" components that it might contain do not escape \"refs/\".\n+ * Names that do not start with \"refs/\" are considered safe iff they\n+ * consist entirely of upper case characters and '_' (like \"HEAD\" and\n+ * \"MERGE_HEAD\" but not \"config\" or \"FOO/BAR\").\n+ */\n+int refname_is_safe(const char *refname);\n+\n+/*\n  * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken\n  * refs (i.e., because the reference is about to be deleted anyway).\n  */\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 0d0579f..31f1b19 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -949,3 +949,27 @@ int ref_transaction_verify(struct ref_transaction *transaction,\n \t\t\t\t      NULL, old_sha1,\n \t\t\t\t      flags, NULL, err);\n }\n+\n+int refname_is_safe(const char *refname)\n+{\n+\tif (starts_with(refname, \"refs/\")) {\n+\t\tchar *buf;\n+\t\tint result;\n+\n+\t\tbuf = xmalloc(strlen(refname) + 1);\n+\t\t/*\n+\t\t * Does the refname try to escape refs/?\n+\t\t * For example: refs/foo/../bar is safe but refs/foo/../../bar\n+\t\t * is not.\n+\t\t */\n+\t\tresult = !normalize_path_copy(buf, refname + strlen(\"refs/\"));\n+\t\tfree(buf);\n+\t\treturn result;\n+\t}\n+\twhile (*refname) {\n+\t\tif (!isupper(*refname) && *refname != '_')\n+\t\t\treturn 0;\n+\t\trefname++;\n+\t}\n+\treturn 1;\n+}\n-- \n2.6.2\n"},{"id":"272804","messageId":"226c66afe0bc7eb946c0f3075ab8b1062f074fc3.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 19/25] refs: move copy_msg to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:40:03Z","receivedAt":"2015-11-03T07:40:03Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nRename copy_msg to copy_reflog_msg and add it to refs/refs-internal.h.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 28 +---------------------------\n refs/refs-internal.h |  7 +++++++\n refs/refs.c          | 21 +++++++++++++++++++++\n 3 files changed, 29 insertions(+), 27 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 3a4aff6..4807b32 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2665,32 +2665,6 @@ static int commit_ref(struct ref_lock *lock)\n \treturn 0;\n }\n \n-/*\n- * copy the reflog message msg to buf, which has been allocated sufficiently\n- * large, while cleaning up the whitespaces.  Especially, convert LF to space,\n- * because reflog file is one line per entry.\n- */\n-static int copy_msg(char *buf, const char *msg)\n-{\n-\tchar *cp = buf;\n-\tchar c;\n-\tint wasspace = 1;\n-\n-\t*cp++ = '\\t';\n-\twhile ((c = *msg++)) {\n-\t\tif (wasspace && isspace(c))\n-\t\t\tcontinue;\n-\t\twasspace = isspace(c);\n-\t\tif (wasspace)\n-\t\t\tc = ' ';\n-\t\t*cp++ = c;\n-\t}\n-\twhile (buf < cp && isspace(cp[-1]))\n-\t\tcp--;\n-\t*cp++ = '\\n';\n-\treturn cp - buf;\n-}\n-\n static int should_autocreate_reflog(const char *refname)\n {\n \tif (!log_all_ref_updates)\n@@ -2774,7 +2748,7 @@ static int log_ref_write_fd(int fd, const unsigned char *old_sha1,\n \t\t\tsha1_to_hex(new_sha1),\n \t\t\tcommitter);\n \tif (msglen)\n-\t\tlen += copy_msg(logrec + len - 1, msg) - 1;\n+\t\tlen += copy_reflog_msg(logrec + len - 1, msg) - 1;\n \n \twritten = len <= maxlen ? write_in_full(fd, logrec, len) : -1;\n \tfree(logrec);\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 5ae084b..a1655e3 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -114,4 +114,11 @@ struct ref_transaction {\n \tenum ref_transaction_state state;\n };\n \n+/*\n+ * Copy the reflog message msg to buf, which has been allocated sufficiently\n+ * large, while cleaning up the whitespaces.  Especially, convert LF to space,\n+ * because reflog file is one line per entry.\n+ */\n+int copy_reflog_msg(char *buf, const char *msg);\n+\n #endif /* REFS_REFS_INTERNAL_H */\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 31f1b19..6bf790b 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -827,6 +827,27 @@ int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *c\n \treturn for_each_ref_in_submodule(submodule, \"refs/remotes/\", fn, cb_data);\n }\n \n+int copy_reflog_msg(char *buf, const char *msg)\n+{\n+\tchar *cp = buf;\n+\tchar c;\n+\tint wasspace = 1;\n+\n+\t*cp++ = '\\t';\n+\twhile ((c = *msg++)) {\n+\t\tif (wasspace && isspace(c))\n+\t\t\tcontinue;\n+\t\twasspace = isspace(c);\n+\t\tif (wasspace)\n+\t\t\tc = ' ';\n+\t\t*cp++ = c;\n+\t}\n+\twhile (buf < cp && isspace(cp[-1]))\n+\t\tcp--;\n+\t*cp++ = '\\n';\n+\treturn cp - buf;\n+}\n+\n int head_ref_namespaced(each_ref_fn fn, void *cb_data)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-- \n2.6.2\n"},{"id":"272807","messageId":"da2e70b06e99e0b949a03a9b2fc9f8fccdc01c93.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 20/25] refs: move peel_object to the common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:40:04Z","receivedAt":"2015-11-03T07:40:04Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nThis function does not contain any backend specific code so move it to\nthe common code.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 53 ----------------------------------------------------\n refs/refs-internal.h | 34 +++++++++++++++++++++++++++++++++\n refs/refs.c          | 23 +++++++++++++++++++++++\n 3 files changed, 57 insertions(+), 53 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 4807b32..2073004 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1612,59 +1612,6 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \treturn ret;\n }\n \n-enum peel_status {\n-\t/* object was peeled successfully: */\n-\tPEEL_PEELED = 0,\n-\n-\t/*\n-\t * object cannot be peeled because the named object (or an\n-\t * object referred to by a tag in the peel chain), does not\n-\t * exist.\n-\t */\n-\tPEEL_INVALID = -1,\n-\n-\t/* object cannot be peeled because it is not a tag: */\n-\tPEEL_NON_TAG = -2,\n-\n-\t/* ref_entry contains no peeled value because it is a symref: */\n-\tPEEL_IS_SYMREF = -3,\n-\n-\t/*\n-\t * ref_entry cannot be peeled because it is broken (i.e., the\n-\t * symbolic reference cannot even be resolved to an object\n-\t * name):\n-\t */\n-\tPEEL_BROKEN = -4\n-};\n-\n-/*\n- * Peel the named object; i.e., if the object is a tag, resolve the\n- * tag recursively until a non-tag is found.  If successful, store the\n- * result to sha1 and return PEEL_PEELED.  If the object is not a tag\n- * or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,\n- * and leave sha1 unchanged.\n- */\n-static enum peel_status peel_object(const unsigned char *name, unsigned char *sha1)\n-{\n-\tstruct object *o = lookup_unknown_object(name);\n-\n-\tif (o->type == OBJ_NONE) {\n-\t\tint type = sha1_object_info(name, NULL);\n-\t\tif (type < 0 || !object_as_type(o, type, 0))\n-\t\t\treturn PEEL_INVALID;\n-\t}\n-\n-\tif (o->type != OBJ_TAG)\n-\t\treturn PEEL_NON_TAG;\n-\n-\to = deref_tag_noverify(o);\n-\tif (!o)\n-\t\treturn PEEL_INVALID;\n-\n-\thashcpy(sha1, o->sha1);\n-\treturn PEEL_PEELED;\n-}\n-\n /*\n  * Peel the entry (if possible) and return its new peel_status.  If\n  * repeel is true, re-peel the entry even if there is an old peeled\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex a1655e3..5b4176e 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -59,6 +59,40 @@ int refname_is_safe(const char *refname);\n  * value to ref_update::flags\n  */\n \n+enum peel_status {\n+\t/* object was peeled successfully: */\n+\tPEEL_PEELED = 0,\n+\n+\t/*\n+\t * object cannot be peeled because the named object (or an\n+\t * object referred to by a tag in the peel chain), does not\n+\t * exist.\n+\t */\n+\tPEEL_INVALID = -1,\n+\n+\t/* object cannot be peeled because it is not a tag: */\n+\tPEEL_NON_TAG = -2,\n+\n+\t/* ref_entry contains no peeled value because it is a symref: */\n+\tPEEL_IS_SYMREF = -3,\n+\n+\t/*\n+\t * ref_entry cannot be peeled because it is broken (i.e., the\n+\t * symbolic reference cannot even be resolved to an object\n+\t * name):\n+\t */\n+\tPEEL_BROKEN = -4\n+};\n+\n+/*\n+ * Peel the named object; i.e., if the object is a tag, resolve the\n+ * tag recursively until a non-tag is found.  If successful, store the\n+ * result to sha1 and return PEEL_PEELED.  If the object is not a tag\n+ * or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,\n+ * and leave sha1 unchanged.\n+ */\n+enum peel_status peel_object(const unsigned char *name, unsigned char *sha1);\n+\n /**\n  * Information needed for a single ref update. Set new_sha1 to the new\n  * value or to null_sha1 to delete the ref. To check the old value\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 6bf790b..5d95804 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -4,6 +4,8 @@\n #include \"../cache.h\"\n #include \"refs-internal.h\"\n #include \"../lockfile.h\"\n+#include \"../object.h\"\n+#include \"../tag.h\"\n \n static int is_per_worktree_ref(const char *refname)\n {\n@@ -994,3 +996,24 @@ int refname_is_safe(const char *refname)\n \t}\n \treturn 1;\n }\n+\n+enum peel_status peel_object(const unsigned char *name, unsigned char *sha1)\n+{\n+\tstruct object *o = lookup_unknown_object(name);\n+\n+\tif (o->type == OBJ_NONE) {\n+\t\tint type = sha1_object_info(name, NULL);\n+\t\tif (type < 0 || !object_as_type(o, type, 0))\n+\t\t\treturn PEEL_INVALID;\n+\t}\n+\n+\tif (o->type != OBJ_TAG)\n+\t\treturn PEEL_NON_TAG;\n+\n+\to = deref_tag_noverify(o);\n+\tif (!o)\n+\t\treturn PEEL_INVALID;\n+\n+\thashcpy(sha1, o->sha1);\n+\treturn PEEL_PEELED;\n+}\n-- \n2.6.2\n"},{"id":"272808","messageId":"be1e2f413f193635138ea24e90665a91906c8aa6.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 21/25] refs: move should_autocreate_reflog to common code","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:40:05Z","receivedAt":"2015-11-03T07:40:05Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 10 ----------\n refs/refs-internal.h |  2 ++\n refs/refs.c          | 10 ++++++++++\n 3 files changed, 12 insertions(+), 10 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 2073004..7dc68b8 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2612,16 +2612,6 @@ static int commit_ref(struct ref_lock *lock)\n \treturn 0;\n }\n \n-static int should_autocreate_reflog(const char *refname)\n-{\n-\tif (!log_all_ref_updates)\n-\t\treturn 0;\n-\treturn starts_with(refname, \"refs/heads/\") ||\n-\t\tstarts_with(refname, \"refs/remotes/\") ||\n-\t\tstarts_with(refname, \"refs/notes/\") ||\n-\t\t!strcmp(refname, \"HEAD\");\n-}\n-\n /*\n  * Create a reflog for a ref.  If force_create = 0, the reflog will\n  * only be created for certain refs (those for which\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 5b4176e..d854d9e 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -148,6 +148,8 @@ struct ref_transaction {\n \tenum ref_transaction_state state;\n };\n \n+extern int should_autocreate_reflog(const char *refname);\n+\n /*\n  * Copy the reflog message msg to buf, which has been allocated sufficiently\n  * large, while cleaning up the whitespaces.  Especially, convert LF to space,\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 5d95804..25d4e22 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -625,6 +625,16 @@ char *resolve_refdup(const char *refname, int resolve_flags,\n \t\t\t\t\t\t  sha1, flags));\n }\n \n+int should_autocreate_reflog(const char *refname)\n+{\n+\tif (!log_all_ref_updates)\n+\t\treturn 0;\n+\treturn starts_with(refname, \"refs/heads/\") ||\n+\t\tstarts_with(refname, \"refs/remotes/\") ||\n+\t\tstarts_with(refname, \"refs/notes/\") ||\n+\t\t!strcmp(refname, \"HEAD\");\n+}\n+\n /*\n  * How to handle various characters in refnames:\n  * 0: An acceptable character for refs\n-- \n2.6.2\n"},{"id":"272814","messageId":"f1288dac85d4d298dfe2f03815cde751aa1aa8d0.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 22/25] initdb: make safe_create_dir public","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:40:06Z","receivedAt":"2015-11-03T07:40:06Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nSoon we will want to create initdb functions for ref backends, and\ncode from initdb that calls this function needs to move into the files\nbackend. So this function needs to be public.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n builtin/init-db.c | 12 ------------\n cache.h           |  8 ++++++++\n path.c            | 12 ++++++++++++\n 3 files changed, 20 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/init-db.c b/builtin/init-db.c\nindex f59f407..07229d6 100644\n--- a/builtin/init-db.c\n+++ b/builtin/init-db.c\n@@ -24,18 +24,6 @@ static int init_shared_repository = -1;\n static const char *init_db_template_dir;\n static const char *git_link;\n \n-static void safe_create_dir(const char *dir, int share)\n-{\n-\tif (mkdir(dir, 0777) < 0) {\n-\t\tif (errno != EEXIST) {\n-\t\t\tperror(dir);\n-\t\t\texit(1);\n-\t\t}\n-\t}\n-\telse if (share && adjust_shared_perm(dir))\n-\t\tdie(_(\"Could not make %s writable by group\"), dir);\n-}\n-\n static void copy_templates_1(struct strbuf *path, struct strbuf *template,\n \t\t\t     DIR *dir)\n {\ndiff --git a/cache.h b/cache.h\nindex 9a905a8..0f9808c 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1737,4 +1737,12 @@ void stat_validity_update(struct stat_validity *sv, int fd);\n int versioncmp(const char *s1, const char *s2);\n void sleep_millisec(int millisec);\n \n+/*\n+ * Create a directory and (if share is nonzero) adjust its permissions\n+ * according to the shared_repository setting. Only use this for\n+ * directories under $GIT_DIR.  Don't use it for working tree\n+ * directories.\n+ */\n+void safe_create_dir(const char *dir, int share);\n+\n #endif /* CACHE_H */\ndiff --git a/path.c b/path.c\nindex 212695a..9e0283c 100644\n--- a/path.c\n+++ b/path.c\n@@ -723,6 +723,18 @@ int adjust_shared_perm(const char *path)\n \treturn 0;\n }\n \n+void safe_create_dir(const char *dir, int share)\n+{\n+\tif (mkdir(dir, 0777) < 0) {\n+\t\tif (errno != EEXIST) {\n+\t\t\tperror(dir);\n+\t\t\texit(1);\n+\t\t}\n+\t}\n+\telse if (share && adjust_shared_perm(dir))\n+\t\tdie(_(\"Could not make %s writable by group\"), dir);\n+}\n+\n static int have_same_root(const char *path1, const char *path2)\n {\n \tint is_abs1, is_abs2;\n-- \n2.6.2\n"},{"id":"272815","messageId":"5b305c7ef25dc53e5b6ee11169c16fdbeda4ad86.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 23/25] files_log_ref_write: new function","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:40:07Z","receivedAt":"2015-11-03T07:40:07Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nBecause HEAD and stash are per-worktree, every refs backend needs to\ngo through the files backend to write these refs.\n\nSo create a new function, files_log_ref_write, and add it to\nrefs/refs-internal.h. Later, we will use this to handle reflog updates\nfor per-worktree symbolic refs (HEAD).\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 8 ++++++++\n refs/refs-internal.h | 4 ++++\n 2 files changed, 12 insertions(+)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 7dc68b8..20e2924 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2733,6 +2733,14 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,\n \t\t\t const unsigned char *new_sha1, const char *msg,\n \t\t\t int flags, struct strbuf *err)\n {\n+\treturn files_log_ref_write(refname, old_sha1, new_sha1, msg, flags,\n+\t\t\t\t   err);\n+}\n+\n+int files_log_ref_write(const char *refname, const unsigned char *old_sha1,\n+\t\t\tconst unsigned char *new_sha1, const char *msg,\n+\t\t\tint flags, struct strbuf *err)\n+{\n \tstruct strbuf sb = STRBUF_INIT;\n \tint ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb, flags,\n \t\t\t\t  err);\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex d854d9e..5f447d4 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -157,4 +157,8 @@ extern int should_autocreate_reflog(const char *refname);\n  */\n int copy_reflog_msg(char *buf, const char *msg);\n \n+int files_log_ref_write(const char *refname, const unsigned char *old_sha1,\n+\t\t\tconst unsigned char *new_sha1, const char *msg,\n+\t\t\tint flags, struct strbuf *err);\n+\n #endif /* REFS_REFS_INTERNAL_H */\n-- \n2.6.2\n"},{"id":"272812","messageId":"977f96011c2a35c77a1bc6b25960b357e2bd7ef7.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 24/25] refs: create a shared version of verify_refname_available","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:40:08Z","receivedAt":"2015-11-03T07:40:08Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nCreate a version of verify_refname_available that backends can use,\nand add it to refs/refs-internal.h.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 65 ++++++++++++++++++++++++----------------------------\n refs/refs-internal.h | 20 ++++++++++++++++\n 2 files changed, 50 insertions(+), 35 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 20e2924..e0ae769 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -135,7 +135,7 @@ struct ref_dir {\n  * presence of an empty subdirectory does not block the creation of a\n  * similarly-named reference.  (The fact that reference names with the\n  * same leading components can conflict *with each other* is a\n- * separate issue that is regulated by verify_refname_available().)\n+ * separate issue that is regulated by verify_refname_available_dir().)\n  *\n  * Please note that the name field contains the fully-qualified\n  * reference (or subdirectory) name.  Space could be saved by only\n@@ -720,25 +720,13 @@ static int nonmatching_ref_fn(struct ref_entry *entry, void *vdata)\n /*\n  * Return 0 if a reference named refname could be created without\n  * conflicting with the name of an existing reference in dir.\n- * Otherwise, return a negative value and write an explanation to err.\n- * If extras is non-NULL, it is a list of additional refnames with\n- * which refname is not allowed to conflict. If skip is non-NULL,\n- * ignore potential conflicts with refs in skip (e.g., because they\n- * are scheduled for deletion in the same operation). Behavior is\n- * undefined if the same name is listed in both extras and skip.\n- *\n- * Two reference names conflict if one of them exactly matches the\n- * leading components of the other; e.g., \"refs/foo/bar\" conflicts\n- * with both \"refs/foo\" and with \"refs/foo/bar/baz\" but not with\n- * \"refs/foo/bar\" or \"refs/foo/barbados\".\n- *\n- * extras and skip must be sorted.\n+ * See verify_refname_available for details.\n  */\n-static int verify_refname_available(const char *refname,\n-\t\t\t\t    const struct string_list *extras,\n-\t\t\t\t    const struct string_list *skip,\n-\t\t\t\t    struct ref_dir *dir,\n-\t\t\t\t    struct strbuf *err)\n+static int verify_refname_available_dir(const char *refname,\n+\t\t\t\t\tconst struct string_list *extras,\n+\t\t\t\t\tconst struct string_list *skip,\n+\t\t\t\t\tstruct ref_dir *dir,\n+\t\t\t\t\tstruct strbuf *err)\n {\n \tconst char *slash;\n \tint pos;\n@@ -1942,9 +1930,12 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \t\t */\n \t\tstrbuf_git_path(&orig_ref_file, \"%s\", orig_refname);\n \t\tif (remove_empty_directories(&orig_ref_file)) {\n+\t\t\tstruct ref_dir *loose_refs;\n+\t\t\tloose_refs = get_loose_refs(&ref_cache);\n \t\t\tlast_errno = errno;\n-\t\t\tif (!verify_refname_available(orig_refname, extras, skip,\n-\t\t\t\t\t\t      get_loose_refs(&ref_cache), err))\n+\t\t\tif (!verify_refname_available_dir(orig_refname, extras,\n+\t\t\t\t\t\t\t  skip, loose_refs,\n+\t\t\t\t\t\t\t  err))\n \t\t\t\tstrbuf_addf(err, \"there are still refs under '%s'\",\n \t\t\t\t\t    orig_refname);\n \t\t\tgoto error_return;\n@@ -1957,8 +1948,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \tif (!refname) {\n \t\tlast_errno = errno;\n \t\tif (last_errno != ENOTDIR ||\n-\t\t    !verify_refname_available(orig_refname, extras, skip,\n-\t\t\t\t\t      get_loose_refs(&ref_cache), err))\n+\t\t    !verify_refname_available_dir(orig_refname, extras, skip,\n+\t\t\t\t\t\t  get_loose_refs(&ref_cache),\n+\t\t\t\t\t\t  err))\n \t\t\tstrbuf_addf(err, \"unable to resolve reference %s: %s\",\n \t\t\t\t    orig_refname, strerror(last_errno));\n \n@@ -1971,8 +1963,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \t * our refname.\n \t */\n \tif (is_null_oid(&lock->old_oid) &&\n-\t    verify_refname_available(refname, extras, skip,\n-\t\t\t\t     get_packed_refs(&ref_cache), err)) {\n+\t    verify_refname_available_dir(refname, extras, skip,\n+\t\t\t\t\t get_packed_refs(&ref_cache), err)) {\n \t\tlast_errno = ENOTDIR;\n \t\tgoto error_return;\n \t}\n@@ -2476,10 +2468,7 @@ static int rename_ref_available(const char *oldname, const char *newname)\n \tint ret;\n \n \tstring_list_insert(&skip, oldname);\n-\tret = !verify_refname_available(newname, NULL, &skip,\n-\t\t\t\t\tget_packed_refs(&ref_cache), &err)\n-\t\t&& !verify_refname_available(newname, NULL, &skip,\n-\t\t\t\t\t     get_loose_refs(&ref_cache), &err);\n+\tret = !verify_refname_available(newname, NULL, &skip, &err);\n \tif (!ret)\n \t\terror(\"%s\", err.buf);\n \n@@ -2612,6 +2601,17 @@ static int commit_ref(struct ref_lock *lock)\n \treturn 0;\n }\n \n+int verify_refname_available(const char *newname, struct string_list *extra,\n+\t\t\t     struct string_list *skip, struct strbuf *err)\n+{\n+\tstruct ref_dir *packed_refs = get_packed_refs(&ref_cache);\n+\tstruct ref_dir *loose_refs = get_loose_refs(&ref_cache);\n+\treturn verify_refname_available_dir(newname, extra, skip,\n+\t\t\t\t\t    packed_refs, err) ||\n+\t\tverify_refname_available_dir(newname, extra, skip,\n+\t\t\t\t\t     loose_refs, err);\n+}\n+\n /*\n  * Create a reflog for a ref.  If force_create = 0, the reflog will\n  * only be created for certain refs (those for which\n@@ -3327,8 +3327,6 @@ static int ref_present(const char *refname,\n int initial_ref_transaction_commit(struct ref_transaction *transaction,\n \t\t\t\t   struct strbuf *err)\n {\n-\tstruct ref_dir *loose_refs = get_loose_refs(&ref_cache);\n-\tstruct ref_dir *packed_refs = get_packed_refs(&ref_cache);\n \tint ret = 0, i;\n \tint n = transaction->nr;\n \tstruct ref_update **updates = transaction->updates;\n@@ -3371,10 +3369,7 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,\n \t\t\tdie(\"BUG: initial ref transaction with old_sha1 set\");\n \t\tif (verify_refname_available(update->refname,\n \t\t\t\t\t     &affected_refnames, NULL,\n-\t\t\t\t\t     loose_refs, err) ||\n-\t\t    verify_refname_available(update->refname,\n-\t\t\t\t\t     &affected_refnames, NULL,\n-\t\t\t\t\t     packed_refs, err)) {\n+\t\t\t\t\t     err)) {\n \t\t\tret = TRANSACTION_NAME_CONFLICT;\n \t\t\tgoto cleanup;\n \t\t}\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 5f447d4..f6a79b9 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -93,6 +93,26 @@ enum peel_status {\n  */\n enum peel_status peel_object(const unsigned char *name, unsigned char *sha1);\n \n+/*\n+ * Return 0 if a reference named refname could be created without\n+ * conflicting with the name of an existing reference.\n+ * Otherwise, return a negative value and write an explanation to err.\n+ * If extras is non-NULL, it is a list of additional refnames with\n+ * which refname is not allowed to conflict. If skip is non-NULL,\n+ * ignore potential conflicts with refs in skip (e.g., because they\n+ * are scheduled for deletion in the same operation). Behavior is\n+ * undefined if the same name is listed in both extras and skip.\n+ *\n+ * Two reference names conflict if one of them exactly matches the\n+ * leading components of the other; e.g., \"foo/bar\" conflicts with\n+ * both \"foo\" and with \"foo/bar/baz\" but not with \"foo/bar\" or\n+ * \"foo/barbados\".\n+ *\n+ * skip must be sorted.\n+ */\n+int verify_refname_available(const char *newname, struct string_list *extra,\n+\t\t\t     struct string_list *skip, struct strbuf *err);\n+\n /**\n  * Information needed for a single ref update. Set new_sha1 to the new\n  * value or to null_sha1 to delete the ref. To check the old value\n-- \n2.6.2\n"},{"id":"272800","messageId":"3060e6410e8798064ef84cd31645021d1b84fbb9.1446534991.git.mhagger@alum.mit.edu","threadId":"40663","inReplyTo":"cover.1446534991.git.mhagger@alum.mit.edu","subject":"[PATCH v6 25/25] refs: break out ref conflict checks","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-03T07:40:09Z","receivedAt":"2015-11-03T07:40:09Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nCreate new function verify_no_descendants, to hold one of the ref\nconflict checks used in verify_refname_available. Multiple backends\nwill need this function, so move it to the common code.\n\nAlso move rename_ref_available to the common code, because alternate\nbackends might need it and it has no files-backend-specific code.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs/files-backend.c | 49 +++++++------------------------------------------\n refs/refs-internal.h | 16 ++++++++++++++++\n refs/refs.c          | 44 ++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 67 insertions(+), 42 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex e0ae769..baa13bb 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -729,6 +729,7 @@ static int verify_refname_available_dir(const char *refname,\n \t\t\t\t\tstruct strbuf *err)\n {\n \tconst char *slash;\n+\tconst char *extra_refname;\n \tint pos;\n \tstruct strbuf dirname = STRBUF_INIT;\n \tint ret = -1;\n@@ -834,32 +835,12 @@ static int verify_refname_available_dir(const char *refname,\n \t\t}\n \t}\n \n-\tif (extras) {\n-\t\t/*\n-\t\t * Check for entries in extras that start with\n-\t\t * \"$refname/\". We do that by looking for the place\n-\t\t * where \"$refname/\" would be inserted in extras. If\n-\t\t * there is an entry at that position that starts with\n-\t\t * \"$refname/\" and is not in skip, then we have a\n-\t\t * conflict.\n-\t\t */\n-\t\tfor (pos = string_list_find_insert_index(extras, dirname.buf, 0);\n-\t\t     pos < extras->nr; pos++) {\n-\t\t\tconst char *extra_refname = extras->items[pos].string;\n-\n-\t\t\tif (!starts_with(extra_refname, dirname.buf))\n-\t\t\t\tbreak;\n-\n-\t\t\tif (!skip || !string_list_has_string(skip, extra_refname)) {\n-\t\t\t\tstrbuf_addf(err, \"cannot process '%s' and '%s' at the same time\",\n-\t\t\t\t\t    refname, extra_refname);\n-\t\t\t\tgoto cleanup;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-\t/* No conflicts were found */\n-\tret = 0;\n+\textra_refname = find_descendant_ref(dirname.buf, extras, skip);\n+\tif (extra_refname)\n+\t\tstrbuf_addf(err, \"cannot process '%s' and '%s' at the same time\",\n+\t\t\t    refname, extra_refname);\n+\telse\n+\t\tret = 0;\n \n cleanup:\n \tstrbuf_release(&dirname);\n@@ -2461,22 +2442,6 @@ out:\n \treturn ret;\n }\n \n-static int rename_ref_available(const char *oldname, const char *newname)\n-{\n-\tstruct string_list skip = STRING_LIST_INIT_NODUP;\n-\tstruct strbuf err = STRBUF_INIT;\n-\tint ret;\n-\n-\tstring_list_insert(&skip, oldname);\n-\tret = !verify_refname_available(newname, NULL, &skip, &err);\n-\tif (!ret)\n-\t\terror(\"%s\", err.buf);\n-\n-\tstring_list_clear(&skip, 0);\n-\tstrbuf_release(&err);\n-\treturn ret;\n-}\n-\n static int write_ref_to_lockfile(struct ref_lock *lock,\n \t\t\t\t const unsigned char *sha1, struct strbuf *err);\n static int commit_ref_update(struct ref_lock *lock,\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex f6a79b9..500b708 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -25,6 +25,22 @@\n int refname_is_safe(const char *refname);\n \n /*\n+ * Check for entries in extras that are within the specified\n+ * directory, where dirname is a reference directory name including\n+ * the trailing slash (e.g., \"refs/heads/foo/\"). Ignore any\n+ * conflicting references that are found in skip. If there is a\n+ * conflicting reference, return its name.\n+ *\n+ * extras and skip must be sorted lists of reference names. Either one\n+ * can be NULL, signifying the empty list.\n+ */\n+const char *find_descendant_ref(const char *dirname,\n+\t\t\t\tconst struct string_list *extras,\n+\t\t\t\tconst struct string_list *skip);\n+\n+int rename_ref_available(const char *oldname, const char *newname);\n+\n+/*\n  * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken\n  * refs (i.e., because the reference is about to be deleted anyway).\n  */\ndiff --git a/refs/refs.c b/refs/refs.c\nindex 25d4e22..1c1c6cb 100644\n--- a/refs/refs.c\n+++ b/refs/refs.c\n@@ -1027,3 +1027,47 @@ enum peel_status peel_object(const unsigned char *name, unsigned char *sha1)\n \thashcpy(sha1, o->sha1);\n \treturn PEEL_PEELED;\n }\n+\n+const char *find_descendant_ref(const char *dirname,\n+\t\t\t\tconst struct string_list *extras,\n+\t\t\t\tconst struct string_list *skip)\n+{\n+\tint pos;\n+\n+\tif (!extras)\n+\t\treturn NULL;\n+\n+\t/*\n+\t * Look at the place where dirname would be inserted into\n+\t * extras. If there is an entry at that position that starts\n+\t * with dirname (remember, dirname includes the trailing\n+\t * slash) and is not in skip, then we have a conflict.\n+\t */\n+\tfor (pos = string_list_find_insert_index(extras, dirname, 0);\n+\t     pos < extras->nr; pos++) {\n+\t\tconst char *extra_refname = extras->items[pos].string;\n+\n+\t\tif (!starts_with(extra_refname, dirname))\n+\t\t\tbreak;\n+\n+\t\tif (!skip || !string_list_has_string(skip, extra_refname))\n+\t\t\treturn extra_refname;\n+\t}\n+\treturn NULL;\n+}\n+\n+int rename_ref_available(const char *oldname, const char *newname)\n+{\n+\tstruct string_list skip = STRING_LIST_INIT_NODUP;\n+\tstruct strbuf err = STRBUF_INIT;\n+\tint ret;\n+\n+\tstring_list_insert(&skip, oldname);\n+\tret = !verify_refname_available(newname, NULL, &skip, &err);\n+\tif (!ret)\n+\t\terror(\"%s\", err.buf);\n+\n+\tstring_list_clear(&skip, 0);\n+\tstrbuf_release(&err);\n+\treturn ret;\n+}\n-- \n2.6.2\n"},{"id":"272917","messageId":"1446670884.4131.42.camel@twopensource.com","threadId":"40663","inReplyTo":"3060e6410e8798064ef84cd31645021d1b84fbb9.1446534991.git.mhagger@alum.mit.edu","subject":"Re: [PATCH v6 25/25] refs: break out ref conflict checks","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-11-04T21:01:24Z","receivedAt":"2015-11-04T21:01:24Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"On Tue, 2015-11-03 at 08:40 +0100, Michael Haggerty wrote:\n> + * extras and skip must be sorted lists of reference names. Either one\n> + * can be NULL, signifying the empty list.\n> + */\n\nMy version had:\n\n\"skip can be NULL; extras cannot.\"\n\nThe first thing that function does is:\nstring_list_find_insert_index(extras, dirname, 0)\n\nAnd that crashes when extras is null.  So I think my version is correct\nhere.\n\nOther than that, I've reviewed both the patches themselves and the\noverall diff and everything looks good to me.\n"},{"id":"272931","messageId":"563AD452.2030301@alum.mit.edu","threadId":"40663","inReplyTo":"1446670884.4131.42.camel@twopensource.com","subject":"Re: [PATCH v6 25/25] refs: break out ref conflict checks","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-05T04:00:18Z","receivedAt":"2015-11-05T04:00:18Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 11/04/2015 10:01 PM, David Turner wrote:\n> On Tue, 2015-11-03 at 08:40 +0100, Michael Haggerty wrote:\n>> + * extras and skip must be sorted lists of reference names. Either one\n>> + * can be NULL, signifying the empty list.\n>> + */\n> \n> My version had:\n> \n> \"skip can be NULL; extras cannot.\"\n> \n> The first thing that function does is:\n> string_list_find_insert_index(extras, dirname, 0)\n> \n> And that crashes when extras is null.  So I think my version is correct\n> here.\n\nWe're talking about the function find_descendant_ref(), which was added\nin this patch, right? Because the first thing that function does is\n\n+\tif (!extras)\n+\t\treturn NULL;\n\n(This guard was in your version, too.) Also, the callsite doesn't\nprotect against extras==NULL. So either we're talking about two\ndifferent things here, or I disagree with you.\n\n> Other than that, I've reviewed both the patches themselves and the\n> overall diff and everything looks good to me.\n\nThanks!\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"272958","messageId":"1446740535.4131.50.camel@twopensource.com","threadId":"40663","inReplyTo":"563AD452.2030301@alum.mit.edu","subject":"Re: [PATCH v6 25/25] refs: break out ref conflict checks","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-11-05T16:22:15Z","receivedAt":"2015-11-05T16:22:15Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"On Thu, 2015-11-05 at 05:00 +0100, Michael Haggerty wrote:\n> On 11/04/2015 10:01 PM, David Turner wrote:\n> > On Tue, 2015-11-03 at 08:40 +0100, Michael Haggerty wrote:\n> >> + * extras and skip must be sorted lists of reference names. Either one\n> >> + * can be NULL, signifying the empty list.\n> >> + */\n> > \n> > My version had:\n> > \n> > \"skip can be NULL; extras cannot.\"\n> > \n> > The first thing that function does is:\n> > string_list_find_insert_index(extras, dirname, 0)\n> > \n> > And that crashes when extras is null.  So I think my version is correct\n> > here.\n> \n> We're talking about the function find_descendant_ref(), which was added\n> in this patch, right? Because the first thing that function does is\n> \n> +\tif (!extras)\n> +\t\treturn NULL;\n> \n> (This guard was in your version, too.) Also, the callsite doesn't\n> protect against extras==NULL. So either we're talking about two\n> different things here, or I disagree with you.\n\nYou're right.  I totally missed that.  But while looking at it, I\nnoticed that the commit message doesn't look quite right (my fault):\n\n> Create new function verify_no_descendants, to hold one of the ref\n> conflict checks used in verify_refname_available. Multiple backends\n> will need this function, so move it to the common code.\n\nThe function is find_descendant_ref not verify_no_descendants.\n"},{"id":"273013","messageId":"563CAC58.3070907@alum.mit.edu","threadId":"40663","inReplyTo":"1446740535.4131.50.camel@twopensource.com","subject":"Re: [PATCH v6 25/25] refs: break out ref conflict checks","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-06T13:34:16Z","receivedAt":"2015-11-06T13:34:16Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 11/05/2015 05:22 PM, David Turner wrote:\n> [...] But while looking at it, I\n> noticed that the commit message doesn't look quite right (my fault):\n> \n> On Thu, 2015-11-05 at 05:00 +0100, Michael Haggerty wrote:\n>> Create new function verify_no_descendants, to hold one of the ref\n>> conflict checks used in verify_refname_available. Multiple backends\n>> will need this function, so move it to the common code.\n> \n> The function is find_descendant_ref not verify_no_descendants.\n\nThanks for noticing.\n\nJunio, if there are no more comments, would you mind\n\n    s/verify_no_descendants/find_descendant_ref/\n\nin the log message of this commit? And then, if you are also OK with the\nnew subdirectory introduced in this patch series, David and I seem to be\nin agreement that it is ready to go. It would be great if this patch\nseries could be merged in a timely manner, as it will conflict with\nnearly any other changes that people might want to undertake in the refs\ncode.\n\nThanks,\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"273022","messageId":"xmqq611f3umt.fsf@gitster.mtv.corp.google.com","threadId":"40663","inReplyTo":"563CAC58.3070907@alum.mit.edu","subject":"Re: [PATCH v6 25/25] refs: break out ref conflict checks","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-11-06T17:28:10Z","receivedAt":"2015-11-06T17:28:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> Junio, if there are no more comments, would you mind\n>\n>     s/verify_no_descendants/find_descendant_ref/\n>\n> in the log message of this commit? And then, if you are also OK with the\n> new subdirectory introduced in this patch series, David and I seem to be\n> in agreement that it is ready to go. It would be great if this patch\n> series could be merged in a timely manner, as it will conflict with\n> nearly any other changes that people might want to undertake in the refs\n> code.\n\nThanks for working well together.  Let me see what I can do today...\n"},{"id":"273035","messageId":"xmqqd1vm3e59.fsf@gitster.mtv.corp.google.com","threadId":"40663","inReplyTo":"xmqq611f3umt.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v6 25/25] refs: break out ref conflict checks","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-11-06T23:24:18Z","receivedAt":"2015-11-06T23:24:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Michael Haggerty <mhagger@alum.mit.edu> writes:\n>\n>> Junio, if there are no more comments, would you mind\n>>\n>>     s/verify_no_descendants/find_descendant_ref/\n>>\n>> in the log message of this commit? And then, if you are also OK with the\n>> new subdirectory introduced in this patch series, David and I seem to be\n>> in agreement that it is ready to go. It would be great if this patch\n>> series could be merged in a timely manner, as it will conflict with\n>> nearly any other changes that people might want to undertake in the refs\n>> code.\n>\n> Thanks for working well together.  Let me see what I can do today...\n\nWhat I'll push out later today merges this to the tip of 'pu'.\nThe resolution is the same for 'jch' or 'next' (I checked).\n\nI have to say that the merge of this topioc is not pretty.  A topic\nthat is already in flight has changed ref_is_hidden() in refs.c; you\nmove this block of code first to refs/refs-backend.c and then to\nrefs/refs.c, and the recursive merge ends up saying \"The trunk side\nchanged this block of code in refs/refs-backend.c while the side\nbranch removed that block\".\n\nThe resolution has to become an evil merge that brings in a new file\nrefs/refs.c from the tip of your topic to the trunk while replaying\nthat change in the lost block to that new file.  Because an\nin-flight topic like this one needs to be merged over and over until\nit gets merged to 'master' I'd prepare an evil merge-fix to be\nsquashed into the result of an auto-merge to help this process for\nthe interim maintainer, but this topic is placing more burden than\nit otherwise would to the entire process.\n\nIncidentally, that was why I originally asked you if you want to be\nan interim maintainer for this cycle.  Whoever is doing a large code\nmovement with a large patch series must be the one who would know\nthe best how its interaction with other topics is best managed.\n\nI wonder if refs.c -> refs/refs.c rename is a good idea.  I do agree\nthat refs/ subdirectory that collects the backend implementation\ndetails is a very sensible thing to do, but if the public and\ngeneric API were left in refs.c, this particular conflict might have\nbeen less severe and easier to handle.  Whatever.\n\nFor those who are listening in from sideline, in case when they need\nto deal with a similar situation \"the code our side changed gets\nmoved to elsewhere by a side branch\", here is what I did:\n\n * let \"git merge --conflict=diff3\" attempt and fail.\n\n * a conflicted file will have something like this:\n\n    <<<< ours\n    ... the code with changes made by our side (trunk) ...\n    |||| base\n    ... the code before our side (trunk) made the above changes ...\n    ====\n    >>>> theirs\n\n * create two new files, OURS and BASE.  Save the part in that\n   conflicted file between <<<< and |||| to OURS, and between ||||\n   and ==== to BASE.\n\n * look at \"diff -u BASE OURS\", find in the (failed) automerge\n   result where the original went (a sample of it is at the end of\n   this message), and apply that change manually.\n\nThe above is only to resolve this conflict *once*.\n\nAutomating future merges of this branch into a slightly updated\ncodebase needs help from rerere and also merge-fix/ machinery (this\nis not in core-git proper, but the tool is in the 'todo' branch and\nits use is described in howto/maintain-git.txt).\n\nEssentially the procedure were:\n\n * \"git checkout pu^0\"\n\n * let \"git merge --conflict=diff3\" attempt and fail.\n\n * accept removal of the conflicted block in refs/files-backend.c in\n   the editor, do \"git rerere\" to record it.  commit the result.\n\n * apply the above diff between BASE and OURS, commit the result.\n\n * git update-ref refs/merge-fix/dt/refs-backend-pre-vtable HEAD\n\nWith this, the Reintegrate script (on 'todo', checked out in \"Meta/\"\nsubdirectory) will be able to reproduce the evil merge, e.g.\n\n $ git checkout pu\n $ echo dt/refs-backend-pre-vtable | Meta/Reintegrate\n\nwould first let \"git rerere\" replay the removal of conflicted block\nin refs/files-backend.c and then amend the result by squashing the\nchange in merge-fix/dt/refs-backend-pre-vtable.\n\n\n--- V_BASE\t2015-11-06 14:51:10.150197900 -0800\n+++ V_OURS\t2015-11-06 14:51:05.638059250 -0800\n@@ -117,7 +117,7 @@\n \treturn 0;\n }\n \n-int ref_is_hidden(const char *refname)\n+int ref_is_hidden(const char *refname, const char *refname_full)\n {\n \tint i;\n \n@@ -125,6 +125,7 @@\n \t\treturn 0;\n \tfor (i = hide_refs->nr - 1; i >= 0; i--) {\n \t\tconst char *match = hide_refs->items[i].string;\n+\t\tconst char *subject;\n \t\tint neg = 0;\n \t\tint len;\n \n@@ -133,10 +134,18 @@\n \t\t\tmatch++;\n \t\t}\n \n-\t\tif (!starts_with(refname, match))\n+\t\tif (*match == '^') {\n+\t\t\tsubject = refname_full;\n+\t\t\tmatch++;\n+\t\t} else {\n+\t\t\tsubject = refname;\n+\t\t}\n+\n+\t\t/* refname can be NULL when namespaces are used. */\n+\t\tif (!subject || !starts_with(subject, match))\n \t\t\tcontinue;\n \t\tlen = strlen(match);\n-\t\tif (!refname[len] || refname[len] == '/')\n+\t\tif (!subject[len] || subject[len] == '/')\n \t\t\treturn !neg;\n \t}\n \treturn 0;\n"},{"id":"273059","messageId":"563ED7A0.7040007@alum.mit.edu","threadId":"40663","inReplyTo":"xmqqd1vm3e59.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v6 25/25] refs: break out ref conflict checks","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-08T05:03:28Z","receivedAt":"2015-11-08T05:03:28Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 11/07/2015 12:24 AM, Junio C Hamano wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n>> Michael Haggerty <mhagger@alum.mit.edu> writes:\n>>\n>>> [...] And then, if you are also OK with the\n>>> new subdirectory introduced in this patch series, David and I seem to be\n>>> in agreement that it is ready to go. It would be great if this patch\n>>> series could be merged in a timely manner, as it will conflict with\n>>> nearly any other changes that people might want to undertake in the refs\n>>> code.\n>>\n>> Thanks for working well together.  Let me see what I can do today...\n> \n> What I'll push out later today merges this to the tip of 'pu'.\n> The resolution is the same for 'jch' or 'next' (I checked).\n> \n> I have to say that the merge of this topioc is not pretty.  [...]\n\nI hate to cause the maintainer extra work. I guess I was making two\nnaive assumptions:\n\n* If we make the code-movement series simple and \"obviously correct\"\n  enough, then it could be merged pretty much straight through to\n  master.\n\n* If one or two topics conflict with the code movement, they could\n  be one-time rebased on top of the new master (I would be willing\n  to do this work).\n\nMaybe neither of these assumptions is valid. And maybe the correctness\nof our series in its current form isn't quite obvious enough.\n\nDavid and I will be the ones who benefit most from having this resolved\nquickly, because there is lots more work that has to be done after the\ncode movement and it is kindof hard to continue that work while this\ntopic is up in the air.\n\nI can see a few ways that we could make our series even more\nstraightforward:\n\n1. Leave refs.c in its original location (as suggested by Junio).\n   Optionally, it could be moved at a later date when this area is\n   quiescent.\n\n2. Move content selectively from refs.c to refs/files-backend.c rather\n   than moving the whole file there and then moving content selectively\n   back to refs/refs.c.\n\n3. Separate *all* of the non-obvious changes into a preparatory\n   patch series, to be followed by a separate patch series that *only*\n   moves code.\n\nThe first idea would be a couple of hours of work (including adjusting\ncomments and commit messages). The second and third ideas would probably\nbest be done in combination, and might take a day or two of work because\nthey involve reordering patches.\n\nLet us know what you think.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"273061","messageId":"563EE397.4080608@alum.mit.edu","threadId":"40663","inReplyTo":"563ED7A0.7040007@alum.mit.edu","subject":"Re: [PATCH v6 25/25] refs: break out ref conflict checks","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2015-11-08T05:54:31Z","receivedAt":"2015-11-08T05:54:31Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 11/08/2015 06:03 AM, Michael Haggerty wrote:\n> [...]\n> I can see a few ways that we could make our series even more\n> straightforward:\n> \n> 1. Leave refs.c in its original location (as suggested by Junio).\n>    Optionally, it could be moved at a later date when this area is\n>    quiescent.\n> [...]\n\nI just tried this (it was less work than expected). It doesn't make the\nmerge conflict with lf/ref-is-hidden-namespace go away because the\nfunctions in the new refs.c are ordered differently than in the old\nrefs.c. But it does turn it into a simple rerere-able conflict.\n\nI'll check how much work it would be to make the order of functions in\nthe new refs.c match that in the old one...\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"273069","messageId":"xmqqziyo1hb8.fsf@gitster.mtv.corp.google.com","threadId":"40663","inReplyTo":"563ED7A0.7040007@alum.mit.edu","subject":"Re: [PATCH v6 25/25] refs: break out ref conflict checks","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-11-08T18:23:23Z","receivedAt":"2015-11-08T18:23:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> I hate to cause the maintainer extra work. I guess I was making two\n> naive assumptions:\n>\n> * If we make the code-movement series simple and \"obviously correct\"\n>   enough, then it could be merged pretty much straight through to\n>   master.\n>\n> * If one or two topics conflict with the code movement, they could\n>   be one-time rebased on top of the new master (I would be willing\n>   to do this work).\n>\n> Maybe neither of these assumptions is valid.\n\nIt is sometimes necessary to declare \"This is important, and it is\nsolid enough. Let's fast-track it.  Other people must work on top of\nthis.\" and make a project-wide decision to do so.  It was just that\nwas not doable within the time I had before I had to hand the tree\noff.\n\nYou can still work with the other people involved (Lukas as the\nref-is-hidden topic contributor and Peff as the interim maintainer)\nto make it happen, and I wouldn't be upset.\n\n> I can see a few ways that we could make our series even more\n> straightforward:\n>\n> 1. Leave refs.c in its original location (as suggested by Junio).\n>    Optionally, it could be moved at a later date when this area is\n>    quiescent.\n>\n> 2. Move content selectively from refs.c to refs/files-backend.c rather\n>    than moving the whole file there and then moving content selectively\n>    back to refs/refs.c.\n>\n> 3. Separate *all* of the non-obvious changes into a preparatory\n>    patch series, to be followed by a separate patch series that *only*\n>    moves code.\n\n4. Move everything in the series as-is, *BUT* in each patch where\nthe series moved things to refs/refs.c from refs/files-backend.c,\nmove that back to refs.c instead.  No refs/refs.c anywhere in the\nhistory or in the endgame.\n\nI think having refs.h and refs.c at the toplevel for the public\ninterface, with refs/ hierarchy holding backend specifics, would be\na good organization for the endgame regardless of the conflicts with\nin-flight topics, and 4. achieves that.  Perhaps you meant the same\nthing as your 1.\n\nAs to the reordering of functions and structure defs, I am\nreasonably sure that the order in the final refs/refs.c in your\nseries would be better thought-out than in the original refs.c, so\nthe \"reorder stuff in refs.c\" can be the first step before\neverything is moved to refs/files-backend.c, perhaps?\n\nThanks.\n"}]}