COPYING: fe2a4177a760fd110e78788734f167bd633be8de Makefile: ca50293c4f211452d999b81f122e99babb9f2987 --- Makefile +++ Makefile 2005-04-15 22:17:49.000000000 +1000 @@ -14,7 +14,7 @@ PROG= update-cache show-diff init-db write-tree read-tree commit-tree \ cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \ - check-files ls-tree + check-files ls-tree rename-file SCRIPT= parent-id tree-id git gitXnormid.sh gitadd.sh gitaddremote.sh \ gitcommit.sh gitdiff-do gitdiff.sh gitlog.sh gitls.sh gitlsobj.sh \ @@ -73,6 +73,9 @@ ls-tree: ls-tree.o read-cache.o $(CC) $(CFLAGS) -o ls-tree ls-tree.o read-cache.o $(LIBS) +rename-file: rename-file.o read-cache.o + $(CC) $(CFLAGS) -o rename-file rename-file.o read-cache.o $(LIBS) + read-cache.o: cache.h show-diff.o: cache.h README: ded1a3b20e9bbe1f40e487ba5f9361719a1b6b85 VERSION: c27bd67cd632cc15dd520fbfbf807d482efa2dcf cache.h: 4d382549041d3281f8d44aa2e52f9f8ec47dd420 --- cache.h +++ cache.h 2005-04-14 22:35:59.000000000 +1000 @@ -55,6 +55,7 @@ unsigned int st_gid; unsigned int st_size; unsigned char sha1[20]; + unsigned char guid[20]; unsigned short namelen; char name[0]; }; cat-file.c: 45be1badaa8517d4e3a69e0bf1cac2e90191e475 check-files.c: 927b0b9aca742183fc8e7ccd73d73d8d5427e98f checkout-cache.c: f06871cdbc1b18ea93bdf4e17126aeb4cca1373e commit-id: 65c81756c8f10d513d073ecbd741a3244663c4c9 commit-tree.c: 12196c79f31d004dff0df1f50dda67d8204f5568 diff-tree.c: 7dcc9eb7782fa176e27f1677b161ce78ac1d2070 --- diff-tree.c +++ diff-tree.c 2005-04-16 10:46:52.000000000 +1000 @@ -1,33 +1,144 @@ +#include #include "cache.h" -static int recursive = 0; +enum diff_type { + REMOVE, + ADD, + RENAME, + MODIFY, +}; + +struct guid_cache_entry { + enum diff_type diff; + unsigned char guid[20]; + unsigned char sha1[20]; + struct guid_cache_entry *old; + unsigned int mode; + unsigned int pathlen; + unsigned char path[0]; +}; + +struct guid_cache { + unsigned int nr; + unsigned int alloc; + struct guid_cache_entry **cache; +}; -static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base); +struct guid_cache guid_cache; +struct guid_cache *cache = &guid_cache; -static void update_tree_entry(void **bufp, unsigned long *sizep) +int guid_cache_pos(const char *guid) { - void *buf = *bufp; - unsigned long size = *sizep; - int len = strlen(buf) + 1 + 20; + int first, last; - if (size < len) - die("corrupt tree file"); - *bufp = buf + len; - *sizep = size - len; + first = 0; + last = cache->nr; + while (last > first) { + int next = (last + first) >> 1; + struct guid_cache_entry *gce = cache->cache[next]; + int cmp = memcmp(guid, gce->guid, 20); + if (!cmp) + return next; + if (cmp < 0) { + last = next; + continue; + } + first = next + 1; + } + return - first-1; } -static const unsigned char *extract(void *tree, unsigned long size, const char **pathp, unsigned int *modep) +int add_guid_cache_entry(struct guid_cache_entry *gce) +{ + int pos; + + pos = guid_cache_pos(gce->guid); + + /* if this is a rename or modify, the guid will show up a + * second time */ + if (pos >= 0) { + struct guid_cache_entry *old = cache->cache[pos]; + int cmp = cache_name_compare(old->path, old->pathlen, gce->path, gce->pathlen); + + if (!cmp) { + /* pathname matches, so this must be a + * modify. */ + gce->old = old; + gce->diff = MODIFY; + cache->cache[pos] = gce; + } else { + /* the pathnames are different, so the file + * must have been renamed somewhere along the + * line. */ + gce->old = old; + gce->diff = RENAME; + cache->cache[pos] = gce; + } + return 0; + } + pos = -pos-1; + + if (cache->nr == cache->alloc) { + cache->alloc = alloc_nr(cache->alloc); + cache->cache = realloc(cache->cache, cache->alloc * sizeof(struct guid_cache_entry *)); + } + + cache->nr++; + if (cache->nr > pos) + memmove(cache->cache + pos + 1, cache->cache + pos, (cache->nr - pos - 1) * sizeof(struct guid_cache_entry *)); + cache->cache[pos] = gce; + return 0; +} + +static const unsigned char *extract(void *tree, unsigned long size, const char **pathp, unsigned int *modep, const unsigned char **guid) { int len = strlen(tree)+1; const unsigned char *sha1 = tree + len; const char *path = strchr(tree, ' '); - if (!path || size < len + 20 || sscanf(tree, "%o", modep) != 1) + if (!path || size < len + 40 || sscanf(tree, "%o", modep) != 1) die("corrupt tree file"); *pathp = path+1; + *guid = tree + len + 20; return sha1; } +static void guid_cache_tree_entry(void *buf, unsigned int len, const char *base, enum diff_type diff) +{ + unsigned mode; + const char *path; + const unsigned char *guid; + const unsigned char *sha1 = extract(buf, len, &path, &mode, &guid); + struct guid_cache_entry *gce; + int baselen = strlen(base); + + gce = calloc(1, sizeof(struct guid_cache_entry) + baselen + strlen(path) + 1); + memcpy(gce->guid, guid, 20); + memcpy(gce->sha1, sha1, 20); + gce->diff = diff; + gce->mode = mode; + gce->pathlen = snprintf(gce->path, MAXPATHLEN, "%s%s", base, path); + gce->path[gce->pathlen + 1] = '\0'; + + add_guid_cache_entry(gce); +} + +static int recursive = 0; + +static int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base); + +static void update_tree_entry(void **bufp, unsigned long *sizep) +{ + void *buf = *bufp; + unsigned long size = *sizep; + int len = strlen(buf) + 1 + 40; + + if (size < len) + die("corrupt tree file"); + *bufp = buf + len; + *sizep = size - len; +} + static char *malloc_base(const char *base, const char *path, int pathlen) { int baselen = strlen(base); @@ -38,23 +149,24 @@ return newbase; } -static void show_file(const char *prefix, void *tree, unsigned long size, const char *base); +static void changed_file(void *tree, unsigned long size, const char *base, enum diff_type diff); /* A whole sub-tree went away or appeared */ -static void show_tree(const char *prefix, void *tree, unsigned long size, const char *base) +static void changed_tree(void *tree, unsigned long size, const char *base, enum diff_type diff) { while (size) { - show_file(prefix, tree, size, base); + changed_file(tree, size, base, diff); update_tree_entry(&tree, &size); } } /* A file entry went away or appeared */ -static void show_file(const char *prefix, void *tree, unsigned long size, const char *base) +static void changed_file(void *tree, unsigned long size, const char *base, enum diff_type diff) { unsigned mode; const char *path; - const unsigned char *sha1 = extract(tree, size, &path, &mode); + const unsigned char *guid; + const unsigned char *sha1 = extract(tree, size, &path, &mode, &guid); if (recursive && S_ISDIR(mode)) { char type[20]; @@ -66,38 +178,96 @@ if (!tree || strcmp(type, "tree")) die("corrupt tree sha %s", sha1_to_hex(sha1)); - show_tree(prefix, tree, size, newbase); + changed_tree(tree, size, newbase, diff); free(tree); free(newbase); return; } - printf("%s%o\t%s\t%s\t%s%s%c", prefix, mode, - S_ISDIR(mode) ? "tree" : "blob", - sha1_to_hex(sha1), base, path, 0); + guid_cache_tree_entry(tree, size, base, diff); } +static void show_one_file(struct guid_cache_entry *gce) +{ + struct guid_cache_entry *old; + char old_sha1[50]; + char old_sha2[50]; + + switch(gce->diff) { + case REMOVE: + sprintf(old_sha1, "%s", sha1_to_hex(gce->sha1)); + printf("-%o\t%s\t%s\t%s\t%s%c", gce->mode, + S_ISDIR(gce->mode) ? "tree" : "blob", + old_sha1, sha1_to_hex(gce->guid), gce->path, 0); + break; + case ADD: + sprintf(old_sha1, "%s", sha1_to_hex(gce->sha1)); + printf("+%o\t%s\t%s\t%s\t%s%c", gce->mode, + S_ISDIR(gce->mode) ? "tree" : "blob", + old_sha1, sha1_to_hex(gce->guid), gce->path, 0); + break; + case MODIFY: + old = gce->old; + if (old) { + sprintf(old_sha1, "%s", sha1_to_hex(old->sha1)); + sprintf(old_sha2, "%s", sha1_to_hex(gce->sha1)); + + printf("*%o->%o\t%s\t%s->%s\t%s\t%s%c", old->mode, gce->mode, + S_ISDIR(old->mode) ? "tree" : "blob", + old_sha1, old_sha2, sha1_to_hex(gce->guid), gce->path, 0); + } else { + die("diff-tree: internal error"); + } + break; + case RENAME: + old = gce->old; + if (old) { + sprintf(old_sha1, "%s", sha1_to_hex(gce->sha1)); + sprintf(old_sha2, "%s", sha1_to_hex(old->sha1)); + + printf("r%o->%o\t%s\t%s->%s\t%s\t%s%c", gce->mode, old->mode, + S_ISDIR(old->mode) ? "tree" : "blob", + old_sha1, old_sha2, sha1_to_hex(old->guid), old->path, 0); + } else { + die("diff-tree: internal error"); + } + break; + default: + die("diff-tree: internal error"); + } +} + +/* simply iterate over both caches looking for matching guids, + * showing all files in both caches */ +static void show_cache(void) +{ + int i; + + for (i = 0; i < cache->nr; i++) + show_one_file(cache->cache[i]); +} + static int compare_tree_entry(void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base) { unsigned mode1, mode2; const char *path1, *path2; const unsigned char *sha1, *sha2; + const unsigned char *guid1, *guid2; int cmp, pathlen1, pathlen2; - char old_sha1_hex[50]; - sha1 = extract(tree1, size1, &path1, &mode1); - sha2 = extract(tree2, size2, &path2, &mode2); + sha1 = extract(tree1, size1, &path1, &mode1, &guid1); + sha2 = extract(tree2, size2, &path2, &mode2, &guid2); pathlen1 = strlen(path1); pathlen2 = strlen(path2); cmp = cache_name_compare(path1, pathlen1, path2, pathlen2); if (cmp < 0) { - show_file("-", tree1, size1, base); + changed_file(tree1, size1, base, REMOVE); return -1; } if (cmp > 0) { - show_file("+", tree2, size2, base); + changed_file(tree2, size2, base, ADD); return 1; } if (!memcmp(sha1, sha2, 20) && mode1 == mode2) @@ -108,8 +278,8 @@ * file, we need to consider it a remove and an add. */ if (S_ISDIR(mode1) != S_ISDIR(mode2)) { - show_file("-", tree1, size1, base); - show_file("+", tree2, size2, base); + changed_file(tree1, size1, base, REMOVE); + changed_file(tree2, size2, base, ADD); return 0; } @@ -121,10 +291,14 @@ return retval; } - strcpy(old_sha1_hex, sha1_to_hex(sha1)); - printf("*%o->%o\t%s\t%s->%s\t%s%s%c", mode1, mode2, - S_ISDIR(mode1) ? "tree" : "blob", - old_sha1_hex, sha1_to_hex(sha2), base, path1, 0); + if (!memcmp(guid1, guid2, 20)) { + changed_file(tree1, size1, base, MODIFY); + changed_file(tree2, size2, base, MODIFY); + return 0; + } + + changed_file(tree1, size1, base, REMOVE); + changed_file(tree2, size2, base, ADD); return 0; } @@ -132,12 +306,12 @@ { while (size1 | size2) { if (!size1) { - show_file("+", tree2, size2, base); + changed_file(tree2, size2, base, ADD); update_tree_entry(&tree2, &size2); continue; } if (!size2) { - show_file("-", tree1, size1, base); + changed_file(tree1, size1, base, REMOVE); update_tree_entry(&tree1, &size1); continue; } @@ -179,6 +353,7 @@ int main(int argc, char **argv) { unsigned char old[20], new[20]; + int retval; while (argc > 3) { char *arg = argv[1]; @@ -193,5 +368,7 @@ if (argc != 3 || get_sha1_hex(argv[1], old) || get_sha1_hex(argv[2], new)) usage("diff-tree "); - return diff_tree_sha1(old, new, ""); + retval = diff_tree_sha1(old, new, ""); + show_cache(); + return retval; } fsck-cache.c: 9c900fe458cecd2bdb4c4571a584115b5cf24f22 --- fsck-cache.c +++ fsck-cache.c 2005-04-15 20:39:49.000000000 +1000 @@ -165,9 +165,10 @@ while (size) { int len = 1+strlen(data); unsigned char *file_sha1 = data + len; + unsigned char *guid = file_sha1 + 20; char *path = strchr(data, ' '); unsigned int mode; - if (size < len + 20 || !path || sscanf(data, "%o", &mode) != 1) + if (size < len + 40 || !path || sscanf(data, "%o", &mode) != 1) return -1; /* Warn about trees that don't do the recursive thing.. */ @@ -176,8 +177,8 @@ warn_old_tree = 0; } - data += len + 20; - size -= len + 20; + data += len + 40; + size -= len + 40; mark_needs_sha1(sha1, S_ISDIR(mode) ? "tree" : "blob", file_sha1); } return 0; git: 2c557dcf2032325acc265b577ee104e605fdaede gitXnormid.sh: a5d7a9f4a6e8d4860f35f69500965c2a493d80de gitadd.sh: 3ed93ea0fcb995673ba9ee1982e0e7abdbe35982 gitaddremote.sh: bf1f28823da5b5270aa8fa05b321faa514a57a11 gitapply.sh: d0e3c46e2ce1ee74e1a87ee6137955fa9b35c27b gitcancel.sh: ec58f7444a42cd3cbaae919fc68c70a3866420c0 gitcommit.sh: 3629f67bbd3f171d091552814908b67af7537f4d gitdiff-do: d6174abceab34d22010c36a8453a6c3f3f184fe0 gitdiff.sh: 5e47c4779d73c3f2f39f6be714c0145175933197 gitexport.sh: dad00bf251b38ce522c593ea9631f842d8ccc934 gitlntree.sh: 17c4966ea64aeced96ae4f1b00f3775c1904b0f1 gitlog.sh: 177c6d12dd9fa4b4920b08451ffe4badde544a39 gitls.sh: b6f15d82f16c1e9982c5031f3be22eb5430273af gitlsobj.sh: 128461d3de6a42cfaaa989fc6401bebdfa885b3f gitmerge.sh: 23e4a3ff342c6005928ceea598a2f52de6fb9817 gitpull.sh: 0883898dda579e3fa44944b7b1d909257f6dc63e gitrm.sh: 5c18c38a890c9fd9ad2b866ee7b529539d2f3f8f gittag.sh: c8cb31385d5a9622e95a4e0b2d6a4198038a659c gittrack.sh: 03d6db1fb3a70605ef249c632c04e542457f0808 init-db.c: aa00fbb1b95624f6c30090a17354c9c08a6ac596 ls-tree.c: 3e2a6c7d183a42e41f1073dfec6794e8f8a5e75c --- ls-tree.c +++ ls-tree.c 2005-04-15 15:55:40.000000000 +1000 @@ -10,6 +10,7 @@ void *buffer; unsigned long size; char type[20]; + char old_sha1[50]; buffer = read_sha1_file(sha1, type, &size); if (!buffer) @@ -19,19 +20,21 @@ while (size) { int len = strlen(buffer)+1; unsigned char *sha1 = buffer + len; + unsigned char *guid = buffer + len + 20; char *path = strchr(buffer, ' ')+1; unsigned int mode; unsigned char *type; - if (size < len + 20 || sscanf(buffer, "%o", &mode) != 1) + if (size < len + 40 || sscanf(buffer, "%o", &mode) != 1) die("corrupt 'tree' file"); - buffer = sha1 + 20; - size -= len + 20; + buffer = sha1 + 40; + size -= len + 40; /* XXX: We do some ugly mode heuristics here. * It seems not worth it to read each file just to get this * and the file size. -- pasky@ucw.cz */ type = S_ISDIR(mode) ? "tree" : "blob"; - printf("%03o\t%s\t%s\t%s\n", mode, type, sha1_to_hex(sha1), path); + sprintf(old_sha1, sha1_to_hex(guid)); + printf("%03o\t%s\t%s\t%s\t%s\n", mode, type, sha1_to_hex(sha1), old_sha1, path); } return 0; } parent-id: 1801c6fe426592832e7250f8b760fb9d2e65220f read-cache.c: 7a6ae8b9b489f6b67c82e065dedd5716a6bfc0ef --- read-cache.c +++ read-cache.c 2005-04-16 10:52:51.000000000 +1000 @@ -4,6 +4,8 @@ * Copyright (C) Linus Torvalds, 2005 */ #include +#include +#include #include "cache.h" const char *sha1_file_directory = NULL; @@ -233,6 +235,22 @@ return 0; } +void new_guid(const char *filename, int namelen, unsigned char *returnguid) +{ + size_t size; + time_t now = time(NULL); + char buf[MAXPATHLEN + 20]; + unsigned char guid[20]; + + size = snprintf(buf, MAXPATHLEN + 20, "%ld%s", now, filename) + 1; + + SHA1(buf, size, guid); + + if (returnguid) + memcpy(returnguid, guid, 20); + return; +} + static inline int collision_check(char *filename, void *buf, unsigned int size) { #ifdef COLLISION_CHECK @@ -363,11 +381,14 @@ int add_cache_entry(struct cache_entry *ce, int ok_to_add) { int pos; + unsigned char guid[20]; pos = cache_name_pos(ce->name, ce->namelen); /* existing match? Just replace it */ if (pos >= 0) { + struct cache_entry *old_ce = active_cache[pos]; + memcpy(ce->guid, old_ce->guid, 20); active_cache[pos] = ce; return 0; } @@ -376,6 +397,12 @@ if (!ok_to_add) return -1; + memset(guid, 0, 20); + if (!memcmp(ce->guid, guid, 20)) { + new_guid(ce->name, ce->namelen, guid); + memcpy(ce->guid, guid, 20); + } + /* Make sure the array is big enough .. */ if (active_nr == active_alloc) { active_alloc = alloc_nr(active_alloc); read-tree.c: eb548148aa6d212f05c2c622ffbe62a06cd072f9 --- read-tree.c +++ read-tree.c 2005-04-16 10:41:46.000000000 +1000 @@ -5,7 +5,9 @@ */ #include "cache.h" -static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode) +static int read_one_entry(unsigned char *sha1, unsigned char *guid, + const char *base, int baselen, + const char *pathname, unsigned mode) { int len = strlen(pathname); unsigned int size = cache_entry_size(baselen + len); @@ -18,6 +20,7 @@ memcpy(ce->name, base, baselen); memcpy(ce->name + baselen, pathname, len+1); memcpy(ce->sha1, sha1, 20); + memcpy(ce->guid, guid, 20); return add_cache_entry(ce, 1); } @@ -35,14 +38,15 @@ while (size) { int len = strlen(buffer)+1; unsigned char *sha1 = buffer + len; + unsigned char *guid = buffer + len + 20; char *path = strchr(buffer, ' ')+1; unsigned int mode; - - if (size < len + 20 || sscanf(buffer, "%o", &mode) != 1) + + if (size < len + 40 || sscanf(buffer, "%o", &mode) != 1) return -1; - buffer = sha1 + 20; - size -= len + 20; + buffer = sha1 + 40; + size -= len + 40; if (S_ISDIR(mode)) { int retval; @@ -57,7 +61,7 @@ return -1; continue; } - if (read_one_entry(sha1, base, baselen, path, mode) < 0) + if (read_one_entry(sha1, guid, base, baselen, path, mode) < 0) return -1; } return 0; rev-tree.c: 395b0b3bfadb0537ae0c62744b25ead4b487f3f6 show-diff.c: a531ca4078525d1c8dcf84aae0bfa89fed6e5d96 show-files.c: a9fa6767a418f870a34b39379f417bf37b17ee18 tree-id: cb70e2c508a18107abe305633612ed702aa3ee4f update-cache.c: 62d0a6c41560d40863c44599355af10d9e089312 write-tree.c: 1534477c91169ebddcf953e3f4d2872495477f6b --- write-tree.c +++ write-tree.c 2005-04-15 13:46:05.000000000 +1000 @@ -47,6 +47,7 @@ const char *pathname = ce->name, *filename, *dirname; int pathlen = ce->namelen, entrylen; unsigned char *sha1; + unsigned char *guid; unsigned int mode; /* Did we hit the end of the directory? Return how many we wrote */ @@ -54,6 +55,7 @@ break; sha1 = ce->sha1; + guid = ce->guid; mode = ce->st_mode; /* Do we have _further_ subdirectories? */ @@ -86,6 +88,8 @@ buffer[offset++] = 0; memcpy(buffer + offset, sha1, 20); offset += 20; + memcpy(buffer + offset, guid, 20); + offset += 20; nr++; } while (nr < maxentries);