* [PATCH v3] revision: add --except option
@ 2013-10-12 7:08 Felipe Contreras
0 siblings, 0 replies; only message in thread
From: Felipe Contreras @ 2013-10-12 7:08 UTC (permalink / raw)
To: git; +Cc: Felipe Contreras
So that it's possible to remove certain refs from the list without
removing the objects that are referenced by other refs.
For example this repository:
C (crap)
B (test)
A (HEAD, master)
When using '--branches --except crap':
B (test)
A (HEAD, master)
But when using '--branches --not crap' nothing will come out.
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
Documentation/git-rev-parse.txt | 6 +++
contrib/completion/git-completion.bash | 2 +-
revision.c | 54 +++++++++++++++++++++++-
revision.h | 3 +-
t/t6112-rev-list-except.sh | 77 ++++++++++++++++++++++++++++++++++
5 files changed, 139 insertions(+), 3 deletions(-)
create mode 100755 t/t6112-rev-list-except.sh
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 2b126c0..fe5cc6b 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -110,6 +110,12 @@ can be used.
strip '{caret}' prefix from the object names that already have
one.
+--except::
+ Skip the following object names. For example:
+ '--branches --except master' will show all the branches, except master.
+ This differs from --not in that --except will still show the object, if
+ they are referenced by another object name.
+
--symbolic::
Usually the object names are output in SHA-1 form (with
possible '{caret}' prefix); this option makes them output in a
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 5da920e..aed8c12 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1386,7 +1386,7 @@ _git_ls_tree ()
# Options that go well for log, shortlog and gitk
__git_log_common_options="
- --not --all
+ --not --except --all
--branches --tags --remotes
--first-parent --merges --no-merges
--max-count=
diff --git a/revision.c b/revision.c
index 84ccc05..c92f755 100644
--- a/revision.c
+++ b/revision.c
@@ -1984,6 +1984,9 @@ static int handle_revision_pseudo_opt(const char *submodule,
handle_reflog(revs, *flags);
} else if (!strcmp(arg, "--not")) {
*flags ^= UNINTERESTING | BOTTOM;
+ *flags &= ~SKIP;
+ } else if (!strcmp(arg, "--except")) {
+ *flags |= SKIP;
} else if (!strcmp(arg, "--no-walk")) {
revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
} else if (!prefixcmp(arg, "--no-walk=")) {
@@ -2573,24 +2576,73 @@ void reset_revision_walk(void)
clear_object_flags(SEEN | ADDED | SHOWN);
}
+static int refcmp(const char *a, const char *b)
+{
+ a = prettify_refname(a);
+ if (*a == '^')
+ a++;
+ b = prettify_refname(b);
+ if (*b == '^')
+ b++;
+ return strcmp(a, b);
+}
+
+static int recalculate_flag(struct rev_info *revs, unsigned char *sha1, const char *name)
+{
+ int flags = 0;
+ int i;
+ for (i = 0; i < revs->cmdline.nr; i++) {
+ struct object *object;
+ struct rev_cmdline_entry *ce;
+ ce = &revs->cmdline.rev[i];
+ object = ce->item;
+ while (object->type == OBJ_TAG) {
+ struct tag *tag = (struct tag *) object;
+ if (!tag->tagged)
+ continue;
+ object = parse_object(tag->tagged->sha1);
+ if (!object)
+ continue;
+ }
+ if (hashcmp(object->sha1, sha1))
+ continue;
+ if (!strcmp(ce->name, name))
+ continue;
+ flags |= ce->flags;
+ }
+ return flags;
+}
+
int prepare_revision_walk(struct rev_info *revs)
{
int nr = revs->pending.nr;
struct object_array_entry *e, *list;
struct commit_list **next = &revs->commits;
+ int i;
e = list = revs->pending.objects;
revs->pending.nr = 0;
revs->pending.alloc = 0;
revs->pending.objects = NULL;
while (--nr >= 0) {
- struct commit *commit = handle_commit(revs, e->item, e->name);
+ struct commit *commit;
+ for (i = 0; i < revs->cmdline.nr; i++) {
+ struct rev_cmdline_entry *ce;
+ ce = &revs->cmdline.rev[i];
+ if ((ce->flags & SKIP) && !refcmp(ce->name, e->name) &&
+ ((ce->flags & UNINTERESTING) == (e->item->flags & UNINTERESTING))) {
+ e->item->flags = recalculate_flag(revs, e->item->sha1, ce->name);
+ goto next;
+ }
+ }
+ commit = handle_commit(revs, e->item, e->name);
if (commit) {
if (!(commit->object.flags & SEEN)) {
commit->object.flags |= SEEN;
next = commit_list_append(commit, next);
}
}
+next:
e++;
}
if (!revs->leak_pending)
diff --git a/revision.h b/revision.h
index 95859ba..89f5037 100644
--- a/revision.h
+++ b/revision.h
@@ -17,7 +17,8 @@
#define SYMMETRIC_LEFT (1u<<8)
#define PATCHSAME (1u<<9)
#define BOTTOM (1u<<10)
-#define ALL_REV_FLAGS ((1u<<11)-1)
+#define SKIP (1u<<11)
+#define ALL_REV_FLAGS ((1u<<12)-1)
#define DECORATE_SHORT_REFS 1
#define DECORATE_FULL_REFS 2
diff --git a/t/t6112-rev-list-except.sh b/t/t6112-rev-list-except.sh
new file mode 100755
index 0000000..441e1da
--- /dev/null
+++ b/t/t6112-rev-list-except.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+test_description='test for rev-list --except'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+
+ echo one > content &&
+ git add content &&
+ git commit -m one &&
+ git checkout -b test master &&
+ echo two > content &&
+ git commit -a -m two &&
+ git checkout -b merge master &&
+ git merge test
+'
+
+test_expect_success 'rev-list --except' '
+
+ git rev-list --topo-order --branches --except merge > actual &&
+ git rev-list --topo-order test > expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list --except with extra' '
+
+ echo three > content &&
+ git commit -a -m three &&
+ git rev-list --topo-order --branches --except merge > actual &&
+ git rev-list --topo-order test > expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list --except with full ref' '
+
+ git rev-list --topo-order --branches --except refs/heads/merge > actual &&
+ git rev-list --topo-order test > expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list --except and --not' '
+
+ git rev-list --topo-order test --not master --except master > actual &&
+ git rev-list --topo-order test > expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list --except and --not with proper flags' '
+
+ git checkout -b maint master &&
+ git checkout -b next test &&
+ echo four > content &&
+ git commit -a -m four &&
+ git rev-list --topo-order next --not master maint --except maint > actual &&
+ git rev-list --topo-order next --not master > expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list --not ranges' '
+
+ git rev-list --topo-order test --not master --except master test > actual &&
+ git rev-list --topo-order test > expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list multiple --not ranges' '
+
+ git checkout -b extra test &&
+ echo five > content &&
+ git commit -a -m five &&
+ git rev-list --topo-order test --not master --except master test --not extra > actual &&
+ git rev-list --topo-order test extra > expect &&
+ test_cmp expect actual
+'
+
+test_done
--
1.8.4-fc
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2013-10-12 7:14 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-12 7:08 [PATCH v3] revision: add --except option Felipe Contreras
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).