#include "cache.h"#include "refs.h"#include "tag.h"#include "commit.h"#include "blob.h"#include "diff.h"#include "revision.h"#include "reachable.h"#include "cache-tree.h"staticvoidprocess_blob(structblob*blob,structobject_array*p,structname_path*path,constchar*name){structobject*obj=&blob->object;if(!blob)die("bad blob object");if(obj->flags&SEEN)return;obj->flags|=SEEN;/* Nothing to do, really .. The blob lookup was the important part */}staticvoidprocess_gitlink(constunsignedchar*sha1,structobject_array*p,structname_path*path,constchar*name){/* I don't think we want to recurse into this, really. */}staticvoidprocess_tree(structtree*tree,structobject_array*p,structname_path*path,constchar*name){structobject*obj=&tree->object;structtree_descdesc;structname_entryentry;structname_pathme;if(!tree)die("bad tree object");if(obj->flags&SEEN)return;obj->flags|=SEEN;if(parse_tree(tree)<0)die("bad tree object %s",sha1_to_hex(obj->sha1));add_object(obj,p,path,name);me.up=path;me.elem=name;me.elem_len=strlen(name);init_tree_desc(&desc,tree->buffer,tree->size);while(tree_entry(&desc,&entry)){if(S_ISDIR(entry.mode))process_tree(lookup_tree(entry.sha1),p,&me,entry.path);elseif(S_ISGITLINK(entry.mode))process_gitlink(entry.sha1,p,&me,entry.path);elseprocess_blob(lookup_blob(entry.sha1),p,&me,entry.path);}free(tree->buffer);tree->buffer=NULL;}staticvoidprocess_tag(structtag*tag,structobject_array*p,constchar*name){structobject*obj=&tag->object;if(obj->flags&SEEN)return;obj->flags|=SEEN;if(parse_tag(tag)<0)die("bad tag object %s",sha1_to_hex(obj->sha1));if(tag->tagged)add_object(tag->tagged,p,NULL,name);}staticvoidwalk_commit_list(structrev_info*revs){inti;structcommit*commit;structobject_arrayobjects=OBJECT_ARRAY_INIT;/* Walk all commits, process their trees */while((commit=get_revision(revs))!=NULL)process_tree(commit->tree,&objects,NULL,"");/* Then walk all the pending objects, recursively processing them too */for(i=0;i<revs->pending.nr;i++){structobject_array_entry*pending=revs->pending.objects+i;structobject*obj=pending->item;constchar*name=pending->name;if(obj->type==OBJ_TAG){process_tag((structtag*)obj,&objects,name);continue;}if(obj->type==OBJ_TREE){process_tree((structtree*)obj,&objects,NULL,name);continue;}if(obj->type==OBJ_BLOB){process_blob((structblob*)obj,&objects,NULL,name);continue;}die("unknown pending object %s (%s)",sha1_to_hex(obj->sha1),name);}}staticintadd_one_reflog_ent(unsignedchar*osha1,unsignedchar*nsha1,constchar*email,unsignedlongtimestamp,inttz,constchar*message,void*cb_data){structobject*object;structrev_info*revs=(structrev_info*)cb_data;object=parse_object(osha1);if(object)add_pending_object(revs,object,"");object=parse_object(nsha1);if(object)add_pending_object(revs,object,"");return0;}staticintadd_one_ref(constchar*path,constunsignedchar*sha1,intflag,void*cb_data){structobject*object=parse_object(sha1);structrev_info*revs=(structrev_info*)cb_data;if(!object)die("bad object ref: %s:%s",path,sha1_to_hex(sha1));add_pending_object(revs,object,"");return0;}staticintadd_one_reflog(constchar*path,constunsignedchar*sha1,intflag,void*cb_data){for_each_reflog_ent(path,add_one_reflog_ent,cb_data);return0;}staticvoidadd_one_tree(constunsignedchar*sha1,structrev_info*revs){structtree*tree=lookup_tree(sha1);if(tree)add_pending_object(revs,&tree->object,"");}staticvoidadd_cache_tree(structcache_tree*it,structrev_info*revs){inti;if(it->entry_count>=0)add_one_tree(it->sha1,revs);for(i=0;i<it->subtree_nr;i++)add_cache_tree(it->down[i]->cache_tree,revs);}staticvoidadd_cache_refs(structrev_info*revs){inti;read_cache();for(i=0;i<active_nr;i++){/* * The index can contain blobs and GITLINKs, GITLINKs are hashes * that don't actually point to objects in the repository, it's * almost guaranteed that they are NOT blobs, so we don't call * lookup_blob() on them, to avoid populating the hash table * with invalid information */if(S_ISGITLINK(active_cache[i]->ce_mode))continue;lookup_blob(active_cache[i]->sha1);/* * We could add the blobs to the pending list, but quite * frankly, we don't care. Once we've looked them up, and * added them as objects, we've really done everything * there is to do for a blob */}if(active_cache_tree)add_cache_tree(active_cache_tree,revs);}voidmark_reachable_objects(structrev_info*revs,intmark_reflog){/* * Set up revision parsing, and mark us as being interested * in all object types, not just commits. */revs->tag_objects=1;revs->blob_objects=1;revs->tree_objects=1;/* Add all refs from the index file */add_cache_refs(revs);/* Add all external refs */for_each_ref(add_one_ref,revs);/* Add all reflog info */if(mark_reflog)for_each_reflog(add_one_reflog,revs);/* * Set up the revision walk - this will move all commits * from the pending list to the commit walking list. */if(prepare_revision_walk(revs))die("revision walk setup failed");walk_commit_list(revs);}