1#include"cache.h" 2#include"refs.h" 3#include"tag.h" 4#include"commit.h" 5#include"blob.h" 6#include"diff.h" 7#include"revision.h" 8#include"reachable.h" 9#include"cache-tree.h" 10#include"progress.h" 11#include"list-objects.h" 12 13struct connectivity_progress { 14struct progress *progress; 15unsigned long count; 16}; 17 18static voidupdate_progress(struct connectivity_progress *cp) 19{ 20 cp->count++; 21if((cp->count &1023) ==0) 22display_progress(cp->progress, cp->count); 23} 24 25static intadd_one_ref(const char*path,const unsigned char*sha1,int flag,void*cb_data) 26{ 27struct object *object =parse_object_or_die(sha1, path); 28struct rev_info *revs = (struct rev_info *)cb_data; 29 30add_pending_object(revs, object,""); 31 32return0; 33} 34 35static voidadd_one_tree(const unsigned char*sha1,struct rev_info *revs) 36{ 37struct tree *tree =lookup_tree(sha1); 38if(tree) 39add_pending_object(revs, &tree->object,""); 40} 41 42static voidadd_cache_tree(struct cache_tree *it,struct rev_info *revs) 43{ 44int i; 45 46if(it->entry_count >=0) 47add_one_tree(it->sha1, revs); 48for(i =0; i < it->subtree_nr; i++) 49add_cache_tree(it->down[i]->cache_tree, revs); 50} 51 52static voidadd_cache_refs(struct rev_info *revs) 53{ 54int i; 55 56read_cache(); 57for(i =0; i < active_nr; i++) { 58struct blob *blob; 59 60/* 61 * The index can contain blobs and GITLINKs, GITLINKs are hashes 62 * that don't actually point to objects in the repository, it's 63 * almost guaranteed that they are NOT blobs, so we don't call 64 * lookup_blob() on them, to avoid populating the hash table 65 * with invalid information 66 */ 67if(S_ISGITLINK(active_cache[i]->ce_mode)) 68continue; 69 70 blob =lookup_blob(active_cache[i]->sha1); 71if(blob) 72 blob->object.flags |= SEEN; 73 74/* 75 * We could add the blobs to the pending list, but quite 76 * frankly, we don't care. Once we've looked them up, and 77 * added them as objects, we've really done everything 78 * there is to do for a blob 79 */ 80} 81if(active_cache_tree) 82add_cache_tree(active_cache_tree, revs); 83} 84 85/* 86 * The traversal will have already marked us as SEEN, so we 87 * only need to handle any progress reporting here. 88 */ 89static voidmark_object(struct object *obj,const struct name_path *path, 90const char*name,void*data) 91{ 92update_progress(data); 93} 94 95static voidmark_commit(struct commit *c,void*data) 96{ 97mark_object(&c->object, NULL, NULL, data); 98} 99 100struct recent_data { 101struct rev_info *revs; 102unsigned long timestamp; 103}; 104 105static voidadd_recent_object(const unsigned char*sha1, 106unsigned long mtime, 107struct recent_data *data) 108{ 109struct object *obj; 110enum object_type type; 111 112if(mtime <= data->timestamp) 113return; 114 115/* 116 * We do not want to call parse_object here, because 117 * inflating blobs and trees could be very expensive. 118 * However, we do need to know the correct type for 119 * later processing, and the revision machinery expects 120 * commits and tags to have been parsed. 121 */ 122 type =sha1_object_info(sha1, NULL); 123if(type <0) 124die("unable to get object info for%s",sha1_to_hex(sha1)); 125 126switch(type) { 127case OBJ_TAG: 128case OBJ_COMMIT: 129 obj =parse_object_or_die(sha1, NULL); 130break; 131case OBJ_TREE: 132 obj = (struct object *)lookup_tree(sha1); 133break; 134case OBJ_BLOB: 135 obj = (struct object *)lookup_blob(sha1); 136break; 137default: 138die("unknown object type for%s:%s", 139sha1_to_hex(sha1),typename(type)); 140} 141 142if(!obj) 143die("unable to lookup%s",sha1_to_hex(sha1)); 144 145add_pending_object(data->revs, obj,""); 146} 147 148static intadd_recent_loose(const unsigned char*sha1, 149const char*path,void*data) 150{ 151struct stat st; 152struct object *obj =lookup_object(sha1); 153 154if(obj && obj->flags & SEEN) 155return0; 156 157if(stat(path, &st) <0) { 158/* 159 * It's OK if an object went away during our iteration; this 160 * could be due to a simultaneous repack. But anything else 161 * we should abort, since we might then fail to mark objects 162 * which should not be pruned. 163 */ 164if(errno == ENOENT) 165return0; 166returnerror("unable to stat%s:%s", 167sha1_to_hex(sha1),strerror(errno)); 168} 169 170add_recent_object(sha1, st.st_mtime, data); 171return0; 172} 173 174static intadd_recent_packed(const unsigned char*sha1, 175struct packed_git *p,uint32_t pos, 176void*data) 177{ 178struct object *obj =lookup_object(sha1); 179 180if(obj && obj->flags & SEEN) 181return0; 182add_recent_object(sha1, p->mtime, data); 183return0; 184} 185 186intadd_unseen_recent_objects_to_traversal(struct rev_info *revs, 187unsigned long timestamp) 188{ 189struct recent_data data; 190int r; 191 192 data.revs = revs; 193 data.timestamp = timestamp; 194 195 r =for_each_loose_object(add_recent_loose, &data); 196if(r) 197return r; 198returnfor_each_packed_object(add_recent_packed, &data); 199} 200 201voidmark_reachable_objects(struct rev_info *revs,int mark_reflog, 202unsigned long mark_recent, 203struct progress *progress) 204{ 205struct connectivity_progress cp; 206 207/* 208 * Set up revision parsing, and mark us as being interested 209 * in all object types, not just commits. 210 */ 211 revs->tag_objects =1; 212 revs->blob_objects =1; 213 revs->tree_objects =1; 214 215/* Add all refs from the index file */ 216add_cache_refs(revs); 217 218/* Add all external refs */ 219for_each_ref(add_one_ref, revs); 220 221/* detached HEAD is not included in the list above */ 222head_ref(add_one_ref, revs); 223 224/* Add all reflog info */ 225if(mark_reflog) 226add_reflogs_to_pending(revs,0); 227 228 cp.progress = progress; 229 cp.count =0; 230 231/* 232 * Set up the revision walk - this will move all commits 233 * from the pending list to the commit walking list. 234 */ 235if(prepare_revision_walk(revs)) 236die("revision walk setup failed"); 237traverse_commit_list(revs, mark_commit, mark_object, &cp); 238 239if(mark_recent) { 240 revs->ignore_missing_links =1; 241if(add_unseen_recent_objects_to_traversal(revs, mark_recent)) 242die("unable to mark recent objects"); 243if(prepare_revision_walk(revs)) 244die("revision walk setup failed"); 245traverse_commit_list(revs, mark_commit, mark_object, &cp); 246} 247 248display_progress(cp.progress, cp.count); 249}