Skip to content

Commit

Permalink
Teach revision walking machinery to walk multiple times sequencially
Browse files Browse the repository at this point in the history
Previously it was not possible to iterate revisions twice using the
revision walking api. We add a reset_revision_walk() which clears the
used flags. This allows us to do multiple sequencial revision walks.

We add the appropriate calls to the existing submodule machinery doing
revision walks. This is done to avoid surprises if future code wants to
call these functions more than once during the processes lifetime.

Signed-off-by: Heiko Voigt <hvoigt@hvoigt.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Heiko Voigt authored and Junio C Hamano committed Mar 30, 2012
1 parent 6f5e880 commit bcc0a3e
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@
/test-mktemp
/test-parse-options
/test-path-utils
/test-revision-walking
/test-run-command
/test-sha1
/test-sigchain
Expand Down
5 changes: 5 additions & 0 deletions Documentation/technical/api-revision-walking.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ function.
returning a `struct commit *` each time you call it. The end of the
revision list is indicated by returning a NULL pointer.

`reset_revision_walk`::

Reset the flags used by the revision walking api. You can use
this to do multiple sequencial revision walks.

Data structures
---------------

Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ TEST_PROGRAMS_NEED_X += test-match-trees
TEST_PROGRAMS_NEED_X += test-mktemp
TEST_PROGRAMS_NEED_X += test-parse-options
TEST_PROGRAMS_NEED_X += test-path-utils
TEST_PROGRAMS_NEED_X += test-revision-walking
TEST_PROGRAMS_NEED_X += test-run-command
TEST_PROGRAMS_NEED_X += test-sha1
TEST_PROGRAMS_NEED_X += test-sigchain
Expand Down
11 changes: 11 additions & 0 deletions object.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,14 @@ void object_array_remove_duplicates(struct object_array *array)
array->nr = dst;
}
}

void clear_object_flags(unsigned flags)
{
int i;

for (i=0; i < obj_hash_size; i++) {
struct object *obj = obj_hash[i];
if (obj)
obj->flags &= ~flags;
}
}
2 changes: 2 additions & 0 deletions object.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,6 @@ void add_object_array(struct object *obj, const char *name, struct object_array
void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode);
void object_array_remove_duplicates(struct object_array *);

void clear_object_flags(unsigned flags);

#endif /* OBJECT_H */
5 changes: 5 additions & 0 deletions revision.c
Original file line number Diff line number Diff line change
Expand Up @@ -2061,6 +2061,11 @@ static void set_children(struct rev_info *revs)
}
}

void reset_revision_walk(void)
{
clear_object_flags(SEEN | ADDED | SHOWN);
}

int prepare_revision_walk(struct rev_info *revs)
{
int nr = revs->pending.nr;
Expand Down
1 change: 1 addition & 0 deletions revision.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ extern void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ct
const char * const usagestr[]);
extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,int cant_be_filename);

extern void reset_revision_walk(void);
extern int prepare_revision_walk(struct rev_info *revs);
extern struct commit *get_revision(struct rev_info *revs);
extern char *get_revision_mark(const struct rev_info *revs, const struct commit *commit);
Expand Down
2 changes: 2 additions & 0 deletions submodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ int check_submodule_needs_pushing(unsigned char new_sha1[20], const char *remote
while ((commit = get_revision(&rev)) && !needs_pushing)
commit_need_pushing(commit, &needs_pushing);

reset_revision_walk();
free(sha1_copy);
strbuf_release(&remotes_arg);

Expand Down Expand Up @@ -741,6 +742,7 @@ static int find_first_merges(struct object_array *result, const char *path,
if (in_merge_bases(b, &commit, 1))
add_object_array(o, NULL, &merges);
}
reset_revision_walk();

/* Now we've got all merges that contain a and b. Prune all
* merges that contain another found merge and save them in
Expand Down
33 changes: 33 additions & 0 deletions t/t0062-revision-walking.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/sh
#
# Copyright (c) 2012 Heiko Voigt
#

test_description='Test revision walking api'

. ./test-lib.sh

cat >run_twice_expected <<-EOF
1st
> add b
> add a
2nd
> add b
> add a
EOF

test_expect_success 'setup' '
echo a > a &&
git add a &&
git commit -m "add a" &&
echo b > b &&
git add b &&
git commit -m "add b"
'

test_expect_success 'revision walking can be done twice' '
test-revision-walking run-twice > run_twice_actual
test_cmp run_twice_expected run_twice_actual
'

test_done
66 changes: 66 additions & 0 deletions test-revision-walking.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* test-revision-walking.c: test revision walking API.
*
* (C) 2012 Heiko Voigt <hvoigt@hvoigt.net>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/

#include "cache.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"

static void print_commit(struct commit *commit)
{
struct strbuf sb = STRBUF_INIT;
struct pretty_print_context ctx = {0};
ctx.date_mode = DATE_NORMAL;
format_commit_message(commit, " %m %s", &sb, &ctx);
printf("%s\n", sb.buf);
strbuf_release(&sb);
}

static int run_revision_walk(void)
{
struct rev_info rev;
struct commit *commit;
const char *argv[] = {NULL, "--all", NULL};
int argc = ARRAY_SIZE(argv) - 1;
int got_revision = 0;

init_revisions(&rev, NULL);
setup_revisions(argc, argv, &rev, NULL);
if (prepare_revision_walk(&rev))
die("revision walk setup failed");

while ((commit = get_revision(&rev)) != NULL) {
print_commit(commit);
got_revision = 1;
}

reset_revision_walk();
return got_revision;
}

int main(int argc, char **argv)
{
if (argc < 2)
return 1;

if (!strcmp(argv[1], "run-twice")) {
printf("1st\n");
if (!run_revision_walk())
return 1;
printf("2nd\n");
if (!run_revision_walk())
return 1;

return 0;
}

fprintf(stderr, "check usage\n");
return 1;
}

0 comments on commit bcc0a3e

Please sign in to comment.