{"thread":{"id":"31911","subject":"[PATCH] Move try_merge_command and checkout_fast_forward to libgit.a","startedAt":"2012-10-23T02:24:51Z","lastAt":"2012-10-29T07:43:52Z","messageCount":13,"participants":["Nguyễn Thái Ngọc Duy","Jeff King","Nguyen Thai Ngoc Duy"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"201717","messageId":"1350959091-30030-1-git-send-email-pclouds@gmail.com","threadId":"31911","inReplyTo":null,"subject":"[PATCH] Move try_merge_command and checkout_fast_forward to libgit.a","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-10-23T02:24:51Z","receivedAt":"2012-10-23T02:24:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"These functions are called in sequencer.c, which is part of\nlibgit.a. This makes libgit.a potentially require builtin/merge.c for\nexternal git commands.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n I made some unrelated changes in sequencer.c and this problem shown\n up. merge-recursive.c is probably not the best place for these\n functions. I just don't want to create merge.c for them.\n\n builtin/merge.c   | 106 +----------------------------------------------------\n cache.h           |   3 --\n merge-recursive.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n merge-recursive.h |   4 ++\n sequencer.c       |   2 +-\n 5 files changed, 115 insertions(+), 108 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 0ec8f0d..a96e8ea 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -628,59 +628,6 @@ static void write_tree_trivial(unsigned char *sha1)\n \t\tdie(_(\"git write-tree failed to write a tree\"));\n }\n \n-static const char *merge_argument(struct commit *commit)\n-{\n-\tif (commit)\n-\t\treturn sha1_to_hex(commit->object.sha1);\n-\telse\n-\t\treturn EMPTY_TREE_SHA1_HEX;\n-}\n-\n-int try_merge_command(const char *strategy, size_t xopts_nr,\n-\t\t      const char **xopts, struct commit_list *common,\n-\t\t      const char *head_arg, struct commit_list *remotes)\n-{\n-\tconst char **args;\n-\tint i = 0, x = 0, ret;\n-\tstruct commit_list *j;\n-\tstruct strbuf buf = STRBUF_INIT;\n-\n-\targs = xmalloc((4 + xopts_nr + commit_list_count(common) +\n-\t\t\tcommit_list_count(remotes)) * sizeof(char *));\n-\tstrbuf_addf(&buf, \"merge-%s\", strategy);\n-\targs[i++] = buf.buf;\n-\tfor (x = 0; x < xopts_nr; x++) {\n-\t\tchar *s = xmalloc(strlen(xopts[x])+2+1);\n-\t\tstrcpy(s, \"--\");\n-\t\tstrcpy(s+2, xopts[x]);\n-\t\targs[i++] = s;\n-\t}\n-\tfor (j = common; j; j = j->next)\n-\t\targs[i++] = xstrdup(merge_argument(j->item));\n-\targs[i++] = \"--\";\n-\targs[i++] = head_arg;\n-\tfor (j = remotes; j; j = j->next)\n-\t\targs[i++] = xstrdup(merge_argument(j->item));\n-\targs[i] = NULL;\n-\tret = run_command_v_opt(args, RUN_GIT_CMD);\n-\tstrbuf_release(&buf);\n-\ti = 1;\n-\tfor (x = 0; x < xopts_nr; x++)\n-\t\tfree((void *)args[i++]);\n-\tfor (j = common; j; j = j->next)\n-\t\tfree((void *)args[i++]);\n-\ti += 2;\n-\tfor (j = remotes; j; j = j->next)\n-\t\tfree((void *)args[i++]);\n-\tfree(args);\n-\tdiscard_cache();\n-\tif (read_cache() < 0)\n-\t\tdie(_(\"failed to read the cache\"));\n-\tresolve_undo_clear();\n-\n-\treturn ret;\n-}\n-\n static int try_merge_strategy(const char *strategy, struct commit_list *common,\n \t\t\t      struct commit_list *remoteheads,\n \t\t\t      struct commit *head, const char *head_arg)\n@@ -762,56 +709,6 @@ static int count_unmerged_entries(void)\n \treturn ret;\n }\n \n-int checkout_fast_forward(const unsigned char *head, const unsigned char *remote)\n-{\n-\tstruct tree *trees[MAX_UNPACK_TREES];\n-\tstruct unpack_trees_options opts;\n-\tstruct tree_desc t[MAX_UNPACK_TREES];\n-\tint i, fd, nr_trees = 0;\n-\tstruct dir_struct dir;\n-\tstruct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));\n-\n-\trefresh_cache(REFRESH_QUIET);\n-\n-\tfd = hold_locked_index(lock_file, 1);\n-\n-\tmemset(&trees, 0, sizeof(trees));\n-\tmemset(&opts, 0, sizeof(opts));\n-\tmemset(&t, 0, sizeof(t));\n-\tif (overwrite_ignore) {\n-\t\tmemset(&dir, 0, sizeof(dir));\n-\t\tdir.flags |= DIR_SHOW_IGNORED;\n-\t\tsetup_standard_excludes(&dir);\n-\t\topts.dir = &dir;\n-\t}\n-\n-\topts.head_idx = 1;\n-\topts.src_index = &the_index;\n-\topts.dst_index = &the_index;\n-\topts.update = 1;\n-\topts.verbose_update = 1;\n-\topts.merge = 1;\n-\topts.fn = twoway_merge;\n-\tsetup_unpack_trees_porcelain(&opts, \"merge\");\n-\n-\ttrees[nr_trees] = parse_tree_indirect(head);\n-\tif (!trees[nr_trees++])\n-\t\treturn -1;\n-\ttrees[nr_trees] = parse_tree_indirect(remote);\n-\tif (!trees[nr_trees++])\n-\t\treturn -1;\n-\tfor (i = 0; i < nr_trees; i++) {\n-\t\tparse_tree(trees[i]);\n-\t\tinit_tree_desc(t+i, trees[i]->buffer, trees[i]->size);\n-\t}\n-\tif (unpack_trees(nr_trees, t, &opts))\n-\t\treturn -1;\n-\tif (write_cache(fd, active_cache, active_nr) ||\n-\t\tcommit_locked_index(lock_file))\n-\t\tdie(_(\"unable to write new index file\"));\n-\treturn 0;\n-}\n-\n static void split_merge_strategies(const char *string, struct strategy **list,\n \t\t\t\t   int *nr, int *alloc)\n {\n@@ -1424,7 +1321,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t}\n \n \t\tif (checkout_fast_forward(head_commit->object.sha1,\n-\t\t\t\t\t  commit->object.sha1)) {\n+\t\t\t\t\t  commit->object.sha1,\n+\t\t\t\t\t  overwrite_ignore)) {\n \t\t\tret = 1;\n \t\t\tgoto done;\n \t\t}\ndiff --git a/cache.h b/cache.h\nindex a58df84..415c777 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1265,9 +1265,6 @@ struct startup_info {\n };\n extern struct startup_info *startup_info;\n \n-/* builtin/merge.c */\n-int checkout_fast_forward(const unsigned char *from, const unsigned char *to);\n-\n int sane_execvp(const char *file, char *const argv[]);\n \n #endif /* CACHE_H */\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex d882060..4d2422a 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -21,6 +21,9 @@\n #include \"merge-recursive.h\"\n #include \"dir.h\"\n #include \"submodule.h\"\n+#include \"run-command.h\"\n+#include \"resolve-undo.h\"\n+#include \"unpack-trees.h\"\n \n static struct tree *shift_tree_object(struct tree *one, struct tree *two,\n \t\t\t\t      const char *subtree_shift)\n@@ -2087,3 +2090,108 @@ int parse_merge_opt(struct merge_options *o, const char *s)\n \t\treturn -1;\n \treturn 0;\n }\n+\n+static const char *merge_argument(struct commit *commit)\n+{\n+\tif (commit)\n+\t\treturn sha1_to_hex(commit->object.sha1);\n+\telse\n+\t\treturn EMPTY_TREE_SHA1_HEX;\n+}\n+\n+int try_merge_command(const char *strategy, size_t xopts_nr,\n+\t\t      const char **xopts, struct commit_list *common,\n+\t\t      const char *head_arg, struct commit_list *remotes)\n+{\n+\tconst char **args;\n+\tint i = 0, x = 0, ret;\n+\tstruct commit_list *j;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\n+\targs = xmalloc((4 + xopts_nr + commit_list_count(common) +\n+\t\t\tcommit_list_count(remotes)) * sizeof(char *));\n+\tstrbuf_addf(&buf, \"merge-%s\", strategy);\n+\targs[i++] = buf.buf;\n+\tfor (x = 0; x < xopts_nr; x++) {\n+\t\tchar *s = xmalloc(strlen(xopts[x])+2+1);\n+\t\tstrcpy(s, \"--\");\n+\t\tstrcpy(s+2, xopts[x]);\n+\t\targs[i++] = s;\n+\t}\n+\tfor (j = common; j; j = j->next)\n+\t\targs[i++] = xstrdup(merge_argument(j->item));\n+\targs[i++] = \"--\";\n+\targs[i++] = head_arg;\n+\tfor (j = remotes; j; j = j->next)\n+\t\targs[i++] = xstrdup(merge_argument(j->item));\n+\targs[i] = NULL;\n+\tret = run_command_v_opt(args, RUN_GIT_CMD);\n+\tstrbuf_release(&buf);\n+\ti = 1;\n+\tfor (x = 0; x < xopts_nr; x++)\n+\t\tfree((void *)args[i++]);\n+\tfor (j = common; j; j = j->next)\n+\t\tfree((void *)args[i++]);\n+\ti += 2;\n+\tfor (j = remotes; j; j = j->next)\n+\t\tfree((void *)args[i++]);\n+\tfree(args);\n+\tdiscard_cache();\n+\tif (read_cache() < 0)\n+\t\tdie(_(\"failed to read the cache\"));\n+\tresolve_undo_clear();\n+\n+\treturn ret;\n+}\n+\n+int checkout_fast_forward(const unsigned char *head,\n+\t\t\t  const unsigned char *remote,\n+\t\t\t  int overwrite_ignore)\n+{\n+\tstruct tree *trees[MAX_UNPACK_TREES];\n+\tstruct unpack_trees_options opts;\n+\tstruct tree_desc t[MAX_UNPACK_TREES];\n+\tint i, fd, nr_trees = 0;\n+\tstruct dir_struct dir;\n+\tstruct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));\n+\n+\trefresh_cache(REFRESH_QUIET);\n+\n+\tfd = hold_locked_index(lock_file, 1);\n+\n+\tmemset(&trees, 0, sizeof(trees));\n+\tmemset(&opts, 0, sizeof(opts));\n+\tmemset(&t, 0, sizeof(t));\n+\tif (overwrite_ignore) {\n+\t\tmemset(&dir, 0, sizeof(dir));\n+\t\tdir.flags |= DIR_SHOW_IGNORED;\n+\t\tsetup_standard_excludes(&dir);\n+\t\topts.dir = &dir;\n+\t}\n+\n+\topts.head_idx = 1;\n+\topts.src_index = &the_index;\n+\topts.dst_index = &the_index;\n+\topts.update = 1;\n+\topts.verbose_update = 1;\n+\topts.merge = 1;\n+\topts.fn = twoway_merge;\n+\tsetup_unpack_trees_porcelain(&opts, \"merge\");\n+\n+\ttrees[nr_trees] = parse_tree_indirect(head);\n+\tif (!trees[nr_trees++])\n+\t\treturn -1;\n+\ttrees[nr_trees] = parse_tree_indirect(remote);\n+\tif (!trees[nr_trees++])\n+\t\treturn -1;\n+\tfor (i = 0; i < nr_trees; i++) {\n+\t\tparse_tree(trees[i]);\n+\t\tinit_tree_desc(t+i, trees[i]->buffer, trees[i]->size);\n+\t}\n+\tif (unpack_trees(nr_trees, t, &opts))\n+\t\treturn -1;\n+\tif (write_cache(fd, active_cache, active_nr) ||\n+\t\tcommit_locked_index(lock_file))\n+\t\tdie(_(\"unable to write new index file\"));\n+\treturn 0;\n+}\ndiff --git a/merge-recursive.h b/merge-recursive.h\nindex 58f3435..e01a9c0 100644\n--- a/merge-recursive.h\n+++ b/merge-recursive.h\n@@ -64,4 +64,8 @@ int try_merge_command(const char *strategy, size_t xopts_nr,\n \t\tconst char **xopts, struct commit_list *common,\n \t\tconst char *head_arg, struct commit_list *remotes);\n \n+int checkout_fast_forward(const unsigned char *from,\n+\t\t\t  const unsigned char *to,\n+\t\t\t  int overwrite_ignore);\n+\n #endif\ndiff --git a/sequencer.c b/sequencer.c\nindex e3723d2..be0cb8b 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -191,7 +191,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from)\n \tstruct ref_lock *ref_lock;\n \n \tread_cache();\n-\tif (checkout_fast_forward(from, to))\n+\tif (checkout_fast_forward(from, to, 1))\n \t\texit(1); /* the callee should have complained already */\n \tref_lock = lock_any_ref_for_update(\"HEAD\", from, 0);\n \treturn write_ref_sha1(ref_lock, to, \"cherry-pick\");\n-- \n1.8.0.rc3.18.g0d9b108\n"},{"id":"201879","messageId":"20121025094500.GJ8390@sigill.intra.peff.net","threadId":"31911","inReplyTo":"1350959091-30030-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH] Move try_merge_command and checkout_fast_forward to libgit.a","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-10-25T09:45:01Z","receivedAt":"2012-10-25T09:45:01Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Oct 23, 2012 at 09:24:51AM +0700, Nguyen Thai Ngoc Duy wrote:\n\n> These functions are called in sequencer.c, which is part of\n> libgit.a. This makes libgit.a potentially require builtin/merge.c for\n> external git commands.\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  I made some unrelated changes in sequencer.c and this problem shown\n>  up. merge-recursive.c is probably not the best place for these\n>  functions. I just don't want to create merge.c for them.\n\nI'm fine with this conceptually, but merge-recursive really is the wrong\nplace. I'd much rather see a new merge.c to collect merge-related helper\nfunctions that are not strategy-specific.\n\n-Peff\n"},{"id":"201898","messageId":"CACsJy8D1_c9NP_nwvp6uJyKikG+_jqnm1hVEs_t_wnsYTLZ4Yg@mail.gmail.com","threadId":"31911","inReplyTo":"20121025094500.GJ8390@sigill.intra.peff.net","subject":"Re: [PATCH] Move try_merge_command and checkout_fast_forward to libgit.a","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-10-25T12:50:26Z","receivedAt":"2012-10-25T12:50:26Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Oct 25, 2012 at 4:45 PM, Jeff King <peff@peff.net> wrote:\n> On Tue, Oct 23, 2012 at 09:24:51AM +0700, Nguyen Thai Ngoc Duy wrote:\n>\n>> These functions are called in sequencer.c, which is part of\n>> libgit.a. This makes libgit.a potentially require builtin/merge.c for\n>> external git commands.\n>>\n>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n>> ---\n>>  I made some unrelated changes in sequencer.c and this problem shown\n>>  up. merge-recursive.c is probably not the best place for these\n>>  functions. I just don't want to create merge.c for them.\n>\n> I'm fine with this conceptually, but merge-recursive really is the wrong\n> place. I'd much rather see a new merge.c to collect merge-related helper\n> functions that are not strategy-specific.\n\nOK. I checked around for similar issues and found these used by\nlibgit.a but stay in builtin/ instead:\n\nestimate_bisect_steps: bisect.c and builtin/rev-list.c\nprint_commit_list: bisect.c and builtin/rev-list.c\n\n -> move them to bisect.c? another candidate is revision.c.\n\nfetch_pack: transport.c and builtin/fetch-pack.c\nsend_pack: transport.c and builtin/send-pack.c\n\n -> move them to transport.c? or new files fetch-pack.c and\nsend-pack.c? I haven't check how many functions they may pull\ntogether.\n\nsetup_diff_pager: diff-no-index.c and builtin/diff.c\n\n -> to diff-lib.c?\n-- \nDuy\n"},{"id":"201936","messageId":"20121026120253.GA1455@sigill.intra.peff.net","threadId":"31911","inReplyTo":"CACsJy8D1_c9NP_nwvp6uJyKikG+_jqnm1hVEs_t_wnsYTLZ4Yg@mail.gmail.com","subject":"Re: [PATCH] Move try_merge_command and checkout_fast_forward to libgit.a","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-10-26T12:02:54Z","receivedAt":"2012-10-26T12:02:54Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Oct 25, 2012 at 07:50:26PM +0700, Nguyen Thai Ngoc Duy wrote:\n\n> On Thu, Oct 25, 2012 at 4:45 PM, Jeff King <peff@peff.net> wrote:\n> > On Tue, Oct 23, 2012 at 09:24:51AM +0700, Nguyen Thai Ngoc Duy wrote:\n> >\n> >> These functions are called in sequencer.c, which is part of\n> >> libgit.a. This makes libgit.a potentially require builtin/merge.c for\n> >> external git commands.\n> >>\n> >> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> >> ---\n> >>  I made some unrelated changes in sequencer.c and this problem shown\n> >>  up. merge-recursive.c is probably not the best place for these\n> >>  functions. I just don't want to create merge.c for them.\n> >\n> > I'm fine with this conceptually, but merge-recursive really is the wrong\n> > place. I'd much rather see a new merge.c to collect merge-related helper\n> > functions that are not strategy-specific.\n> \n> OK. I checked around for similar issues and found these used by\n> libgit.a but stay in builtin/ instead:\n\nYeah, we have traditionally been kind of lazy about the distinction,\nbecause it doesn't really matter for our build system (i.e., libgit.a is\nnot _really_ a library, but just a convenience in the build process). So\none option is just not caring about these. I'm also fine with fixing.\n\n> estimate_bisect_steps: bisect.c and builtin/rev-list.c\n> print_commit_list: bisect.c and builtin/rev-list.c\n> \n>  -> move them to bisect.c? another candidate is revision.c.\n\nI'd probably say bisect.c for the first, and commit.c for the latter\n(that is where commit_list functions are defined, and it is really about\nthat).\n\n> fetch_pack: transport.c and builtin/fetch-pack.c\n> send_pack: transport.c and builtin/send-pack.c\n> \n>  -> move them to transport.c? or new files fetch-pack.c and\n> send-pack.c? I haven't check how many functions they may pull\n> together.\n\nI think I'd rather have fetch-pack.c and send-pack.c than putting them\ninto transport.c (which is getting kind of bloated already).\n\n> setup_diff_pager: diff-no-index.c and builtin/diff.c\n> \n>  -> to diff-lib.c?\n\nI'm not sure (to be honest, I am not even sure of the intended\ndifference between diff.c and diff-lib.c). That function is really not\nfor general diffing, but for diff-like commands. Probably it would be OK\nin diff.c.\n\n-Peff\n"},{"id":"201957","messageId":"1351266835-22610-1-git-send-email-pclouds@gmail.com","threadId":"31911","inReplyTo":"20121026120253.GA1455@sigill.intra.peff.net","subject":"[PATCH 0/7] Move code from builtin to libgit.a","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-10-26T15:53:48Z","receivedAt":"2012-10-26T15:53:48Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Oct 26, 2012 at 7:02 PM, Jeff King <peff@peff.net> wrote:\n>> OK. I checked around for similar issues and found these used by\n>> libgit.a but stay in builtin/ instead:\n>\n> Yeah, we have traditionally been kind of lazy about the distinction,\n> because it doesn't really matter for our build system (i.e., libgit.a is\n> not _really_ a library, but just a convenience in the build process). So\n> one option is just not caring about these.\n\nYeah. We can fix it up when we encounter new undefined reference\nerrors (e.g. a new test program that links to libgit.a). Anyway it\ndoes not look too difficult to do. Take it or drop it. Your call.\n\n> I'm also fine with fixing.\n>\n>> estimate_bisect_steps: bisect.c and builtin/rev-list.c\n>> print_commit_list: bisect.c and builtin/rev-list.c\n>>\n>>  -> move them to bisect.c? another candidate is revision.c.\n>\n> I'd probably say bisect.c for the first, and commit.c for the latter\n> (that is where commit_list functions are defined, and it is really about\n> that).\n\nMakes sense.\n\n>> setup_diff_pager: diff-no-index.c and builtin/diff.c\n>>\n>>  -> to diff-lib.c?\n>\n> I'm not sure (to be honest, I am not even sure of the intended\n> difference between diff.c and diff-lib.c). That function is really not\n> for general diffing, but for diff-like commands. Probably it would be OK\n> in diff.c.\n\nDitto. check_pager_config() is also moved from git.c to pager.c.\n\n>> fetch_pack: transport.c and builtin/fetch-pack.c\n>> send_pack: transport.c and builtin/send-pack.c\n>>\n>>  -> move them to transport.c? or new files fetch-pack.c and\n>> send-pack.c? I haven't check how many functions they may pull\n>> together.\n>\n> I think I'd rather have fetch-pack.c and send-pack.c than putting them\n> into transport.c (which is getting kind of bloated already).\n\nThese two are big code moves, basically all {fetch,send}-pack code.\nWhile I think this is good cleanup (I get surprise every time I look\nat transport.c and it leads to buitin/fetch-pack.c), this is probably\nnot a good idea if we have on flight topics, which may cause lots of\nconflicts for you and Junio. Fortunately we don't at the moment.\n\nNguyễn Thái Ngọc Duy (7):\n  Move try_merge_command and checkout_fast_forward to libgit.a\n  Move estimate_bisect_steps to libgit.a\n  Move print_commit_list to libgit.a\n  Move setup_diff_pager to libgit.a\n  send-pack: move core code to libgit.a\n  fetch-pack: remove global (static) configuration variable \"args\"\n  fetch-pack: move core code to libgit.a\n\n Makefile             |   3 +\n bisect.c             |  38 ++\n bisect.h             |   4 -\n builtin.h            |   4 -\n builtin/diff.c       |  16 -\n builtin/fetch-pack.c | 951 +--------------------------------------------------\n builtin/merge.c      | 106 +-----\n builtin/rev-list.c   |  49 ---\n builtin/send-pack.c  | 333 ------------------\n cache.h              |  12 +-\n commit.c             |  10 +\n commit.h             |   4 +\n diff.c               |  16 +\n diff.h               |   1 +\n fetch-pack.c         | 951 +++++++++++++++++++++++++++++++++++++++++++++++++++\n git.c                |  33 --\n merge-recursive.h    |   5 -\n merge.c              | 112 ++++++\n pager.c              |  34 ++\n send-pack.c          | 344 +++++++++++++++++++\n sequencer.c          |   2 +-\n transport.h          |   5 +\n 22 files changed, 1535 insertions(+), 1498 deletions(-)\n create mode 100644 fetch-pack.c\n create mode 100644 merge.c\n create mode 100644 send-pack.c\n\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"201958","messageId":"1351266835-22610-2-git-send-email-pclouds@gmail.com","threadId":"31911","inReplyTo":"1351266835-22610-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 1/7] Move try_merge_command and checkout_fast_forward to libgit.a","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-10-26T15:53:49Z","receivedAt":"2012-10-26T15:53:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"These functions are called in sequencer.c, which is part of\nlibgit.a. This makes libgit.a potentially require builtin/merge.c for\nexternal git commands.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Makefile          |   1 +\n builtin/merge.c   | 106 +--------------------------------------------------\n cache.h           |  11 +++++-\n merge-recursive.h |   5 ---\n merge.c           | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n sequencer.c       |   2 +-\n 6 files changed, 125 insertions(+), 112 deletions(-)\n create mode 100644 merge.c\n\ndiff --git a/Makefile b/Makefile\nindex f69979e..2c333dc 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -762,6 +762,7 @@ LIB_OBJS += lockfile.o\n LIB_OBJS += log-tree.o\n LIB_OBJS += mailmap.o\n LIB_OBJS += match-trees.o\n+LIB_OBJS += merge.o\n LIB_OBJS += merge-file.o\n LIB_OBJS += merge-recursive.o\n LIB_OBJS += mergesort.o\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 0ec8f0d..a96e8ea 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -628,59 +628,6 @@ static void write_tree_trivial(unsigned char *sha1)\n \t\tdie(_(\"git write-tree failed to write a tree\"));\n }\n \n-static const char *merge_argument(struct commit *commit)\n-{\n-\tif (commit)\n-\t\treturn sha1_to_hex(commit->object.sha1);\n-\telse\n-\t\treturn EMPTY_TREE_SHA1_HEX;\n-}\n-\n-int try_merge_command(const char *strategy, size_t xopts_nr,\n-\t\t      const char **xopts, struct commit_list *common,\n-\t\t      const char *head_arg, struct commit_list *remotes)\n-{\n-\tconst char **args;\n-\tint i = 0, x = 0, ret;\n-\tstruct commit_list *j;\n-\tstruct strbuf buf = STRBUF_INIT;\n-\n-\targs = xmalloc((4 + xopts_nr + commit_list_count(common) +\n-\t\t\tcommit_list_count(remotes)) * sizeof(char *));\n-\tstrbuf_addf(&buf, \"merge-%s\", strategy);\n-\targs[i++] = buf.buf;\n-\tfor (x = 0; x < xopts_nr; x++) {\n-\t\tchar *s = xmalloc(strlen(xopts[x])+2+1);\n-\t\tstrcpy(s, \"--\");\n-\t\tstrcpy(s+2, xopts[x]);\n-\t\targs[i++] = s;\n-\t}\n-\tfor (j = common; j; j = j->next)\n-\t\targs[i++] = xstrdup(merge_argument(j->item));\n-\targs[i++] = \"--\";\n-\targs[i++] = head_arg;\n-\tfor (j = remotes; j; j = j->next)\n-\t\targs[i++] = xstrdup(merge_argument(j->item));\n-\targs[i] = NULL;\n-\tret = run_command_v_opt(args, RUN_GIT_CMD);\n-\tstrbuf_release(&buf);\n-\ti = 1;\n-\tfor (x = 0; x < xopts_nr; x++)\n-\t\tfree((void *)args[i++]);\n-\tfor (j = common; j; j = j->next)\n-\t\tfree((void *)args[i++]);\n-\ti += 2;\n-\tfor (j = remotes; j; j = j->next)\n-\t\tfree((void *)args[i++]);\n-\tfree(args);\n-\tdiscard_cache();\n-\tif (read_cache() < 0)\n-\t\tdie(_(\"failed to read the cache\"));\n-\tresolve_undo_clear();\n-\n-\treturn ret;\n-}\n-\n static int try_merge_strategy(const char *strategy, struct commit_list *common,\n \t\t\t      struct commit_list *remoteheads,\n \t\t\t      struct commit *head, const char *head_arg)\n@@ -762,56 +709,6 @@ static int count_unmerged_entries(void)\n \treturn ret;\n }\n \n-int checkout_fast_forward(const unsigned char *head, const unsigned char *remote)\n-{\n-\tstruct tree *trees[MAX_UNPACK_TREES];\n-\tstruct unpack_trees_options opts;\n-\tstruct tree_desc t[MAX_UNPACK_TREES];\n-\tint i, fd, nr_trees = 0;\n-\tstruct dir_struct dir;\n-\tstruct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));\n-\n-\trefresh_cache(REFRESH_QUIET);\n-\n-\tfd = hold_locked_index(lock_file, 1);\n-\n-\tmemset(&trees, 0, sizeof(trees));\n-\tmemset(&opts, 0, sizeof(opts));\n-\tmemset(&t, 0, sizeof(t));\n-\tif (overwrite_ignore) {\n-\t\tmemset(&dir, 0, sizeof(dir));\n-\t\tdir.flags |= DIR_SHOW_IGNORED;\n-\t\tsetup_standard_excludes(&dir);\n-\t\topts.dir = &dir;\n-\t}\n-\n-\topts.head_idx = 1;\n-\topts.src_index = &the_index;\n-\topts.dst_index = &the_index;\n-\topts.update = 1;\n-\topts.verbose_update = 1;\n-\topts.merge = 1;\n-\topts.fn = twoway_merge;\n-\tsetup_unpack_trees_porcelain(&opts, \"merge\");\n-\n-\ttrees[nr_trees] = parse_tree_indirect(head);\n-\tif (!trees[nr_trees++])\n-\t\treturn -1;\n-\ttrees[nr_trees] = parse_tree_indirect(remote);\n-\tif (!trees[nr_trees++])\n-\t\treturn -1;\n-\tfor (i = 0; i < nr_trees; i++) {\n-\t\tparse_tree(trees[i]);\n-\t\tinit_tree_desc(t+i, trees[i]->buffer, trees[i]->size);\n-\t}\n-\tif (unpack_trees(nr_trees, t, &opts))\n-\t\treturn -1;\n-\tif (write_cache(fd, active_cache, active_nr) ||\n-\t\tcommit_locked_index(lock_file))\n-\t\tdie(_(\"unable to write new index file\"));\n-\treturn 0;\n-}\n-\n static void split_merge_strategies(const char *string, struct strategy **list,\n \t\t\t\t   int *nr, int *alloc)\n {\n@@ -1424,7 +1321,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t}\n \n \t\tif (checkout_fast_forward(head_commit->object.sha1,\n-\t\t\t\t\t  commit->object.sha1)) {\n+\t\t\t\t\t  commit->object.sha1,\n+\t\t\t\t\t  overwrite_ignore)) {\n \t\t\tret = 1;\n \t\t\tgoto done;\n \t\t}\ndiff --git a/cache.h b/cache.h\nindex a58df84..2dc4dec 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1265,8 +1265,15 @@ struct startup_info {\n };\n extern struct startup_info *startup_info;\n \n-/* builtin/merge.c */\n-int checkout_fast_forward(const unsigned char *from, const unsigned char *to);\n+/* merge.c */\n+struct commit_list;\n+int try_merge_command(const char *strategy, size_t xopts_nr,\n+\t\tconst char **xopts, struct commit_list *common,\n+\t\tconst char *head_arg, struct commit_list *remotes);\n+int checkout_fast_forward(const unsigned char *from,\n+\t\t\t  const unsigned char *to,\n+\t\t\t  int overwrite_ignore);\n+\n \n int sane_execvp(const char *file, char *const argv[]);\n \ndiff --git a/merge-recursive.h b/merge-recursive.h\nindex 58f3435..9e090a3 100644\n--- a/merge-recursive.h\n+++ b/merge-recursive.h\n@@ -59,9 +59,4 @@ struct tree *write_tree_from_memory(struct merge_options *o);\n \n int parse_merge_opt(struct merge_options *out, const char *s);\n \n-/* builtin/merge.c */\n-int try_merge_command(const char *strategy, size_t xopts_nr,\n-\t\tconst char **xopts, struct commit_list *common,\n-\t\tconst char *head_arg, struct commit_list *remotes);\n-\n #endif\ndiff --git a/merge.c b/merge.c\nnew file mode 100644\nindex 0000000..70f1000\n--- /dev/null\n+++ b/merge.c\n@@ -0,0 +1,112 @@\n+#include \"cache.h\"\n+#include \"commit.h\"\n+#include \"run-command.h\"\n+#include \"resolve-undo.h\"\n+#include \"tree-walk.h\"\n+#include \"unpack-trees.h\"\n+#include \"dir.h\"\n+\n+static const char *merge_argument(struct commit *commit)\n+{\n+\tif (commit)\n+\t\treturn sha1_to_hex(commit->object.sha1);\n+\telse\n+\t\treturn EMPTY_TREE_SHA1_HEX;\n+}\n+\n+int try_merge_command(const char *strategy, size_t xopts_nr,\n+\t\t      const char **xopts, struct commit_list *common,\n+\t\t      const char *head_arg, struct commit_list *remotes)\n+{\n+\tconst char **args;\n+\tint i = 0, x = 0, ret;\n+\tstruct commit_list *j;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\n+\targs = xmalloc((4 + xopts_nr + commit_list_count(common) +\n+\t\t\tcommit_list_count(remotes)) * sizeof(char *));\n+\tstrbuf_addf(&buf, \"merge-%s\", strategy);\n+\targs[i++] = buf.buf;\n+\tfor (x = 0; x < xopts_nr; x++) {\n+\t\tchar *s = xmalloc(strlen(xopts[x])+2+1);\n+\t\tstrcpy(s, \"--\");\n+\t\tstrcpy(s+2, xopts[x]);\n+\t\targs[i++] = s;\n+\t}\n+\tfor (j = common; j; j = j->next)\n+\t\targs[i++] = xstrdup(merge_argument(j->item));\n+\targs[i++] = \"--\";\n+\targs[i++] = head_arg;\n+\tfor (j = remotes; j; j = j->next)\n+\t\targs[i++] = xstrdup(merge_argument(j->item));\n+\targs[i] = NULL;\n+\tret = run_command_v_opt(args, RUN_GIT_CMD);\n+\tstrbuf_release(&buf);\n+\ti = 1;\n+\tfor (x = 0; x < xopts_nr; x++)\n+\t\tfree((void *)args[i++]);\n+\tfor (j = common; j; j = j->next)\n+\t\tfree((void *)args[i++]);\n+\ti += 2;\n+\tfor (j = remotes; j; j = j->next)\n+\t\tfree((void *)args[i++]);\n+\tfree(args);\n+\tdiscard_cache();\n+\tif (read_cache() < 0)\n+\t\tdie(_(\"failed to read the cache\"));\n+\tresolve_undo_clear();\n+\n+\treturn ret;\n+}\n+\n+int checkout_fast_forward(const unsigned char *head,\n+\t\t\t  const unsigned char *remote,\n+\t\t\t  int overwrite_ignore)\n+{\n+\tstruct tree *trees[MAX_UNPACK_TREES];\n+\tstruct unpack_trees_options opts;\n+\tstruct tree_desc t[MAX_UNPACK_TREES];\n+\tint i, fd, nr_trees = 0;\n+\tstruct dir_struct dir;\n+\tstruct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));\n+\n+\trefresh_cache(REFRESH_QUIET);\n+\n+\tfd = hold_locked_index(lock_file, 1);\n+\n+\tmemset(&trees, 0, sizeof(trees));\n+\tmemset(&opts, 0, sizeof(opts));\n+\tmemset(&t, 0, sizeof(t));\n+\tif (overwrite_ignore) {\n+\t\tmemset(&dir, 0, sizeof(dir));\n+\t\tdir.flags |= DIR_SHOW_IGNORED;\n+\t\tsetup_standard_excludes(&dir);\n+\t\topts.dir = &dir;\n+\t}\n+\n+\topts.head_idx = 1;\n+\topts.src_index = &the_index;\n+\topts.dst_index = &the_index;\n+\topts.update = 1;\n+\topts.verbose_update = 1;\n+\topts.merge = 1;\n+\topts.fn = twoway_merge;\n+\tsetup_unpack_trees_porcelain(&opts, \"merge\");\n+\n+\ttrees[nr_trees] = parse_tree_indirect(head);\n+\tif (!trees[nr_trees++])\n+\t\treturn -1;\n+\ttrees[nr_trees] = parse_tree_indirect(remote);\n+\tif (!trees[nr_trees++])\n+\t\treturn -1;\n+\tfor (i = 0; i < nr_trees; i++) {\n+\t\tparse_tree(trees[i]);\n+\t\tinit_tree_desc(t+i, trees[i]->buffer, trees[i]->size);\n+\t}\n+\tif (unpack_trees(nr_trees, t, &opts))\n+\t\treturn -1;\n+\tif (write_cache(fd, active_cache, active_nr) ||\n+\t\tcommit_locked_index(lock_file))\n+\t\tdie(_(\"unable to write new index file\"));\n+\treturn 0;\n+}\ndiff --git a/sequencer.c b/sequencer.c\nindex e3723d2..be0cb8b 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -191,7 +191,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from)\n \tstruct ref_lock *ref_lock;\n \n \tread_cache();\n-\tif (checkout_fast_forward(from, to))\n+\tif (checkout_fast_forward(from, to, 1))\n \t\texit(1); /* the callee should have complained already */\n \tref_lock = lock_any_ref_for_update(\"HEAD\", from, 0);\n \treturn write_ref_sha1(ref_lock, to, \"cherry-pick\");\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"201959","messageId":"1351266835-22610-3-git-send-email-pclouds@gmail.com","threadId":"31911","inReplyTo":"1351266835-22610-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 2/7] Move estimate_bisect_steps to libgit.a","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-10-26T15:53:50Z","receivedAt":"2012-10-26T15:53:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This function is used by bisect.c, part of libgit.a while\nestimate_bisect_steps stays in builtin/rev-list.c. Move it to bisect.a\nso we won't have undefine reference if a standalone program that uses\nlibgit.a happens to pull it in.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n bisect.c           | 38 ++++++++++++++++++++++++++++++++++++++\n builtin/rev-list.c | 39 ---------------------------------------\n 2 files changed, 38 insertions(+), 39 deletions(-)\n\ndiff --git a/bisect.c b/bisect.c\nindex 1aad49b..bd1b7b5 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -956,3 +956,41 @@ int bisect_next_all(const char *prefix, int no_checkout)\n \treturn bisect_checkout(bisect_rev_hex, no_checkout);\n }\n \n+static inline int log2i(int n)\n+{\n+\tint log2 = 0;\n+\n+\tfor (; n > 1; n >>= 1)\n+\t\tlog2++;\n+\n+\treturn log2;\n+}\n+\n+static inline int exp2i(int n)\n+{\n+\treturn 1 << n;\n+}\n+\n+/*\n+ * Estimate the number of bisect steps left (after the current step)\n+ *\n+ * For any x between 0 included and 2^n excluded, the probability for\n+ * n - 1 steps left looks like:\n+ *\n+ * P(2^n + x) == (2^n - x) / (2^n + x)\n+ *\n+ * and P(2^n + x) < 0.5 means 2^n < 3x\n+ */\n+int estimate_bisect_steps(int all)\n+{\n+\tint n, x, e;\n+\n+\tif (all < 3)\n+\t\treturn 0;\n+\n+\tn = log2i(all);\n+\te = exp2i(n);\n+\tx = all - e;\n+\n+\treturn (e < 3 * x) ? n : n - 1;\n+}\ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex ff5a383..a0ec84e 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -201,45 +201,6 @@ static void show_edge(struct commit *commit)\n \tprintf(\"-%s\\n\", sha1_to_hex(commit->object.sha1));\n }\n \n-static inline int log2i(int n)\n-{\n-\tint log2 = 0;\n-\n-\tfor (; n > 1; n >>= 1)\n-\t\tlog2++;\n-\n-\treturn log2;\n-}\n-\n-static inline int exp2i(int n)\n-{\n-\treturn 1 << n;\n-}\n-\n-/*\n- * Estimate the number of bisect steps left (after the current step)\n- *\n- * For any x between 0 included and 2^n excluded, the probability for\n- * n - 1 steps left looks like:\n- *\n- * P(2^n + x) == (2^n - x) / (2^n + x)\n- *\n- * and P(2^n + x) < 0.5 means 2^n < 3x\n- */\n-int estimate_bisect_steps(int all)\n-{\n-\tint n, x, e;\n-\n-\tif (all < 3)\n-\t\treturn 0;\n-\n-\tn = log2i(all);\n-\te = exp2i(n);\n-\tx = all - e;\n-\n-\treturn (e < 3 * x) ? n : n - 1;\n-}\n-\n void print_commit_list(struct commit_list *list,\n \t\t       const char *format_cur,\n \t\t       const char *format_last)\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"201960","messageId":"1351266835-22610-4-git-send-email-pclouds@gmail.com","threadId":"31911","inReplyTo":"1351266835-22610-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 3/7] Move print_commit_list to libgit.a","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-10-26T15:53:51Z","receivedAt":"2012-10-26T15:53:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is used by bisect.c, part of libgit.a while it stays in\nbuiltin/rev-list.c. Move it to commit.c so that we won't get undefined\nreference if a program that uses libgit.a happens to pull it in.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n bisect.h           |  4 ----\n builtin/rev-list.c | 10 ----------\n commit.c           | 10 ++++++++++\n commit.h           |  4 ++++\n 4 files changed, 14 insertions(+), 14 deletions(-)\n\ndiff --git a/bisect.h b/bisect.h\nindex ec3c3ff..2a6c831 100644\n--- a/bisect.h\n+++ b/bisect.h\n@@ -11,10 +11,6 @@ extern struct commit_list *filter_skipped(struct commit_list *list,\n \t\t\t\t\t  int *count,\n \t\t\t\t\t  int *skipped_first);\n \n-extern void print_commit_list(struct commit_list *list,\n-\t\t\t      const char *format_cur,\n-\t\t\t      const char *format_last);\n-\n #define BISECT_SHOW_ALL\t\t(1<<0)\n #define REV_LIST_QUIET\t\t(1<<1)\n \ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex a0ec84e..67701be 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -201,16 +201,6 @@ static void show_edge(struct commit *commit)\n \tprintf(\"-%s\\n\", sha1_to_hex(commit->object.sha1));\n }\n \n-void print_commit_list(struct commit_list *list,\n-\t\t       const char *format_cur,\n-\t\t       const char *format_last)\n-{\n-\tfor ( ; list; list = list->next) {\n-\t\tconst char *format = list->next ? format_cur : format_last;\n-\t\tprintf(format, sha1_to_hex(list->item->object.sha1));\n-\t}\n-}\n-\n static void print_var_str(const char *var, const char *val)\n {\n \tprintf(\"%s='%s'\\n\", var, val);\ndiff --git a/commit.c b/commit.c\nindex 213bc98..e8eb0ae 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -1347,3 +1347,13 @@ struct commit_list **commit_list_append(struct commit *commit,\n \tnew->next = NULL;\n \treturn &new->next;\n }\n+\n+void print_commit_list(struct commit_list *list,\n+\t\t       const char *format_cur,\n+\t\t       const char *format_last)\n+{\n+\tfor ( ; list; list = list->next) {\n+\t\tconst char *format = list->next ? format_cur : format_last;\n+\t\tprintf(format, sha1_to_hex(list->item->object.sha1));\n+\t}\n+}\ndiff --git a/commit.h b/commit.h\nindex 9f21313..c4cd046 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -222,4 +222,8 @@ struct commit *get_merge_parent(const char *name);\n \n extern int parse_signed_commit(const unsigned char *sha1,\n \t\t\t       struct strbuf *message, struct strbuf *signature);\n+extern void print_commit_list(struct commit_list *list,\n+\t\t\t      const char *format_cur,\n+\t\t\t      const char *format_last);\n+\n #endif /* COMMIT_H */\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"201961","messageId":"1351266835-22610-5-git-send-email-pclouds@gmail.com","threadId":"31911","inReplyTo":"1351266835-22610-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 4/7] Move setup_diff_pager to libgit.a","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-10-26T15:53:52Z","receivedAt":"2012-10-26T15:53:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is used by diff-no-index.c, part of libgit.a while it stays in\nbuiltin/diff.c. Move it to diff.c so that we won't get undefined\nreference if a program that uses libgit.a happens to pull it in.\n\nWhile at it, move check_pager from git.c to pager.c. It makes more\nsense there and pager.c is also part of libgit.a\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin.h      |  4 ----\n builtin/diff.c | 16 ----------------\n cache.h        |  1 +\n diff.c         | 16 ++++++++++++++++\n diff.h         |  1 +\n git.c          | 33 ---------------------------------\n pager.c        | 34 ++++++++++++++++++++++++++++++++++\n 7 files changed, 52 insertions(+), 53 deletions(-)\n\ndiff --git a/builtin.h b/builtin.h\nindex 95116b8..3faf9d6 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -37,10 +37,6 @@ int copy_note_for_rewrite(struct notes_rewrite_cfg *c,\n \t\t\t  const unsigned char *from_obj, const unsigned char *to_obj);\n void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c);\n \n-extern int check_pager_config(const char *cmd);\n-struct diff_options;\n-extern void setup_diff_pager(struct diff_options *);\n-\n extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size);\n \n extern int cmd_add(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex 9650be2..9c70e40 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -418,19 +418,3 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n \t\trefresh_index_quietly();\n \treturn result;\n }\n-\n-void setup_diff_pager(struct diff_options *opt)\n-{\n-\t/*\n-\t * If the user asked for our exit code, then either they want --quiet\n-\t * or --exit-code. We should definitely not bother with a pager in the\n-\t * former case, as we will generate no output. Since we still properly\n-\t * report our exit code even when a pager is run, we _could_ run a\n-\t * pager with --exit-code. But since we have not done so historically,\n-\t * and because it is easy to find people oneline advising \"git diff\n-\t * --exit-code\" in hooks and other scripts, we do not do so.\n-\t */\n-\tif (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&\n-\t    check_pager_config(\"diff\") != 0)\n-\t\tsetup_pager();\n-}\ndiff --git a/cache.h b/cache.h\nindex 2dc4dec..dbd8018 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1183,6 +1183,7 @@ extern int pager_in_use(void);\n extern int pager_use_color;\n extern int term_columns(void);\n extern int decimal_width(int);\n+extern int check_pager_config(const char *cmd);\n \n extern const char *editor_program;\n extern const char *askpass_program;\ndiff --git a/diff.c b/diff.c\nindex 35d3f07..1b5727d 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -4871,3 +4871,19 @@ size_t fill_textconv(struct userdiff_driver *driver,\n \n \treturn size;\n }\n+\n+void setup_diff_pager(struct diff_options *opt)\n+{\n+\t/*\n+\t * If the user asked for our exit code, then either they want --quiet\n+\t * or --exit-code. We should definitely not bother with a pager in the\n+\t * former case, as we will generate no output. Since we still properly\n+\t * report our exit code even when a pager is run, we _could_ run a\n+\t * pager with --exit-code. But since we have not done so historically,\n+\t * and because it is easy to find people oneline advising \"git diff\n+\t * --exit-code\" in hooks and other scripts, we do not do so.\n+\t */\n+\tif (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&\n+\t    check_pager_config(\"diff\") != 0)\n+\t\tsetup_pager();\n+}\ndiff --git a/diff.h b/diff.h\nindex a658f85..a47bae4 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -335,5 +335,6 @@ extern int parse_rename_score(const char **cp_p);\n \n extern int print_stat_summary(FILE *fp, int files,\n \t\t\t      int insertions, int deletions);\n+extern void setup_diff_pager(struct diff_options *);\n \n #endif /* DIFF_H */\ndiff --git a/git.c b/git.c\nindex 8788b32..d33f9b3 100644\n--- a/git.c\n+++ b/git.c\n@@ -17,39 +17,6 @@ const char git_more_info_string[] =\n \n static struct startup_info git_startup_info;\n static int use_pager = -1;\n-struct pager_config {\n-\tconst char *cmd;\n-\tint want;\n-\tchar *value;\n-};\n-\n-static int pager_command_config(const char *var, const char *value, void *data)\n-{\n-\tstruct pager_config *c = data;\n-\tif (!prefixcmp(var, \"pager.\") && !strcmp(var + 6, c->cmd)) {\n-\t\tint b = git_config_maybe_bool(var, value);\n-\t\tif (b >= 0)\n-\t\t\tc->want = b;\n-\t\telse {\n-\t\t\tc->want = 1;\n-\t\t\tc->value = xstrdup(value);\n-\t\t}\n-\t}\n-\treturn 0;\n-}\n-\n-/* returns 0 for \"no pager\", 1 for \"use pager\", and -1 for \"not specified\" */\n-int check_pager_config(const char *cmd)\n-{\n-\tstruct pager_config c;\n-\tc.cmd = cmd;\n-\tc.want = -1;\n-\tc.value = NULL;\n-\tgit_config(pager_command_config, &c);\n-\tif (c.value)\n-\t\tpager_program = c.value;\n-\treturn c.want;\n-}\n \n static void commit_pager_choice(void) {\n \tswitch (use_pager) {\ndiff --git a/pager.c b/pager.c\nindex 4dcb08d..060fa88 100644\n--- a/pager.c\n+++ b/pager.c\n@@ -6,6 +6,12 @@\n #define DEFAULT_PAGER \"less\"\n #endif\n \n+struct pager_config {\n+\tconst char *cmd;\n+\tint want;\n+\tchar *value;\n+};\n+\n /*\n  * This is split up from the rest of git so that we can do\n  * something different on Windows.\n@@ -159,3 +165,31 @@ int decimal_width(int number)\n \t\ti *= 10;\n \treturn width;\n }\n+\n+static int pager_command_config(const char *var, const char *value, void *data)\n+{\n+\tstruct pager_config *c = data;\n+\tif (!prefixcmp(var, \"pager.\") && !strcmp(var + 6, c->cmd)) {\n+\t\tint b = git_config_maybe_bool(var, value);\n+\t\tif (b >= 0)\n+\t\t\tc->want = b;\n+\t\telse {\n+\t\t\tc->want = 1;\n+\t\t\tc->value = xstrdup(value);\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+/* returns 0 for \"no pager\", 1 for \"use pager\", and -1 for \"not specified\" */\n+int check_pager_config(const char *cmd)\n+{\n+\tstruct pager_config c;\n+\tc.cmd = cmd;\n+\tc.want = -1;\n+\tc.value = NULL;\n+\tgit_config(pager_command_config, &c);\n+\tif (c.value)\n+\t\tpager_program = c.value;\n+\treturn c.want;\n+}\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"201962","messageId":"1351266835-22610-6-git-send-email-pclouds@gmail.com","threadId":"31911","inReplyTo":"1351266835-22610-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 5/7] send-pack: move core code to libgit.a","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-10-26T15:53:53Z","receivedAt":"2012-10-26T15:53:53Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"send_pack() is used by transport.c, part of libgit.a while it stays in\nbuiltin/send-pack.c. Move it to send-pack.c so that we won't get\nundefined reference if a program that uses libgit.a happens to pull it\nin.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Makefile            |   1 +\n builtin/send-pack.c | 333 --------------------------------------------------\n send-pack.c         | 344 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n transport.h         |   5 +\n 4 files changed, 350 insertions(+), 333 deletions(-)\n create mode 100644 send-pack.c\n\ndiff --git a/Makefile b/Makefile\nindex 2c333dc..414f15f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -797,6 +797,7 @@ LIB_OBJS += rerere.o\n LIB_OBJS += resolve-undo.o\n LIB_OBJS += revision.o\n LIB_OBJS += run-command.o\n+LIB_OBJS += send-pack.o\n LIB_OBJS += sequencer.o\n LIB_OBJS += server-info.o\n LIB_OBJS += setup.o\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex 7d05064..d342013 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -16,164 +16,6 @@ static const char send_pack_usage[] =\n \n static struct send_pack_args args;\n \n-static int feed_object(const unsigned char *sha1, int fd, int negative)\n-{\n-\tchar buf[42];\n-\n-\tif (negative && !has_sha1_file(sha1))\n-\t\treturn 1;\n-\n-\tmemcpy(buf + negative, sha1_to_hex(sha1), 40);\n-\tif (negative)\n-\t\tbuf[0] = '^';\n-\tbuf[40 + negative] = '\\n';\n-\treturn write_or_whine(fd, buf, 41 + negative, \"send-pack: send refs\");\n-}\n-\n-/*\n- * Make a pack stream and spit it out into file descriptor fd\n- */\n-static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args)\n-{\n-\t/*\n-\t * The child becomes pack-objects --revs; we feed\n-\t * the revision parameters to it via its stdin and\n-\t * let its stdout go back to the other end.\n-\t */\n-\tconst char *argv[] = {\n-\t\t\"pack-objects\",\n-\t\t\"--all-progress-implied\",\n-\t\t\"--revs\",\n-\t\t\"--stdout\",\n-\t\tNULL,\n-\t\tNULL,\n-\t\tNULL,\n-\t\tNULL,\n-\t\tNULL,\n-\t};\n-\tstruct child_process po;\n-\tint i;\n-\n-\ti = 4;\n-\tif (args->use_thin_pack)\n-\t\targv[i++] = \"--thin\";\n-\tif (args->use_ofs_delta)\n-\t\targv[i++] = \"--delta-base-offset\";\n-\tif (args->quiet || !args->progress)\n-\t\targv[i++] = \"-q\";\n-\tif (args->progress)\n-\t\targv[i++] = \"--progress\";\n-\tmemset(&po, 0, sizeof(po));\n-\tpo.argv = argv;\n-\tpo.in = -1;\n-\tpo.out = args->stateless_rpc ? -1 : fd;\n-\tpo.git_cmd = 1;\n-\tif (start_command(&po))\n-\t\tdie_errno(\"git pack-objects failed\");\n-\n-\t/*\n-\t * We feed the pack-objects we just spawned with revision\n-\t * parameters by writing to the pipe.\n-\t */\n-\tfor (i = 0; i < extra->nr; i++)\n-\t\tif (!feed_object(extra->array[i], po.in, 1))\n-\t\t\tbreak;\n-\n-\twhile (refs) {\n-\t\tif (!is_null_sha1(refs->old_sha1) &&\n-\t\t    !feed_object(refs->old_sha1, po.in, 1))\n-\t\t\tbreak;\n-\t\tif (!is_null_sha1(refs->new_sha1) &&\n-\t\t    !feed_object(refs->new_sha1, po.in, 0))\n-\t\t\tbreak;\n-\t\trefs = refs->next;\n-\t}\n-\n-\tclose(po.in);\n-\n-\tif (args->stateless_rpc) {\n-\t\tchar *buf = xmalloc(LARGE_PACKET_MAX);\n-\t\twhile (1) {\n-\t\t\tssize_t n = xread(po.out, buf, LARGE_PACKET_MAX);\n-\t\t\tif (n <= 0)\n-\t\t\t\tbreak;\n-\t\t\tsend_sideband(fd, -1, buf, n, LARGE_PACKET_MAX);\n-\t\t}\n-\t\tfree(buf);\n-\t\tclose(po.out);\n-\t\tpo.out = -1;\n-\t}\n-\n-\tif (finish_command(&po))\n-\t\treturn -1;\n-\treturn 0;\n-}\n-\n-static int receive_status(int in, struct ref *refs)\n-{\n-\tstruct ref *hint;\n-\tchar line[1000];\n-\tint ret = 0;\n-\tint len = packet_read_line(in, line, sizeof(line));\n-\tif (len < 10 || memcmp(line, \"unpack \", 7))\n-\t\treturn error(\"did not receive remote status\");\n-\tif (memcmp(line, \"unpack ok\\n\", 10)) {\n-\t\tchar *p = line + strlen(line) - 1;\n-\t\tif (*p == '\\n')\n-\t\t\t*p = '\\0';\n-\t\terror(\"unpack failed: %s\", line + 7);\n-\t\tret = -1;\n-\t}\n-\thint = NULL;\n-\twhile (1) {\n-\t\tchar *refname;\n-\t\tchar *msg;\n-\t\tlen = packet_read_line(in, line, sizeof(line));\n-\t\tif (!len)\n-\t\t\tbreak;\n-\t\tif (len < 3 ||\n-\t\t    (memcmp(line, \"ok \", 3) && memcmp(line, \"ng \", 3))) {\n-\t\t\tfprintf(stderr, \"protocol error: %s\\n\", line);\n-\t\t\tret = -1;\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tline[strlen(line)-1] = '\\0';\n-\t\trefname = line + 3;\n-\t\tmsg = strchr(refname, ' ');\n-\t\tif (msg)\n-\t\t\t*msg++ = '\\0';\n-\n-\t\t/* first try searching at our hint, falling back to all refs */\n-\t\tif (hint)\n-\t\t\thint = find_ref_by_name(hint, refname);\n-\t\tif (!hint)\n-\t\t\thint = find_ref_by_name(refs, refname);\n-\t\tif (!hint) {\n-\t\t\twarning(\"remote reported status on unknown ref: %s\",\n-\t\t\t\t\trefname);\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (hint->status != REF_STATUS_EXPECTING_REPORT) {\n-\t\t\twarning(\"remote reported status on unexpected ref: %s\",\n-\t\t\t\t\trefname);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (line[0] == 'o' && line[1] == 'k')\n-\t\t\thint->status = REF_STATUS_OK;\n-\t\telse {\n-\t\t\thint->status = REF_STATUS_REMOTE_REJECT;\n-\t\t\tret = -1;\n-\t\t}\n-\t\tif (msg)\n-\t\t\thint->remote_status = xstrdup(msg);\n-\t\t/* start our next search from the next ref */\n-\t\thint = hint->next;\n-\t}\n-\treturn ret;\n-}\n-\n static void print_helper_status(struct ref *ref)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -227,181 +69,6 @@ static void print_helper_status(struct ref *ref)\n \tstrbuf_release(&buf);\n }\n \n-static int sideband_demux(int in, int out, void *data)\n-{\n-\tint *fd = data, ret;\n-#ifdef NO_PTHREADS\n-\tclose(fd[1]);\n-#endif\n-\tret = recv_sideband(\"send-pack\", fd[0], out);\n-\tclose(out);\n-\treturn ret;\n-}\n-\n-int send_pack(struct send_pack_args *args,\n-\t      int fd[], struct child_process *conn,\n-\t      struct ref *remote_refs,\n-\t      struct extra_have_objects *extra_have)\n-{\n-\tint in = fd[0];\n-\tint out = fd[1];\n-\tstruct strbuf req_buf = STRBUF_INIT;\n-\tstruct ref *ref;\n-\tint new_refs;\n-\tint allow_deleting_refs = 0;\n-\tint status_report = 0;\n-\tint use_sideband = 0;\n-\tint quiet_supported = 0;\n-\tint agent_supported = 0;\n-\tunsigned cmds_sent = 0;\n-\tint ret;\n-\tstruct async demux;\n-\n-\t/* Does the other end support the reporting? */\n-\tif (server_supports(\"report-status\"))\n-\t\tstatus_report = 1;\n-\tif (server_supports(\"delete-refs\"))\n-\t\tallow_deleting_refs = 1;\n-\tif (server_supports(\"ofs-delta\"))\n-\t\targs->use_ofs_delta = 1;\n-\tif (server_supports(\"side-band-64k\"))\n-\t\tuse_sideband = 1;\n-\tif (server_supports(\"quiet\"))\n-\t\tquiet_supported = 1;\n-\tif (server_supports(\"agent\"))\n-\t\tagent_supported = 1;\n-\n-\tif (!remote_refs) {\n-\t\tfprintf(stderr, \"No refs in common and none specified; doing nothing.\\n\"\n-\t\t\t\"Perhaps you should specify a branch such as 'master'.\\n\");\n-\t\treturn 0;\n-\t}\n-\n-\t/*\n-\t * Finally, tell the other end!\n-\t */\n-\tnew_refs = 0;\n-\tfor (ref = remote_refs; ref; ref = ref->next) {\n-\t\tif (!ref->peer_ref && !args->send_mirror)\n-\t\t\tcontinue;\n-\n-\t\t/* Check for statuses set by set_ref_status_for_push() */\n-\t\tswitch (ref->status) {\n-\t\tcase REF_STATUS_REJECT_NONFASTFORWARD:\n-\t\tcase REF_STATUS_UPTODATE:\n-\t\t\tcontinue;\n-\t\tdefault:\n-\t\t\t; /* do nothing */\n-\t\t}\n-\n-\t\tif (ref->deletion && !allow_deleting_refs) {\n-\t\t\tref->status = REF_STATUS_REJECT_NODELETE;\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (!ref->deletion)\n-\t\t\tnew_refs++;\n-\n-\t\tif (args->dry_run) {\n-\t\t\tref->status = REF_STATUS_OK;\n-\t\t} else {\n-\t\t\tchar *old_hex = sha1_to_hex(ref->old_sha1);\n-\t\t\tchar *new_hex = sha1_to_hex(ref->new_sha1);\n-\t\t\tint quiet = quiet_supported && (args->quiet || !args->progress);\n-\n-\t\t\tif (!cmds_sent && (status_report || use_sideband ||\n-\t\t\t\t\t   quiet || agent_supported)) {\n-\t\t\t\tpacket_buf_write(&req_buf,\n-\t\t\t\t\t\t \"%s %s %s%c%s%s%s%s%s\",\n-\t\t\t\t\t\t old_hex, new_hex, ref->name, 0,\n-\t\t\t\t\t\t status_report ? \" report-status\" : \"\",\n-\t\t\t\t\t\t use_sideband ? \" side-band-64k\" : \"\",\n-\t\t\t\t\t\t quiet ? \" quiet\" : \"\",\n-\t\t\t\t\t\t agent_supported ? \" agent=\" : \"\",\n-\t\t\t\t\t\t agent_supported ? git_user_agent_sanitized() : \"\"\n-\t\t\t\t\t\t);\n-\t\t\t}\n-\t\t\telse\n-\t\t\t\tpacket_buf_write(&req_buf, \"%s %s %s\",\n-\t\t\t\t\t\t old_hex, new_hex, ref->name);\n-\t\t\tref->status = status_report ?\n-\t\t\t\tREF_STATUS_EXPECTING_REPORT :\n-\t\t\t\tREF_STATUS_OK;\n-\t\t\tcmds_sent++;\n-\t\t}\n-\t}\n-\n-\tif (args->stateless_rpc) {\n-\t\tif (!args->dry_run && cmds_sent) {\n-\t\t\tpacket_buf_flush(&req_buf);\n-\t\t\tsend_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);\n-\t\t}\n-\t} else {\n-\t\tsafe_write(out, req_buf.buf, req_buf.len);\n-\t\tpacket_flush(out);\n-\t}\n-\tstrbuf_release(&req_buf);\n-\n-\tif (use_sideband && cmds_sent) {\n-\t\tmemset(&demux, 0, sizeof(demux));\n-\t\tdemux.proc = sideband_demux;\n-\t\tdemux.data = fd;\n-\t\tdemux.out = -1;\n-\t\tif (start_async(&demux))\n-\t\t\tdie(\"send-pack: unable to fork off sideband demultiplexer\");\n-\t\tin = demux.out;\n-\t}\n-\n-\tif (new_refs && cmds_sent) {\n-\t\tif (pack_objects(out, remote_refs, extra_have, args) < 0) {\n-\t\t\tfor (ref = remote_refs; ref; ref = ref->next)\n-\t\t\t\tref->status = REF_STATUS_NONE;\n-\t\t\tif (args->stateless_rpc)\n-\t\t\t\tclose(out);\n-\t\t\tif (git_connection_is_socket(conn))\n-\t\t\t\tshutdown(fd[0], SHUT_WR);\n-\t\t\tif (use_sideband)\n-\t\t\t\tfinish_async(&demux);\n-\t\t\treturn -1;\n-\t\t}\n-\t}\n-\tif (args->stateless_rpc && cmds_sent)\n-\t\tpacket_flush(out);\n-\n-\tif (status_report && cmds_sent)\n-\t\tret = receive_status(in, remote_refs);\n-\telse\n-\t\tret = 0;\n-\tif (args->stateless_rpc)\n-\t\tpacket_flush(out);\n-\n-\tif (use_sideband && cmds_sent) {\n-\t\tif (finish_async(&demux)) {\n-\t\t\terror(\"error in sideband demultiplexer\");\n-\t\t\tret = -1;\n-\t\t}\n-\t\tclose(demux.out);\n-\t}\n-\n-\tif (ret < 0)\n-\t\treturn ret;\n-\n-\tif (args->porcelain)\n-\t\treturn 0;\n-\n-\tfor (ref = remote_refs; ref; ref = ref->next) {\n-\t\tswitch (ref->status) {\n-\t\tcase REF_STATUS_NONE:\n-\t\tcase REF_STATUS_UPTODATE:\n-\t\tcase REF_STATUS_OK:\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\treturn -1;\n-\t\t}\n-\t}\n-\treturn 0;\n-}\n-\n int cmd_send_pack(int argc, const char **argv, const char *prefix)\n {\n \tint i, nr_refspecs = 0;\ndiff --git a/send-pack.c b/send-pack.c\nnew file mode 100644\nindex 0000000..f50dfd9\n--- /dev/null\n+++ b/send-pack.c\n@@ -0,0 +1,344 @@\n+#include \"builtin.h\"\n+#include \"commit.h\"\n+#include \"refs.h\"\n+#include \"pkt-line.h\"\n+#include \"sideband.h\"\n+#include \"run-command.h\"\n+#include \"remote.h\"\n+#include \"send-pack.h\"\n+#include \"quote.h\"\n+#include \"transport.h\"\n+#include \"version.h\"\n+\n+static int feed_object(const unsigned char *sha1, int fd, int negative)\n+{\n+\tchar buf[42];\n+\n+\tif (negative && !has_sha1_file(sha1))\n+\t\treturn 1;\n+\n+\tmemcpy(buf + negative, sha1_to_hex(sha1), 40);\n+\tif (negative)\n+\t\tbuf[0] = '^';\n+\tbuf[40 + negative] = '\\n';\n+\treturn write_or_whine(fd, buf, 41 + negative, \"send-pack: send refs\");\n+}\n+\n+/*\n+ * Make a pack stream and spit it out into file descriptor fd\n+ */\n+static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args)\n+{\n+\t/*\n+\t * The child becomes pack-objects --revs; we feed\n+\t * the revision parameters to it via its stdin and\n+\t * let its stdout go back to the other end.\n+\t */\n+\tconst char *argv[] = {\n+\t\t\"pack-objects\",\n+\t\t\"--all-progress-implied\",\n+\t\t\"--revs\",\n+\t\t\"--stdout\",\n+\t\tNULL,\n+\t\tNULL,\n+\t\tNULL,\n+\t\tNULL,\n+\t\tNULL,\n+\t};\n+\tstruct child_process po;\n+\tint i;\n+\n+\ti = 4;\n+\tif (args->use_thin_pack)\n+\t\targv[i++] = \"--thin\";\n+\tif (args->use_ofs_delta)\n+\t\targv[i++] = \"--delta-base-offset\";\n+\tif (args->quiet || !args->progress)\n+\t\targv[i++] = \"-q\";\n+\tif (args->progress)\n+\t\targv[i++] = \"--progress\";\n+\tmemset(&po, 0, sizeof(po));\n+\tpo.argv = argv;\n+\tpo.in = -1;\n+\tpo.out = args->stateless_rpc ? -1 : fd;\n+\tpo.git_cmd = 1;\n+\tif (start_command(&po))\n+\t\tdie_errno(\"git pack-objects failed\");\n+\n+\t/*\n+\t * We feed the pack-objects we just spawned with revision\n+\t * parameters by writing to the pipe.\n+\t */\n+\tfor (i = 0; i < extra->nr; i++)\n+\t\tif (!feed_object(extra->array[i], po.in, 1))\n+\t\t\tbreak;\n+\n+\twhile (refs) {\n+\t\tif (!is_null_sha1(refs->old_sha1) &&\n+\t\t    !feed_object(refs->old_sha1, po.in, 1))\n+\t\t\tbreak;\n+\t\tif (!is_null_sha1(refs->new_sha1) &&\n+\t\t    !feed_object(refs->new_sha1, po.in, 0))\n+\t\t\tbreak;\n+\t\trefs = refs->next;\n+\t}\n+\n+\tclose(po.in);\n+\n+\tif (args->stateless_rpc) {\n+\t\tchar *buf = xmalloc(LARGE_PACKET_MAX);\n+\t\twhile (1) {\n+\t\t\tssize_t n = xread(po.out, buf, LARGE_PACKET_MAX);\n+\t\t\tif (n <= 0)\n+\t\t\t\tbreak;\n+\t\t\tsend_sideband(fd, -1, buf, n, LARGE_PACKET_MAX);\n+\t\t}\n+\t\tfree(buf);\n+\t\tclose(po.out);\n+\t\tpo.out = -1;\n+\t}\n+\n+\tif (finish_command(&po))\n+\t\treturn -1;\n+\treturn 0;\n+}\n+\n+static int receive_status(int in, struct ref *refs)\n+{\n+\tstruct ref *hint;\n+\tchar line[1000];\n+\tint ret = 0;\n+\tint len = packet_read_line(in, line, sizeof(line));\n+\tif (len < 10 || memcmp(line, \"unpack \", 7))\n+\t\treturn error(\"did not receive remote status\");\n+\tif (memcmp(line, \"unpack ok\\n\", 10)) {\n+\t\tchar *p = line + strlen(line) - 1;\n+\t\tif (*p == '\\n')\n+\t\t\t*p = '\\0';\n+\t\terror(\"unpack failed: %s\", line + 7);\n+\t\tret = -1;\n+\t}\n+\thint = NULL;\n+\twhile (1) {\n+\t\tchar *refname;\n+\t\tchar *msg;\n+\t\tlen = packet_read_line(in, line, sizeof(line));\n+\t\tif (!len)\n+\t\t\tbreak;\n+\t\tif (len < 3 ||\n+\t\t    (memcmp(line, \"ok \", 3) && memcmp(line, \"ng \", 3))) {\n+\t\t\tfprintf(stderr, \"protocol error: %s\\n\", line);\n+\t\t\tret = -1;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tline[strlen(line)-1] = '\\0';\n+\t\trefname = line + 3;\n+\t\tmsg = strchr(refname, ' ');\n+\t\tif (msg)\n+\t\t\t*msg++ = '\\0';\n+\n+\t\t/* first try searching at our hint, falling back to all refs */\n+\t\tif (hint)\n+\t\t\thint = find_ref_by_name(hint, refname);\n+\t\tif (!hint)\n+\t\t\thint = find_ref_by_name(refs, refname);\n+\t\tif (!hint) {\n+\t\t\twarning(\"remote reported status on unknown ref: %s\",\n+\t\t\t\t\trefname);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (hint->status != REF_STATUS_EXPECTING_REPORT) {\n+\t\t\twarning(\"remote reported status on unexpected ref: %s\",\n+\t\t\t\t\trefname);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (line[0] == 'o' && line[1] == 'k')\n+\t\t\thint->status = REF_STATUS_OK;\n+\t\telse {\n+\t\t\thint->status = REF_STATUS_REMOTE_REJECT;\n+\t\t\tret = -1;\n+\t\t}\n+\t\tif (msg)\n+\t\t\thint->remote_status = xstrdup(msg);\n+\t\t/* start our next search from the next ref */\n+\t\thint = hint->next;\n+\t}\n+\treturn ret;\n+}\n+\n+static int sideband_demux(int in, int out, void *data)\n+{\n+\tint *fd = data, ret;\n+#ifdef NO_PTHREADS\n+\tclose(fd[1]);\n+#endif\n+\tret = recv_sideband(\"send-pack\", fd[0], out);\n+\tclose(out);\n+\treturn ret;\n+}\n+\n+int send_pack(struct send_pack_args *args,\n+\t      int fd[], struct child_process *conn,\n+\t      struct ref *remote_refs,\n+\t      struct extra_have_objects *extra_have)\n+{\n+\tint in = fd[0];\n+\tint out = fd[1];\n+\tstruct strbuf req_buf = STRBUF_INIT;\n+\tstruct ref *ref;\n+\tint new_refs;\n+\tint allow_deleting_refs = 0;\n+\tint status_report = 0;\n+\tint use_sideband = 0;\n+\tint quiet_supported = 0;\n+\tint agent_supported = 0;\n+\tunsigned cmds_sent = 0;\n+\tint ret;\n+\tstruct async demux;\n+\n+\t/* Does the other end support the reporting? */\n+\tif (server_supports(\"report-status\"))\n+\t\tstatus_report = 1;\n+\tif (server_supports(\"delete-refs\"))\n+\t\tallow_deleting_refs = 1;\n+\tif (server_supports(\"ofs-delta\"))\n+\t\targs->use_ofs_delta = 1;\n+\tif (server_supports(\"side-band-64k\"))\n+\t\tuse_sideband = 1;\n+\tif (server_supports(\"quiet\"))\n+\t\tquiet_supported = 1;\n+\tif (server_supports(\"agent\"))\n+\t\tagent_supported = 1;\n+\n+\tif (!remote_refs) {\n+\t\tfprintf(stderr, \"No refs in common and none specified; doing nothing.\\n\"\n+\t\t\t\"Perhaps you should specify a branch such as 'master'.\\n\");\n+\t\treturn 0;\n+\t}\n+\n+\t/*\n+\t * Finally, tell the other end!\n+\t */\n+\tnew_refs = 0;\n+\tfor (ref = remote_refs; ref; ref = ref->next) {\n+\t\tif (!ref->peer_ref && !args->send_mirror)\n+\t\t\tcontinue;\n+\n+\t\t/* Check for statuses set by set_ref_status_for_push() */\n+\t\tswitch (ref->status) {\n+\t\tcase REF_STATUS_REJECT_NONFASTFORWARD:\n+\t\tcase REF_STATUS_UPTODATE:\n+\t\t\tcontinue;\n+\t\tdefault:\n+\t\t\t; /* do nothing */\n+\t\t}\n+\n+\t\tif (ref->deletion && !allow_deleting_refs) {\n+\t\t\tref->status = REF_STATUS_REJECT_NODELETE;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (!ref->deletion)\n+\t\t\tnew_refs++;\n+\n+\t\tif (args->dry_run) {\n+\t\t\tref->status = REF_STATUS_OK;\n+\t\t} else {\n+\t\t\tchar *old_hex = sha1_to_hex(ref->old_sha1);\n+\t\t\tchar *new_hex = sha1_to_hex(ref->new_sha1);\n+\t\t\tint quiet = quiet_supported && (args->quiet || !args->progress);\n+\n+\t\t\tif (!cmds_sent && (status_report || use_sideband ||\n+\t\t\t\t\t   quiet || agent_supported)) {\n+\t\t\t\tpacket_buf_write(&req_buf,\n+\t\t\t\t\t\t \"%s %s %s%c%s%s%s%s%s\",\n+\t\t\t\t\t\t old_hex, new_hex, ref->name, 0,\n+\t\t\t\t\t\t status_report ? \" report-status\" : \"\",\n+\t\t\t\t\t\t use_sideband ? \" side-band-64k\" : \"\",\n+\t\t\t\t\t\t quiet ? \" quiet\" : \"\",\n+\t\t\t\t\t\t agent_supported ? \" agent=\" : \"\",\n+\t\t\t\t\t\t agent_supported ? git_user_agent_sanitized() : \"\"\n+\t\t\t\t\t\t);\n+\t\t\t}\n+\t\t\telse\n+\t\t\t\tpacket_buf_write(&req_buf, \"%s %s %s\",\n+\t\t\t\t\t\t old_hex, new_hex, ref->name);\n+\t\t\tref->status = status_report ?\n+\t\t\t\tREF_STATUS_EXPECTING_REPORT :\n+\t\t\t\tREF_STATUS_OK;\n+\t\t\tcmds_sent++;\n+\t\t}\n+\t}\n+\n+\tif (args->stateless_rpc) {\n+\t\tif (!args->dry_run && cmds_sent) {\n+\t\t\tpacket_buf_flush(&req_buf);\n+\t\t\tsend_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);\n+\t\t}\n+\t} else {\n+\t\tsafe_write(out, req_buf.buf, req_buf.len);\n+\t\tpacket_flush(out);\n+\t}\n+\tstrbuf_release(&req_buf);\n+\n+\tif (use_sideband && cmds_sent) {\n+\t\tmemset(&demux, 0, sizeof(demux));\n+\t\tdemux.proc = sideband_demux;\n+\t\tdemux.data = fd;\n+\t\tdemux.out = -1;\n+\t\tif (start_async(&demux))\n+\t\t\tdie(\"send-pack: unable to fork off sideband demultiplexer\");\n+\t\tin = demux.out;\n+\t}\n+\n+\tif (new_refs && cmds_sent) {\n+\t\tif (pack_objects(out, remote_refs, extra_have, args) < 0) {\n+\t\t\tfor (ref = remote_refs; ref; ref = ref->next)\n+\t\t\t\tref->status = REF_STATUS_NONE;\n+\t\t\tif (args->stateless_rpc)\n+\t\t\t\tclose(out);\n+\t\t\tif (git_connection_is_socket(conn))\n+\t\t\t\tshutdown(fd[0], SHUT_WR);\n+\t\t\tif (use_sideband)\n+\t\t\t\tfinish_async(&demux);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\tif (args->stateless_rpc && cmds_sent)\n+\t\tpacket_flush(out);\n+\n+\tif (status_report && cmds_sent)\n+\t\tret = receive_status(in, remote_refs);\n+\telse\n+\t\tret = 0;\n+\tif (args->stateless_rpc)\n+\t\tpacket_flush(out);\n+\n+\tif (use_sideband && cmds_sent) {\n+\t\tif (finish_async(&demux)) {\n+\t\t\terror(\"error in sideband demultiplexer\");\n+\t\t\tret = -1;\n+\t\t}\n+\t\tclose(demux.out);\n+\t}\n+\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tif (args->porcelain)\n+\t\treturn 0;\n+\n+\tfor (ref = remote_refs; ref; ref = ref->next) {\n+\t\tswitch (ref->status) {\n+\t\tcase REF_STATUS_NONE:\n+\t\tcase REF_STATUS_UPTODATE:\n+\t\tcase REF_STATUS_OK:\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\ndiff --git a/transport.h b/transport.h\nindex 3b21c4a..4a61c0c 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -175,4 +175,9 @@ void transport_print_push_status(const char *dest, struct ref *refs,\n typedef void alternate_ref_fn(const struct ref *, void *);\n extern void for_each_alternate_ref(alternate_ref_fn, void *);\n \n+struct send_pack_args;\n+extern int send_pack(struct send_pack_args *args,\n+\t\t     int fd[], struct child_process *conn,\n+\t\t     struct ref *remote_refs,\n+\t\t     struct extra_have_objects *extra_have);\n #endif\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"201963","messageId":"1351266835-22610-7-git-send-email-pclouds@gmail.com","threadId":"31911","inReplyTo":"1351266835-22610-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 6/7] fetch-pack: remove global (static) configuration variable \"args\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-10-26T15:53:54Z","receivedAt":"2012-10-26T15:53:54Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This helps removes the hack in fetch_pack() that copies my_args to args.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/fetch-pack.c | 160 ++++++++++++++++++++++++++-------------------------\n 1 file changed, 83 insertions(+), 77 deletions(-)\n\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex e644398..d0fd707 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -20,9 +20,6 @@ static int no_done;\n static int fetch_fsck_objects = -1;\n static int transfer_fsck_objects = -1;\n static int agent_supported;\n-static struct fetch_pack_args args = {\n-\t/* .uploadpack = */ \"git-upload-pack\",\n-};\n \n static const char fetch_pack_usage[] =\n \"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] \"\n@@ -173,9 +170,9 @@ enum ack_type {\n \tACK_ready\n };\n \n-static void consume_shallow_list(int fd)\n+static void consume_shallow_list(struct fetch_pack_args *args, int fd)\n {\n-\tif (args.stateless_rpc && args.depth > 0) {\n+\tif (args->stateless_rpc && args->depth > 0) {\n \t\t/* If we sent a depth we will get back \"duplicate\"\n \t\t * shallow and unshallow commands every time there\n \t\t * is a block of have lines exchanged.\n@@ -246,9 +243,10 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1)\n \tdie(\"git fetch_pack: expected ACK/NAK, got '%s'\", line);\n }\n \n-static void send_request(int fd, struct strbuf *buf)\n+static void send_request(struct fetch_pack_args *args,\n+\t\t\t int fd, struct strbuf *buf)\n {\n-\tif (args.stateless_rpc) {\n+\tif (args->stateless_rpc) {\n \t\tsend_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX);\n \t\tpacket_flush(fd);\n \t} else\n@@ -264,9 +262,9 @@ static void insert_one_alternate_ref(const struct ref *ref, void *unused)\n #define PIPESAFE_FLUSH 32\n #define LARGE_FLUSH 1024\n \n-static int next_flush(int count)\n+static int next_flush(struct fetch_pack_args *args, int count)\n {\n-\tint flush_limit = args.stateless_rpc ? LARGE_FLUSH : PIPESAFE_FLUSH;\n+\tint flush_limit = args->stateless_rpc ? LARGE_FLUSH : PIPESAFE_FLUSH;\n \n \tif (count < flush_limit)\n \t\tcount <<= 1;\n@@ -275,7 +273,8 @@ static int next_flush(int count)\n \treturn count;\n }\n \n-static int find_common(int fd[2], unsigned char *result_sha1,\n+static int find_common(struct fetch_pack_args *args,\n+\t\t       int fd[2], unsigned char *result_sha1,\n \t\t       struct ref *refs)\n {\n \tint fetching;\n@@ -287,7 +286,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,\n \tstruct strbuf req_buf = STRBUF_INIT;\n \tsize_t state_len = 0;\n \n-\tif (args.stateless_rpc && multi_ack == 1)\n+\tif (args->stateless_rpc && multi_ack == 1)\n \t\tdie(\"--stateless-rpc requires multi_ack_detailed\");\n \tif (marked)\n \t\tfor_each_ref(clear_marks, NULL);\n@@ -325,9 +324,9 @@ static int find_common(int fd[2], unsigned char *result_sha1,\n \t\t\tif (no_done)            strbuf_addstr(&c, \" no-done\");\n \t\t\tif (use_sideband == 2)  strbuf_addstr(&c, \" side-band-64k\");\n \t\t\tif (use_sideband == 1)  strbuf_addstr(&c, \" side-band\");\n-\t\t\tif (args.use_thin_pack) strbuf_addstr(&c, \" thin-pack\");\n-\t\t\tif (args.no_progress)   strbuf_addstr(&c, \" no-progress\");\n-\t\t\tif (args.include_tag)   strbuf_addstr(&c, \" include-tag\");\n+\t\t\tif (args->use_thin_pack) strbuf_addstr(&c, \" thin-pack\");\n+\t\t\tif (args->no_progress)   strbuf_addstr(&c, \" no-progress\");\n+\t\t\tif (args->include_tag)   strbuf_addstr(&c, \" include-tag\");\n \t\t\tif (prefer_ofs_delta)   strbuf_addstr(&c, \" ofs-delta\");\n \t\t\tif (agent_supported)    strbuf_addf(&c, \" agent=%s\",\n \t\t\t\t\t\t\t    git_user_agent_sanitized());\n@@ -346,16 +345,16 @@ static int find_common(int fd[2], unsigned char *result_sha1,\n \n \tif (is_repository_shallow())\n \t\twrite_shallow_commits(&req_buf, 1);\n-\tif (args.depth > 0)\n-\t\tpacket_buf_write(&req_buf, \"deepen %d\", args.depth);\n+\tif (args->depth > 0)\n+\t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tpacket_buf_flush(&req_buf);\n \tstate_len = req_buf.len;\n \n-\tif (args.depth > 0) {\n+\tif (args->depth > 0) {\n \t\tchar line[1024];\n \t\tunsigned char sha1[20];\n \n-\t\tsend_request(fd[1], &req_buf);\n+\t\tsend_request(args, fd[1], &req_buf);\n \t\twhile (packet_read_line(fd[0], line, sizeof(line))) {\n \t\t\tif (!prefixcmp(line, \"shallow \")) {\n \t\t\t\tif (get_sha1_hex(line + 8, sha1))\n@@ -377,10 +376,10 @@ static int find_common(int fd[2], unsigned char *result_sha1,\n \t\t\t}\n \t\t\tdie(\"expected shallow/unshallow, got %s\", line);\n \t\t}\n-\t} else if (!args.stateless_rpc)\n-\t\tsend_request(fd[1], &req_buf);\n+\t} else if (!args->stateless_rpc)\n+\t\tsend_request(args, fd[1], &req_buf);\n \n-\tif (!args.stateless_rpc) {\n+\tif (!args->stateless_rpc) {\n \t\t/* If we aren't using the stateless-rpc interface\n \t\t * we don't need to retain the headers.\n \t\t */\n@@ -392,29 +391,29 @@ static int find_common(int fd[2], unsigned char *result_sha1,\n \tretval = -1;\n \twhile ((sha1 = get_rev())) {\n \t\tpacket_buf_write(&req_buf, \"have %s\\n\", sha1_to_hex(sha1));\n-\t\tif (args.verbose)\n+\t\tif (args->verbose)\n \t\t\tfprintf(stderr, \"have %s\\n\", sha1_to_hex(sha1));\n \t\tin_vain++;\n \t\tif (flush_at <= ++count) {\n \t\t\tint ack;\n \n \t\t\tpacket_buf_flush(&req_buf);\n-\t\t\tsend_request(fd[1], &req_buf);\n+\t\t\tsend_request(args, fd[1], &req_buf);\n \t\t\tstrbuf_setlen(&req_buf, state_len);\n \t\t\tflushes++;\n-\t\t\tflush_at = next_flush(count);\n+\t\t\tflush_at = next_flush(args, count);\n \n \t\t\t/*\n \t\t\t * We keep one window \"ahead\" of the other side, and\n \t\t\t * will wait for an ACK only on the next one\n \t\t\t */\n-\t\t\tif (!args.stateless_rpc && count == INITIAL_FLUSH)\n+\t\t\tif (!args->stateless_rpc && count == INITIAL_FLUSH)\n \t\t\t\tcontinue;\n \n-\t\t\tconsume_shallow_list(fd[0]);\n+\t\t\tconsume_shallow_list(args, fd[0]);\n \t\t\tdo {\n \t\t\t\tack = get_ack(fd[0], result_sha1);\n-\t\t\t\tif (args.verbose && ack)\n+\t\t\t\tif (args->verbose && ack)\n \t\t\t\t\tfprintf(stderr, \"got ack %d %s\\n\", ack,\n \t\t\t\t\t\t\tsha1_to_hex(result_sha1));\n \t\t\t\tswitch (ack) {\n@@ -430,7 +429,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,\n \t\t\t\t\t\tlookup_commit(result_sha1);\n \t\t\t\t\tif (!commit)\n \t\t\t\t\t\tdie(\"invalid commit %s\", sha1_to_hex(result_sha1));\n-\t\t\t\t\tif (args.stateless_rpc\n+\t\t\t\t\tif (args->stateless_rpc\n \t\t\t\t\t && ack == ACK_common\n \t\t\t\t\t && !(commit->object.flags & COMMON)) {\n \t\t\t\t\t\t/* We need to replay the have for this object\n@@ -455,7 +454,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,\n \t\t\t} while (ack);\n \t\t\tflushes--;\n \t\t\tif (got_continue && MAX_IN_VAIN < in_vain) {\n-\t\t\t\tif (args.verbose)\n+\t\t\t\tif (args->verbose)\n \t\t\t\t\tfprintf(stderr, \"giving up\\n\");\n \t\t\t\tbreak; /* give up */\n \t\t\t}\n@@ -464,9 +463,9 @@ static int find_common(int fd[2], unsigned char *result_sha1,\n done:\n \tif (!got_ready || !no_done) {\n \t\tpacket_buf_write(&req_buf, \"done\\n\");\n-\t\tsend_request(fd[1], &req_buf);\n+\t\tsend_request(args, fd[1], &req_buf);\n \t}\n-\tif (args.verbose)\n+\tif (args->verbose)\n \t\tfprintf(stderr, \"done\\n\");\n \tif (retval != 0) {\n \t\tmulti_ack = 0;\n@@ -474,11 +473,11 @@ done:\n \t}\n \tstrbuf_release(&req_buf);\n \n-\tconsume_shallow_list(fd[0]);\n+\tconsume_shallow_list(args, fd[0]);\n \twhile (flushes || multi_ack) {\n \t\tint ack = get_ack(fd[0], result_sha1);\n \t\tif (ack) {\n-\t\t\tif (args.verbose)\n+\t\t\tif (args->verbose)\n \t\t\t\tfprintf(stderr, \"got ack (%d) %s\\n\", ack,\n \t\t\t\t\tsha1_to_hex(result_sha1));\n \t\t\tif (ack == ACK)\n@@ -515,10 +514,11 @@ static int mark_complete(const char *refname, const unsigned char *sha1, int fla\n \treturn 0;\n }\n \n-static void mark_recent_complete_commits(unsigned long cutoff)\n+static void mark_recent_complete_commits(struct fetch_pack_args *args,\n+\t\t\t\t\t unsigned long cutoff)\n {\n \twhile (complete && cutoff <= complete->item->date) {\n-\t\tif (args.verbose)\n+\t\tif (args->verbose)\n \t\t\tfprintf(stderr, \"Marking %s as complete\\n\",\n \t\t\t\tsha1_to_hex(complete->item->object.sha1));\n \t\tpop_most_recent_commit(&complete, COMPLETE);\n@@ -535,7 +535,8 @@ static int non_matching_ref(struct string_list_item *item, void *unused)\n \t\treturn 1;\n }\n \n-static void filter_refs(struct ref **refs, struct string_list *sought)\n+static void filter_refs(struct fetch_pack_args *args,\n+\t\t\tstruct ref **refs, struct string_list *sought)\n {\n \tstruct ref *newlist = NULL;\n \tstruct ref **newtail = &newlist;\n@@ -564,8 +565,8 @@ static void filter_refs(struct ref **refs, struct string_list *sought)\n \t\t\t}\n \t\t}\n \n-\t\tif (! keep && args.fetch_all &&\n-\t\t    (!args.depth || prefixcmp(ref->name, \"refs/tags/\")))\n+\t\tif (! keep && args->fetch_all &&\n+\t\t    (!args->depth || prefixcmp(ref->name, \"refs/tags/\")))\n \t\t\tkeep = 1;\n \n \t\tif (keep) {\n@@ -586,7 +587,8 @@ static void mark_alternate_complete(const struct ref *ref, void *unused)\n \tmark_complete(NULL, ref->old_sha1, 0, NULL);\n }\n \n-static int everything_local(struct ref **refs, struct string_list *sought)\n+static int everything_local(struct fetch_pack_args *args,\n+\t\t\t    struct ref **refs, struct string_list *sought)\n {\n \tstruct ref *ref;\n \tint retval;\n@@ -612,11 +614,11 @@ static int everything_local(struct ref **refs, struct string_list *sought)\n \t\t}\n \t}\n \n-\tif (!args.depth) {\n+\tif (!args->depth) {\n \t\tfor_each_ref(mark_complete, NULL);\n \t\tfor_each_alternate_ref(mark_alternate_complete, NULL);\n \t\tif (cutoff)\n-\t\t\tmark_recent_complete_commits(cutoff);\n+\t\t\tmark_recent_complete_commits(args, cutoff);\n \t}\n \n \t/*\n@@ -637,7 +639,7 @@ static int everything_local(struct ref **refs, struct string_list *sought)\n \t\t}\n \t}\n \n-\tfilter_refs(refs, sought);\n+\tfilter_refs(args, refs, sought);\n \n \tfor (retval = 1, ref = *refs; ref ; ref = ref->next) {\n \t\tconst unsigned char *remote = ref->old_sha1;\n@@ -647,7 +649,7 @@ static int everything_local(struct ref **refs, struct string_list *sought)\n \t\to = lookup_object(remote);\n \t\tif (!o || !(o->flags & COMPLETE)) {\n \t\t\tretval = 0;\n-\t\t\tif (!args.verbose)\n+\t\t\tif (!args->verbose)\n \t\t\t\tcontinue;\n \t\t\tfprintf(stderr,\n \t\t\t\t\"want %s (%s)\\n\", sha1_to_hex(remote),\n@@ -656,7 +658,7 @@ static int everything_local(struct ref **refs, struct string_list *sought)\n \t\t}\n \n \t\thashcpy(ref->new_sha1, local);\n-\t\tif (!args.verbose)\n+\t\tif (!args->verbose)\n \t\t\tcontinue;\n \t\tfprintf(stderr,\n \t\t\t\"already have %s (%s)\\n\", sha1_to_hex(remote),\n@@ -674,14 +676,15 @@ static int sideband_demux(int in, int out, void *data)\n \treturn ret;\n }\n \n-static int get_pack(int xd[2], char **pack_lockfile)\n+static int get_pack(struct fetch_pack_args *args,\n+\t\t    int xd[2], char **pack_lockfile)\n {\n \tstruct async demux;\n \tconst char *argv[20];\n \tchar keep_arg[256];\n \tchar hdr_arg[256];\n \tconst char **av;\n-\tint do_keep = args.keep_pack;\n+\tint do_keep = args->keep_pack;\n \tstruct child_process cmd;\n \n \tmemset(&demux, 0, sizeof(demux));\n@@ -704,7 +707,7 @@ static int get_pack(int xd[2], char **pack_lockfile)\n \tcmd.argv = argv;\n \tav = argv;\n \t*hdr_arg = 0;\n-\tif (!args.keep_pack && unpack_limit) {\n+\tif (!args->keep_pack && unpack_limit) {\n \t\tstruct pack_header header;\n \n \t\tif (read_pack_header(demux.out, &header))\n@@ -723,11 +726,11 @@ static int get_pack(int xd[2], char **pack_lockfile)\n \t\t\tcmd.out = -1;\n \t\t*av++ = \"index-pack\";\n \t\t*av++ = \"--stdin\";\n-\t\tif (!args.quiet && !args.no_progress)\n+\t\tif (!args->quiet && !args->no_progress)\n \t\t\t*av++ = \"-v\";\n-\t\tif (args.use_thin_pack)\n+\t\tif (args->use_thin_pack)\n \t\t\t*av++ = \"--fix-thin\";\n-\t\tif (args.lock_pack || unpack_limit) {\n+\t\tif (args->lock_pack || unpack_limit) {\n \t\t\tint s = sprintf(keep_arg,\n \t\t\t\t\t\"--keep=fetch-pack %\"PRIuMAX \" on \", (uintmax_t) getpid());\n \t\t\tif (gethostname(keep_arg + s, sizeof(keep_arg) - s))\n@@ -737,7 +740,7 @@ static int get_pack(int xd[2], char **pack_lockfile)\n \t}\n \telse {\n \t\t*av++ = \"unpack-objects\";\n-\t\tif (args.quiet || args.no_progress)\n+\t\tif (args->quiet || args->no_progress)\n \t\t\t*av++ = \"-q\";\n \t}\n \tif (*hdr_arg)\n@@ -766,10 +769,11 @@ static int get_pack(int xd[2], char **pack_lockfile)\n \treturn 0;\n }\n \n-static struct ref *do_fetch_pack(int fd[2],\n-\t\tconst struct ref *orig_ref,\n-\t\tstruct string_list *sought,\n-\t\tchar **pack_lockfile)\n+static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n+\t\t\t\t int fd[2],\n+\t\t\t\t const struct ref *orig_ref,\n+\t\t\t\t struct string_list *sought,\n+\t\t\t\t char **pack_lockfile)\n {\n \tstruct ref *ref = copy_ref_list(orig_ref);\n \tunsigned char sha1[20];\n@@ -781,64 +785,64 @@ static struct ref *do_fetch_pack(int fd[2],\n \tif (is_repository_shallow() && !server_supports(\"shallow\"))\n \t\tdie(\"Server does not support shallow clients\");\n \tif (server_supports(\"multi_ack_detailed\")) {\n-\t\tif (args.verbose)\n+\t\tif (args->verbose)\n \t\t\tfprintf(stderr, \"Server supports multi_ack_detailed\\n\");\n \t\tmulti_ack = 2;\n \t\tif (server_supports(\"no-done\")) {\n-\t\t\tif (args.verbose)\n+\t\t\tif (args->verbose)\n \t\t\t\tfprintf(stderr, \"Server supports no-done\\n\");\n-\t\t\tif (args.stateless_rpc)\n+\t\t\tif (args->stateless_rpc)\n \t\t\t\tno_done = 1;\n \t\t}\n \t}\n \telse if (server_supports(\"multi_ack\")) {\n-\t\tif (args.verbose)\n+\t\tif (args->verbose)\n \t\t\tfprintf(stderr, \"Server supports multi_ack\\n\");\n \t\tmulti_ack = 1;\n \t}\n \tif (server_supports(\"side-band-64k\")) {\n-\t\tif (args.verbose)\n+\t\tif (args->verbose)\n \t\t\tfprintf(stderr, \"Server supports side-band-64k\\n\");\n \t\tuse_sideband = 2;\n \t}\n \telse if (server_supports(\"side-band\")) {\n-\t\tif (args.verbose)\n+\t\tif (args->verbose)\n \t\t\tfprintf(stderr, \"Server supports side-band\\n\");\n \t\tuse_sideband = 1;\n \t}\n \tif (!server_supports(\"thin-pack\"))\n-\t\targs.use_thin_pack = 0;\n+\t\targs->use_thin_pack = 0;\n \tif (!server_supports(\"no-progress\"))\n-\t\targs.no_progress = 0;\n+\t\targs->no_progress = 0;\n \tif (!server_supports(\"include-tag\"))\n-\t\targs.include_tag = 0;\n+\t\targs->include_tag = 0;\n \tif (server_supports(\"ofs-delta\")) {\n-\t\tif (args.verbose)\n+\t\tif (args->verbose)\n \t\t\tfprintf(stderr, \"Server supports ofs-delta\\n\");\n \t} else\n \t\tprefer_ofs_delta = 0;\n \n \tif ((agent_feature = server_feature_value(\"agent\", &agent_len))) {\n \t\tagent_supported = 1;\n-\t\tif (args.verbose && agent_len)\n+\t\tif (args->verbose && agent_len)\n \t\t\tfprintf(stderr, \"Server version is %.*s\\n\",\n \t\t\t\tagent_len, agent_feature);\n \t}\n \n-\tif (everything_local(&ref, sought)) {\n+\tif (everything_local(args, &ref, sought)) {\n \t\tpacket_flush(fd[1]);\n \t\tgoto all_done;\n \t}\n-\tif (find_common(fd, sha1, ref) < 0)\n-\t\tif (!args.keep_pack)\n+\tif (find_common(args, fd, sha1, ref) < 0)\n+\t\tif (!args->keep_pack)\n \t\t\t/* When cloning, it is not unusual to have\n \t\t\t * no common commit.\n \t\t\t */\n \t\t\twarning(\"no common commits\");\n \n-\tif (args.stateless_rpc)\n+\tif (args->stateless_rpc)\n \t\tpacket_flush(fd[1]);\n-\tif (get_pack(fd, pack_lockfile))\n+\tif (get_pack(args, fd, pack_lockfile))\n \t\tdie(\"git fetch-pack: fetch failed.\");\n \n  all_done:\n@@ -900,9 +904,13 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \tchar *pack_lockfile = NULL;\n \tchar **pack_lockfile_ptr = NULL;\n \tstruct child_process *conn;\n+\tstruct fetch_pack_args args;\n \n \tpacket_trace_identity(\"fetch-pack\");\n \n+\tmemset(&args, 0, sizeof(args));\n+\targs.uploadpack = \"git-upload-pack\";\n+\n \tfor (i = 1; i < argc && *argv[i] == '-'; i++) {\n \t\tconst char *arg = argv[i];\n \n@@ -1039,7 +1047,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \treturn ret;\n }\n \n-struct ref *fetch_pack(struct fetch_pack_args *my_args,\n+struct ref *fetch_pack(struct fetch_pack_args *args,\n \t\t       int fd[], struct child_process *conn,\n \t\t       const struct ref *ref,\n \t\t       const char *dest,\n@@ -1050,9 +1058,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,\n \tstruct ref *ref_cpy;\n \n \tfetch_pack_setup();\n-\tif (&args != my_args)\n-\t\tmemcpy(&args, my_args, sizeof(args));\n-\tif (args.depth > 0) {\n+\tif (args->depth > 0) {\n \t\tif (stat(git_path(\"shallow\"), &st))\n \t\t\tst.st_mtime = 0;\n \t}\n@@ -1066,9 +1072,9 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,\n \t\tpacket_flush(fd[1]);\n \t\tdie(\"no matching remote head\");\n \t}\n-\tref_cpy = do_fetch_pack(fd, ref, sought, pack_lockfile);\n+\tref_cpy = do_fetch_pack(args, fd, ref, sought, pack_lockfile);\n \n-\tif (args.depth > 0) {\n+\tif (args->depth > 0) {\n \t\tstruct cache_time mtime;\n \t\tstruct strbuf sb = STRBUF_INIT;\n \t\tchar *shallow = git_path(\"shallow\");\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"201964","messageId":"1351266835-22610-8-git-send-email-pclouds@gmail.com","threadId":"31911","inReplyTo":"1351266835-22610-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 7/7] fetch-pack: move core code to libgit.a","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-10-26T15:53:55Z","receivedAt":"2012-10-26T15:53:55Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"fetch_pack() is used by transport.c, part of libgit.a while it stays\nin builtin/fetch-pack.c. Move it to fetch-pack.c so that we won't get\nundefined reference if a program that uses libgit.a happens to pull it\nin.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Makefile             |   1 +\n builtin/fetch-pack.c | 949 --------------------------------------------------\n fetch-pack.c         | 951 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 952 insertions(+), 949 deletions(-)\n create mode 100644 fetch-pack.c\n\ndiff --git a/Makefile b/Makefile\nindex 414f15f..2997908 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -745,6 +745,7 @@ LIB_OBJS += editor.o\n LIB_OBJS += entry.o\n LIB_OBJS += environment.o\n LIB_OBJS += exec_cmd.o\n+LIB_OBJS += fetch-pack.o\n LIB_OBJS += fsck.o\n LIB_OBJS += gettext.o\n LIB_OBJS += gpg-interface.o\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex d0fd707..570d26f 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -1,899 +1,11 @@\n #include \"builtin.h\"\n-#include \"refs.h\"\n-#include \"pkt-line.h\"\n-#include \"commit.h\"\n-#include \"tag.h\"\n-#include \"exec_cmd.h\"\n-#include \"pack.h\"\n-#include \"sideband.h\"\n #include \"fetch-pack.h\"\n-#include \"remote.h\"\n-#include \"run-command.h\"\n-#include \"transport.h\"\n-#include \"version.h\"\n-\n-static int transfer_unpack_limit = -1;\n-static int fetch_unpack_limit = -1;\n-static int unpack_limit = 100;\n-static int prefer_ofs_delta = 1;\n-static int no_done;\n-static int fetch_fsck_objects = -1;\n-static int transfer_fsck_objects = -1;\n-static int agent_supported;\n \n static const char fetch_pack_usage[] =\n \"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] \"\n \"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] \"\n \"[--no-progress] [-v] [<host>:]<directory> [<refs>...]\";\n \n-#define COMPLETE\t(1U << 0)\n-#define COMMON\t\t(1U << 1)\n-#define COMMON_REF\t(1U << 2)\n-#define SEEN\t\t(1U << 3)\n-#define POPPED\t\t(1U << 4)\n-\n-static int marked;\n-\n-/*\n- * After sending this many \"have\"s if we do not get any new ACK , we\n- * give up traversing our history.\n- */\n-#define MAX_IN_VAIN 256\n-\n-static struct commit_list *rev_list;\n-static int non_common_revs, multi_ack, use_sideband;\n-\n-static void rev_list_push(struct commit *commit, int mark)\n-{\n-\tif (!(commit->object.flags & mark)) {\n-\t\tcommit->object.flags |= mark;\n-\n-\t\tif (!(commit->object.parsed))\n-\t\t\tif (parse_commit(commit))\n-\t\t\t\treturn;\n-\n-\t\tcommit_list_insert_by_date(commit, &rev_list);\n-\n-\t\tif (!(commit->object.flags & COMMON))\n-\t\t\tnon_common_revs++;\n-\t}\n-}\n-\n-static int rev_list_insert_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n-{\n-\tstruct object *o = deref_tag(parse_object(sha1), refname, 0);\n-\n-\tif (o && o->type == OBJ_COMMIT)\n-\t\trev_list_push((struct commit *)o, SEEN);\n-\n-\treturn 0;\n-}\n-\n-static int clear_marks(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n-{\n-\tstruct object *o = deref_tag(parse_object(sha1), refname, 0);\n-\n-\tif (o && o->type == OBJ_COMMIT)\n-\t\tclear_commit_marks((struct commit *)o,\n-\t\t\t\t   COMMON | COMMON_REF | SEEN | POPPED);\n-\treturn 0;\n-}\n-\n-/*\n-   This function marks a rev and its ancestors as common.\n-   In some cases, it is desirable to mark only the ancestors (for example\n-   when only the server does not yet know that they are common).\n-*/\n-\n-static void mark_common(struct commit *commit,\n-\t\tint ancestors_only, int dont_parse)\n-{\n-\tif (commit != NULL && !(commit->object.flags & COMMON)) {\n-\t\tstruct object *o = (struct object *)commit;\n-\n-\t\tif (!ancestors_only)\n-\t\t\to->flags |= COMMON;\n-\n-\t\tif (!(o->flags & SEEN))\n-\t\t\trev_list_push(commit, SEEN);\n-\t\telse {\n-\t\t\tstruct commit_list *parents;\n-\n-\t\t\tif (!ancestors_only && !(o->flags & POPPED))\n-\t\t\t\tnon_common_revs--;\n-\t\t\tif (!o->parsed && !dont_parse)\n-\t\t\t\tif (parse_commit(commit))\n-\t\t\t\t\treturn;\n-\n-\t\t\tfor (parents = commit->parents;\n-\t\t\t\t\tparents;\n-\t\t\t\t\tparents = parents->next)\n-\t\t\t\tmark_common(parents->item, 0, dont_parse);\n-\t\t}\n-\t}\n-}\n-\n-/*\n-  Get the next rev to send, ignoring the common.\n-*/\n-\n-static const unsigned char *get_rev(void)\n-{\n-\tstruct commit *commit = NULL;\n-\n-\twhile (commit == NULL) {\n-\t\tunsigned int mark;\n-\t\tstruct commit_list *parents;\n-\n-\t\tif (rev_list == NULL || non_common_revs == 0)\n-\t\t\treturn NULL;\n-\n-\t\tcommit = rev_list->item;\n-\t\tif (!commit->object.parsed)\n-\t\t\tparse_commit(commit);\n-\t\tparents = commit->parents;\n-\n-\t\tcommit->object.flags |= POPPED;\n-\t\tif (!(commit->object.flags & COMMON))\n-\t\t\tnon_common_revs--;\n-\n-\t\tif (commit->object.flags & COMMON) {\n-\t\t\t/* do not send \"have\", and ignore ancestors */\n-\t\t\tcommit = NULL;\n-\t\t\tmark = COMMON | SEEN;\n-\t\t} else if (commit->object.flags & COMMON_REF)\n-\t\t\t/* send \"have\", and ignore ancestors */\n-\t\t\tmark = COMMON | SEEN;\n-\t\telse\n-\t\t\t/* send \"have\", also for its ancestors */\n-\t\t\tmark = SEEN;\n-\n-\t\twhile (parents) {\n-\t\t\tif (!(parents->item->object.flags & SEEN))\n-\t\t\t\trev_list_push(parents->item, mark);\n-\t\t\tif (mark & COMMON)\n-\t\t\t\tmark_common(parents->item, 1, 0);\n-\t\t\tparents = parents->next;\n-\t\t}\n-\n-\t\trev_list = rev_list->next;\n-\t}\n-\n-\treturn commit->object.sha1;\n-}\n-\n-enum ack_type {\n-\tNAK = 0,\n-\tACK,\n-\tACK_continue,\n-\tACK_common,\n-\tACK_ready\n-};\n-\n-static void consume_shallow_list(struct fetch_pack_args *args, int fd)\n-{\n-\tif (args->stateless_rpc && args->depth > 0) {\n-\t\t/* If we sent a depth we will get back \"duplicate\"\n-\t\t * shallow and unshallow commands every time there\n-\t\t * is a block of have lines exchanged.\n-\t\t */\n-\t\tchar line[1000];\n-\t\twhile (packet_read_line(fd, line, sizeof(line))) {\n-\t\t\tif (!prefixcmp(line, \"shallow \"))\n-\t\t\t\tcontinue;\n-\t\t\tif (!prefixcmp(line, \"unshallow \"))\n-\t\t\t\tcontinue;\n-\t\t\tdie(\"git fetch-pack: expected shallow list\");\n-\t\t}\n-\t}\n-}\n-\n-struct write_shallow_data {\n-\tstruct strbuf *out;\n-\tint use_pack_protocol;\n-\tint count;\n-};\n-\n-static int write_one_shallow(const struct commit_graft *graft, void *cb_data)\n-{\n-\tstruct write_shallow_data *data = cb_data;\n-\tconst char *hex = sha1_to_hex(graft->sha1);\n-\tdata->count++;\n-\tif (data->use_pack_protocol)\n-\t\tpacket_buf_write(data->out, \"shallow %s\", hex);\n-\telse {\n-\t\tstrbuf_addstr(data->out, hex);\n-\t\tstrbuf_addch(data->out, '\\n');\n-\t}\n-\treturn 0;\n-}\n-\n-static int write_shallow_commits(struct strbuf *out, int use_pack_protocol)\n-{\n-\tstruct write_shallow_data data;\n-\tdata.out = out;\n-\tdata.use_pack_protocol = use_pack_protocol;\n-\tdata.count = 0;\n-\tfor_each_commit_graft(write_one_shallow, &data);\n-\treturn data.count;\n-}\n-\n-static enum ack_type get_ack(int fd, unsigned char *result_sha1)\n-{\n-\tstatic char line[1000];\n-\tint len = packet_read_line(fd, line, sizeof(line));\n-\n-\tif (!len)\n-\t\tdie(\"git fetch-pack: expected ACK/NAK, got EOF\");\n-\tif (line[len-1] == '\\n')\n-\t\tline[--len] = 0;\n-\tif (!strcmp(line, \"NAK\"))\n-\t\treturn NAK;\n-\tif (!prefixcmp(line, \"ACK \")) {\n-\t\tif (!get_sha1_hex(line+4, result_sha1)) {\n-\t\t\tif (strstr(line+45, \"continue\"))\n-\t\t\t\treturn ACK_continue;\n-\t\t\tif (strstr(line+45, \"common\"))\n-\t\t\t\treturn ACK_common;\n-\t\t\tif (strstr(line+45, \"ready\"))\n-\t\t\t\treturn ACK_ready;\n-\t\t\treturn ACK;\n-\t\t}\n-\t}\n-\tdie(\"git fetch_pack: expected ACK/NAK, got '%s'\", line);\n-}\n-\n-static void send_request(struct fetch_pack_args *args,\n-\t\t\t int fd, struct strbuf *buf)\n-{\n-\tif (args->stateless_rpc) {\n-\t\tsend_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX);\n-\t\tpacket_flush(fd);\n-\t} else\n-\t\tsafe_write(fd, buf->buf, buf->len);\n-}\n-\n-static void insert_one_alternate_ref(const struct ref *ref, void *unused)\n-{\n-\trev_list_insert_ref(NULL, ref->old_sha1, 0, NULL);\n-}\n-\n-#define INITIAL_FLUSH 16\n-#define PIPESAFE_FLUSH 32\n-#define LARGE_FLUSH 1024\n-\n-static int next_flush(struct fetch_pack_args *args, int count)\n-{\n-\tint flush_limit = args->stateless_rpc ? LARGE_FLUSH : PIPESAFE_FLUSH;\n-\n-\tif (count < flush_limit)\n-\t\tcount <<= 1;\n-\telse\n-\t\tcount += flush_limit;\n-\treturn count;\n-}\n-\n-static int find_common(struct fetch_pack_args *args,\n-\t\t       int fd[2], unsigned char *result_sha1,\n-\t\t       struct ref *refs)\n-{\n-\tint fetching;\n-\tint count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval;\n-\tconst unsigned char *sha1;\n-\tunsigned in_vain = 0;\n-\tint got_continue = 0;\n-\tint got_ready = 0;\n-\tstruct strbuf req_buf = STRBUF_INIT;\n-\tsize_t state_len = 0;\n-\n-\tif (args->stateless_rpc && multi_ack == 1)\n-\t\tdie(\"--stateless-rpc requires multi_ack_detailed\");\n-\tif (marked)\n-\t\tfor_each_ref(clear_marks, NULL);\n-\tmarked = 1;\n-\n-\tfor_each_ref(rev_list_insert_ref, NULL);\n-\tfor_each_alternate_ref(insert_one_alternate_ref, NULL);\n-\n-\tfetching = 0;\n-\tfor ( ; refs ; refs = refs->next) {\n-\t\tunsigned char *remote = refs->old_sha1;\n-\t\tconst char *remote_hex;\n-\t\tstruct object *o;\n-\n-\t\t/*\n-\t\t * If that object is complete (i.e. it is an ancestor of a\n-\t\t * local ref), we tell them we have it but do not have to\n-\t\t * tell them about its ancestors, which they already know\n-\t\t * about.\n-\t\t *\n-\t\t * We use lookup_object here because we are only\n-\t\t * interested in the case we *know* the object is\n-\t\t * reachable and we have already scanned it.\n-\t\t */\n-\t\tif (((o = lookup_object(remote)) != NULL) &&\n-\t\t\t\t(o->flags & COMPLETE)) {\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tremote_hex = sha1_to_hex(remote);\n-\t\tif (!fetching) {\n-\t\t\tstruct strbuf c = STRBUF_INIT;\n-\t\t\tif (multi_ack == 2)     strbuf_addstr(&c, \" multi_ack_detailed\");\n-\t\t\tif (multi_ack == 1)     strbuf_addstr(&c, \" multi_ack\");\n-\t\t\tif (no_done)            strbuf_addstr(&c, \" no-done\");\n-\t\t\tif (use_sideband == 2)  strbuf_addstr(&c, \" side-band-64k\");\n-\t\t\tif (use_sideband == 1)  strbuf_addstr(&c, \" side-band\");\n-\t\t\tif (args->use_thin_pack) strbuf_addstr(&c, \" thin-pack\");\n-\t\t\tif (args->no_progress)   strbuf_addstr(&c, \" no-progress\");\n-\t\t\tif (args->include_tag)   strbuf_addstr(&c, \" include-tag\");\n-\t\t\tif (prefer_ofs_delta)   strbuf_addstr(&c, \" ofs-delta\");\n-\t\t\tif (agent_supported)    strbuf_addf(&c, \" agent=%s\",\n-\t\t\t\t\t\t\t    git_user_agent_sanitized());\n-\t\t\tpacket_buf_write(&req_buf, \"want %s%s\\n\", remote_hex, c.buf);\n-\t\t\tstrbuf_release(&c);\n-\t\t} else\n-\t\t\tpacket_buf_write(&req_buf, \"want %s\\n\", remote_hex);\n-\t\tfetching++;\n-\t}\n-\n-\tif (!fetching) {\n-\t\tstrbuf_release(&req_buf);\n-\t\tpacket_flush(fd[1]);\n-\t\treturn 1;\n-\t}\n-\n-\tif (is_repository_shallow())\n-\t\twrite_shallow_commits(&req_buf, 1);\n-\tif (args->depth > 0)\n-\t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n-\tpacket_buf_flush(&req_buf);\n-\tstate_len = req_buf.len;\n-\n-\tif (args->depth > 0) {\n-\t\tchar line[1024];\n-\t\tunsigned char sha1[20];\n-\n-\t\tsend_request(args, fd[1], &req_buf);\n-\t\twhile (packet_read_line(fd[0], line, sizeof(line))) {\n-\t\t\tif (!prefixcmp(line, \"shallow \")) {\n-\t\t\t\tif (get_sha1_hex(line + 8, sha1))\n-\t\t\t\t\tdie(\"invalid shallow line: %s\", line);\n-\t\t\t\tregister_shallow(sha1);\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (!prefixcmp(line, \"unshallow \")) {\n-\t\t\t\tif (get_sha1_hex(line + 10, sha1))\n-\t\t\t\t\tdie(\"invalid unshallow line: %s\", line);\n-\t\t\t\tif (!lookup_object(sha1))\n-\t\t\t\t\tdie(\"object not found: %s\", line);\n-\t\t\t\t/* make sure that it is parsed as shallow */\n-\t\t\t\tif (!parse_object(sha1))\n-\t\t\t\t\tdie(\"error in object: %s\", line);\n-\t\t\t\tif (unregister_shallow(sha1))\n-\t\t\t\t\tdie(\"no shallow found: %s\", line);\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tdie(\"expected shallow/unshallow, got %s\", line);\n-\t\t}\n-\t} else if (!args->stateless_rpc)\n-\t\tsend_request(args, fd[1], &req_buf);\n-\n-\tif (!args->stateless_rpc) {\n-\t\t/* If we aren't using the stateless-rpc interface\n-\t\t * we don't need to retain the headers.\n-\t\t */\n-\t\tstrbuf_setlen(&req_buf, 0);\n-\t\tstate_len = 0;\n-\t}\n-\n-\tflushes = 0;\n-\tretval = -1;\n-\twhile ((sha1 = get_rev())) {\n-\t\tpacket_buf_write(&req_buf, \"have %s\\n\", sha1_to_hex(sha1));\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"have %s\\n\", sha1_to_hex(sha1));\n-\t\tin_vain++;\n-\t\tif (flush_at <= ++count) {\n-\t\t\tint ack;\n-\n-\t\t\tpacket_buf_flush(&req_buf);\n-\t\t\tsend_request(args, fd[1], &req_buf);\n-\t\t\tstrbuf_setlen(&req_buf, state_len);\n-\t\t\tflushes++;\n-\t\t\tflush_at = next_flush(args, count);\n-\n-\t\t\t/*\n-\t\t\t * We keep one window \"ahead\" of the other side, and\n-\t\t\t * will wait for an ACK only on the next one\n-\t\t\t */\n-\t\t\tif (!args->stateless_rpc && count == INITIAL_FLUSH)\n-\t\t\t\tcontinue;\n-\n-\t\t\tconsume_shallow_list(args, fd[0]);\n-\t\t\tdo {\n-\t\t\t\tack = get_ack(fd[0], result_sha1);\n-\t\t\t\tif (args->verbose && ack)\n-\t\t\t\t\tfprintf(stderr, \"got ack %d %s\\n\", ack,\n-\t\t\t\t\t\t\tsha1_to_hex(result_sha1));\n-\t\t\t\tswitch (ack) {\n-\t\t\t\tcase ACK:\n-\t\t\t\t\tflushes = 0;\n-\t\t\t\t\tmulti_ack = 0;\n-\t\t\t\t\tretval = 0;\n-\t\t\t\t\tgoto done;\n-\t\t\t\tcase ACK_common:\n-\t\t\t\tcase ACK_ready:\n-\t\t\t\tcase ACK_continue: {\n-\t\t\t\t\tstruct commit *commit =\n-\t\t\t\t\t\tlookup_commit(result_sha1);\n-\t\t\t\t\tif (!commit)\n-\t\t\t\t\t\tdie(\"invalid commit %s\", sha1_to_hex(result_sha1));\n-\t\t\t\t\tif (args->stateless_rpc\n-\t\t\t\t\t && ack == ACK_common\n-\t\t\t\t\t && !(commit->object.flags & COMMON)) {\n-\t\t\t\t\t\t/* We need to replay the have for this object\n-\t\t\t\t\t\t * on the next RPC request so the peer knows\n-\t\t\t\t\t\t * it is in common with us.\n-\t\t\t\t\t\t */\n-\t\t\t\t\t\tconst char *hex = sha1_to_hex(result_sha1);\n-\t\t\t\t\t\tpacket_buf_write(&req_buf, \"have %s\\n\", hex);\n-\t\t\t\t\t\tstate_len = req_buf.len;\n-\t\t\t\t\t}\n-\t\t\t\t\tmark_common(commit, 0, 1);\n-\t\t\t\t\tretval = 0;\n-\t\t\t\t\tin_vain = 0;\n-\t\t\t\t\tgot_continue = 1;\n-\t\t\t\t\tif (ack == ACK_ready) {\n-\t\t\t\t\t\trev_list = NULL;\n-\t\t\t\t\t\tgot_ready = 1;\n-\t\t\t\t\t}\n-\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t} while (ack);\n-\t\t\tflushes--;\n-\t\t\tif (got_continue && MAX_IN_VAIN < in_vain) {\n-\t\t\t\tif (args->verbose)\n-\t\t\t\t\tfprintf(stderr, \"giving up\\n\");\n-\t\t\t\tbreak; /* give up */\n-\t\t\t}\n-\t\t}\n-\t}\n-done:\n-\tif (!got_ready || !no_done) {\n-\t\tpacket_buf_write(&req_buf, \"done\\n\");\n-\t\tsend_request(args, fd[1], &req_buf);\n-\t}\n-\tif (args->verbose)\n-\t\tfprintf(stderr, \"done\\n\");\n-\tif (retval != 0) {\n-\t\tmulti_ack = 0;\n-\t\tflushes++;\n-\t}\n-\tstrbuf_release(&req_buf);\n-\n-\tconsume_shallow_list(args, fd[0]);\n-\twhile (flushes || multi_ack) {\n-\t\tint ack = get_ack(fd[0], result_sha1);\n-\t\tif (ack) {\n-\t\t\tif (args->verbose)\n-\t\t\t\tfprintf(stderr, \"got ack (%d) %s\\n\", ack,\n-\t\t\t\t\tsha1_to_hex(result_sha1));\n-\t\t\tif (ack == ACK)\n-\t\t\t\treturn 0;\n-\t\t\tmulti_ack = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tflushes--;\n-\t}\n-\t/* it is no error to fetch into a completely empty repo */\n-\treturn count ? retval : 0;\n-}\n-\n-static struct commit_list *complete;\n-\n-static int mark_complete(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n-{\n-\tstruct object *o = parse_object(sha1);\n-\n-\twhile (o && o->type == OBJ_TAG) {\n-\t\tstruct tag *t = (struct tag *) o;\n-\t\tif (!t->tagged)\n-\t\t\tbreak; /* broken repository */\n-\t\to->flags |= COMPLETE;\n-\t\to = parse_object(t->tagged->sha1);\n-\t}\n-\tif (o && o->type == OBJ_COMMIT) {\n-\t\tstruct commit *commit = (struct commit *)o;\n-\t\tif (!(commit->object.flags & COMPLETE)) {\n-\t\t\tcommit->object.flags |= COMPLETE;\n-\t\t\tcommit_list_insert_by_date(commit, &complete);\n-\t\t}\n-\t}\n-\treturn 0;\n-}\n-\n-static void mark_recent_complete_commits(struct fetch_pack_args *args,\n-\t\t\t\t\t unsigned long cutoff)\n-{\n-\twhile (complete && cutoff <= complete->item->date) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Marking %s as complete\\n\",\n-\t\t\t\tsha1_to_hex(complete->item->object.sha1));\n-\t\tpop_most_recent_commit(&complete, COMPLETE);\n-\t}\n-}\n-\n-static int non_matching_ref(struct string_list_item *item, void *unused)\n-{\n-\tif (item->util) {\n-\t\titem->util = NULL;\n-\t\treturn 0;\n-\t}\n-\telse\n-\t\treturn 1;\n-}\n-\n-static void filter_refs(struct fetch_pack_args *args,\n-\t\t\tstruct ref **refs, struct string_list *sought)\n-{\n-\tstruct ref *newlist = NULL;\n-\tstruct ref **newtail = &newlist;\n-\tstruct ref *ref, *next;\n-\tint sought_pos;\n-\n-\tsought_pos = 0;\n-\tfor (ref = *refs; ref; ref = next) {\n-\t\tint keep = 0;\n-\t\tnext = ref->next;\n-\t\tif (!memcmp(ref->name, \"refs/\", 5) &&\n-\t\t    check_refname_format(ref->name + 5, 0))\n-\t\t\t; /* trash */\n-\t\telse {\n-\t\t\twhile (sought_pos < sought->nr) {\n-\t\t\t\tint cmp = strcmp(ref->name, sought->items[sought_pos].string);\n-\t\t\t\tif (cmp < 0)\n-\t\t\t\t\tbreak; /* definitely do not have it */\n-\t\t\t\telse if (cmp == 0) {\n-\t\t\t\t\tkeep = 1; /* definitely have it */\n-\t\t\t\t\tsought->items[sought_pos++].util = \"matched\";\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t\telse\n-\t\t\t\t\tsought_pos++; /* might have it; keep looking */\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (! keep && args->fetch_all &&\n-\t\t    (!args->depth || prefixcmp(ref->name, \"refs/tags/\")))\n-\t\t\tkeep = 1;\n-\n-\t\tif (keep) {\n-\t\t\t*newtail = ref;\n-\t\t\tref->next = NULL;\n-\t\t\tnewtail = &ref->next;\n-\t\t} else {\n-\t\t\tfree(ref);\n-\t\t}\n-\t}\n-\n-\tfilter_string_list(sought, 0, non_matching_ref, NULL);\n-\t*refs = newlist;\n-}\n-\n-static void mark_alternate_complete(const struct ref *ref, void *unused)\n-{\n-\tmark_complete(NULL, ref->old_sha1, 0, NULL);\n-}\n-\n-static int everything_local(struct fetch_pack_args *args,\n-\t\t\t    struct ref **refs, struct string_list *sought)\n-{\n-\tstruct ref *ref;\n-\tint retval;\n-\tunsigned long cutoff = 0;\n-\n-\tsave_commit_buffer = 0;\n-\n-\tfor (ref = *refs; ref; ref = ref->next) {\n-\t\tstruct object *o;\n-\n-\t\to = parse_object(ref->old_sha1);\n-\t\tif (!o)\n-\t\t\tcontinue;\n-\n-\t\t/* We already have it -- which may mean that we were\n-\t\t * in sync with the other side at some time after\n-\t\t * that (it is OK if we guess wrong here).\n-\t\t */\n-\t\tif (o->type == OBJ_COMMIT) {\n-\t\t\tstruct commit *commit = (struct commit *)o;\n-\t\t\tif (!cutoff || cutoff < commit->date)\n-\t\t\t\tcutoff = commit->date;\n-\t\t}\n-\t}\n-\n-\tif (!args->depth) {\n-\t\tfor_each_ref(mark_complete, NULL);\n-\t\tfor_each_alternate_ref(mark_alternate_complete, NULL);\n-\t\tif (cutoff)\n-\t\t\tmark_recent_complete_commits(args, cutoff);\n-\t}\n-\n-\t/*\n-\t * Mark all complete remote refs as common refs.\n-\t * Don't mark them common yet; the server has to be told so first.\n-\t */\n-\tfor (ref = *refs; ref; ref = ref->next) {\n-\t\tstruct object *o = deref_tag(lookup_object(ref->old_sha1),\n-\t\t\t\t\t     NULL, 0);\n-\n-\t\tif (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))\n-\t\t\tcontinue;\n-\n-\t\tif (!(o->flags & SEEN)) {\n-\t\t\trev_list_push((struct commit *)o, COMMON_REF | SEEN);\n-\n-\t\t\tmark_common((struct commit *)o, 1, 1);\n-\t\t}\n-\t}\n-\n-\tfilter_refs(args, refs, sought);\n-\n-\tfor (retval = 1, ref = *refs; ref ; ref = ref->next) {\n-\t\tconst unsigned char *remote = ref->old_sha1;\n-\t\tunsigned char local[20];\n-\t\tstruct object *o;\n-\n-\t\to = lookup_object(remote);\n-\t\tif (!o || !(o->flags & COMPLETE)) {\n-\t\t\tretval = 0;\n-\t\t\tif (!args->verbose)\n-\t\t\t\tcontinue;\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"want %s (%s)\\n\", sha1_to_hex(remote),\n-\t\t\t\tref->name);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\thashcpy(ref->new_sha1, local);\n-\t\tif (!args->verbose)\n-\t\t\tcontinue;\n-\t\tfprintf(stderr,\n-\t\t\t\"already have %s (%s)\\n\", sha1_to_hex(remote),\n-\t\t\tref->name);\n-\t}\n-\treturn retval;\n-}\n-\n-static int sideband_demux(int in, int out, void *data)\n-{\n-\tint *xd = data;\n-\n-\tint ret = recv_sideband(\"fetch-pack\", xd[0], out);\n-\tclose(out);\n-\treturn ret;\n-}\n-\n-static int get_pack(struct fetch_pack_args *args,\n-\t\t    int xd[2], char **pack_lockfile)\n-{\n-\tstruct async demux;\n-\tconst char *argv[20];\n-\tchar keep_arg[256];\n-\tchar hdr_arg[256];\n-\tconst char **av;\n-\tint do_keep = args->keep_pack;\n-\tstruct child_process cmd;\n-\n-\tmemset(&demux, 0, sizeof(demux));\n-\tif (use_sideband) {\n-\t\t/* xd[] is talking with upload-pack; subprocess reads from\n-\t\t * xd[0], spits out band#2 to stderr, and feeds us band#1\n-\t\t * through demux->out.\n-\t\t */\n-\t\tdemux.proc = sideband_demux;\n-\t\tdemux.data = xd;\n-\t\tdemux.out = -1;\n-\t\tif (start_async(&demux))\n-\t\t\tdie(\"fetch-pack: unable to fork off sideband\"\n-\t\t\t    \" demultiplexer\");\n-\t}\n-\telse\n-\t\tdemux.out = xd[0];\n-\n-\tmemset(&cmd, 0, sizeof(cmd));\n-\tcmd.argv = argv;\n-\tav = argv;\n-\t*hdr_arg = 0;\n-\tif (!args->keep_pack && unpack_limit) {\n-\t\tstruct pack_header header;\n-\n-\t\tif (read_pack_header(demux.out, &header))\n-\t\t\tdie(\"protocol error: bad pack header\");\n-\t\tsnprintf(hdr_arg, sizeof(hdr_arg),\n-\t\t\t \"--pack_header=%\"PRIu32\",%\"PRIu32,\n-\t\t\t ntohl(header.hdr_version), ntohl(header.hdr_entries));\n-\t\tif (ntohl(header.hdr_entries) < unpack_limit)\n-\t\t\tdo_keep = 0;\n-\t\telse\n-\t\t\tdo_keep = 1;\n-\t}\n-\n-\tif (do_keep) {\n-\t\tif (pack_lockfile)\n-\t\t\tcmd.out = -1;\n-\t\t*av++ = \"index-pack\";\n-\t\t*av++ = \"--stdin\";\n-\t\tif (!args->quiet && !args->no_progress)\n-\t\t\t*av++ = \"-v\";\n-\t\tif (args->use_thin_pack)\n-\t\t\t*av++ = \"--fix-thin\";\n-\t\tif (args->lock_pack || unpack_limit) {\n-\t\t\tint s = sprintf(keep_arg,\n-\t\t\t\t\t\"--keep=fetch-pack %\"PRIuMAX \" on \", (uintmax_t) getpid());\n-\t\t\tif (gethostname(keep_arg + s, sizeof(keep_arg) - s))\n-\t\t\t\tstrcpy(keep_arg + s, \"localhost\");\n-\t\t\t*av++ = keep_arg;\n-\t\t}\n-\t}\n-\telse {\n-\t\t*av++ = \"unpack-objects\";\n-\t\tif (args->quiet || args->no_progress)\n-\t\t\t*av++ = \"-q\";\n-\t}\n-\tif (*hdr_arg)\n-\t\t*av++ = hdr_arg;\n-\tif (fetch_fsck_objects >= 0\n-\t    ? fetch_fsck_objects\n-\t    : transfer_fsck_objects >= 0\n-\t    ? transfer_fsck_objects\n-\t    : 0)\n-\t\t*av++ = \"--strict\";\n-\t*av++ = NULL;\n-\n-\tcmd.in = demux.out;\n-\tcmd.git_cmd = 1;\n-\tif (start_command(&cmd))\n-\t\tdie(\"fetch-pack: unable to fork off %s\", argv[0]);\n-\tif (do_keep && pack_lockfile) {\n-\t\t*pack_lockfile = index_pack_lockfile(cmd.out);\n-\t\tclose(cmd.out);\n-\t}\n-\n-\tif (finish_command(&cmd))\n-\t\tdie(\"%s failed\", argv[0]);\n-\tif (use_sideband && finish_async(&demux))\n-\t\tdie(\"error in sideband demultiplexer\");\n-\treturn 0;\n-}\n-\n-static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n-\t\t\t\t int fd[2],\n-\t\t\t\t const struct ref *orig_ref,\n-\t\t\t\t struct string_list *sought,\n-\t\t\t\t char **pack_lockfile)\n-{\n-\tstruct ref *ref = copy_ref_list(orig_ref);\n-\tunsigned char sha1[20];\n-\tconst char *agent_feature;\n-\tint agent_len;\n-\n-\tsort_ref_list(&ref, ref_compare_name);\n-\n-\tif (is_repository_shallow() && !server_supports(\"shallow\"))\n-\t\tdie(\"Server does not support shallow clients\");\n-\tif (server_supports(\"multi_ack_detailed\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports multi_ack_detailed\\n\");\n-\t\tmulti_ack = 2;\n-\t\tif (server_supports(\"no-done\")) {\n-\t\t\tif (args->verbose)\n-\t\t\t\tfprintf(stderr, \"Server supports no-done\\n\");\n-\t\t\tif (args->stateless_rpc)\n-\t\t\t\tno_done = 1;\n-\t\t}\n-\t}\n-\telse if (server_supports(\"multi_ack\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports multi_ack\\n\");\n-\t\tmulti_ack = 1;\n-\t}\n-\tif (server_supports(\"side-band-64k\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports side-band-64k\\n\");\n-\t\tuse_sideband = 2;\n-\t}\n-\telse if (server_supports(\"side-band\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports side-band\\n\");\n-\t\tuse_sideband = 1;\n-\t}\n-\tif (!server_supports(\"thin-pack\"))\n-\t\targs->use_thin_pack = 0;\n-\tif (!server_supports(\"no-progress\"))\n-\t\targs->no_progress = 0;\n-\tif (!server_supports(\"include-tag\"))\n-\t\targs->include_tag = 0;\n-\tif (server_supports(\"ofs-delta\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports ofs-delta\\n\");\n-\t} else\n-\t\tprefer_ofs_delta = 0;\n-\n-\tif ((agent_feature = server_feature_value(\"agent\", &agent_len))) {\n-\t\tagent_supported = 1;\n-\t\tif (args->verbose && agent_len)\n-\t\t\tfprintf(stderr, \"Server version is %.*s\\n\",\n-\t\t\t\tagent_len, agent_feature);\n-\t}\n-\n-\tif (everything_local(args, &ref, sought)) {\n-\t\tpacket_flush(fd[1]);\n-\t\tgoto all_done;\n-\t}\n-\tif (find_common(args, fd, sha1, ref) < 0)\n-\t\tif (!args->keep_pack)\n-\t\t\t/* When cloning, it is not unusual to have\n-\t\t\t * no common commit.\n-\t\t\t */\n-\t\t\twarning(\"no common commits\");\n-\n-\tif (args->stateless_rpc)\n-\t\tpacket_flush(fd[1]);\n-\tif (get_pack(args, fd, pack_lockfile))\n-\t\tdie(\"git fetch-pack: fetch failed.\");\n-\n- all_done:\n-\treturn ref;\n-}\n-\n-static int fetch_pack_config(const char *var, const char *value, void *cb)\n-{\n-\tif (strcmp(var, \"fetch.unpacklimit\") == 0) {\n-\t\tfetch_unpack_limit = git_config_int(var, value);\n-\t\treturn 0;\n-\t}\n-\n-\tif (strcmp(var, \"transfer.unpacklimit\") == 0) {\n-\t\ttransfer_unpack_limit = git_config_int(var, value);\n-\t\treturn 0;\n-\t}\n-\n-\tif (strcmp(var, \"repack.usedeltabaseoffset\") == 0) {\n-\t\tprefer_ofs_delta = git_config_bool(var, value);\n-\t\treturn 0;\n-\t}\n-\n-\tif (!strcmp(var, \"fetch.fsckobjects\")) {\n-\t\tfetch_fsck_objects = git_config_bool(var, value);\n-\t\treturn 0;\n-\t}\n-\n-\tif (!strcmp(var, \"transfer.fsckobjects\")) {\n-\t\ttransfer_fsck_objects = git_config_bool(var, value);\n-\t\treturn 0;\n-\t}\n-\n-\treturn git_default_config(var, value, cb);\n-}\n-\n-static struct lock_file lock;\n-\n-static void fetch_pack_setup(void)\n-{\n-\tstatic int did_setup;\n-\tif (did_setup)\n-\t\treturn;\n-\tgit_config(fetch_pack_config, NULL);\n-\tif (0 <= transfer_unpack_limit)\n-\t\tunpack_limit = transfer_unpack_limit;\n-\telse if (0 <= fetch_unpack_limit)\n-\t\tunpack_limit = fetch_unpack_limit;\n-\tdid_setup = 1;\n-}\n-\n int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n {\n \tint i, ret;\n@@ -1046,64 +158,3 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \n \treturn ret;\n }\n-\n-struct ref *fetch_pack(struct fetch_pack_args *args,\n-\t\t       int fd[], struct child_process *conn,\n-\t\t       const struct ref *ref,\n-\t\t       const char *dest,\n-\t\t       struct string_list *sought,\n-\t\t       char **pack_lockfile)\n-{\n-\tstruct stat st;\n-\tstruct ref *ref_cpy;\n-\n-\tfetch_pack_setup();\n-\tif (args->depth > 0) {\n-\t\tif (stat(git_path(\"shallow\"), &st))\n-\t\t\tst.st_mtime = 0;\n-\t}\n-\n-\tif (sought->nr) {\n-\t\tsort_string_list(sought);\n-\t\tstring_list_remove_duplicates(sought, 0);\n-\t}\n-\n-\tif (!ref) {\n-\t\tpacket_flush(fd[1]);\n-\t\tdie(\"no matching remote head\");\n-\t}\n-\tref_cpy = do_fetch_pack(args, fd, ref, sought, pack_lockfile);\n-\n-\tif (args->depth > 0) {\n-\t\tstruct cache_time mtime;\n-\t\tstruct strbuf sb = STRBUF_INIT;\n-\t\tchar *shallow = git_path(\"shallow\");\n-\t\tint fd;\n-\n-\t\tmtime.sec = st.st_mtime;\n-\t\tmtime.nsec = ST_MTIME_NSEC(st);\n-\t\tif (stat(shallow, &st)) {\n-\t\t\tif (mtime.sec)\n-\t\t\t\tdie(\"shallow file was removed during fetch\");\n-\t\t} else if (st.st_mtime != mtime.sec\n-#ifdef USE_NSEC\n-\t\t\t\t|| ST_MTIME_NSEC(st) != mtime.nsec\n-#endif\n-\t\t\t  )\n-\t\t\tdie(\"shallow file was changed during fetch\");\n-\n-\t\tfd = hold_lock_file_for_update(&lock, shallow,\n-\t\t\t\t\t       LOCK_DIE_ON_ERROR);\n-\t\tif (!write_shallow_commits(&sb, 0)\n-\t\t || write_in_full(fd, sb.buf, sb.len) != sb.len) {\n-\t\t\tunlink_or_warn(shallow);\n-\t\t\trollback_lock_file(&lock);\n-\t\t} else {\n-\t\t\tcommit_lock_file(&lock);\n-\t\t}\n-\t\tstrbuf_release(&sb);\n-\t}\n-\n-\treprepare_packed_git();\n-\treturn ref_cpy;\n-}\ndiff --git a/fetch-pack.c b/fetch-pack.c\nnew file mode 100644\nindex 0000000..099ff4d\n--- /dev/null\n+++ b/fetch-pack.c\n@@ -0,0 +1,951 @@\n+#include \"cache.h\"\n+#include \"refs.h\"\n+#include \"pkt-line.h\"\n+#include \"commit.h\"\n+#include \"tag.h\"\n+#include \"exec_cmd.h\"\n+#include \"pack.h\"\n+#include \"sideband.h\"\n+#include \"fetch-pack.h\"\n+#include \"remote.h\"\n+#include \"run-command.h\"\n+#include \"transport.h\"\n+#include \"version.h\"\n+\n+static int transfer_unpack_limit = -1;\n+static int fetch_unpack_limit = -1;\n+static int unpack_limit = 100;\n+static int prefer_ofs_delta = 1;\n+static int no_done;\n+static int fetch_fsck_objects = -1;\n+static int transfer_fsck_objects = -1;\n+static int agent_supported;\n+\n+#define COMPLETE\t(1U << 0)\n+#define COMMON\t\t(1U << 1)\n+#define COMMON_REF\t(1U << 2)\n+#define SEEN\t\t(1U << 3)\n+#define POPPED\t\t(1U << 4)\n+\n+static int marked;\n+\n+/*\n+ * After sending this many \"have\"s if we do not get any new ACK , we\n+ * give up traversing our history.\n+ */\n+#define MAX_IN_VAIN 256\n+\n+static struct commit_list *rev_list;\n+static int non_common_revs, multi_ack, use_sideband;\n+\n+static void rev_list_push(struct commit *commit, int mark)\n+{\n+\tif (!(commit->object.flags & mark)) {\n+\t\tcommit->object.flags |= mark;\n+\n+\t\tif (!(commit->object.parsed))\n+\t\t\tif (parse_commit(commit))\n+\t\t\t\treturn;\n+\n+\t\tcommit_list_insert_by_date(commit, &rev_list);\n+\n+\t\tif (!(commit->object.flags & COMMON))\n+\t\t\tnon_common_revs++;\n+\t}\n+}\n+\n+static int rev_list_insert_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n+{\n+\tstruct object *o = deref_tag(parse_object(sha1), refname, 0);\n+\n+\tif (o && o->type == OBJ_COMMIT)\n+\t\trev_list_push((struct commit *)o, SEEN);\n+\n+\treturn 0;\n+}\n+\n+static int clear_marks(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n+{\n+\tstruct object *o = deref_tag(parse_object(sha1), refname, 0);\n+\n+\tif (o && o->type == OBJ_COMMIT)\n+\t\tclear_commit_marks((struct commit *)o,\n+\t\t\t\t   COMMON | COMMON_REF | SEEN | POPPED);\n+\treturn 0;\n+}\n+\n+/*\n+   This function marks a rev and its ancestors as common.\n+   In some cases, it is desirable to mark only the ancestors (for example\n+   when only the server does not yet know that they are common).\n+*/\n+\n+static void mark_common(struct commit *commit,\n+\t\tint ancestors_only, int dont_parse)\n+{\n+\tif (commit != NULL && !(commit->object.flags & COMMON)) {\n+\t\tstruct object *o = (struct object *)commit;\n+\n+\t\tif (!ancestors_only)\n+\t\t\to->flags |= COMMON;\n+\n+\t\tif (!(o->flags & SEEN))\n+\t\t\trev_list_push(commit, SEEN);\n+\t\telse {\n+\t\t\tstruct commit_list *parents;\n+\n+\t\t\tif (!ancestors_only && !(o->flags & POPPED))\n+\t\t\t\tnon_common_revs--;\n+\t\t\tif (!o->parsed && !dont_parse)\n+\t\t\t\tif (parse_commit(commit))\n+\t\t\t\t\treturn;\n+\n+\t\t\tfor (parents = commit->parents;\n+\t\t\t\t\tparents;\n+\t\t\t\t\tparents = parents->next)\n+\t\t\t\tmark_common(parents->item, 0, dont_parse);\n+\t\t}\n+\t}\n+}\n+\n+/*\n+  Get the next rev to send, ignoring the common.\n+*/\n+\n+static const unsigned char *get_rev(void)\n+{\n+\tstruct commit *commit = NULL;\n+\n+\twhile (commit == NULL) {\n+\t\tunsigned int mark;\n+\t\tstruct commit_list *parents;\n+\n+\t\tif (rev_list == NULL || non_common_revs == 0)\n+\t\t\treturn NULL;\n+\n+\t\tcommit = rev_list->item;\n+\t\tif (!commit->object.parsed)\n+\t\t\tparse_commit(commit);\n+\t\tparents = commit->parents;\n+\n+\t\tcommit->object.flags |= POPPED;\n+\t\tif (!(commit->object.flags & COMMON))\n+\t\t\tnon_common_revs--;\n+\n+\t\tif (commit->object.flags & COMMON) {\n+\t\t\t/* do not send \"have\", and ignore ancestors */\n+\t\t\tcommit = NULL;\n+\t\t\tmark = COMMON | SEEN;\n+\t\t} else if (commit->object.flags & COMMON_REF)\n+\t\t\t/* send \"have\", and ignore ancestors */\n+\t\t\tmark = COMMON | SEEN;\n+\t\telse\n+\t\t\t/* send \"have\", also for its ancestors */\n+\t\t\tmark = SEEN;\n+\n+\t\twhile (parents) {\n+\t\t\tif (!(parents->item->object.flags & SEEN))\n+\t\t\t\trev_list_push(parents->item, mark);\n+\t\t\tif (mark & COMMON)\n+\t\t\t\tmark_common(parents->item, 1, 0);\n+\t\t\tparents = parents->next;\n+\t\t}\n+\n+\t\trev_list = rev_list->next;\n+\t}\n+\n+\treturn commit->object.sha1;\n+}\n+\n+enum ack_type {\n+\tNAK = 0,\n+\tACK,\n+\tACK_continue,\n+\tACK_common,\n+\tACK_ready\n+};\n+\n+static void consume_shallow_list(struct fetch_pack_args *args, int fd)\n+{\n+\tif (args->stateless_rpc && args->depth > 0) {\n+\t\t/* If we sent a depth we will get back \"duplicate\"\n+\t\t * shallow and unshallow commands every time there\n+\t\t * is a block of have lines exchanged.\n+\t\t */\n+\t\tchar line[1000];\n+\t\twhile (packet_read_line(fd, line, sizeof(line))) {\n+\t\t\tif (!prefixcmp(line, \"shallow \"))\n+\t\t\t\tcontinue;\n+\t\t\tif (!prefixcmp(line, \"unshallow \"))\n+\t\t\t\tcontinue;\n+\t\t\tdie(\"git fetch-pack: expected shallow list\");\n+\t\t}\n+\t}\n+}\n+\n+struct write_shallow_data {\n+\tstruct strbuf *out;\n+\tint use_pack_protocol;\n+\tint count;\n+};\n+\n+static int write_one_shallow(const struct commit_graft *graft, void *cb_data)\n+{\n+\tstruct write_shallow_data *data = cb_data;\n+\tconst char *hex = sha1_to_hex(graft->sha1);\n+\tdata->count++;\n+\tif (data->use_pack_protocol)\n+\t\tpacket_buf_write(data->out, \"shallow %s\", hex);\n+\telse {\n+\t\tstrbuf_addstr(data->out, hex);\n+\t\tstrbuf_addch(data->out, '\\n');\n+\t}\n+\treturn 0;\n+}\n+\n+static int write_shallow_commits(struct strbuf *out, int use_pack_protocol)\n+{\n+\tstruct write_shallow_data data;\n+\tdata.out = out;\n+\tdata.use_pack_protocol = use_pack_protocol;\n+\tdata.count = 0;\n+\tfor_each_commit_graft(write_one_shallow, &data);\n+\treturn data.count;\n+}\n+\n+static enum ack_type get_ack(int fd, unsigned char *result_sha1)\n+{\n+\tstatic char line[1000];\n+\tint len = packet_read_line(fd, line, sizeof(line));\n+\n+\tif (!len)\n+\t\tdie(\"git fetch-pack: expected ACK/NAK, got EOF\");\n+\tif (line[len-1] == '\\n')\n+\t\tline[--len] = 0;\n+\tif (!strcmp(line, \"NAK\"))\n+\t\treturn NAK;\n+\tif (!prefixcmp(line, \"ACK \")) {\n+\t\tif (!get_sha1_hex(line+4, result_sha1)) {\n+\t\t\tif (strstr(line+45, \"continue\"))\n+\t\t\t\treturn ACK_continue;\n+\t\t\tif (strstr(line+45, \"common\"))\n+\t\t\t\treturn ACK_common;\n+\t\t\tif (strstr(line+45, \"ready\"))\n+\t\t\t\treturn ACK_ready;\n+\t\t\treturn ACK;\n+\t\t}\n+\t}\n+\tdie(\"git fetch_pack: expected ACK/NAK, got '%s'\", line);\n+}\n+\n+static void send_request(struct fetch_pack_args *args,\n+\t\t\t int fd, struct strbuf *buf)\n+{\n+\tif (args->stateless_rpc) {\n+\t\tsend_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX);\n+\t\tpacket_flush(fd);\n+\t} else\n+\t\tsafe_write(fd, buf->buf, buf->len);\n+}\n+\n+static void insert_one_alternate_ref(const struct ref *ref, void *unused)\n+{\n+\trev_list_insert_ref(NULL, ref->old_sha1, 0, NULL);\n+}\n+\n+#define INITIAL_FLUSH 16\n+#define PIPESAFE_FLUSH 32\n+#define LARGE_FLUSH 1024\n+\n+static int next_flush(struct fetch_pack_args *args, int count)\n+{\n+\tint flush_limit = args->stateless_rpc ? LARGE_FLUSH : PIPESAFE_FLUSH;\n+\n+\tif (count < flush_limit)\n+\t\tcount <<= 1;\n+\telse\n+\t\tcount += flush_limit;\n+\treturn count;\n+}\n+\n+static int find_common(struct fetch_pack_args *args,\n+\t\t       int fd[2], unsigned char *result_sha1,\n+\t\t       struct ref *refs)\n+{\n+\tint fetching;\n+\tint count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval;\n+\tconst unsigned char *sha1;\n+\tunsigned in_vain = 0;\n+\tint got_continue = 0;\n+\tint got_ready = 0;\n+\tstruct strbuf req_buf = STRBUF_INIT;\n+\tsize_t state_len = 0;\n+\n+\tif (args->stateless_rpc && multi_ack == 1)\n+\t\tdie(\"--stateless-rpc requires multi_ack_detailed\");\n+\tif (marked)\n+\t\tfor_each_ref(clear_marks, NULL);\n+\tmarked = 1;\n+\n+\tfor_each_ref(rev_list_insert_ref, NULL);\n+\tfor_each_alternate_ref(insert_one_alternate_ref, NULL);\n+\n+\tfetching = 0;\n+\tfor ( ; refs ; refs = refs->next) {\n+\t\tunsigned char *remote = refs->old_sha1;\n+\t\tconst char *remote_hex;\n+\t\tstruct object *o;\n+\n+\t\t/*\n+\t\t * If that object is complete (i.e. it is an ancestor of a\n+\t\t * local ref), we tell them we have it but do not have to\n+\t\t * tell them about its ancestors, which they already know\n+\t\t * about.\n+\t\t *\n+\t\t * We use lookup_object here because we are only\n+\t\t * interested in the case we *know* the object is\n+\t\t * reachable and we have already scanned it.\n+\t\t */\n+\t\tif (((o = lookup_object(remote)) != NULL) &&\n+\t\t\t\t(o->flags & COMPLETE)) {\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tremote_hex = sha1_to_hex(remote);\n+\t\tif (!fetching) {\n+\t\t\tstruct strbuf c = STRBUF_INIT;\n+\t\t\tif (multi_ack == 2)     strbuf_addstr(&c, \" multi_ack_detailed\");\n+\t\t\tif (multi_ack == 1)     strbuf_addstr(&c, \" multi_ack\");\n+\t\t\tif (no_done)            strbuf_addstr(&c, \" no-done\");\n+\t\t\tif (use_sideband == 2)  strbuf_addstr(&c, \" side-band-64k\");\n+\t\t\tif (use_sideband == 1)  strbuf_addstr(&c, \" side-band\");\n+\t\t\tif (args->use_thin_pack) strbuf_addstr(&c, \" thin-pack\");\n+\t\t\tif (args->no_progress)   strbuf_addstr(&c, \" no-progress\");\n+\t\t\tif (args->include_tag)   strbuf_addstr(&c, \" include-tag\");\n+\t\t\tif (prefer_ofs_delta)   strbuf_addstr(&c, \" ofs-delta\");\n+\t\t\tif (agent_supported)    strbuf_addf(&c, \" agent=%s\",\n+\t\t\t\t\t\t\t    git_user_agent_sanitized());\n+\t\t\tpacket_buf_write(&req_buf, \"want %s%s\\n\", remote_hex, c.buf);\n+\t\t\tstrbuf_release(&c);\n+\t\t} else\n+\t\t\tpacket_buf_write(&req_buf, \"want %s\\n\", remote_hex);\n+\t\tfetching++;\n+\t}\n+\n+\tif (!fetching) {\n+\t\tstrbuf_release(&req_buf);\n+\t\tpacket_flush(fd[1]);\n+\t\treturn 1;\n+\t}\n+\n+\tif (is_repository_shallow())\n+\t\twrite_shallow_commits(&req_buf, 1);\n+\tif (args->depth > 0)\n+\t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n+\tpacket_buf_flush(&req_buf);\n+\tstate_len = req_buf.len;\n+\n+\tif (args->depth > 0) {\n+\t\tchar line[1024];\n+\t\tunsigned char sha1[20];\n+\n+\t\tsend_request(args, fd[1], &req_buf);\n+\t\twhile (packet_read_line(fd[0], line, sizeof(line))) {\n+\t\t\tif (!prefixcmp(line, \"shallow \")) {\n+\t\t\t\tif (get_sha1_hex(line + 8, sha1))\n+\t\t\t\t\tdie(\"invalid shallow line: %s\", line);\n+\t\t\t\tregister_shallow(sha1);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!prefixcmp(line, \"unshallow \")) {\n+\t\t\t\tif (get_sha1_hex(line + 10, sha1))\n+\t\t\t\t\tdie(\"invalid unshallow line: %s\", line);\n+\t\t\t\tif (!lookup_object(sha1))\n+\t\t\t\t\tdie(\"object not found: %s\", line);\n+\t\t\t\t/* make sure that it is parsed as shallow */\n+\t\t\t\tif (!parse_object(sha1))\n+\t\t\t\t\tdie(\"error in object: %s\", line);\n+\t\t\t\tif (unregister_shallow(sha1))\n+\t\t\t\t\tdie(\"no shallow found: %s\", line);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tdie(\"expected shallow/unshallow, got %s\", line);\n+\t\t}\n+\t} else if (!args->stateless_rpc)\n+\t\tsend_request(args, fd[1], &req_buf);\n+\n+\tif (!args->stateless_rpc) {\n+\t\t/* If we aren't using the stateless-rpc interface\n+\t\t * we don't need to retain the headers.\n+\t\t */\n+\t\tstrbuf_setlen(&req_buf, 0);\n+\t\tstate_len = 0;\n+\t}\n+\n+\tflushes = 0;\n+\tretval = -1;\n+\twhile ((sha1 = get_rev())) {\n+\t\tpacket_buf_write(&req_buf, \"have %s\\n\", sha1_to_hex(sha1));\n+\t\tif (args->verbose)\n+\t\t\tfprintf(stderr, \"have %s\\n\", sha1_to_hex(sha1));\n+\t\tin_vain++;\n+\t\tif (flush_at <= ++count) {\n+\t\t\tint ack;\n+\n+\t\t\tpacket_buf_flush(&req_buf);\n+\t\t\tsend_request(args, fd[1], &req_buf);\n+\t\t\tstrbuf_setlen(&req_buf, state_len);\n+\t\t\tflushes++;\n+\t\t\tflush_at = next_flush(args, count);\n+\n+\t\t\t/*\n+\t\t\t * We keep one window \"ahead\" of the other side, and\n+\t\t\t * will wait for an ACK only on the next one\n+\t\t\t */\n+\t\t\tif (!args->stateless_rpc && count == INITIAL_FLUSH)\n+\t\t\t\tcontinue;\n+\n+\t\t\tconsume_shallow_list(args, fd[0]);\n+\t\t\tdo {\n+\t\t\t\tack = get_ack(fd[0], result_sha1);\n+\t\t\t\tif (args->verbose && ack)\n+\t\t\t\t\tfprintf(stderr, \"got ack %d %s\\n\", ack,\n+\t\t\t\t\t\t\tsha1_to_hex(result_sha1));\n+\t\t\t\tswitch (ack) {\n+\t\t\t\tcase ACK:\n+\t\t\t\t\tflushes = 0;\n+\t\t\t\t\tmulti_ack = 0;\n+\t\t\t\t\tretval = 0;\n+\t\t\t\t\tgoto done;\n+\t\t\t\tcase ACK_common:\n+\t\t\t\tcase ACK_ready:\n+\t\t\t\tcase ACK_continue: {\n+\t\t\t\t\tstruct commit *commit =\n+\t\t\t\t\t\tlookup_commit(result_sha1);\n+\t\t\t\t\tif (!commit)\n+\t\t\t\t\t\tdie(\"invalid commit %s\", sha1_to_hex(result_sha1));\n+\t\t\t\t\tif (args->stateless_rpc\n+\t\t\t\t\t && ack == ACK_common\n+\t\t\t\t\t && !(commit->object.flags & COMMON)) {\n+\t\t\t\t\t\t/* We need to replay the have for this object\n+\t\t\t\t\t\t * on the next RPC request so the peer knows\n+\t\t\t\t\t\t * it is in common with us.\n+\t\t\t\t\t\t */\n+\t\t\t\t\t\tconst char *hex = sha1_to_hex(result_sha1);\n+\t\t\t\t\t\tpacket_buf_write(&req_buf, \"have %s\\n\", hex);\n+\t\t\t\t\t\tstate_len = req_buf.len;\n+\t\t\t\t\t}\n+\t\t\t\t\tmark_common(commit, 0, 1);\n+\t\t\t\t\tretval = 0;\n+\t\t\t\t\tin_vain = 0;\n+\t\t\t\t\tgot_continue = 1;\n+\t\t\t\t\tif (ack == ACK_ready) {\n+\t\t\t\t\t\trev_list = NULL;\n+\t\t\t\t\t\tgot_ready = 1;\n+\t\t\t\t\t}\n+\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t} while (ack);\n+\t\t\tflushes--;\n+\t\t\tif (got_continue && MAX_IN_VAIN < in_vain) {\n+\t\t\t\tif (args->verbose)\n+\t\t\t\t\tfprintf(stderr, \"giving up\\n\");\n+\t\t\t\tbreak; /* give up */\n+\t\t\t}\n+\t\t}\n+\t}\n+done:\n+\tif (!got_ready || !no_done) {\n+\t\tpacket_buf_write(&req_buf, \"done\\n\");\n+\t\tsend_request(args, fd[1], &req_buf);\n+\t}\n+\tif (args->verbose)\n+\t\tfprintf(stderr, \"done\\n\");\n+\tif (retval != 0) {\n+\t\tmulti_ack = 0;\n+\t\tflushes++;\n+\t}\n+\tstrbuf_release(&req_buf);\n+\n+\tconsume_shallow_list(args, fd[0]);\n+\twhile (flushes || multi_ack) {\n+\t\tint ack = get_ack(fd[0], result_sha1);\n+\t\tif (ack) {\n+\t\t\tif (args->verbose)\n+\t\t\t\tfprintf(stderr, \"got ack (%d) %s\\n\", ack,\n+\t\t\t\t\tsha1_to_hex(result_sha1));\n+\t\t\tif (ack == ACK)\n+\t\t\t\treturn 0;\n+\t\t\tmulti_ack = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tflushes--;\n+\t}\n+\t/* it is no error to fetch into a completely empty repo */\n+\treturn count ? retval : 0;\n+}\n+\n+static struct commit_list *complete;\n+\n+static int mark_complete(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n+{\n+\tstruct object *o = parse_object(sha1);\n+\n+\twhile (o && o->type == OBJ_TAG) {\n+\t\tstruct tag *t = (struct tag *) o;\n+\t\tif (!t->tagged)\n+\t\t\tbreak; /* broken repository */\n+\t\to->flags |= COMPLETE;\n+\t\to = parse_object(t->tagged->sha1);\n+\t}\n+\tif (o && o->type == OBJ_COMMIT) {\n+\t\tstruct commit *commit = (struct commit *)o;\n+\t\tif (!(commit->object.flags & COMPLETE)) {\n+\t\t\tcommit->object.flags |= COMPLETE;\n+\t\t\tcommit_list_insert_by_date(commit, &complete);\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+static void mark_recent_complete_commits(struct fetch_pack_args *args,\n+\t\t\t\t\t unsigned long cutoff)\n+{\n+\twhile (complete && cutoff <= complete->item->date) {\n+\t\tif (args->verbose)\n+\t\t\tfprintf(stderr, \"Marking %s as complete\\n\",\n+\t\t\t\tsha1_to_hex(complete->item->object.sha1));\n+\t\tpop_most_recent_commit(&complete, COMPLETE);\n+\t}\n+}\n+\n+static int non_matching_ref(struct string_list_item *item, void *unused)\n+{\n+\tif (item->util) {\n+\t\titem->util = NULL;\n+\t\treturn 0;\n+\t}\n+\telse\n+\t\treturn 1;\n+}\n+\n+static void filter_refs(struct fetch_pack_args *args,\n+\t\t\tstruct ref **refs, struct string_list *sought)\n+{\n+\tstruct ref *newlist = NULL;\n+\tstruct ref **newtail = &newlist;\n+\tstruct ref *ref, *next;\n+\tint sought_pos;\n+\n+\tsought_pos = 0;\n+\tfor (ref = *refs; ref; ref = next) {\n+\t\tint keep = 0;\n+\t\tnext = ref->next;\n+\t\tif (!memcmp(ref->name, \"refs/\", 5) &&\n+\t\t    check_refname_format(ref->name + 5, 0))\n+\t\t\t; /* trash */\n+\t\telse {\n+\t\t\twhile (sought_pos < sought->nr) {\n+\t\t\t\tint cmp = strcmp(ref->name, sought->items[sought_pos].string);\n+\t\t\t\tif (cmp < 0)\n+\t\t\t\t\tbreak; /* definitely do not have it */\n+\t\t\t\telse if (cmp == 0) {\n+\t\t\t\t\tkeep = 1; /* definitely have it */\n+\t\t\t\t\tsought->items[sought_pos++].util = \"matched\";\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\telse\n+\t\t\t\t\tsought_pos++; /* might have it; keep looking */\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (! keep && args->fetch_all &&\n+\t\t    (!args->depth || prefixcmp(ref->name, \"refs/tags/\")))\n+\t\t\tkeep = 1;\n+\n+\t\tif (keep) {\n+\t\t\t*newtail = ref;\n+\t\t\tref->next = NULL;\n+\t\t\tnewtail = &ref->next;\n+\t\t} else {\n+\t\t\tfree(ref);\n+\t\t}\n+\t}\n+\n+\tfilter_string_list(sought, 0, non_matching_ref, NULL);\n+\t*refs = newlist;\n+}\n+\n+static void mark_alternate_complete(const struct ref *ref, void *unused)\n+{\n+\tmark_complete(NULL, ref->old_sha1, 0, NULL);\n+}\n+\n+static int everything_local(struct fetch_pack_args *args,\n+\t\t\t    struct ref **refs, struct string_list *sought)\n+{\n+\tstruct ref *ref;\n+\tint retval;\n+\tunsigned long cutoff = 0;\n+\n+\tsave_commit_buffer = 0;\n+\n+\tfor (ref = *refs; ref; ref = ref->next) {\n+\t\tstruct object *o;\n+\n+\t\to = parse_object(ref->old_sha1);\n+\t\tif (!o)\n+\t\t\tcontinue;\n+\n+\t\t/* We already have it -- which may mean that we were\n+\t\t * in sync with the other side at some time after\n+\t\t * that (it is OK if we guess wrong here).\n+\t\t */\n+\t\tif (o->type == OBJ_COMMIT) {\n+\t\t\tstruct commit *commit = (struct commit *)o;\n+\t\t\tif (!cutoff || cutoff < commit->date)\n+\t\t\t\tcutoff = commit->date;\n+\t\t}\n+\t}\n+\n+\tif (!args->depth) {\n+\t\tfor_each_ref(mark_complete, NULL);\n+\t\tfor_each_alternate_ref(mark_alternate_complete, NULL);\n+\t\tif (cutoff)\n+\t\t\tmark_recent_complete_commits(args, cutoff);\n+\t}\n+\n+\t/*\n+\t * Mark all complete remote refs as common refs.\n+\t * Don't mark them common yet; the server has to be told so first.\n+\t */\n+\tfor (ref = *refs; ref; ref = ref->next) {\n+\t\tstruct object *o = deref_tag(lookup_object(ref->old_sha1),\n+\t\t\t\t\t     NULL, 0);\n+\n+\t\tif (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))\n+\t\t\tcontinue;\n+\n+\t\tif (!(o->flags & SEEN)) {\n+\t\t\trev_list_push((struct commit *)o, COMMON_REF | SEEN);\n+\n+\t\t\tmark_common((struct commit *)o, 1, 1);\n+\t\t}\n+\t}\n+\n+\tfilter_refs(args, refs, sought);\n+\n+\tfor (retval = 1, ref = *refs; ref ; ref = ref->next) {\n+\t\tconst unsigned char *remote = ref->old_sha1;\n+\t\tunsigned char local[20];\n+\t\tstruct object *o;\n+\n+\t\to = lookup_object(remote);\n+\t\tif (!o || !(o->flags & COMPLETE)) {\n+\t\t\tretval = 0;\n+\t\t\tif (!args->verbose)\n+\t\t\t\tcontinue;\n+\t\t\tfprintf(stderr,\n+\t\t\t\t\"want %s (%s)\\n\", sha1_to_hex(remote),\n+\t\t\t\tref->name);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\thashcpy(ref->new_sha1, local);\n+\t\tif (!args->verbose)\n+\t\t\tcontinue;\n+\t\tfprintf(stderr,\n+\t\t\t\"already have %s (%s)\\n\", sha1_to_hex(remote),\n+\t\t\tref->name);\n+\t}\n+\treturn retval;\n+}\n+\n+static int sideband_demux(int in, int out, void *data)\n+{\n+\tint *xd = data;\n+\n+\tint ret = recv_sideband(\"fetch-pack\", xd[0], out);\n+\tclose(out);\n+\treturn ret;\n+}\n+\n+static int get_pack(struct fetch_pack_args *args,\n+\t\t    int xd[2], char **pack_lockfile)\n+{\n+\tstruct async demux;\n+\tconst char *argv[20];\n+\tchar keep_arg[256];\n+\tchar hdr_arg[256];\n+\tconst char **av;\n+\tint do_keep = args->keep_pack;\n+\tstruct child_process cmd;\n+\n+\tmemset(&demux, 0, sizeof(demux));\n+\tif (use_sideband) {\n+\t\t/* xd[] is talking with upload-pack; subprocess reads from\n+\t\t * xd[0], spits out band#2 to stderr, and feeds us band#1\n+\t\t * through demux->out.\n+\t\t */\n+\t\tdemux.proc = sideband_demux;\n+\t\tdemux.data = xd;\n+\t\tdemux.out = -1;\n+\t\tif (start_async(&demux))\n+\t\t\tdie(\"fetch-pack: unable to fork off sideband\"\n+\t\t\t    \" demultiplexer\");\n+\t}\n+\telse\n+\t\tdemux.out = xd[0];\n+\n+\tmemset(&cmd, 0, sizeof(cmd));\n+\tcmd.argv = argv;\n+\tav = argv;\n+\t*hdr_arg = 0;\n+\tif (!args->keep_pack && unpack_limit) {\n+\t\tstruct pack_header header;\n+\n+\t\tif (read_pack_header(demux.out, &header))\n+\t\t\tdie(\"protocol error: bad pack header\");\n+\t\tsnprintf(hdr_arg, sizeof(hdr_arg),\n+\t\t\t \"--pack_header=%\"PRIu32\",%\"PRIu32,\n+\t\t\t ntohl(header.hdr_version), ntohl(header.hdr_entries));\n+\t\tif (ntohl(header.hdr_entries) < unpack_limit)\n+\t\t\tdo_keep = 0;\n+\t\telse\n+\t\t\tdo_keep = 1;\n+\t}\n+\n+\tif (do_keep) {\n+\t\tif (pack_lockfile)\n+\t\t\tcmd.out = -1;\n+\t\t*av++ = \"index-pack\";\n+\t\t*av++ = \"--stdin\";\n+\t\tif (!args->quiet && !args->no_progress)\n+\t\t\t*av++ = \"-v\";\n+\t\tif (args->use_thin_pack)\n+\t\t\t*av++ = \"--fix-thin\";\n+\t\tif (args->lock_pack || unpack_limit) {\n+\t\t\tint s = sprintf(keep_arg,\n+\t\t\t\t\t\"--keep=fetch-pack %\"PRIuMAX \" on \", (uintmax_t) getpid());\n+\t\t\tif (gethostname(keep_arg + s, sizeof(keep_arg) - s))\n+\t\t\t\tstrcpy(keep_arg + s, \"localhost\");\n+\t\t\t*av++ = keep_arg;\n+\t\t}\n+\t}\n+\telse {\n+\t\t*av++ = \"unpack-objects\";\n+\t\tif (args->quiet || args->no_progress)\n+\t\t\t*av++ = \"-q\";\n+\t}\n+\tif (*hdr_arg)\n+\t\t*av++ = hdr_arg;\n+\tif (fetch_fsck_objects >= 0\n+\t    ? fetch_fsck_objects\n+\t    : transfer_fsck_objects >= 0\n+\t    ? transfer_fsck_objects\n+\t    : 0)\n+\t\t*av++ = \"--strict\";\n+\t*av++ = NULL;\n+\n+\tcmd.in = demux.out;\n+\tcmd.git_cmd = 1;\n+\tif (start_command(&cmd))\n+\t\tdie(\"fetch-pack: unable to fork off %s\", argv[0]);\n+\tif (do_keep && pack_lockfile) {\n+\t\t*pack_lockfile = index_pack_lockfile(cmd.out);\n+\t\tclose(cmd.out);\n+\t}\n+\n+\tif (finish_command(&cmd))\n+\t\tdie(\"%s failed\", argv[0]);\n+\tif (use_sideband && finish_async(&demux))\n+\t\tdie(\"error in sideband demultiplexer\");\n+\treturn 0;\n+}\n+\n+static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n+\t\t\t\t int fd[2],\n+\t\t\t\t const struct ref *orig_ref,\n+\t\t\t\t struct string_list *sought,\n+\t\t\t\t char **pack_lockfile)\n+{\n+\tstruct ref *ref = copy_ref_list(orig_ref);\n+\tunsigned char sha1[20];\n+\tconst char *agent_feature;\n+\tint agent_len;\n+\n+\tsort_ref_list(&ref, ref_compare_name);\n+\n+\tif (is_repository_shallow() && !server_supports(\"shallow\"))\n+\t\tdie(\"Server does not support shallow clients\");\n+\tif (server_supports(\"multi_ack_detailed\")) {\n+\t\tif (args->verbose)\n+\t\t\tfprintf(stderr, \"Server supports multi_ack_detailed\\n\");\n+\t\tmulti_ack = 2;\n+\t\tif (server_supports(\"no-done\")) {\n+\t\t\tif (args->verbose)\n+\t\t\t\tfprintf(stderr, \"Server supports no-done\\n\");\n+\t\t\tif (args->stateless_rpc)\n+\t\t\t\tno_done = 1;\n+\t\t}\n+\t}\n+\telse if (server_supports(\"multi_ack\")) {\n+\t\tif (args->verbose)\n+\t\t\tfprintf(stderr, \"Server supports multi_ack\\n\");\n+\t\tmulti_ack = 1;\n+\t}\n+\tif (server_supports(\"side-band-64k\")) {\n+\t\tif (args->verbose)\n+\t\t\tfprintf(stderr, \"Server supports side-band-64k\\n\");\n+\t\tuse_sideband = 2;\n+\t}\n+\telse if (server_supports(\"side-band\")) {\n+\t\tif (args->verbose)\n+\t\t\tfprintf(stderr, \"Server supports side-band\\n\");\n+\t\tuse_sideband = 1;\n+\t}\n+\tif (!server_supports(\"thin-pack\"))\n+\t\targs->use_thin_pack = 0;\n+\tif (!server_supports(\"no-progress\"))\n+\t\targs->no_progress = 0;\n+\tif (!server_supports(\"include-tag\"))\n+\t\targs->include_tag = 0;\n+\tif (server_supports(\"ofs-delta\")) {\n+\t\tif (args->verbose)\n+\t\t\tfprintf(stderr, \"Server supports ofs-delta\\n\");\n+\t} else\n+\t\tprefer_ofs_delta = 0;\n+\n+\tif ((agent_feature = server_feature_value(\"agent\", &agent_len))) {\n+\t\tagent_supported = 1;\n+\t\tif (args->verbose && agent_len)\n+\t\t\tfprintf(stderr, \"Server version is %.*s\\n\",\n+\t\t\t\tagent_len, agent_feature);\n+\t}\n+\n+\tif (everything_local(args, &ref, sought)) {\n+\t\tpacket_flush(fd[1]);\n+\t\tgoto all_done;\n+\t}\n+\tif (find_common(args, fd, sha1, ref) < 0)\n+\t\tif (!args->keep_pack)\n+\t\t\t/* When cloning, it is not unusual to have\n+\t\t\t * no common commit.\n+\t\t\t */\n+\t\t\twarning(\"no common commits\");\n+\n+\tif (args->stateless_rpc)\n+\t\tpacket_flush(fd[1]);\n+\tif (get_pack(args, fd, pack_lockfile))\n+\t\tdie(\"git fetch-pack: fetch failed.\");\n+\n+ all_done:\n+\treturn ref;\n+}\n+\n+static int fetch_pack_config(const char *var, const char *value, void *cb)\n+{\n+\tif (strcmp(var, \"fetch.unpacklimit\") == 0) {\n+\t\tfetch_unpack_limit = git_config_int(var, value);\n+\t\treturn 0;\n+\t}\n+\n+\tif (strcmp(var, \"transfer.unpacklimit\") == 0) {\n+\t\ttransfer_unpack_limit = git_config_int(var, value);\n+\t\treturn 0;\n+\t}\n+\n+\tif (strcmp(var, \"repack.usedeltabaseoffset\") == 0) {\n+\t\tprefer_ofs_delta = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n+\tif (!strcmp(var, \"fetch.fsckobjects\")) {\n+\t\tfetch_fsck_objects = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n+\tif (!strcmp(var, \"transfer.fsckobjects\")) {\n+\t\ttransfer_fsck_objects = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n+\treturn git_default_config(var, value, cb);\n+}\n+\n+static struct lock_file lock;\n+\n+static void fetch_pack_setup(void)\n+{\n+\tstatic int did_setup;\n+\tif (did_setup)\n+\t\treturn;\n+\tgit_config(fetch_pack_config, NULL);\n+\tif (0 <= transfer_unpack_limit)\n+\t\tunpack_limit = transfer_unpack_limit;\n+\telse if (0 <= fetch_unpack_limit)\n+\t\tunpack_limit = fetch_unpack_limit;\n+\tdid_setup = 1;\n+}\n+\n+struct ref *fetch_pack(struct fetch_pack_args *args,\n+\t\t       int fd[], struct child_process *conn,\n+\t\t       const struct ref *ref,\n+\t\t       const char *dest,\n+\t\t       struct string_list *sought,\n+\t\t       char **pack_lockfile)\n+{\n+\tstruct stat st;\n+\tstruct ref *ref_cpy;\n+\n+\tfetch_pack_setup();\n+\tif (args->depth > 0) {\n+\t\tif (stat(git_path(\"shallow\"), &st))\n+\t\t\tst.st_mtime = 0;\n+\t}\n+\n+\tif (sought->nr) {\n+\t\tsort_string_list(sought);\n+\t\tstring_list_remove_duplicates(sought, 0);\n+\t}\n+\n+\tif (!ref) {\n+\t\tpacket_flush(fd[1]);\n+\t\tdie(\"no matching remote head\");\n+\t}\n+\tref_cpy = do_fetch_pack(args, fd, ref, sought, pack_lockfile);\n+\n+\tif (args->depth > 0) {\n+\t\tstruct cache_time mtime;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\tchar *shallow = git_path(\"shallow\");\n+\t\tint fd;\n+\n+\t\tmtime.sec = st.st_mtime;\n+\t\tmtime.nsec = ST_MTIME_NSEC(st);\n+\t\tif (stat(shallow, &st)) {\n+\t\t\tif (mtime.sec)\n+\t\t\t\tdie(\"shallow file was removed during fetch\");\n+\t\t} else if (st.st_mtime != mtime.sec\n+#ifdef USE_NSEC\n+\t\t\t\t|| ST_MTIME_NSEC(st) != mtime.nsec\n+#endif\n+\t\t\t  )\n+\t\t\tdie(\"shallow file was changed during fetch\");\n+\n+\t\tfd = hold_lock_file_for_update(&lock, shallow,\n+\t\t\t\t\t       LOCK_DIE_ON_ERROR);\n+\t\tif (!write_shallow_commits(&sb, 0)\n+\t\t || write_in_full(fd, sb.buf, sb.len) != sb.len) {\n+\t\t\tunlink_or_warn(shallow);\n+\t\t\trollback_lock_file(&lock);\n+\t\t} else {\n+\t\t\tcommit_lock_file(&lock);\n+\t\t}\n+\t\tstrbuf_release(&sb);\n+\t}\n+\n+\treprepare_packed_git();\n+\treturn ref_cpy;\n+}\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"202100","messageId":"20121029074352.GF5102@sigill.intra.peff.net","threadId":"31911","inReplyTo":"1351266835-22610-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 0/7] Move code from builtin to libgit.a","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-10-29T07:43:52Z","receivedAt":"2012-10-29T07:43:52Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Oct 26, 2012 at 10:53:48PM +0700, Nguyen Thai Ngoc Duy wrote:\n\n> These two are big code moves, basically all {fetch,send}-pack code.\n> While I think this is good cleanup (I get surprise every time I look\n> at transport.c and it leads to buitin/fetch-pack.c), this is probably\n> not a good idea if we have on flight topics, which may cause lots of\n> conflicts for you and Junio. Fortunately we don't at the moment.\n> \n> Nguyễn Thái Ngọc Duy (7):\n>   Move try_merge_command and checkout_fast_forward to libgit.a\n>   Move estimate_bisect_steps to libgit.a\n>   Move print_commit_list to libgit.a\n>   Move setup_diff_pager to libgit.a\n>   send-pack: move core code to libgit.a\n>   fetch-pack: remove global (static) configuration variable \"args\"\n>   fetch-pack: move core code to libgit.a\n\nThis does not seem to disturb anything in pu, so I am very tempted.\n\nI tweaked the last one, which removed the inclusion of pkt-line.h from\nbuiltin/fetch-pack.c; it is still needed by the use of packet_read_line\nwhen reading stateless rpc refs from stdin (caught by \"-Wall -Werror\").\n\n-Peff\n"}]}