Index: cache.h =================================================================== --- a/cache.h (mode:100644) +++ b/cache.h (mode:100644) @@ -157,6 +157,7 @@ extern int write_sha1_from_fd(const unsigned char *sha1, int fd); extern int has_sha1_file(const unsigned char *sha1); +extern unsigned long sha1_local_date(const unsigned char *sha1); /* Convert to/from hex/sha1 representation */ extern int get_sha1(const char *str, unsigned char *sha1); Index: cg-pull =================================================================== --- a/cg-pull (mode:100755) +++ b/cg-pull (mode:100755) @@ -143,7 +143,7 @@ [ "$1" = "-i" ] && shift [ "$1" = "-s" ] && shift - cp_flags_l="-va" + cp_flags_l="-vdR" if [ "$1" = "-u" ]; then cp_flags_l="$cp_flags_l -lu" shift @@ -163,7 +163,7 @@ } pull_local () { - git-local-pull -a -l -v "$(cat "$_git/refs/heads/$1")" "$2" + git-local-pull -a -v "$(cat "$_git/refs/heads/$1")" "$2" } if echo "$uri" | grep -q "^http://"; then Index: commit.c =================================================================== --- a/commit.c (mode:100644) +++ b/commit.c (mode:100644) @@ -2,6 +2,7 @@ #include "cache.h" #include #include +#include const char *commit_type = "commit"; @@ -13,6 +14,7 @@ memset(ret, 0, sizeof(struct commit)); created_object(sha1, &ret->object); ret->object.type = commit_type; + ret->local_date = sha1_local_date(sha1); return ret; } if (obj->type != commit_type) { @@ -41,6 +43,18 @@ return date; } +static void insert_by_local_date(struct commit_list **list, struct commit *item) +{ + struct commit_list **pp = list; + struct commit_list *p; + while ((p = *pp) != NULL) { + if (p->item->local_date > item->local_date) + break; + pp = &p->next; + } + commit_list_insert(item, pp); +} + int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size) { void *bufptr = buffer; @@ -58,12 +72,13 @@ !get_sha1_hex(bufptr + 7, parent)) { struct commit *new_parent = lookup_commit(parent); if (new_parent) { - commit_list_insert(new_parent, &item->parents); + insert_by_local_date(&item->parents, new_parent); add_ref(&item->object, &new_parent->object); } bufptr += 48; } item->date = parse_commit_date(bufptr); + item->merge_nodes = NULL; return 0; } @@ -152,3 +167,107 @@ } return ret; } + +struct commit_list *copy_commit_list(struct commit_list *list) +{ + struct commit_list *copy = NULL; + while (list) { + commit_list_insert(list->item, ©); + list = list->next; + } + return copy; +} + +int found_on_list(struct commit *item, struct commit_list *list) +{ + while (list) { + if (list->item == item) + return 1; + list = list->next; + } + return 0; +} + +static struct commit *process_local_list(struct commit_list **list_p, + int this_mark, int other_mark) +{ + struct commit *item = (*list_p)->item; + + if (item->object.flags & other_mark) { + return item; + } else { + pop_most_recent_commit(list_p, this_mark); + } + return NULL; +} + +struct commit *common_local_ancestor(struct commit *rev1, struct commit *rev2) +{ + struct commit_list *rev1list = NULL; + struct commit_list *rev2list = NULL; + + commit_list_insert(rev1, &rev1list); rev1->object.flags |= 0x1; + commit_list_insert(rev2, &rev2list); rev2->object.flags |= 0x2; + parse_commit(rev1); parse_commit(rev2); + + while (rev1list || rev2list) { + struct commit *ret; + if (!rev1list) { + // process 2 + ret = process_local_list(&rev2list, 0x2, 0x1); + } else if (!rev2list) { + // process 1 + ret = process_local_list(&rev1list, 0x1, 0x2); + } else if (rev1list->item->local_date + < rev2list->item->local_date) { + // process 2 + ret = process_local_list(&rev2list, 0x2, 0x1); + } else { + // process 1 + ret = process_local_list(&rev1list, 0x1, 0x2); + } + if (ret) { + free_commit_list(rev1list); + free_commit_list(rev2list); + return ret; + } + } + return NULL; +} + +void insert_merge_nodes(struct commit_list *plist, + struct commit_list *stop, + struct commit *node) +{ + struct commit_list *p; + for (p=plist; p != stop; p=p->next) + commit_list_insert( common_local_ancestor(node, p->item), + &node->merge_nodes); +} + +struct commit *pop_newest_local_commit( struct commit_list **list, + unsigned int mark) +{ + struct commit *ret = (*list)->item; + struct commit_list *parents = ret->parents; + struct commit_list *old = *list; + struct commit_list *prev = ret->merge_nodes; + + *list = (*list)->next; + free(old); + + /* Loop expects parents to be ordered oldest to newest on local time */ + while (parents) { + struct commit *commit = parents->item; + parse_commit(commit); + if (!((commit->object.flags & mark) | + found_on_list(commit, ret->merge_nodes))) { + commit->object.flags |= mark; + prev = commit->merge_nodes = copy_commit_list(prev); + insert_merge_nodes(ret->parents, parents, commit); + commit_list_insert(commit, list); + } + parents = parents->next; + } + return ret; +} Index: commit.h =================================================================== --- a/commit.h (mode:100644) +++ b/commit.h (mode:100644) @@ -11,8 +11,9 @@ struct commit { struct object object; - unsigned long date; + unsigned long date, local_date; struct commit_list *parents; + struct commit_list *merge_nodes; struct tree *tree; }; @@ -36,4 +37,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list, unsigned int mark); +struct commit *pop_newest_local_commit( struct commit_list **list, + unsigned int mark); + #endif /* COMMIT_H */ Index: rev-list.c =================================================================== --- a/rev-list.c (mode:100644) +++ b/rev-list.c (mode:100644) @@ -38,7 +38,7 @@ commit_list_insert(commit, &list); do { - struct commit *commit = pop_most_recent_commit(&list, 0x1); + struct commit *commit = pop_newest_local_commit(&list, 0x4); if (min_age != -1 && (commit->date > min_age)) continue; Index: sha1_file.c =================================================================== --- a/sha1_file.c (mode:100644) +++ b/sha1_file.c (mode:100644) @@ -577,6 +577,14 @@ return !!find_sha1_file(sha1, &st); } +unsigned long sha1_local_date(const unsigned char *sha1) +{ + struct stat st; + if (find_sha1_file(sha1, &st)) + return st.st_mtime; + return 0; +} + int index_fd(unsigned char *sha1, int fd, struct stat *st) { unsigned long size = st->st_size;