{"thread":{"id":"28848","subject":"[PATCH] prune: show progress while marking reachable objects","startedAt":"2011-11-05T12:00:08Z","lastAt":"2011-11-09T04:26:42Z","messageCount":7,"participants":["Nguyễn Thái Ngọc Duy","Jeff King","Junio C Hamano","Nguyen Thai Ngoc Duy"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"178897","messageId":"1320494408-6373-1-git-send-email-pclouds@gmail.com","threadId":"28848","inReplyTo":null,"subject":"[PATCH] prune: show progress while marking reachable objects","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-11-05T12:00:08Z","receivedAt":"2011-11-05T12:00:08Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"prune already shows progress meter while pruning. The marking part may\ntake a few seconds or more, depending on repository size. Show\nprogress meter during this time too.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/prune.c  |    6 +++++-\n builtin/reflog.c |    2 +-\n reachable.c      |   14 ++++++++++----\n reachable.h      |    3 ++-\n 4 files changed, 18 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/prune.c b/builtin/prune.c\nindex e65690b..6b39d3f 100644\n--- a/builtin/prune.c\n+++ b/builtin/prune.c\n@@ -5,6 +5,7 @@\n #include \"builtin.h\"\n #include \"reachable.h\"\n #include \"parse-options.h\"\n+#include \"progress.h\"\n #include \"dir.h\"\n \n static const char * const prune_usage[] = {\n@@ -124,6 +125,7 @@ static void remove_temporary_files(const char *path)\n int cmd_prune(int argc, const char **argv, const char *prefix)\n {\n \tstruct rev_info revs;\n+\tstruct progress *progress;\n \tconst struct option options[] = {\n \t\tOPT__DRY_RUN(&show_only, \"do not remove, show only\"),\n \t\tOPT__VERBOSE(&verbose, \"report pruned objects\"),\n@@ -152,7 +154,9 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n \t\telse\n \t\t\tdie(\"unrecognized argument: %s\", name);\n \t}\n-\tmark_reachable_objects(&revs, 1);\n+\tprogress = start_progress_delay(\"Checking connectivity\", 0, 0, 2);\n+\tmark_reachable_objects(&revs, 1, progress);\n+\tstop_progress(&progress);\n \tprune_object_dir(get_object_directory());\n \n \tprune_packed_objects(show_only);\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 3a9c80f..062d7da 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -647,7 +647,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n \t\tinit_revisions(&cb.revs, prefix);\n \t\tif (cb.verbose)\n \t\t\tprintf(\"Marking reachable objects...\");\n-\t\tmark_reachable_objects(&cb.revs, 0);\n+\t\tmark_reachable_objects(&cb.revs, 0, NULL);\n \t\tif (cb.verbose)\n \t\t\tputchar('\\n');\n \t}\ndiff --git a/reachable.c b/reachable.c\nindex 3fc6b1d..293d37d 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -7,6 +7,7 @@\n #include \"revision.h\"\n #include \"reachable.h\"\n #include \"cache-tree.h\"\n+#include \"progress.h\"\n \n static void process_blob(struct blob *blob,\n \t\t\t struct object_array *p,\n@@ -81,21 +82,25 @@ static void process_tag(struct tag *tag, struct object_array *p, const char *nam\n \t\tadd_object(tag->tagged, p, NULL, name);\n }\n \n-static void walk_commit_list(struct rev_info *revs)\n+static void walk_commit_list(struct rev_info *revs, struct progress *progress)\n {\n \tint i;\n \tstruct commit *commit;\n \tstruct object_array objects = OBJECT_ARRAY_INIT;\n+\tuint32_t count = 0;\n \n \t/* Walk all commits, process their trees */\n-\twhile ((commit = get_revision(revs)) != NULL)\n+\twhile ((commit = get_revision(revs)) != NULL) {\n \t\tprocess_tree(commit->tree, &objects, NULL, \"\");\n+\t\tdisplay_progress(progress, ++count);\n+\t}\n \n \t/* Then walk all the pending objects, recursively processing them too */\n \tfor (i = 0; i < revs->pending.nr; i++) {\n \t\tstruct object_array_entry *pending = revs->pending.objects + i;\n \t\tstruct object *obj = pending->item;\n \t\tconst char *name = pending->name;\n+\t\tdisplay_progress(progress, ++count);\n \t\tif (obj->type == OBJ_TAG) {\n \t\t\tprocess_tag((struct tag *) obj, &objects, name);\n \t\t\tcontinue;\n@@ -191,7 +196,8 @@ static void add_cache_refs(struct rev_info *revs)\n \t\tadd_cache_tree(active_cache_tree, revs);\n }\n \n-void mark_reachable_objects(struct rev_info *revs, int mark_reflog)\n+void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n+\t\t\t    struct progress *progress)\n {\n \t/*\n \t * Set up revision parsing, and mark us as being interested\n@@ -217,5 +223,5 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog)\n \t */\n \tif (prepare_revision_walk(revs))\n \t\tdie(\"revision walk setup failed\");\n-\twalk_commit_list(revs);\n+\twalk_commit_list(revs, progress);\n }\ndiff --git a/reachable.h b/reachable.h\nindex 4075181..5d082ad 100644\n--- a/reachable.h\n+++ b/reachable.h\n@@ -1,6 +1,7 @@\n #ifndef REACHEABLE_H\n #define REACHEABLE_H\n \n-extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog);\n+struct progress;\n+extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog, struct progress *);\n \n #endif\n-- \n1.7.4.74.g639db\n"},{"id":"179117","messageId":"20111108053149.GA29643@sigill.intra.peff.net","threadId":"28848","inReplyTo":"1320494408-6373-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH] prune: show progress while marking reachable objects","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-08T05:31:49Z","receivedAt":"2011-11-08T05:31:49Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Nov 05, 2011 at 07:00:08PM +0700, Nguyen Thai Ngoc Duy wrote:\n\n> prune already shows progress meter while pruning. The marking part may\n> take a few seconds or more, depending on repository size. Show\n> progress meter during this time too.\n\nThanks, this is a nice start. It's missing a few things IMHO:\n\n  1. It actually counts commits, not all objects. I'm tempted to say\n     this doesn't matter, as any eye candy is helpful. Except that the\n     most common use of prune is as part of \"git gc\", in which case\n     pack-objects will have just done the \"counting objects\" phase and\n     come up with some number. If we count all objects, then our end\n     number is the same (modulo any .keep packs, but at least it's\n     probably in the same order of magnitude). That gives the user a\n     better sense of completion time.\n\n  2. Prune should learn --progress/--no-progress, isatty(2), etc. And\n     git-gc should pass --no-progress when it's told to be quiet.\n\nPatches for both in a moment.\n\n-Peff\n"},{"id":"179118","messageId":"20111108053407.GA16852@sigill.intra.peff.net","threadId":"28848","inReplyTo":"20111108053149.GA29643@sigill.intra.peff.net","subject":"[PATCH 1/2] prune: handle --progress/no-progress","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-08T05:34:08Z","receivedAt":"2011-11-08T05:34:08Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"And have \"git gc\" pass no-progress when quiet.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nOn top of the prune progress patch you sent earlier.\n\nI did these as separate patches so you could see each change, but I'd\nalso be fine if they are just squashed into your patch.\n\n builtin/gc.c    |    4 +++-\n builtin/prune.c |   11 +++++++++--\n 2 files changed, 12 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex 0498094..271376d 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -32,7 +32,7 @@\n static const char *argv_pack_refs[] = {\"pack-refs\", \"--all\", \"--prune\", NULL};\n static const char *argv_reflog[] = {\"reflog\", \"expire\", \"--all\", NULL};\n static const char *argv_repack[MAX_ADD] = {\"repack\", \"-d\", \"-l\", NULL};\n-static const char *argv_prune[] = {\"prune\", \"--expire\", NULL, NULL};\n+static const char *argv_prune[] = {\"prune\", \"--expire\", NULL, NULL, NULL};\n static const char *argv_rerere[] = {\"rerere\", \"gc\", NULL};\n \n static int gc_config(const char *var, const char *value, void *cb)\n@@ -243,6 +243,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)\n \n \tif (prune_expire) {\n \t\targv_prune[2] = prune_expire;\n+\t\tif (quiet)\n+\t\t\targv_prune[3] = \"--no-progress\";\n \t\tif (run_command_v_opt(argv_prune, RUN_GIT_CMD))\n \t\t\treturn error(FAILED_RUN, argv_prune[0]);\n \t}\ndiff --git a/builtin/prune.c b/builtin/prune.c\nindex 6b39d3f..58d7cb8 100644\n--- a/builtin/prune.c\n+++ b/builtin/prune.c\n@@ -15,6 +15,7 @@\n static int show_only;\n static int verbose;\n static unsigned long expire;\n+static int show_progress = -1;\n \n static int prune_tmp_object(const char *path, const char *filename)\n {\n@@ -125,10 +126,11 @@ static void remove_temporary_files(const char *path)\n int cmd_prune(int argc, const char **argv, const char *prefix)\n {\n \tstruct rev_info revs;\n-\tstruct progress *progress;\n+\tstruct progress *progress = NULL;\n \tconst struct option options[] = {\n \t\tOPT__DRY_RUN(&show_only, \"do not remove, show only\"),\n \t\tOPT__VERBOSE(&verbose, \"report pruned objects\"),\n+\t\tOPT_BOOL(0, \"progress\", &show_progress, \"show progress\"),\n \t\tOPT_DATE(0, \"expire\", &expire,\n \t\t\t \"expire objects older than <time>\"),\n \t\tOPT_END()\n@@ -154,7 +156,12 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n \t\telse\n \t\t\tdie(\"unrecognized argument: %s\", name);\n \t}\n-\tprogress = start_progress_delay(\"Checking connectivity\", 0, 0, 2);\n+\n+\tif (show_progress == -1)\n+\t\tshow_progress = isatty(2);\n+\tif (show_progress)\n+\t\tprogress = start_progress_delay(\"Checking connectivity\", 0, 0, 2);\n+\n \tmark_reachable_objects(&revs, 1, progress);\n \tstop_progress(&progress);\n \tprune_object_dir(get_object_directory());\n-- \n1.7.7.2.7.g9f96f.dirty\n"},{"id":"179119","messageId":"20111108053700.GB16852@sigill.intra.peff.net","threadId":"28848","inReplyTo":"20111108053149.GA29643@sigill.intra.peff.net","subject":"[PATCH 2/2] reachable: per-object progress","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-08T05:37:00Z","receivedAt":"2011-11-08T05:37:00Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The current progress code really just counts commits.\nThis patch makes it count all objects, giving us a \"total\"\ncount close to what a repack would show. This is nice when\nusing \"git gc\", which will usually have just repacked the\nwhole repo.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nThis makes the change a lot more invasive, but it is at least confined\nto reachable.c. I think matching repack's numbers is worth it. I did a\nfew basic measurements, and with \"& 1023\" trick and reasonable\noptimizations, it doesn't seem to make prune any slower.\n\nAgain, I'd be OK if this is squashed into your original patch.\n\n reachable.c |   51 +++++++++++++++++++++++++++++++++++++--------------\n 1 files changed, 37 insertions(+), 14 deletions(-)\n\ndiff --git a/reachable.c b/reachable.c\nindex 293d37d..bf79706 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -9,10 +9,23 @@\n #include \"cache-tree.h\"\n #include \"progress.h\"\n \n+struct connectivity_progress {\n+\tstruct progress *progress;\n+\tunsigned long count;\n+};\n+\n+static void update_progress(struct connectivity_progress *cp)\n+{\n+\tcp->count++;\n+\tif ((cp->count & 1023) == 0)\n+\t\tdisplay_progress(cp->progress, cp->count);\n+}\n+\n static void process_blob(struct blob *blob,\n \t\t\t struct object_array *p,\n \t\t\t struct name_path *path,\n-\t\t\t const char *name)\n+\t\t\t const char *name,\n+\t\t\t struct connectivity_progress *cp)\n {\n \tstruct object *obj = &blob->object;\n \n@@ -21,6 +34,7 @@ static void process_blob(struct blob *blob,\n \tif (obj->flags & SEEN)\n \t\treturn;\n \tobj->flags |= SEEN;\n+\tupdate_progress(cp);\n \t/* Nothing to do, really .. The blob lookup was the important part */\n }\n \n@@ -35,7 +49,8 @@ static void process_gitlink(const unsigned char *sha1,\n static void process_tree(struct tree *tree,\n \t\t\t struct object_array *p,\n \t\t\t struct name_path *path,\n-\t\t\t const char *name)\n+\t\t\t const char *name,\n+\t\t\t struct connectivity_progress *cp)\n {\n \tstruct object *obj = &tree->object;\n \tstruct tree_desc desc;\n@@ -47,6 +62,7 @@ static void process_tree(struct tree *tree,\n \tif (obj->flags & SEEN)\n \t\treturn;\n \tobj->flags |= SEEN;\n+\tupdate_progress(cp);\n \tif (parse_tree(tree) < 0)\n \t\tdie(\"bad tree object %s\", sha1_to_hex(obj->sha1));\n \tadd_object(obj, p, path, name);\n@@ -58,23 +74,25 @@ static void process_tree(struct tree *tree,\n \n \twhile (tree_entry(&desc, &entry)) {\n \t\tif (S_ISDIR(entry.mode))\n-\t\t\tprocess_tree(lookup_tree(entry.sha1), p, &me, entry.path);\n+\t\t\tprocess_tree(lookup_tree(entry.sha1), p, &me, entry.path, cp);\n \t\telse if (S_ISGITLINK(entry.mode))\n \t\t\tprocess_gitlink(entry.sha1, p, &me, entry.path);\n \t\telse\n-\t\t\tprocess_blob(lookup_blob(entry.sha1), p, &me, entry.path);\n+\t\t\tprocess_blob(lookup_blob(entry.sha1), p, &me, entry.path, cp);\n \t}\n \tfree(tree->buffer);\n \ttree->buffer = NULL;\n }\n \n-static void process_tag(struct tag *tag, struct object_array *p, const char *name)\n+static void process_tag(struct tag *tag, struct object_array *p,\n+\t\t\tconst char *name, struct connectivity_progress *cp)\n {\n \tstruct object *obj = &tag->object;\n \n \tif (obj->flags & SEEN)\n \t\treturn;\n \tobj->flags |= SEEN;\n+\tupdate_progress(cp);\n \n \tif (parse_tag(tag) < 0)\n \t\tdie(\"bad tag object %s\", sha1_to_hex(obj->sha1));\n@@ -82,17 +100,17 @@ static void process_tag(struct tag *tag, struct object_array *p, const char *nam\n \t\tadd_object(tag->tagged, p, NULL, name);\n }\n \n-static void walk_commit_list(struct rev_info *revs, struct progress *progress)\n+static void walk_commit_list(struct rev_info *revs,\n+\t\t\t     struct connectivity_progress *cp)\n {\n \tint i;\n \tstruct commit *commit;\n \tstruct object_array objects = OBJECT_ARRAY_INIT;\n-\tuint32_t count = 0;\n \n \t/* Walk all commits, process their trees */\n \twhile ((commit = get_revision(revs)) != NULL) {\n-\t\tprocess_tree(commit->tree, &objects, NULL, \"\");\n-\t\tdisplay_progress(progress, ++count);\n+\t\tprocess_tree(commit->tree, &objects, NULL, \"\", cp);\n+\t\tupdate_progress(cp);\n \t}\n \n \t/* Then walk all the pending objects, recursively processing them too */\n@@ -100,17 +118,16 @@ static void walk_commit_list(struct rev_info *revs, struct progress *progress)\n \t\tstruct object_array_entry *pending = revs->pending.objects + i;\n \t\tstruct object *obj = pending->item;\n \t\tconst char *name = pending->name;\n-\t\tdisplay_progress(progress, ++count);\n \t\tif (obj->type == OBJ_TAG) {\n-\t\t\tprocess_tag((struct tag *) obj, &objects, name);\n+\t\t\tprocess_tag((struct tag *) obj, &objects, name, cp);\n \t\t\tcontinue;\n \t\t}\n \t\tif (obj->type == OBJ_TREE) {\n-\t\t\tprocess_tree((struct tree *)obj, &objects, NULL, name);\n+\t\t\tprocess_tree((struct tree *)obj, &objects, NULL, name, cp);\n \t\t\tcontinue;\n \t\t}\n \t\tif (obj->type == OBJ_BLOB) {\n-\t\t\tprocess_blob((struct blob *)obj, &objects, NULL, name);\n+\t\t\tprocess_blob((struct blob *)obj, &objects, NULL, name, cp);\n \t\t\tcontinue;\n \t\t}\n \t\tdie(\"unknown pending object %s (%s)\", sha1_to_hex(obj->sha1), name);\n@@ -199,6 +216,8 @@ static void add_cache_refs(struct rev_info *revs)\n void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n \t\t\t    struct progress *progress)\n {\n+\tstruct connectivity_progress cp;\n+\n \t/*\n \t * Set up revision parsing, and mark us as being interested\n \t * in all object types, not just commits.\n@@ -217,11 +236,15 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n \tif (mark_reflog)\n \t\tfor_each_reflog(add_one_reflog, revs);\n \n+\tcp.progress = progress;\n+\tcp.count = 0;\n+\n \t/*\n \t * Set up the revision walk - this will move all commits\n \t * from the pending list to the commit walking list.\n \t */\n \tif (prepare_revision_walk(revs))\n \t\tdie(\"revision walk setup failed\");\n-\twalk_commit_list(revs, progress);\n+\twalk_commit_list(revs, &cp);\n+\tdisplay_progress(cp.progress, cp.count);\n }\n-- \n1.7.7.2.7.g9f96f.dirty\n"},{"id":"179121","messageId":"7vk47byxwf.fsf@alter.siamese.dyndns.org","threadId":"28848","inReplyTo":"20111108053149.GA29643@sigill.intra.peff.net","subject":"Re: [PATCH] prune: show progress while marking reachable objects","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-11-08T05:40:48Z","receivedAt":"2011-11-08T05:40:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Both patches look sensible from a quick glance.\n"},{"id":"179194","messageId":"1320812597-11175-1-git-send-email-pclouds@gmail.com","threadId":"28848","inReplyTo":"20111108053407.GA16852@sigill.intra.peff.net","subject":"[PATCH] prune: handle --progress/no-progress","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-11-09T04:23:17Z","receivedAt":"2011-11-09T04:23:17Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nAnd have \"git gc\" pass no-progress when quiet.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Added documentation.\n\n Documentation/git-prune.txt |    9 ++++++++-\n builtin/gc.c                |    4 +++-\n builtin/prune.c             |   11 +++++++++--\n 3 files changed, 20 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt\nindex 80d01b0..6da99e2 100644\n--- a/Documentation/git-prune.txt\n+++ b/Documentation/git-prune.txt\n@@ -9,7 +9,7 @@ git-prune - Prune all unreachable objects from the object database\n SYNOPSIS\n --------\n [verse]\n-'git prune' [-n] [-v] [--expire <expire>] [--] [<head>...]\n+'git prune' [-n] [-v] [--expire <expire>] [--[no-]progress] [--] [<head>...]\n \n DESCRIPTION\n -----------\n@@ -46,6 +46,13 @@ OPTIONS\n --expire <time>::\n \tOnly expire loose objects older than <time>.\n \n+--progress::\n+--no-progress::\n+\tProgress status is reported on the standard error stream\n+\tby default when it is attached to a terminal, unless --no-progress\n+\tis specified. This flag forces progress status even if the\n+\tstandard error stream is not directed to a terminal.\n+\n <head>...::\n \tIn addition to objects\n \treachable from any of our references, keep objects\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex 0498094..271376d 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -32,7 +32,7 @@ static const char *prune_expire = \"2.weeks.ago\";\n static const char *argv_pack_refs[] = {\"pack-refs\", \"--all\", \"--prune\", NULL};\n static const char *argv_reflog[] = {\"reflog\", \"expire\", \"--all\", NULL};\n static const char *argv_repack[MAX_ADD] = {\"repack\", \"-d\", \"-l\", NULL};\n-static const char *argv_prune[] = {\"prune\", \"--expire\", NULL, NULL};\n+static const char *argv_prune[] = {\"prune\", \"--expire\", NULL, NULL, NULL};\n static const char *argv_rerere[] = {\"rerere\", \"gc\", NULL};\n \n static int gc_config(const char *var, const char *value, void *cb)\n@@ -243,6 +243,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)\n \n \tif (prune_expire) {\n \t\targv_prune[2] = prune_expire;\n+\t\tif (quiet)\n+\t\t\targv_prune[3] = \"--no-progress\";\n \t\tif (run_command_v_opt(argv_prune, RUN_GIT_CMD))\n \t\t\treturn error(FAILED_RUN, argv_prune[0]);\n \t}\ndiff --git a/builtin/prune.c b/builtin/prune.c\nindex 6b39d3f..58d7cb8 100644\n--- a/builtin/prune.c\n+++ b/builtin/prune.c\n@@ -15,6 +15,7 @@ static const char * const prune_usage[] = {\n static int show_only;\n static int verbose;\n static unsigned long expire;\n+static int show_progress = -1;\n \n static int prune_tmp_object(const char *path, const char *filename)\n {\n@@ -125,10 +126,11 @@ static void remove_temporary_files(const char *path)\n int cmd_prune(int argc, const char **argv, const char *prefix)\n {\n \tstruct rev_info revs;\n-\tstruct progress *progress;\n+\tstruct progress *progress = NULL;\n \tconst struct option options[] = {\n \t\tOPT__DRY_RUN(&show_only, \"do not remove, show only\"),\n \t\tOPT__VERBOSE(&verbose, \"report pruned objects\"),\n+\t\tOPT_BOOL(0, \"progress\", &show_progress, \"show progress\"),\n \t\tOPT_DATE(0, \"expire\", &expire,\n \t\t\t \"expire objects older than <time>\"),\n \t\tOPT_END()\n@@ -154,7 +156,12 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n \t\telse\n \t\t\tdie(\"unrecognized argument: %s\", name);\n \t}\n-\tprogress = start_progress_delay(\"Checking connectivity\", 0, 0, 2);\n+\n+\tif (show_progress == -1)\n+\t\tshow_progress = isatty(2);\n+\tif (show_progress)\n+\t\tprogress = start_progress_delay(\"Checking connectivity\", 0, 0, 2);\n+\n \tmark_reachable_objects(&revs, 1, progress);\n \tstop_progress(&progress);\n \tprune_object_dir(get_object_directory());\n-- \n1.7.3.1.256.g2539c.dirty\n"},{"id":"179195","messageId":"20111109042642.GA11222@duynguyen-vnpc.dek-tpc.internal","threadId":"28848","inReplyTo":"20111108053149.GA29643@sigill.intra.peff.net","subject":"Re: [PATCH] prune: show progress while marking reachable objects","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-11-09T04:26:42Z","receivedAt":"2011-11-09T04:26:42Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Nov 08, 2011 at 12:31:49AM -0500, Jeff King wrote:\n> On Sat, Nov 05, 2011 at 07:00:08PM +0700, Nguyen Thai Ngoc Duy wrote:\n> \n> > prune already shows progress meter while pruning. The marking part may\n> > take a few seconds or more, depending on repository size. Show\n> > progress meter during this time too.\n> \n> Thanks, this is a nice start. It's missing a few things IMHO:\n> \n>   1. It actually counts commits, not all objects. I'm tempted to say\n>      this doesn't matter, as any eye candy is helpful. Except that the\n>      most common use of prune is as part of \"git gc\", in which case\n>      pack-objects will have just done the \"counting objects\" phase and\n>      come up with some number. If we count all objects, then our end\n>      number is the same (modulo any .keep packs, but at least it's\n>      probably in the same order of magnitude). That gives the user a\n>      better sense of completion time.\n> \n>   2. Prune should learn --progress/--no-progress, isatty(2), etc. And\n>      git-gc should pass --no-progress when it's told to be quiet.\n\n  3. Show progress meter while pruning packed objects. It does not\n     seem to take long enough time to show the meter. Anyway the code\n     is there we should enable it.\n\n-- 8< --\nSubject: [PATCH] prune: show progress meter while pruning packed objects\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin.h              |    4 ++++\n builtin/prune-packed.c |   13 +++++--------\n builtin/prune.c        |   13 +++++++++----\n 3 files changed, 18 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin.h b/builtin.h\nindex 0e9da90..0a5b511 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -13,6 +13,10 @@ extern const char git_version_string[];\n extern const char git_usage_string[];\n extern const char git_more_info_string[];\n \n+#define PRUNE_DRY_RUN  01\n+#define PRUNE_PROGRESS 02\n+#define PRUNE_VERBOSE  04\n+\n extern void prune_packed_objects(int);\n extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,\n \t\t\t int merge_title, int shortlog_len);\ndiff --git a/builtin/prune-packed.c b/builtin/prune-packed.c\nindex f9463de..d9f6d1d 100644\n--- a/builtin/prune-packed.c\n+++ b/builtin/prune-packed.c\n@@ -8,9 +8,6 @@ static const char * const prune_packed_usage[] = {\n \tNULL\n };\n \n-#define DRY_RUN 01\n-#define VERBOSE 02\n-\n static struct progress *progress;\n \n static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)\n@@ -29,7 +26,7 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)\n \t\tif (!has_sha1_pack(sha1))\n \t\t\tcontinue;\n \t\tmemcpy(pathname + len, de->d_name, 38);\n-\t\tif (opts & DRY_RUN)\n+\t\tif (opts & PRUNE_DRY_RUN)\n \t\t\tprintf(\"rm -f %s\\n\", pathname);\n \t\telse\n \t\t\tunlink_or_warn(pathname);\n@@ -46,7 +43,7 @@ void prune_packed_objects(int opts)\n \tconst char *dir = get_object_directory();\n \tint len = strlen(dir);\n \n-\tif (opts == VERBOSE)\n+\tif (opts & PRUNE_PROGRESS)\n \t\tprogress = start_progress_delay(\"Removing duplicate objects\",\n \t\t\t256, 95, 2);\n \n@@ -71,10 +68,10 @@ void prune_packed_objects(int opts)\n \n int cmd_prune_packed(int argc, const char **argv, const char *prefix)\n {\n-\tint opts = isatty(2) ? VERBOSE : 0;\n+\tint opts = isatty(2) ? PRUNE_PROGRESS : 0;\n \tconst struct option prune_packed_options[] = {\n-\t\tOPT_BIT('n', \"dry-run\", &opts, \"dry run\", DRY_RUN),\n-\t\tOPT_NEGBIT('q', \"quiet\", &opts, \"be quiet\", VERBOSE),\n+\t\tOPT_BIT('n', \"dry-run\", &opts, \"dry run\", PRUNE_DRY_RUN),\n+\t\tOPT_NEGBIT('q', \"quiet\", &opts, \"be quiet\", PRUNE_PROGRESS),\n \t\tOPT_END()\n \t};\n \ndiff --git a/builtin/prune.c b/builtin/prune.c\nindex 58d7cb8..4cdbac0 100644\n--- a/builtin/prune.c\n+++ b/builtin/prune.c\n@@ -127,9 +127,10 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n {\n \tstruct rev_info revs;\n \tstruct progress *progress = NULL;\n+\tint prune_opts = 0;\n \tconst struct option options[] = {\n-\t\tOPT__DRY_RUN(&show_only, \"do not remove, show only\"),\n-\t\tOPT__VERBOSE(&verbose, \"report pruned objects\"),\n+\t\tOPT_BIT('n', \"dry-run\", &prune_opts, \"do not remove, show only\", PRUNE_DRY_RUN),\n+\t\tOPT_BIT('v', \"verbose\", &prune_opts, \"report pruned objects\", PRUNE_VERBOSE),\n \t\tOPT_BOOL(0, \"progress\", &show_progress, \"show progress\"),\n \t\tOPT_DATE(0, \"expire\", &expire,\n \t\t\t \"expire objects older than <time>\"),\n@@ -143,6 +144,8 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n \tinit_revisions(&revs, prefix);\n \n \targc = parse_options(argc, argv, prefix, options, prune_usage, 0);\n+\tshow_only = prune_opts & PRUNE_DRY_RUN;\n+\tverbose = prune_opts & PRUNE_VERBOSE;\n \twhile (argc--) {\n \t\tunsigned char sha1[20];\n \t\tconst char *name = *argv++;\n@@ -159,14 +162,16 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n \n \tif (show_progress == -1)\n \t\tshow_progress = isatty(2);\n-\tif (show_progress)\n+\tif (show_progress) {\n+\t\tprune_opts |= PRUNE_PROGRESS;\n \t\tprogress = start_progress_delay(\"Checking connectivity\", 0, 0, 2);\n+\t}\n \n \tmark_reachable_objects(&revs, 1, progress);\n \tstop_progress(&progress);\n \tprune_object_dir(get_object_directory());\n \n-\tprune_packed_objects(show_only);\n+\tprune_packed_objects(prune_opts);\n \tremove_temporary_files(get_object_directory());\n \ts = xstrdup(mkpath(\"%s/pack\", get_object_directory()));\n \tremove_temporary_files(s);\n-- \n1.7.3.1.256.g2539c.dirty\n\n-- 8< --\n"}]}