Skip to content

Commit

Permalink
WIP: --find-objects: find root trees, too
Browse files Browse the repository at this point in the history
TODO: add test, document that `-c` and `--cc` are buggy and show commit
headers even though the pickaxe machinery does not select the commit.

Due to technical reasons, the diff machinery does not print out the root
tree of any given commit when running with the `-t` option (for details,
see https://git-scm.com/docs/git-log#Documentation/git-log.txt--t).

However, quite often that is precisely what I need to find: the commit
that introduced a certain change that ended up with the exact
problematic (recursive) tree shape.

The underlying problem is that the layer at which `-t` prints entries is
when iterating the tree items, but the root tree is not a child of
another tree, therefore it is never reached through such an iteration.

So let's fudge things by specifically adding the root tree OID into the
`objfind` set for commits that change the top-level tree.

Signed-off-by: Johannes Schindelin <[email protected]>
  • Loading branch information
dscho committed Nov 20, 2023
1 parent cfb8a6e commit 3191fa9
Showing 1 changed file with 41 additions and 0 deletions.
41 changes: 41 additions & 0 deletions tree-diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "tree.h"
#include "tree-walk.h"
#include "environment.h"
#include "commit.h"

/*
* Some mode bits are also used internally for computations.
Expand Down Expand Up @@ -699,6 +700,22 @@ static void try_to_follow_renames(const struct object_id *old_oid,
q->nr = 1;
}

static struct object_id *peel_to_tree(const struct object_id *oid, struct object_id *out)
{
if (!oid)
oidcpy(out, null_oid());
else {
struct object *o = parse_object(the_repository, oid);

if (o->type == OBJ_TREE)
oidcpy(out, oid);
else
oidcpy(out, get_commit_tree_oid((struct commit *)o));
}

return out;
}

static void ll_diff_tree_oid(const struct object_id *old_oid,
const struct object_id *new_oid,
struct strbuf *base, struct diff_options *opt)
Expand All @@ -708,6 +725,30 @@ static void ll_diff_tree_oid(const struct object_id *old_oid,

phead.next = NULL;
opt->pathchange = emit_diff_first_parent_only;

/*
* Allow --find-object to find the root tree by adding a diff pair with
* empty path.
*
* We might need to peel the provided OIDs to tree OIDs because
* `diff_tree_combined()` passes commit OIDs instead of tree OIDs.
*/
if (opt->objfind) {
struct object_id old_tree_oid, new_tree_oid;

peel_to_tree(old_oid, &old_tree_oid);
peel_to_tree(new_oid, &new_tree_oid);

if (!oideq(&old_tree_oid, &new_tree_oid)) {
p = path_appendnew(&phead, 1, base, "", 0, S_IFREG | 0755, &new_tree_oid);
p->parent[0].mode = p->mode;
oidcpy(&p->parent[0].oid, &old_tree_oid);
opt->pathchange(opt, p);

FREE_AND_NULL(phead.next);
}
}

diff_tree_paths(&phead, new_oid, &old_oid, 1, base, opt);

for (p = phead.next; p;) {
Expand Down

0 comments on commit 3191fa9

Please sign in to comment.