1#include"cache.h" 2#include"diff.h" 3#include"commit.h" 4#include"sha1-lookup.h" 5#include"patch-ids.h" 6 7static intpatch_id_defined(struct commit *commit) 8{ 9/* must be 0 or 1 parents */ 10return!commit->parents || !commit->parents->next; 11} 12 13intcommit_patch_id(struct commit *commit,struct diff_options *options, 14struct object_id *oid,int diff_header_only) 15{ 16if(!patch_id_defined(commit)) 17return-1; 18 19if(commit->parents) 20diff_tree_oid(&commit->parents->item->object.oid, 21&commit->object.oid,"", options); 22else 23diff_root_tree_oid(&commit->object.oid,"", options); 24diffcore_std(options); 25returndiff_flush_patch_id(options, oid, diff_header_only); 26} 27 28/* 29 * When we cannot load the full patch-id for both commits for whatever 30 * reason, the function returns -1 (i.e. return error(...)). Despite 31 * the "cmp" in the name of this function, the caller only cares about 32 * the return value being zero (a and b are equivalent) or non-zero (a 33 * and b are different), and returning non-zero would keep both in the 34 * result, even if they actually were equivalent, in order to err on 35 * the side of safety. The actual value being negative does not have 36 * any significance; only that it is non-zero matters. 37 */ 38static intpatch_id_cmp(const void*unused_cmp_data, 39struct patch_id *a, 40struct patch_id *b, 41struct diff_options *opt) 42{ 43if(is_null_oid(&a->patch_id) && 44commit_patch_id(a->commit, opt, &a->patch_id,0)) 45returnerror("Could not get patch ID for%s", 46oid_to_hex(&a->commit->object.oid)); 47if(is_null_oid(&b->patch_id) && 48commit_patch_id(b->commit, opt, &b->patch_id,0)) 49returnerror("Could not get patch ID for%s", 50oid_to_hex(&b->commit->object.oid)); 51returnoidcmp(&a->patch_id, &b->patch_id); 52} 53 54intinit_patch_ids(struct patch_ids *ids) 55{ 56memset(ids,0,sizeof(*ids)); 57diff_setup(&ids->diffopts); 58 ids->diffopts.detect_rename =0; 59DIFF_OPT_SET(&ids->diffopts, RECURSIVE); 60diff_setup_done(&ids->diffopts); 61hashmap_init(&ids->patches, (hashmap_cmp_fn)patch_id_cmp, 62 NULL,256); 63return0; 64} 65 66intfree_patch_ids(struct patch_ids *ids) 67{ 68hashmap_free(&ids->patches,1); 69return0; 70} 71 72static intinit_patch_id_entry(struct patch_id *patch, 73struct commit *commit, 74struct patch_ids *ids) 75{ 76struct object_id header_only_patch_id; 77 78 patch->commit = commit; 79if(commit_patch_id(commit, &ids->diffopts, &header_only_patch_id,1)) 80return-1; 81 82hashmap_entry_init(patch,sha1hash(header_only_patch_id.hash)); 83return0; 84} 85 86struct patch_id *has_commit_patch_id(struct commit *commit, 87struct patch_ids *ids) 88{ 89struct patch_id patch; 90 91if(!patch_id_defined(commit)) 92return NULL; 93 94memset(&patch,0,sizeof(patch)); 95if(init_patch_id_entry(&patch, commit, ids)) 96return NULL; 97 98returnhashmap_get(&ids->patches, &patch, &ids->diffopts); 99} 100 101struct patch_id *add_commit_patch_id(struct commit *commit, 102struct patch_ids *ids) 103{ 104struct patch_id *key; 105 106if(!patch_id_defined(commit)) 107return NULL; 108 109 key =xcalloc(1,sizeof(*key)); 110if(init_patch_id_entry(key, commit, ids)) { 111free(key); 112return NULL; 113} 114 115hashmap_add(&ids->patches, key); 116return key; 117}