1 #include "git-compat-util.h"
5 #include "hash-lookup.h"
9 static int patch_id_defined(struct commit
*commit
)
11 /* must be 0 or 1 parents */
12 return !commit
->parents
|| !commit
->parents
->next
;
15 int commit_patch_id(struct commit
*commit
, struct diff_options
*options
,
16 struct object_id
*oid
, int diff_header_only
)
18 if (!patch_id_defined(commit
))
22 diff_tree_oid(&commit
->parents
->item
->object
.oid
,
23 &commit
->object
.oid
, "", options
);
25 diff_root_tree_oid(&commit
->object
.oid
, "", options
);
26 diffcore_std(options
);
27 return diff_flush_patch_id(options
, oid
, diff_header_only
);
31 * When we cannot load the full patch-id for both commits for whatever
32 * reason, the function returns -1 (i.e. return error(...)). Despite
33 * the "neq" in the name of this function, the caller only cares about
34 * the return value being zero (a and b are equivalent) or non-zero (a
35 * and b are different), and returning non-zero would keep both in the
36 * result, even if they actually were equivalent, in order to err on
37 * the side of safety. The actual value being negative does not have
38 * any significance; only that it is non-zero matters.
40 static int patch_id_neq(const void *cmpfn_data
,
41 const struct hashmap_entry
*eptr
,
42 const struct hashmap_entry
*entry_or_key
,
43 const void *keydata UNUSED
)
45 /* NEEDSWORK: const correctness? */
46 struct diff_options
*opt
= (void *)cmpfn_data
;
47 struct patch_id
*a
, *b
;
49 a
= container_of(eptr
, struct patch_id
, ent
);
50 b
= container_of(entry_or_key
, struct patch_id
, ent
);
52 if (is_null_oid(&a
->patch_id
) &&
53 commit_patch_id(a
->commit
, opt
, &a
->patch_id
, 0))
54 return error("Could not get patch ID for %s",
55 oid_to_hex(&a
->commit
->object
.oid
));
56 if (is_null_oid(&b
->patch_id
) &&
57 commit_patch_id(b
->commit
, opt
, &b
->patch_id
, 0))
58 return error("Could not get patch ID for %s",
59 oid_to_hex(&b
->commit
->object
.oid
));
60 return !oideq(&a
->patch_id
, &b
->patch_id
);
63 int init_patch_ids(struct repository
*r
, struct patch_ids
*ids
)
65 memset(ids
, 0, sizeof(*ids
));
66 repo_diff_setup(r
, &ids
->diffopts
);
67 ids
->diffopts
.detect_rename
= 0;
68 ids
->diffopts
.flags
.recursive
= 1;
69 diff_setup_done(&ids
->diffopts
);
70 hashmap_init(&ids
->patches
, patch_id_neq
, &ids
->diffopts
, 256);
74 int free_patch_ids(struct patch_ids
*ids
)
76 hashmap_clear_and_free(&ids
->patches
, struct patch_id
, ent
);
80 static int init_patch_id_entry(struct patch_id
*patch
,
81 struct commit
*commit
,
82 struct patch_ids
*ids
)
84 struct object_id header_only_patch_id
;
86 patch
->commit
= commit
;
87 if (commit_patch_id(commit
, &ids
->diffopts
, &header_only_patch_id
, 1))
90 hashmap_entry_init(&patch
->ent
, oidhash(&header_only_patch_id
));
94 struct patch_id
*patch_id_iter_first(struct commit
*commit
,
95 struct patch_ids
*ids
)
97 struct patch_id patch
;
99 if (!patch_id_defined(commit
))
102 memset(&patch
, 0, sizeof(patch
));
103 if (init_patch_id_entry(&patch
, commit
, ids
))
106 return hashmap_get_entry(&ids
->patches
, &patch
, ent
, NULL
);
109 struct patch_id
*patch_id_iter_next(struct patch_id
*cur
,
110 struct patch_ids
*ids
)
112 return hashmap_get_next_entry(&ids
->patches
, cur
, ent
);
115 int has_commit_patch_id(struct commit
*commit
,
116 struct patch_ids
*ids
)
118 return !!patch_id_iter_first(commit
, ids
);
121 struct patch_id
*add_commit_patch_id(struct commit
*commit
,
122 struct patch_ids
*ids
)
124 struct patch_id
*key
;
126 if (!patch_id_defined(commit
))
129 CALLOC_ARRAY(key
, 1);
130 if (init_patch_id_entry(key
, commit
, ids
)) {
135 hashmap_add(&ids
->patches
, &key
->ent
);