{"thread":{"id":"34820","subject":"[PATCH v2] revision: add --except option","startedAt":"2013-08-31T21:26:23Z","lastAt":"2013-09-02T06:52:36Z","messageCount":3,"participants":["Felipe Contreras","Johannes Sixt"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"226448","messageId":"1377984383-15770-1-git-send-email-felipe.contreras@gmail.com","threadId":"34820","inReplyTo":null,"subject":"[PATCH v2] revision: add --except option","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-08-31T21:26:23Z","receivedAt":"2013-08-31T21:26:23Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"So that it's possible to remove certain refs from the list without\nremoving the objects that are referenced by other refs.\n\nFor example this repository:\n\n  C (crap)\n  B (test)\n  A (HEAD, master)\n\nWhen using '--branches --except crap':\n\n  B (test)\n  A (HEAD, master)\n\nBut when using '--branches --not crap' nothing will come out.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n\nI don't like the complexity of recalculate_flag(), but it seems to be the most\nstraight-forward way of making --not and --except work.\n\n Documentation/git-rev-parse.txt        |  6 ++++\n contrib/completion/git-completion.bash |  2 +-\n revision.c                             | 52 ++++++++++++++++++++++++++++-\n revision.h                             |  3 +-\n t/t6112-rev-list-except.sh             | 60 ++++++++++++++++++++++++++++++++++\n 5 files changed, 120 insertions(+), 3 deletions(-)\n create mode 100755 t/t6112-rev-list-except.sh\n\ndiff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt\nindex 2b126c0..fe5cc6b 100644\n--- a/Documentation/git-rev-parse.txt\n+++ b/Documentation/git-rev-parse.txt\n@@ -110,6 +110,12 @@ can be used.\n \tstrip '{caret}' prefix from the object names that already have\n \tone.\n \n+--except::\n+\tSkip the following object names. For example:\n+\t'--branches --except master' will show all the branches, except master.\n+\tThis differs from --not in that --except will still show the object, if\n+\tthey are referenced by another object name.\n+\n --symbolic::\n \tUsually the object names are output in SHA-1 form (with\n \tpossible '{caret}' prefix); this option makes them output in a\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 5da920e..aed8c12 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1386,7 +1386,7 @@ _git_ls_tree ()\n \n # Options that go well for log, shortlog and gitk\n __git_log_common_options=\"\n-\t--not --all\n+\t--not --except --all\n \t--branches --tags --remotes\n \t--first-parent --merges --no-merges\n \t--max-count=\ndiff --git a/revision.c b/revision.c\nindex 84ccc05..a7664dd 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1984,6 +1984,8 @@ static int handle_revision_pseudo_opt(const char *submodule,\n \t\thandle_reflog(revs, *flags);\n \t} else if (!strcmp(arg, \"--not\")) {\n \t\t*flags ^= UNINTERESTING | BOTTOM;\n+\t} else if (!strcmp(arg, \"--except\")) {\n+\t\t*flags |= SKIP;\n \t} else if (!strcmp(arg, \"--no-walk\")) {\n \t\trevs->no_walk = REVISION_WALK_NO_WALK_SORTED;\n \t} else if (!prefixcmp(arg, \"--no-walk=\")) {\n@@ -2573,24 +2575,72 @@ void reset_revision_walk(void)\n \tclear_object_flags(SEEN | ADDED | SHOWN);\n }\n \n+static int refcmp(const char *a, const char *b)\n+{\n+\ta = prettify_refname(a);\n+\tif (*a == '^')\n+\t\ta++;\n+\tb = prettify_refname(b);\n+\tif (*b == '^')\n+\t\tb++;\n+\treturn strcmp(a, b);\n+}\n+\n+static int recalculate_flag(struct rev_info *revs, unsigned char *sha1, const char *name)\n+{\n+\tint flags = 0;\n+\tint i;\n+\tfor (i = 0; i < revs->cmdline.nr; i++) {\n+\t\tstruct object *object;\n+\t\tstruct rev_cmdline_entry *ce;\n+\t\tce = &revs->cmdline.rev[i];\n+\t\tobject = ce->item;\n+\t\twhile (object->type == OBJ_TAG) {\n+\t\t\tstruct tag *tag = (struct tag *) object;\n+\t\t\tif (!tag->tagged)\n+\t\t\t\tcontinue;\n+\t\t\tobject = parse_object(tag->tagged->sha1);\n+\t\t\tif (!object)\n+\t\t\t\tcontinue;\n+\t\t}\n+\t\tif (hashcmp(object->sha1, sha1))\n+\t\t\tcontinue;\n+\t\tif (!strcmp(ce->name, name))\n+\t\t\tcontinue;\n+\t\tflags |= ce->flags;\n+\t}\n+\treturn flags;\n+}\n+\n int prepare_revision_walk(struct rev_info *revs)\n {\n \tint nr = revs->pending.nr;\n \tstruct object_array_entry *e, *list;\n \tstruct commit_list **next = &revs->commits;\n+\tint i;\n \n \te = list = revs->pending.objects;\n \trevs->pending.nr = 0;\n \trevs->pending.alloc = 0;\n \trevs->pending.objects = NULL;\n \twhile (--nr >= 0) {\n-\t\tstruct commit *commit = handle_commit(revs, e->item, e->name);\n+\t\tstruct commit *commit;\n+\t\tfor (i = 0; i < revs->cmdline.nr; i++) {\n+\t\t\tstruct rev_cmdline_entry *ce;\n+\t\t\tce = &revs->cmdline.rev[i];\n+\t\t\tif ((ce->flags & SKIP) && !refcmp(ce->name, e->name)) {\n+\t\t\t\te->item->flags = recalculate_flag(revs, e->item->sha1, ce->name);\n+\t\t\t\tgoto next;\n+\t\t\t}\n+\t\t}\n+\t\tcommit = handle_commit(revs, e->item, e->name);\n \t\tif (commit) {\n \t\t\tif (!(commit->object.flags & SEEN)) {\n \t\t\t\tcommit->object.flags |= SEEN;\n \t\t\t\tnext = commit_list_append(commit, next);\n \t\t\t}\n \t\t}\n+next:\n \t\te++;\n \t}\n \tif (!revs->leak_pending)\ndiff --git a/revision.h b/revision.h\nindex 95859ba..89f5037 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -17,7 +17,8 @@\n #define SYMMETRIC_LEFT\t(1u<<8)\n #define PATCHSAME\t(1u<<9)\n #define BOTTOM\t\t(1u<<10)\n-#define ALL_REV_FLAGS\t((1u<<11)-1)\n+#define SKIP\t\t(1u<<11)\n+#define ALL_REV_FLAGS\t((1u<<12)-1)\n \n #define DECORATE_SHORT_REFS\t1\n #define DECORATE_FULL_REFS\t2\ndiff --git a/t/t6112-rev-list-except.sh b/t/t6112-rev-list-except.sh\nnew file mode 100755\nindex 0000000..a40a641\n--- /dev/null\n+++ b/t/t6112-rev-list-except.sh\n@@ -0,0 +1,60 @@\n+#!/bin/sh\n+\n+test_description='test for rev-list --except'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\n+\techo one > content &&\n+\tgit add content &&\n+\tgit commit -m one &&\n+\tgit checkout -b test master &&\n+\techo two > content &&\n+\tgit commit -a -m two &&\n+\tgit checkout -b merge master &&\n+\tgit merge test\n+'\n+\n+test_expect_success 'rev-list --except' '\n+\n+\tgit rev-list --topo-order --branches --except merge > actual &&\n+\tgit rev-list --topo-order test > expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'rev-list --except with extra' '\n+\n+\techo three > content &&\n+\tgit commit -a -m three &&\n+\tgit rev-list --topo-order --branches --except merge > actual &&\n+\tgit rev-list --topo-order test > expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'rev-list --except with full ref' '\n+\n+\tgit rev-list --topo-order --branches --except refs/heads/merge > actual &&\n+\tgit rev-list --topo-order test > expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'rev-list --except and --not' '\n+\n+\tgit rev-list --topo-order test --not master --except master > actual &&\n+\tgit rev-list --topo-order test > expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'rev-list --except and --not with proper flags' '\n+\n+\tgit checkout -b maint master &&\n+\tgit checkout -b next test &&\n+\techo four > content &&\n+\tgit commit -a -m four &&\n+\tgit rev-list --topo-order next --not master maint --except maint > actual &&\n+\tgit rev-list --topo-order next --not master > expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_done\n-- \n1.8.4-337-g7358a66-dirty\n"},{"id":"226505","messageId":"52243086.6030102@viscovery.net","threadId":"34820","inReplyTo":"1377984383-15770-1-git-send-email-felipe.contreras@gmail.com","subject":"Re: [PATCH v2] revision: add --except option","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2013-09-02T06:30:30Z","receivedAt":"2013-09-02T06:30:30Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 8/31/2013 23:26, schrieb Felipe Contreras:\n> +--except::\n> +\tSkip the following object names. For example:\n> +\t'--branches --except master' will show all the branches, except master.\n> +\tThis differs from --not in that --except will still show the object, if\n> +\tthey are referenced by another object name.\n\n--except needs a bit more documentation, in particular, how it interacts\nwith --not.\n\nIt would be better to settle on the meaning of --except before throwing\nback and forth implementations.\n\n-- Hannes\n"},{"id":"226516","messageId":"CAMP44s0UMb9OOqoLnf219UuH9On0O8hvT5oufSSqO_qnPFb_Mg@mail.gmail.com","threadId":"34820","inReplyTo":"52243086.6030102@viscovery.net","subject":"Re: [PATCH v2] revision: add --except option","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-09-02T06:52:36Z","receivedAt":"2013-09-02T06:52:36Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Mon, Sep 2, 2013 at 1:30 AM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n\n> It would be better to settle on the meaning of --except before throwing\n> back and forth implementations.\n\nI've lost the count of features that get discussed endlessly, and\nnobody implements them ever. The implementation should dictate the\nbehavior, because it doesn't matter if you have described perfect\nbehavior, and the implementation is nearly impossible. If you\ndisagree, feel free to write the code.\n\nTalk is cheap, show me the code. -- Linus Torvalds\n\n-- \nFelipe Contreras\n"}]}