just increment the commit counter and move on.
The callback for non-commits is a little different, as we'll need to check
which kind of object we're dealing with:
----
static void walken_show_object(struct object *obj, const char *str, void *buf)
{
switch (obj->type) {
case OBJ_TREE:
tree_count++;
break;
case OBJ_BLOB:
blob_count++;
break;
case OBJ_TAG:
tag_count++;
break;
case OBJ_COMMIT:
BUG("unexpected commit object in walken_show_object\n");
default:
BUG("unexpected object type %s in walken_show_object\n",
type_name(obj->type));
}
}
----
Again, `obj` is fairly self-explanatory, and we can guess that `buf` is the same
context pointer that `walken_show_commit()` receives: the `show_data` argument
to `traverse_commit_list()` and `traverse_commit_list_filtered()`. Finally,
`str` contains the name of the object, which ends up being something like
`foo.txt` (blob), `bar/baz` (tree), or `v1.2.3` (tag).
To help assure us that we aren't double-counting commits, we'll include some
complaining if a commit object is routed through our non-commit callback; we'll
also complain if we see an invalid object type. Since those two cases should be
unreachable, and would only change in the event of a semantic change to the Git
codebase, we complain by using `BUG()` - which is a signal to a developer that
the change they made caused unintended consequences, and the rest of the
codebase needs to be updated to understand that change. `BUG()` is not intended
to be seen by the public, so it is not localized.
Our main object walk implementation is substantially different from our commit
walk implementation, so let's make a new function to perform the object walk. We
can perform setup which is applicable to all objects here, too, to keep separate
from setup which is applicable to commit-only walks.
We'll start by enabling all types of objects in the `struct rev_info`. We'll
also turn on `tree_blobs_in_commit_order`, which means that we will walk a
commit's tree and everything it points to immediately after we find each commit,
as opposed to waiting for the end and walking through all trees after the commit
history has been discovered. With the appropriate settings configured, we are
ready to call `prepare_revision_walk()`.
----
static void walken_object_walk(struct rev_info *rev)
{
rev->tree_objects = 1;
rev->blob_objects = 1;
rev->tag_objects = 1;
rev->tree_blobs_in_commit_order = 1;
if (prepare_revision_walk(rev))
die(_("revision walk setup failed"));
commit_count = 0;
tag_count = 0;
blob_count = 0;
tree_count = 0;
----
Let's start by calling just the unfiltered walk and reporting our counts.
Complete your implementation of `walken_object_walk()`.
We'll also need to include the `list-objects.h` header.
----
#include "list-objects.h"
...
traverse_commit_list(rev, walken_show_commit, walken_show_object, NULL);
printf("commits %d\nblobs %d\ntags %d\ntrees %d\n", commit_count,
blob_count, tag_count, tree_count);
}
----
NOTE: This output is intended to be machine-parsed. Therefore, we are not
sending it to `trace_printf()`, and we are not localizing it - we need scripts
to be able to count on the formatting to be exactly the way it is shown here.
If we were intending this output to be read by humans, we would need to localize
it with `_()`.
Finally, we'll ask `cmd_walken()` to use the object walk instead. Discussing
command line options is out of scope for this tutorial, so we'll just hardcode
a branch we can change at compile time. Where you call `final_rev_info_setup()`
and `walken_commit_walk()`, instead branch like so:
----
if (1) {
add_head_to_pending(&rev);
walken_object_walk(&rev);
} else {
final_rev_info_setup(argc, argv, prefix, &rev);
walken_commit_walk(&rev);
}
----
NOTE: For simplicity, we've avoided all the filters and sorts we applied in
`final_rev_info_setup()` and simply added `HEAD` to our pending queue. If you
want, you can certainly use the filters we added before