Git development
 help / color / mirror / Atom feed
* Re: [PATCH 6/6 (v4)] support for path name caching in rev-cache
From: Nick Edelen @ 2009-08-18 11:51 UTC (permalink / raw)
  To: Nick Edelen, Junio C Hamano, Nicolas Pitre, Johannes Schindelin,
	Sam Vilain
In-Reply-To: <op.uys3qwlmtdk399@sirnot.private>

An update to caching mechanism, allowing path names to be cached for blob and
tree objects.  A list of names appearing in each cache slice is appended to the
end of the slice, which is referenced by variable-sized indexes per entry.
This allows pack-objects to more intelligently schedule unpacked/poorly packed
object, and enables proper duplication of rev-list's behaivor.

Signed-off-by: Nick Edelen <sirnot@gmail.com>

---
 builtin-rev-cache.c       |    3 +-
 rev-cache.c               |  314 +++++++++++++++++++++++++++++++++++++--------
 rev-cache.h               |   16 ++-
 revision.h                |    6 +-
 t/t6015-rev-cache-list.sh |    6 +-
 5 files changed, 283 insertions(+), 62 deletions(-)

diff --git a/builtin-rev-cache.c b/builtin-rev-cache.c
index 8f41123..4c1766d 100644
--- a/builtin-rev-cache.c
+++ b/builtin-rev-cache.c
@@ -177,13 +177,14 @@ static int handle_walk(int argc, const char *argv[])
 	fprintf(stderr, "pending:\n");
 	for (i = 0; i < revs.pending.nr; i++) {
 		struct object *obj = revs.pending.objects[i].item;
+		const char *name = revs.pending.objects[i].name;
 
 		/* unfortunately, despite our careful generation, object duplication *is* a possibility...
 		 * (eg. same object introduced into two different branches) */
 		if (obj->flags & SEEN)
 			continue;
 
-		printf("%s\n", sha1_to_hex(revs.pending.objects[i].item->sha1));
+		printf("%s %s\n", sha1_to_hex(revs.pending.objects[i].item->sha1), name);
 		obj->flags |= SEEN;
 	}
 
diff --git a/rev-cache.c b/rev-cache.c
index 04a9b02..8801794 100644
--- a/rev-cache.c
+++ b/rev-cache.c
@@ -17,6 +17,14 @@ struct bad_slice {
 	struct bad_slice *next;
 };
 
+struct name_list {
+	unsigned char sha1[20];
+	unsigned int len;
+	struct name_list *next;
+
+	char buf[FLEX_ARRAY];
+};
+
 struct cache_slice_pointer {
 	char signature[8]; /* REVCOPTR */
 	char version;
@@ -29,10 +37,13 @@ static uint32_t fanout[0xff + 2];
 static unsigned char *idx_map;
 static int idx_size;
 static struct rc_index_header idx_head;
-static char no_idx, add_to_pending;
-static struct bad_slice *bad_slices;
+static char no_idx, add_to_pending, add_names;
 static unsigned char *idx_caches;
 
+static struct bad_slice *bad_slices;
+static struct name_list *name_lists, *cur_name_list;
+
+static struct strbuf *acc_name_buffer;
 static struct strbuf *acc_buffer;
 
 #define SLOP			5
@@ -79,7 +90,7 @@ struct rc_object_entry *from_disked_rc_object_entry(struct rc_object_entry_ondis
 	if (!dst)
 		dst = &entry[cur++ & 0x3];
 
-	dst->type = src->flags >> 5;
+	dst->type = src->flags >> 5 & 0x03;
 	dst->is_end = !!(src->flags & 0x10);
 	dst->is_start = !!(src->flags & 0x08);
 	dst->uninteresting = !!(src->flags & 0x04);
@@ -90,8 +101,9 @@ struct rc_object_entry *from_disked_rc_object_entry(struct rc_object_entry_ondis
 	dst->merge_nr = src->merge_nr;
 	dst->split_nr = src->split_nr;
 
-	dst->size_size = src->sizes >> 5;
-	dst->padding = src->sizes & 0x1f;
+	dst->size_size = src->sizes >> 5 & 0x03;
+	dst->name_size = src->sizes >> 2 & 0x03;
+	dst->padding = src->sizes & 0x02;
 
 	dst->date = ntohl(src->date);
 	dst->path = ntohs(src->path);
@@ -120,6 +132,7 @@ struct rc_object_entry_ondisk *to_disked_rc_object_entry(struct rc_object_entry
 	dst->split_nr = src->split_nr;
 
 	dst->sizes  = (unsigned char)src->size_size << 5;
+	dst->sizes |= (unsigned char)src->name_size << 2;
 	dst->sizes |= (unsigned char)src->padding;
 
 	dst->date = htonl(src->date);
@@ -192,6 +205,12 @@ static void cleanup_cache_slices(void)
 		idx_map = 0;
 	}
 
+	while (name_lists) {
+		struct name_list *nl = name_lists->next;
+		free(name_lists);
+		name_lists = nl;
+	}
+
 }
 
 static int init_index(void)
@@ -324,7 +343,7 @@ static void handle_noncommit(struct rev_info *revs, struct commit *commit, unsig
 	struct blob *blob;
 	struct tree *tree;
 	struct object *obj;
-	unsigned long size;
+	unsigned long size, name_index;
 
 	size = decode_size(ptr + RC_ENTRY_SIZE_OFFSET(entry), entry->size_size);
 	switch (entry->type) {
@@ -357,9 +376,22 @@ static void handle_noncommit(struct rev_info *revs, struct commit *commit, unsig
 		return;
 	}
 
+	if (add_names && cur_name_list) {
+		name_index = decode_size(ptr + RC_ENTRY_NAME_OFFSET(entry), entry->name_size);
+
+		if (name_index >= cur_name_list->len)
+			name_index = 0;
+	} else name_index = 0;
+
 	obj->flags |= FACE_VALUE;
-	if (add_to_pending)
-		add_pending_object(revs, obj, "");
+	if (add_to_pending) {
+		char *name = "";
+
+		if (name_index)
+			name = cur_name_list->buf + name_index;
+
+		add_pending_object(revs, obj, name);
+	}
 }
 
 static int setup_traversal(struct rc_slice_header *head, unsigned char *map, struct commit *commit, struct commit_list **work,
@@ -714,15 +746,44 @@ end:
 	return retval;
 }
 
-static int get_cache_slice_header(unsigned char *cache_sha1, unsigned char *map, int len, struct rc_slice_header *head)
+static struct name_list *get_cache_slice_name_list(struct rc_slice_header *head, int fd)
+{
+	struct name_list *nl = name_lists;
+
+	while (nl) {
+		if (!hashcmp(nl->sha1, head->sha1))
+			break;
+		nl = nl->next;
+	}
+
+	if (nl)
+		return nl;
+
+	nl = xcalloc(1, sizeof(struct name_list) + head->name_size);
+	nl->len = head->name_size;
+	hashcpy(nl->sha1, head->sha1);
+
+	lseek(fd, head->size, SEEK_SET);
+	read_in_full(fd, nl->buf, head->name_size);
+
+	nl->next = name_lists;
+	name_lists = nl;
+
+	return nl;
+}
+
+static int get_cache_slice_header(int fd, unsigned char *cache_sha1, int len, struct rc_slice_header *head)
 {
 	int t;
 
-	memcpy(head, map, sizeof(struct rc_slice_header));
+	if (xread(fd, head, sizeof(struct rc_slice_header)) != sizeof(struct rc_slice_header))
+		return -1;
+
 	head->ofs_objects = ntohl(head->ofs_objects);
 	head->object_nr = ntohl(head->object_nr);
 	head->size = ntohl(head->size);
 	head->path_nr = ntohs(head->path_nr);
+	head->name_size = ntohl(head->name_size);
 
 	if (memcmp(head->signature, "REVCACHE", 8))
 		return -1;
@@ -731,10 +792,10 @@ static int get_cache_slice_header(unsigned char *cache_sha1, unsigned char *map,
 	if (hashcmp(head->sha1, cache_sha1))
 		return -3;
 	t = sizeof(struct rc_slice_header);
-	if (t != head->ofs_objects || t >= len)
+	if (t != head->ofs_objects)
 		return -4;
-
-	head->size = len;
+	if (head->size + head->name_size != len)
+		return -5;
 
 	return 0;
 }
@@ -786,7 +847,7 @@ int traverse_cache_slice(struct rev_info *revs,
 	unsigned long *date_so_far, int *slop_so_far,
 	struct commit_list ***queue, struct commit_list **work)
 {
-	int fd = -1, retval = -3;
+	int fd = -1, t, retval;
 	struct stat fi;
 	struct rc_slice_header head;
 	struct rev_cache_info *rci;
@@ -802,26 +863,31 @@ int traverse_cache_slice(struct rev_info *revs,
 	/* load options */
 	rci = &revs->rev_cache_info;
 	add_to_pending = rci->add_to_pending;
+	add_names = rci->add_names;
 
 	memset(&head, 0, sizeof(struct rc_slice_header));
+#	define ERROR(x)		do { retval = (x); goto end; } while (0);
 
 	fd = open_cache_slice(cache_sha1, O_RDONLY);
 	if (fd == -1)
-		goto end;
+		ERROR(-1);
 	if (fstat(fd, &fi) || fi.st_size < sizeof(struct rc_slice_header))
-		goto end;
+		ERROR(-2);
+
+	if ((t = get_cache_slice_header(fd, cache_sha1, fi.st_size, &head)) < 0)
+		ERROR(-t);
+	if (add_names)
+		cur_name_list = get_cache_slice_name_list(&head, fd);
 
-	map = xmmap(0, fi.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+	map = xmmap(0, head.size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
 	if (map == MAP_FAILED)
-		goto end;
-	if (get_cache_slice_header(cache_sha1, map, fi.st_size, &head))
-		goto end;
+		ERROR(-3);
 
 	retval = traverse_cache_slice_1(&head, map, revs, commit, date_so_far, slop_so_far, queue, work);
 
 end:
 	if (map != MAP_FAILED)
-		munmap(map, fi.st_size);
+		munmap(map, head.size);
 	if (fd != -1)
 		close(fd);
 
@@ -829,6 +895,7 @@ end:
 	if (retval)
 		mark_bad_slice(cache_sha1);
 
+#	undef ERROR
 	return retval;
 }
 
@@ -1113,23 +1180,110 @@ static unsigned long decode_size(unsigned char *str, int len)
 	return size;
 }
 
+
+#define NL_HASH_TABLE_SIZE		(0xffff + 1)
+#define NL_HASH_NUMBER			(NL_HASH_TABLE_SIZE >> 3)
+
+struct name_list_hash {
+	int ind;
+	struct name_list_hash *next;
+};
+
+static struct name_list_hash **nl_hash_table;
+static unsigned char *nl_hashes;
+
+/* FNV-1a hash */
+static unsigned int hash_name(const char *name)
+{
+	unsigned int hash = 2166136261ul;
+	const char *p = name;
+
+	while (*p) {
+		hash ^= *p++;
+		hash *= 16777619ul;
+	}
+
+	return hash & 0xffff;
+}
+
+static int name_in_list(const char *name)
+{
+	unsigned int h = hash_name(name);
+	struct name_list_hash *entry = nl_hash_table[h];
+
+	while (entry && strcmp(acc_name_buffer->buf + entry->ind, name))
+		entry = entry->next;
+
+	if (entry)
+		return entry->ind;
+
+	/* add name to buffer and create hash reference */
+	entry = xcalloc(1, sizeof(struct name_list_hash));
+	entry->ind = acc_name_buffer->len;
+	strbuf_add(acc_name_buffer, name, strlen(name) + 1);
+
+	entry->next = nl_hash_table[h];
+	nl_hash_table[h] = entry;
+
+	nl_hashes[h / 8] |= h % 8;
+
+	return entry->ind;
+}
+
+static void init_name_list_hash(void)
+{
+	nl_hash_table = xcalloc(NL_HASH_TABLE_SIZE, sizeof(struct name_list_hash));
+	nl_hashes = xcalloc(NL_HASH_NUMBER, 1);
+}
+
+static void cleanup_name_list_hash(void)
+{
+	int i;
+
+	for (i = 0; i < NL_HASH_NUMBER; i++) {
+		int j, ind = nl_hashes[i];
+
+		if (!ind)
+			continue;
+
+		for (j = 0; j < 8; j++) {
+			struct name_list_hash **entryp;
+
+			if (!(ind & 1 << j))
+				continue;
+
+			entryp = &nl_hash_table[i * 8 + j];
+			while (*entryp) {
+				struct name_list_hash *t = (*entryp)->next;
+
+				free(*entryp);
+				*entryp = t;
+			}
+		}
+	} /* code overhang! */
+
+	free(nl_hashes);
+	free(nl_hash_table);
+}
+
 static void add_object_entry(const unsigned char *sha1, struct rc_object_entry *entryp,
-	struct strbuf *merge_str, struct strbuf *split_str)
+	struct strbuf *merge_str, struct strbuf *split_str, char *name, unsigned long size)
 {
 	struct rc_object_entry entry;
-	unsigned char size_str[7];
-	unsigned long size;
+	unsigned char size_str[7], name_str[7];
 	enum object_type type;
 	void *data;
 
 	if (entryp)
 		sha1 = entryp->sha1;
 
-	/* retrieve size data */
-	data = read_sha1_file(sha1, &type, &size);
+	if (!size) {
+		/* retrieve size data */
+		data = read_sha1_file(sha1, &type, &size);
 
-	if (data)
-		free(data);
+		if (data)
+			free(data);
+	}
 
 	/* initialize! */
 	if (!entryp) {
@@ -1147,6 +1301,9 @@ static void add_object_entry(const unsigned char *sha1, struct rc_object_entry *
 
 	entryp->size_size = encode_size(size, size_str);
 
+	if (name)
+		entryp->name_size = encode_size(name_in_list(name), name_str);
+
 	/* write the muvabitch */
 	strbuf_add(acc_buffer, to_disked_rc_object_entry(entryp, 0), sizeof(struct rc_object_entry_ondisk));
 
@@ -1156,6 +1313,9 @@ static void add_object_entry(const unsigned char *sha1, struct rc_object_entry *
 		strbuf_add(acc_buffer, split_str->buf, split_str->len);
 
 	strbuf_add(acc_buffer, size_str, entryp->size_size);
+
+	if (name)
+		strbuf_add(acc_buffer, name_str, entryp->name_size);
 }
 
 /* returns non-zero to continue parsing, 0 to skip */
@@ -1200,6 +1360,9 @@ continue_loop:
 static int dump_tree_callback(const unsigned char *sha1, const char *path, unsigned int mode)
 {
 	strbuf_add(acc_buffer, sha1, 20);
+	strbuf_add(acc_buffer, (char *)&acc_name_buffer->len, sizeof(size_t));
+
+	strbuf_add(acc_name_buffer, path, strlen(path) + 1);
 
 	return 1;
 }
@@ -1213,6 +1376,9 @@ static void tree_addremove(struct diff_options *options,
 		return;
 
 	strbuf_add(acc_buffer, sha1, 20);
+	strbuf_add(acc_buffer, (char *)&acc_name_buffer->len, sizeof(size_t));
+
+	strbuf_add(acc_name_buffer, concatpath, strlen(concatpath) + 1);
 }
 
 static void tree_change(struct diff_options *options,
@@ -1225,12 +1391,15 @@ static void tree_change(struct diff_options *options,
 		return;
 
 	strbuf_add(acc_buffer, new_sha1, 20);
+	strbuf_add(acc_buffer, (char *)&acc_name_buffer->len, sizeof(size_t));
+
+	strbuf_add(acc_name_buffer, concatpath, strlen(concatpath) + 1);
 }
 
 static int add_unique_objects(struct commit *commit)
 {
 	struct commit_list *list;
-	struct strbuf os, ost, *orig_buf;
+	struct strbuf os, ost, names, *orig_name_buf, *orig_buf;
 	struct diff_options opts;
 	int i, j, next;
 	char is_first = 1;
@@ -1238,13 +1407,17 @@ static int add_unique_objects(struct commit *commit)
 	/* ...no, calculate unique objects */
 	strbuf_init(&os, 0);
 	strbuf_init(&ost, 0);
+	strbuf_init(&names, 0);
 	orig_buf = acc_buffer;
+	orig_name_buf = acc_name_buffer;
+	acc_name_buffer = &names;
 
 	diff_setup(&opts);
 	DIFF_OPT_SET(&opts, RECURSIVE);
 	DIFF_OPT_SET(&opts, TREE_IN_RECURSIVE);
 	opts.change = tree_change;
 	opts.add_remove = tree_addremove;
+#	define ENTRY_SIZE (20 + sizeof(size_t))
 
 	/* this is only called for non-ends (ie. all parents interesting) */
 	for (list = commit->parents; list; list = list->next) {
@@ -1255,20 +1428,20 @@ static int add_unique_objects(struct commit *commit)
 
 		strbuf_setlen(acc_buffer, 0);
 		diff_tree_sha1(list->item->tree->object.sha1, commit->tree->object.sha1, "", &opts);
-		qsort(acc_buffer->buf, acc_buffer->len / 20, 20, (int (*)(const void *, const void *))hashcmp);
+		qsort(acc_buffer->buf, acc_buffer->len / ENTRY_SIZE, ENTRY_SIZE, (int (*)(const void *, const void *))hashcmp);
 
 		/* take intersection */
 		if (!is_first) {
-			for (next = i = j = 0; i < os.len; i += 20) {
+			for (next = i = j = 0; i < os.len; i += ENTRY_SIZE) {
 				while (j < ost.len && hashcmp((unsigned char *)(ost.buf + j), (unsigned char *)(os.buf + i)) < 0)
-					j += 20;
+					j += ENTRY_SIZE;
 
 				if (j >= ost.len || hashcmp((unsigned char *)(ost.buf + j), (unsigned char *)(os.buf + i)))
 					continue;
 
 				if (next != i)
-					memcpy(os.buf + next, os.buf + i, 20);
-				next += 20;
+					memcpy(os.buf + next, os.buf + i, ENTRY_SIZE);
+				next += ENTRY_SIZE;
 			}
 
 			if (next != i)
@@ -1285,26 +1458,34 @@ static int add_unique_objects(struct commit *commit)
 
 	/* the ordering of non-commit objects dosn't really matter, so we're not gonna bother */
 	acc_buffer = orig_buf;
-	for (i = 0; i < os.len; i += 20)
-		add_object_entry((unsigned char *)(os.buf + i), 0, 0, 0);
+	acc_name_buffer = orig_name_buf;
+	for (i = 0; i < os.len; i += ENTRY_SIZE)
+		add_object_entry((unsigned char *)(os.buf + i), 0, 0, 0, names.buf + *(size_t *)(os.buf + i + 20), 0);
 
 	/* last but not least, the main tree */
-	add_object_entry(commit->tree->object.sha1, 0, 0, 0);
+	add_object_entry(commit->tree->object.sha1, 0, 0, 0, 0, 0);
+
+	strbuf_release(&ost);
+	strbuf_release(&os);
+	strbuf_release(&names);
 
-	return i / 20 + 1;
+	return i / ENTRY_SIZE + 1;
+#	undef ENTRY_SIZE
 }
 
 static int add_objects_verbatim_1(struct rev_cache_slice_map *mapping, int *index)
 {
-	unsigned char *map = mapping->map;
 	int i = *index, object_nr = 0;
+	unsigned char *map = mapping->map;
 	struct rc_object_entry *entry = RC_OBTAIN_OBJECT_ENTRY(map + i);
+	unsigned long size;
 
 	i += RC_ACTUAL_OBJECT_ENTRY_SIZE(entry);
 	while (i < mapping->size) {
-		int pos = i;
+		char *name;
+		int name_index, pos = i;
 
-		entry = RC_OBTAIN_OBJECT_ENTRY(map + i;
+		entry = RC_OBTAIN_OBJECT_ENTRY(map + i);
 		i += RC_ACTUAL_OBJECT_ENTRY_SIZE(entry);
 
 		if (entry->type == OBJ_COMMIT) {
@@ -1312,7 +1493,15 @@ static int add_objects_verbatim_1(struct rev_cache_slice_map *mapping, int *inde
 			return object_nr;
 		}
 
-		strbuf_add(acc_buffer, map + pos, i - pos);
+		name_index = decode_size(map + pos + RC_ENTRY_NAME_OFFSET(entry), entry->name_size);
+		if (name_index && name_index < mapping->name_size)
+			name = mapping->names + name_index;
+		else
+			name = 0;
+
+		size = decode_size(map + pos + RC_ENTRY_SIZE_OFFSET(entry), entry->size_size);
+
+		add_object_entry(0, entry, 0, 0, name, size);
 		object_nr++;
 	}
 
@@ -1397,6 +1586,7 @@ void init_rev_cache_info(struct rev_cache_info *rci)
 	rci->overwrite_all = 0;
 
 	rci->add_to_pending = 1;
+	rci->add_names = 1;
 
 	rci->ignore_size = 0;
 }
@@ -1421,9 +1611,9 @@ int make_cache_slice(struct rev_cache_info *rci,
 	struct rc_slice_header head;
 	struct commit *commit;
 	unsigned char sha1[20];
-	struct strbuf merge_paths, split_paths;
+	struct strbuf merge_paths, split_paths, namelist;
 	int object_nr, total_sz, fd;
-	char file[PATH_MAX], *newfile;
+	char file[PATH_MAX], null, *newfile;
 	struct rev_cache_info *trci;
 	git_SHA_CTX ctx;
 
@@ -1438,7 +1628,13 @@ int make_cache_slice(struct rev_cache_info *rci,
 	strbuf_init(&endlist, 0);
 	strbuf_init(&merge_paths, 0);
 	strbuf_init(&split_paths, 0);
+	strbuf_init(&namelist, 0);
 	acc_buffer = &buffer;
+	acc_name_buffer = &namelist;
+
+	null = 0;
+	strbuf_add(&namelist, &null, 1);
+	init_name_list_hash();
 
 	if (!revs) {
 		revs = &therevs;
@@ -1469,6 +1665,7 @@ int make_cache_slice(struct rev_cache_info *rci,
 	trci = &revs->rev_cache_info;
 	init_rev_cache_info(trci);
 	trci->add_to_pending = 0;
+	trci->add_names = 0;
 
 	setup_revisions(0, 0, revs, 0);
 	if (prepare_revision_walk(revs))
@@ -1506,7 +1703,7 @@ int make_cache_slice(struct rev_cache_info *rci,
 
 		commit->indegree = 0;
 
-		add_object_entry(0, &object, &merge_paths, &split_paths);
+		add_object_entry(0, &object, &merge_paths, &split_paths, 0, 0);
 		object_nr++;
 
 		if (rci->objects && !object.is_end) {
@@ -1532,10 +1729,16 @@ int make_cache_slice(struct rev_cache_info *rci,
 		total_sz += buffer.len;
 	}
 
+	/* write path name lookup list */
+	head.name_size = htonl(namelist.len);
+	write_in_full(fd, namelist.buf, namelist.len);
+
 	/* go ahead a free some stuff... */
 	strbuf_release(&buffer);
 	strbuf_release(&merge_paths);
 	strbuf_release(&split_paths);
+	strbuf_release(&namelist);
+	cleanup_name_list_hash();
 	if (path_sz)
 		free(paths);
 	while (path_track_alloc)
@@ -1993,6 +2196,7 @@ int fuse_cache_slices(struct rev_cache_info *rci, struct rev_info *revs)
 	for (i = idx_head.cache_nr - 1; i >= 0; i--) {
 		struct rev_cache_slice_map *map = rci->maps + i;
 		struct stat fi;
+		struct rc_slice_header head;
 		int fd;
 
 		if (!map->size)
@@ -2005,13 +2209,20 @@ int fuse_cache_slices(struct rev_cache_info *rci, struct rev_info *revs)
 			continue;
 		if (fi.st_size < sizeof(struct rc_slice_header))
 			continue;
+		if (get_cache_slice_header(fd, idx_caches + i * 20, fi.st_size, &head))
+			continue;
 
-		map->map = xmmap(0, fi.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+		map->map = xmmap(0, head.size, PROT_READ, MAP_PRIVATE, fd, 0);
 		if (map->map == MAP_FAILED)
 			continue;
 
+		lseek(fd, head.size, SEEK_SET);
+		map->names = xcalloc(head.name_size, 1);
+		read_in_full(fd, map->names, head.name_size);
+
 		close(fd);
-		map->size = fi.st_size;
+		map->size = head.size;
+		map->name_size = head.name_size;
 	}
 
 	rci->make_index = 0;
@@ -2028,6 +2239,7 @@ int fuse_cache_slices(struct rev_cache_info *rci, struct rev_info *revs)
 		if (!map->size)
 			continue;
 
+		free(map->names);
 		munmap(map->map, map->size);
 	}
 	free(rci->maps);
@@ -2049,7 +2261,6 @@ static int verify_cache_slice(const char *slice_path, unsigned char *sha1)
 {
 	struct rc_slice_header head;
 	int fd, len, retval = -1;
-	unsigned char *map = MAP_FAILED;
 	struct stat fi;
 
 	len = strlen(slice_path);
@@ -2064,17 +2275,12 @@ static int verify_cache_slice(const char *slice_path, unsigned char *sha1)
 	if (fstat(fd, &fi) || fi.st_size < sizeof(head))
 		goto end;
 
-	map = xmmap(0, sizeof(head), PROT_READ, MAP_PRIVATE, fd, 0);
-	if (map == MAP_FAILED)
-		goto end;
-	if (get_cache_slice_header(sha1, map, fi.st_size, &head))
+	if (get_cache_slice_header(fd, sha1, fi.st_size, &head))
 		goto end;
 
 	retval = 0;
 
 end:
-	if (map != MAP_FAILED)
-		munmap(map, sizeof(head));
 	if (fd > 0)
 		close(fd);
 
diff --git a/rev-cache.h b/rev-cache.h
index 14437d8..c88ceae 100644
--- a/rev-cache.h
+++ b/rev-cache.h
@@ -10,8 +10,14 @@
 #define RC_OBTAIN_OBJECT_ENTRY(p)			from_disked_rc_object_entry((struct rc_object_entry_ondisk *)(p), 0)
 #define RC_OBTAIN_INDEX_ENTRY(p)			from_disked_rc_index_entry((struct rc_index_entry_ondisk *)(p), 0)
 
-#define RC_ACTUAL_OBJECT_ENTRY_SIZE(e)		(sizeof(struct rc_object_entry_ondisk) + RC_PATH_SIZE((e)->merge_nr + (e)->split_nr) + (e)->size_size)
-#define RC_ENTRY_SIZE_OFFSET(e)				(RC_ACTUAL_OBJECT_ENTRY_SIZE(e) - (e)->size_size)
+#define RC_ACTUAL_OBJECT_ENTRY_SIZE(e)	(\
+	sizeof(struct rc_object_entry_ondisk) + \
+	RC_PATH_SIZE((e)->merge_nr + (e)->split_nr) + \
+	(e)->size_size + \
+	(e)->name_size\
+)
+#define RC_ENTRY_SIZE_OFFSET(e)			(RC_ACTUAL_OBJECT_ENTRY_SIZE(e) - (e)->name_size - (e)->size_size)
+#define RC_ENTRY_NAME_OFFSET(e)			(RC_ACTUAL_OBJECT_ENTRY_SIZE(e) - (e)->name_size)
 
 /* single index maps objects to cache files */
 struct rc_index_header {
@@ -50,6 +56,8 @@ struct rc_slice_header {
 	uint32_t size;
 
 	unsigned char sha1[20];
+
+	uint32_t name_size;
 };
 
 struct rc_object_entry_ondisk {
@@ -76,7 +84,8 @@ struct rc_object_entry {
 	unsigned char merge_nr; /* : 7 */
 	unsigned char split_nr; /* : 7 */
 	unsigned size_size : 3;
-	unsigned padding : 5;
+	unsigned name_size : 3;
+	unsigned padding : 2;
 
 	uint32_t date;
 	uint16_t path;
@@ -84,6 +93,7 @@ struct rc_object_entry {
 	/* merge paths */
 	/* split paths */
 	/* size */
+	/* name id */
 };
 
 struct rc_index_entry *from_disked_rc_index_entry(struct rc_index_entry_ondisk *src, struct rc_index_entry *dst);
diff --git a/revision.h b/revision.h
index c3ec1b3..b2d5834 100644
--- a/revision.h
+++ b/revision.h
@@ -23,6 +23,9 @@ struct rev_cache_slice_map {
 	unsigned char *map;
 	int size;
 	int last_index;
+
+	char *names;
+	int name_size;
 };
 
 struct rev_cache_info {
@@ -36,7 +39,8 @@ struct rev_cache_info {
 	unsigned overwrite_all : 1;
 
 	/* traversal flags */
-	unsigned add_to_pending : 1;
+	unsigned add_to_pending : 1,
+		add_names : 1;
 
 	/* fuse options */
 	unsigned int ignore_size;
diff --git a/t/t6015-rev-cache-list.sh b/t/t6015-rev-cache-list.sh
index 065f214..e603f85 100755
--- a/t/t6015-rev-cache-list.sh
+++ b/t/t6015-rev-cache-list.sh
@@ -4,8 +4,8 @@ test_description='git rev-cache tests'
 . ./test-lib.sh
 
 test_cmp_sorted() {
-	grep -io "[a-f0-9]*" $1 | sort >.tmpfile1 &&
-	grep -io "[a-f0-9]*" $2 | sort >.tmpfile2 &&
+	sort $1 >.tmpfile1 &&
+	sort $2 >.tmpfile2 &&
 	test_cmp .tmpfile1 .tmpfile2
 }
 
@@ -75,7 +75,7 @@ test_expect_success 'init repo' '
 	sleep 2 &&
 	git checkout master &&
 	git merge -m "triple merge" b1 b11 &&
-	git rm -r d1 && 
+	git rm -r d1 &&
 	sleep 2 &&
 	git commit -a -m "oh noes"
 '
-- 
tg: (635e0b5..) t/revcache/names (depends on: t/revcache/docs)

^ permalink raw reply related

* Re: [PATCH 5/6 (v4)] full integration of rev-cache into git, completed test suite
From: Nick Edelen @ 2009-08-18 11:51 UTC (permalink / raw)
  To: Nick Edelen, Junio C Hamano, Nicolas Pitre, Johannes Schindelin,
	Sam Vilain
In-Reply-To: <op.uys3quhbtdk399@sirnot.private>

This last patch provides a working integration of rev-cache into the revision
walker, along with some touch-ups:
 - integration into revision walker and list-objects
 - tweak of object generation to take advantage of the 'unique' field
 - more fluid handling of damaged cache slices
 - numerous tests for both features from the previous patch, and the
integration's integrity

'Integration' is rather broad -- a more detailed description follows for each
aspect:
 - rev-cache
the traversal mechanism is updated to handle many of the non-prune options
rev-list does (date limiting, slop-handling, etc.), and is adjusted to allow
for non-fatal cache-traversal failures.

 - revision walker
both limited and unlimited traversal attempt to use the cache when possible,
smoothly falling back if it's not.

 - list-objects
object listing does not recurse into cached trees, and has been adjusted to
guarantee commit-tag-tree-blob ordering.

Signed-off-by: Nick Edelen <sirnot@gmail.com>

---
 builtin-rev-cache.c       |   40 ++++++++
 list-objects.c            |   49 ++++++++--
 rev-cache.c               |  228 +++++++++++++++++++++++++++++++++++++++-----
 revision.c                |   88 ++++++++++++++---
 t/t6015-rev-cache-list.sh |  153 +++++++++++++++++++++++++++++--
 5 files changed, 502 insertions(+), 56 deletions(-)

diff --git a/builtin-rev-cache.c b/builtin-rev-cache.c
index b894c54..8f41123 100644
--- a/builtin-rev-cache.c
+++ b/builtin-rev-cache.c
@@ -4,6 +4,7 @@
 #include "diff.h"
 #include "revision.h"
 #include "rev-cache.h"
+#include "list-objects.h"
 
 unsigned long default_ignore_size = 50 * 1024 * 1024; /* 50mb */
 
@@ -78,6 +79,43 @@ static int handle_add(int argc, const char *argv[]) /* args beyond this command
 	return 0;
 }
 
+static void show_commit(struct commit *commit, void *data)
+{
+	printf("%s\n", sha1_to_hex(commit->object.sha1));
+}
+
+static void show_object(struct object *obj, const struct name_path *path, const char *last)
+{
+	printf("%s\n", sha1_to_hex(obj->sha1));
+}
+
+static int test_rev_list(int argc, const char *argv[])
+{
+	struct rev_info revs;
+	unsigned int flags = 0;
+	int i;
+
+	init_revisions(&revs, 0);
+
+	for (i = 0; i < argc; i++) {
+		if (!strcmp(argv[i], "--not"))
+			flags ^= UNINTERESTING;
+		else if (!strcmp(argv[i], "--objects"))
+			revs.tree_objects = revs.blob_objects = 1;
+		else
+			handle_revision_arg(argv[i], &revs, flags, 1);
+	}
+
+	setup_revisions(0, 0, &revs, 0);
+	revs.topo_order = 1;
+	revs.lifo = 1;
+	prepare_revision_walk(&revs);
+
+	traverse_commit_list(&revs, show_commit, show_object, 0);
+
+	return 0;
+}
+
 static int handle_walk(int argc, const char *argv[])
 {
 	struct commit *commit;
@@ -271,6 +309,8 @@ int cmd_rev_cache(int argc, const char *argv[], const char *prefix)
 		r = handle_walk(argc, argv);
 	else if (!strcmp(arg, "index"))
 		r = handle_index(argc, argv);
+	else if (!strcmp(arg, "test"))
+		r = test_rev_list(argc, argv);
 	else if (!strcmp(arg, "alt"))
 		r = handle_alt(argc, argv);
 	else
diff --git a/list-objects.c b/list-objects.c
index 8953548..821a290 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -74,22 +74,33 @@ static void process_tree(struct rev_info *revs,
 		die("bad tree object");
 	if (obj->flags & (UNINTERESTING | SEEN))
 		return;
-	if (parse_tree(tree) < 0)
-		die("bad tree object %s", sha1_to_hex(obj->sha1));
+
 	obj->flags |= SEEN;
 	show(obj, path, name);
+	if (obj->flags & FACE_VALUE)
+		return;
+
+	/* traverse_commit_list is only used for enumeration purposes,
+	 * ie. nothing relies on trees being parsed in this routine */
+	if (parse_tree(tree) < 0)
+		die("bad tree object %s", sha1_to_hex(obj->sha1));
+
 	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))
+		if (S_ISDIR(entry.mode)) {
+			struct tree *subtree = lookup_tree(entry.sha1);
+			if (!subtree)
+				continue;
+
+			subtree->object.flags &= ~FACE_VALUE;
 			process_tree(revs,
-				     lookup_tree(entry.sha1),
+				     subtree,
 				     show, &me, entry.path);
-		else if (S_ISGITLINK(entry.mode))
+		} else if (S_ISGITLINK(entry.mode))
 			process_gitlink(revs, entry.sha1,
 					show, &me, entry.path);
 		else
@@ -136,6 +147,7 @@ void mark_edges_uninteresting(struct commit_list *list,
 
 static void add_pending_tree(struct rev_info *revs, struct tree *tree)
 {
+	tree->object.flags &= ~FACE_VALUE;
 	add_pending_object(revs, &tree->object, "");
 }
 
@@ -146,17 +158,27 @@ void traverse_commit_list(struct rev_info *revs,
 {
 	int i;
 	struct commit *commit;
+	enum object_type what = OBJ_TAG;
+	char face_value = 0;
 
 	while ((commit = get_revision(revs)) != NULL) {
-		add_pending_tree(revs, commit->tree);
+		if (!(commit->object.flags & FACE_VALUE))
+			add_pending_tree(revs, commit->tree);
+		else
+			face_value = 1;
 		show_commit(commit, data);
 	}
+
+loop_objects:
 	for (i = 0; i < revs->pending.nr; i++) {
 		struct object_array_entry *pending = revs->pending.objects + i;
 		struct object *obj = pending->item;
 		const char *name = pending->name;
 		if (obj->flags & (UNINTERESTING | SEEN))
 			continue;
+		if (obj->type != what && face_value)
+			continue;
+
 		if (obj->type == OBJ_TAG) {
 			obj->flags |= SEEN;
 			show_object(obj, NULL, name);
@@ -175,6 +197,19 @@ void traverse_commit_list(struct rev_info *revs,
 		die("unknown pending object %s (%s)",
 		    sha1_to_hex(obj->sha1), name);
 	}
+	if (face_value) {
+		switch (what) {
+		case OBJ_TAG :
+			what = OBJ_TREE;
+			goto loop_objects;
+		case OBJ_TREE :
+			what = OBJ_BLOB;
+			goto loop_objects;
+		default :
+			break;
+		}
+	}
+
 	if (revs->pending.nr) {
 		free(revs->pending.objects);
 		revs->pending.nr = 0;
diff --git a/rev-cache.c b/rev-cache.c
index 8ca97d3..04a9b02 100644
--- a/rev-cache.c
+++ b/rev-cache.c
@@ -11,6 +11,12 @@
 #include "run-command.h"
 #include "string-list.h"
 
+
+struct bad_slice {
+	unsigned char sha1[20];
+	struct bad_slice *next;
+};
+
 struct cache_slice_pointer {
 	char signature[8]; /* REVCOPTR */
 	char version;
@@ -23,8 +29,9 @@ static uint32_t fanout[0xff + 2];
 static unsigned char *idx_map;
 static int idx_size;
 static struct rc_index_header idx_head;
+static char no_idx, add_to_pending;
+static struct bad_slice *bad_slices;
 static unsigned char *idx_caches;
-static char no_idx;
 
 static struct strbuf *acc_buffer;
 
@@ -121,6 +128,30 @@ struct rc_object_entry_ondisk *to_disked_rc_object_entry(struct rc_object_entry
 	return dst;
 }
 
+static void mark_bad_slice(unsigned char *sha1)
+{
+	struct bad_slice *bad;
+
+	bad = xcalloc(sizeof(struct bad_slice), 1);
+	hashcpy(bad->sha1, sha1);
+
+	bad->next = bad_slices;
+	bad_slices = bad;
+}
+
+static int is_bad_slice(unsigned char *sha1)
+{
+	struct bad_slice *bad = bad_slices;
+
+	while (bad) {
+		if (!hashcmp(bad->sha1, sha1))
+			return 1;
+		bad = bad->next;
+	}
+
+	return 0;
+}
+
 static int get_index_head(unsigned char *map, int len, struct rc_index_header *head, uint32_t *fanout, unsigned char **caches)
 {
 	struct rc_index_header whead;
@@ -246,6 +277,7 @@ static struct rc_index_entry *search_index(unsigned char *sha1)
 unsigned char *get_cache_slice(struct commit *commit)
 {
 	struct rc_index_entry *ie;
+	unsigned char *sha1;
 
 	if (!idx_map) {
 		if (no_idx)
@@ -257,8 +289,13 @@ unsigned char *get_cache_slice(struct commit *commit)
 		return 0;
 
 	ie = search_index(commit->object.sha1);
-	if (ie && ie->cache_index < idx_head.cache_nr)
-		return idx_caches + ie->cache_index * 20;
+	if (ie && ie->cache_index < idx_head.cache_nr) {
+		sha1 = idx_caches + ie->cache_index * 20;
+
+		if (is_bad_slice(sha1))
+			return 0;
+		return sha1;
+	}
 
 	return 0;
 }
@@ -268,6 +305,20 @@ unsigned char *get_cache_slice(struct commit *commit)
 
 static unsigned long decode_size(unsigned char *str, int len);
 
+/* on failure */
+static void restore_commit(struct commit *commit)
+{
+	commit->object.flags &= ~(ADDED | SEEN | FACE_VALUE);
+
+	if (!commit->object.parsed) {
+		while (pop_commit(&commit->parents))
+			;
+
+		parse_commit(commit);
+	}
+
+}
+
 static void handle_noncommit(struct rev_info *revs, struct commit *commit, unsigned char *ptr, struct rc_object_entry *entry)
 {
 	struct blob *blob;
@@ -307,23 +358,27 @@ static void handle_noncommit(struct rev_info *revs, struct commit *commit, unsig
 	}
 
 	obj->flags |= FACE_VALUE;
-	add_pending_object(revs, obj, "");
+	if (add_to_pending)
+		add_pending_object(revs, obj, "");
 }
 
-static int setup_traversal(struct rc_slice_header *head, unsigned char *map, struct commit *commit, struct commit_list **work)
+static int setup_traversal(struct rc_slice_header *head, unsigned char *map, struct commit *commit, struct commit_list **work,
+	struct commit_list **unwork, int *ipath_nr, int *upath_nr, char *ioutside)
 {
 	struct rc_index_entry *iep;
 	struct rc_object_entry *oep;
 	struct commit_list *prev, *wp, **wpp;
 	int retval;
 
-	iep = search_index(commit->object.sha1), 0;
+	iep = search_index(commit->object.sha1);
 	oep = RC_OBTAIN_OBJECT_ENTRY(map + iep->pos);
+	if (commit->object.flags & UNINTERESTING) {
+		++*upath_nr;
+		oep->uninteresting = 1;
+	} else
+		++*ipath_nr;
 
-	/* the .uniniteresting bit isn't strictly necessary, as we check the object during traversal as well,
-	 * but we might as well initialize it while we're at it */
 	oep->include = 1;
-	oep->uninteresting = !!(commit->object.flags & UNINTERESTING);
 	to_disked_rc_object_entry(oep, (struct rc_object_entry_ondisk *)(map + iep->pos));
 	retval = iep->pos;
 
@@ -338,6 +393,10 @@ static int setup_traversal(struct rc_slice_header *head, unsigned char *map, str
 		/* is this in our cache slice? */
 		iep = search_index(obj->sha1);
 		if (!iep || hashcmp(idx_caches + iep->cache_index * 20, head->sha1)) {
+			/* there are interesing objects outside the slice */
+			if (!(obj->flags & UNINTERESTING))
+				*ioutside = 1;
+
 			prev = wp;
 			wp = wp->next;
 			wpp = &wp;
@@ -354,11 +413,20 @@ static int setup_traversal(struct rc_slice_header *head, unsigned char *map, str
 		oep->uninteresting = !!(obj->flags & UNINTERESTING);
 		to_disked_rc_object_entry(oep, (struct rc_object_entry_ondisk *)(map + iep->pos));
 
+		/* count even if not in slice so we can stop enumerating if possible */
+		if (obj->flags & UNINTERESTING)
+			++*upath_nr;
+		else
+			++*ipath_nr;
+
 		/* remove from work list */
 		co = pop_commit(wpp);
 		wp = *wpp;
 		if (prev)
 			prev->next = wp;
+
+		/* ...and store in temp list so we can restore work on failure */
+		commit_list_insert(co, unwork);
 	}
 
 	return retval;
@@ -375,13 +443,18 @@ static int traverse_cache_slice_1(struct rc_slice_header *head, unsigned char *m
 	unsigned long *date_so_far, int *slop_so_far,
 	struct commit_list ***queue, struct commit_list **work)
 {
-	struct commit_list *insert_cache = 0;
+	struct commit_list *insert_cache = 0, *myq = 0, **myqp = &myq, *mywork = 0, **myworkp = &mywork, *unwork = 0;
 	struct commit **last_objects, *co;
-	int i, total_path_nr = head->path_nr, retval = -1;
-	char consume_children = 0;
+	unsigned long date = date_so_far ? *date_so_far : ~0ul;
+	int i, ipath_nr = 0, upath_nr = 0, orig_obj_nr = 0,
+		total_path_nr = head->path_nr, retval = -1, slop = slop_so_far ? *slop_so_far : SLOP;
+	char consume_children = 0, ioutside = 0;
 	unsigned char *paths;
 
-	i = setup_traversal(head, map, commit, work);
+	/* take note in case we need to regress */
+	orig_obj_nr = revs->pending.nr;
+
+	i = setup_traversal(head, map, commit, work, &unwork, &ipath_nr, &upath_nr, &ioutside);
 	if (i < 0)
 		return -1;
 
@@ -429,6 +502,7 @@ static int traverse_cache_slice_1(struct rc_slice_header *head, unsigned char *m
 
 		if ((paths[path] & IPATH) && (paths[path] & UPATH)) {
 			paths[path] = UPATH;
+			ipath_nr--;
 
 			/* mark edge */
 			if (last_objects[path]) {
@@ -439,6 +513,7 @@ static int traverse_cache_slice_1(struct rc_slice_header *head, unsigned char *m
 				last_objects[path]->object.flags &= ~FACE_VALUE;
 				last_objects[path] = 0;
 			}
+			obj->flags |= BOUNDARY;
 		}
 
 		/* now we gotta re-assess the whole interesting thing... */
@@ -462,8 +537,10 @@ static int traverse_cache_slice_1(struct rc_slice_header *head, unsigned char *m
 						last_objects[p]->object.flags &= ~FACE_VALUE;
 						last_objects[p] = 0;
 					}
-				} else if (last_objects[p] && !last_objects[p]->object.parsed)
+					obj->flags |= BOUNDARY;
+				} else if (last_objects[p] && !last_objects[p]->object.parsed) {
 					commit_list_insert(co, &last_objects[p]->parents);
+				}
 
 				/* can't close a merge path until all are parents have been encountered */
 				if (GET_COUNT(paths[p])) {
@@ -473,14 +550,33 @@ static int traverse_cache_slice_1(struct rc_slice_header *head, unsigned char *m
 						continue;
 				}
 
+				if (paths[p] & IPATH)
+					ipath_nr--;
+				else
+					upath_nr--;
+
 				paths[p] = 0;
 				last_objects[p] = 0;
 			}
 		}
 
 		/* make topo relations */
-		if (last_objects[path] && !last_objects[path]->object.parsed)
+		if (last_objects[path] && !last_objects[path]->object.parsed) {
 			commit_list_insert(co, &last_objects[path]->parents);
+		}
+
+		/* we've been here already */
+		if (obj->flags & ADDED) {
+			if (entry->uninteresting && !(obj->flags & UNINTERESTING)) {
+				obj->flags |= UNINTERESTING;
+				mark_parents_uninteresting(co);
+				upath_nr--;
+			} else if (!entry->uninteresting)
+				ipath_nr--;
+
+			paths[path] = 0;
+			continue;
+		}
 
 		/* initialize commit */
 		if (!entry->is_end) {
@@ -493,24 +589,51 @@ static int traverse_cache_slice_1(struct rc_slice_header *head, unsigned char *m
 
 		if (entry->uninteresting)
 			obj->flags |= UNINTERESTING;
+		else if (co->date < date)
+			date = co->date;
 
 		/* we need to know what the edges are */
 		last_objects[path] = co;
 
 		/* add to list */
-		if (!(obj->flags & UNINTERESTING) || revs->show_all) {
-			if (entry->is_end)
-				insert_by_date_cached(co, work, insert_cache, &insert_cache);
-			else
-				*queue = &commit_list_insert(co, *queue)->next;
+		if (slop && !(revs->min_age != -1 && co->date > revs->min_age)) {
+
+			if (!(obj->flags & UNINTERESTING) || revs->show_all) {
+				if (entry->is_end)
+					myworkp = &commit_list_insert(co, myworkp)->next;
+				else
+					myqp = &commit_list_insert(co, myqp)->next;
+
+				/* add children to list as well */
+				if (obj->flags & UNINTERESTING)
+					consume_children = 0;
+				else
+					consume_children = 1;
+			}
 
-			/* add children to list as well */
-			if (obj->flags & UNINTERESTING)
-				consume_children = 0;
-			else
-				consume_children = 1;
 		}
 
+		/* should we continue? */
+		if (!slop) {
+			if (!upath_nr) {
+				break;
+			} else if (ioutside || revs->show_all) {
+				/* pass it back to rev-list
+				 * we purposely ignore everything outside this cache, so we don't needlessly traverse the whole
+				 * thing on uninteresting, but that does mean that we may need to bounce back
+				 * and forth a few times with rev-list */
+				myworkp = &commit_list_insert(co, myworkp)->next;
+
+				paths[path] = 0;
+				upath_nr--;
+			} else {
+				break;
+			}
+		} else if (!ipath_nr && co->date <= date)
+			slop--;
+		else
+			slop = SLOP;
+
 		/* open parents */
 		if (entry->merge_nr) {
 			int j, off = index + sizeof(struct rc_object_entry_ondisk);
@@ -525,6 +648,11 @@ static int traverse_cache_slice_1(struct rc_slice_header *head, unsigned char *m
 				if (paths[p] & flag)
 					continue;
 
+				if (flag == IPATH)
+					ipath_nr++;
+				else
+					upath_nr++;
+
 				paths[p] |= flag;
 			}
 
@@ -534,12 +662,55 @@ static int traverse_cache_slice_1(struct rc_slice_header *head, unsigned char *m
 
 	}
 
+	if (date_so_far)
+		*date_so_far = date;
+	if (slop_so_far)
+		*slop_so_far = slop;
 	retval = 0;
 
+	/* success: attach to given lists */
+	if (myqp != &myq) {
+		**queue = myq;
+		*queue = myqp;
+	}
+
+	while ((co = pop_commit(&mywork)) != 0) {
+		insert_by_date_cached(co, work, insert_cache, &insert_cache);
+	}
+
+	/* free backup */
+	while (pop_commit(&unwork))
+		;
+
 end:
 	free(paths);
 	free(last_objects);
 
+	/* failure: restore work to previous condition
+	 * (cache corruption should *not* be fatal) */
+	if (retval) {
+		while ((co = pop_commit(&unwork)) != 0) {
+			restore_commit(co);
+			co->object.flags |= SEEN;
+			insert_by_date(co, work);
+		}
+
+		/* free lists */
+		while ((co = pop_commit(&myq)) != 0)
+			restore_commit(co);
+
+		while ((co = pop_commit(&mywork)) != 0)
+			restore_commit(co);
+
+		/* truncate object array */
+		for (i = orig_obj_nr; i < revs->pending.nr; i++) {
+			struct object *obj = revs->pending.objects[i].item;
+
+			obj->flags &= ~FACE_VALUE;
+		}
+		revs->pending.nr = orig_obj_nr;
+	}
+
 	return retval;
 }
 
@@ -630,6 +801,7 @@ int traverse_cache_slice(struct rev_info *revs,
 
 	/* load options */
 	rci = &revs->rev_cache_info;
+	add_to_pending = rci->add_to_pending;
 
 	memset(&head, 0, sizeof(struct rc_slice_header));
 
@@ -653,6 +825,10 @@ end:
 	if (fd != -1)
 		close(fd);
 
+	/* remember this! */
+	if (retval)
+		mark_bad_slice(cache_sha1);
+
 	return retval;
 }
 
diff --git a/revision.c b/revision.c
index 485bf72..4640536 100644
--- a/revision.c
+++ b/revision.c
@@ -12,6 +12,7 @@
 #include "patch-ids.h"
 #include "decorate.h"
 #include "log-tree.h"
+#include "rev-cache.h"
 
 volatile show_early_output_fn_t show_early_output;
 
@@ -638,6 +639,8 @@ static int limit_list(struct rev_info *revs)
 	struct commit_list *list = revs->commits;
 	struct commit_list *newlist = NULL;
 	struct commit_list **p = &newlist;
+	unsigned char *cache_sha1;
+	char used_cache;
 
 	while (list) {
 		struct commit_list *entry = list;
@@ -650,24 +653,39 @@ static int limit_list(struct rev_info *revs)
 
 		if (revs->max_age != -1 && (commit->date < revs->max_age))
 			obj->flags |= UNINTERESTING;
-		if (add_parents_to_list(revs, commit, &list, NULL) < 0)
-			return -1;
-		if (obj->flags & UNINTERESTING) {
-			mark_parents_uninteresting(commit);
-			if (revs->show_all)
-				p = &commit_list_insert(commit, p)->next;
-			slop = still_interesting(list, date, slop);
-			if (slop)
+
+		/* rev-cache to the rescue!!! */
+		used_cache = 0;
+		if (!revs->dont_cache_me && !(obj->flags & ADDED)) {
+			cache_sha1 = get_cache_slice(commit);
+			if (cache_sha1) {
+				if (traverse_cache_slice(revs, cache_sha1, commit, &date, &slop, &p, &list) < 0)
+					used_cache = 0;
+				else
+					used_cache = 1;
+			}
+		}
+
+		if (!used_cache) {
+			if (add_parents_to_list(revs, commit, &list, NULL) < 0)
+				return -1;
+			if (obj->flags & UNINTERESTING) {
+				mark_parents_uninteresting(commit); /* ME: why? */
+				if (revs->show_all)
+					p = &commit_list_insert(commit, p)->next;
+				slop = still_interesting(list, date, slop);
+				if (slop > 0)
+					continue;
+				/* If showing all, add the whole pending list to the end */
+				if (revs->show_all)
+					*p = list;
+				break;
+			}
+			if (revs->min_age != -1 && (commit->date > revs->min_age))
 				continue;
-			/* If showing all, add the whole pending list to the end */
-			if (revs->show_all)
-				*p = list;
-			break;
+			date = commit->date;
+			p = &commit_list_insert(commit, p)->next;
 		}
-		if (revs->min_age != -1 && (commit->date > revs->min_age))
-			continue;
-		date = commit->date;
-		p = &commit_list_insert(commit, p)->next;
 
 		show = show_early_output;
 		if (!show)
@@ -813,6 +831,8 @@ void init_revisions(struct rev_info *revs, const char *prefix)
 		revs->diffopt.prefix = prefix;
 		revs->diffopt.prefix_length = strlen(prefix);
 	}
+
+	init_rev_cache_info(&revs->rev_cache_info);
 }
 
 static void add_pending_commit_list(struct rev_info *revs,
@@ -1372,6 +1392,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
 	if (revs->reflog_info && revs->graph)
 		die("cannot combine --walk-reflogs with --graph");
 
+	/* limits on caching
+	 * todo: implement this functionality */
+	if (revs->prune || revs->diff)
+		revs->dont_cache_me = 1;
+
 	return left;
 }
 
@@ -1654,6 +1679,8 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
 {
 	if (!opt->grep_filter.pattern_list)
 		return 1;
+	if (!commit->object.parsed)
+		parse_commit(commit);
 	return grep_buffer(&opt->grep_filter,
 			   NULL, /* we say nothing, not even filename */
 			   commit->buffer, strlen(commit->buffer));
@@ -1706,6 +1733,7 @@ static struct commit *get_revision_1(struct rev_info *revs)
 	do {
 		struct commit_list *entry = revs->commits;
 		struct commit *commit = entry->item;
+		struct object *obj = &commit->object;
 
 		revs->commits = entry->next;
 		free(entry);
@@ -1722,11 +1750,39 @@ static struct commit *get_revision_1(struct rev_info *revs)
 			if (revs->max_age != -1 &&
 			    (commit->date < revs->max_age))
 				continue;
+
+			if (!revs->dont_cache_me) {
+				struct commit_list *queue = 0, **queuep = &queue;
+				unsigned char *cache_sha1;
+
+				if (obj->flags & ADDED)
+					goto skip_parenting;
+
+				cache_sha1 = get_cache_slice(commit);
+				if (cache_sha1) {
+					if (!traverse_cache_slice(revs, cache_sha1, commit, 0, 0, &queuep, &revs->commits)) {
+						struct commit_list *work = revs->commits;
+
+						/* attach queue to end of ->commits */
+						while (work && work->next)
+							work = work->next;
+
+						if (work)
+							work->next = queue;
+						else
+							revs->commits = queue;
+
+						goto skip_parenting;
+					}
+				}
+			}
+
 			if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0)
 				die("Failed to traverse parents of commit %s",
 				    sha1_to_hex(commit->object.sha1));
 		}
 
+skip_parenting:
 		switch (simplify_commit(revs, commit)) {
 		case commit_ignore:
 			continue;
diff --git a/t/t6015-rev-cache-list.sh b/t/t6015-rev-cache-list.sh
index dc0fc07..065f214 100755
--- a/t/t6015-rev-cache-list.sh
+++ b/t/t6015-rev-cache-list.sh
@@ -38,6 +38,7 @@ test_expect_success 'init repo' '
 	git add . &&
 	git commit -m "omg" &&
 
+	sleep 2 &&
 	git branch b4 &&
 	git checkout b4 &&
 	echo shazam >file8 &&
@@ -46,7 +47,7 @@ test_expect_success 'init repo' '
 	git merge -m "merge b2" b2 &&
 
 	echo bam >smoke/pipe &&
-	git add .
+	git add . &&
 	git commit -m "bam" &&
 
 	git checkout master &&
@@ -71,18 +72,26 @@ test_expect_success 'init repo' '
 	git add . &&
 	git commit -m "lol" &&
 
+	sleep 2 &&
 	git checkout master &&
 	git merge -m "triple merge" b1 b11 &&
-	git rm -r d1 &&
+	git rm -r d1 && 
+	sleep 2 &&
 	git commit -a -m "oh noes"
 '
 
-git-rev-list HEAD --not HEAD~3 >proper_commit_list_limited
-git-rev-list HEAD >proper_commit_list
-git-rev-list HEAD --objects >proper_object_list
+max_date=`git-rev-list --timestamp HEAD~1 --max-count=1 | grep -e "^[0-9]*" -o`
+min_date=`git-rev-list --timestamp b4 --max-count=1 | grep -e "^[0-9]*" -o`
+
+git-rev-list --topo-order HEAD --not HEAD~3 >proper_commit_list_limited
+git-rev-list --topo-order HEAD --not HEAD~2 >proper_commit_list_limited2
+git-rev-list --topo-order HEAD >proper_commit_list
+git-rev-list --objects HEAD >proper_object_list
+git-rev-list HEAD --max-age=$min_date --min-age=$max_date >proper_list_date_limited
+
+cache_sha1=`git-rev-cache add HEAD 2>output.err`
 
 test_expect_success 'make cache slice' '
-	git-rev-cache add HEAD 2>output.err &&
 	grep "final return value: 0" output.err
 '
 
@@ -102,11 +111,141 @@ test_expect_success 'test rev-caches walker directly (unlimited)' '
 	test_cmp_sorted list proper_commit_list
 '
 
+test_expect_success 'test rev-list traversal (limited)' '
+	git-rev-list HEAD --not HEAD~3 >list &&
+	test_cmp list proper_commit_list_limited
+'
+
+test_expect_success 'test rev-list traversal (unlimited)' '
+	git-rev-list HEAD >list &&
+	test_cmp list proper_commit_list
+'
+
 #do the same for objects
 test_expect_success 'test rev-caches walker with objects' '
 	git-rev-cache walk --objects HEAD >list &&
 	test_cmp_sorted list proper_object_list
 '
 
-test_done
+test_expect_success 'test rev-list with objects (topo order)' '
+	git-rev-list --topo-order --objects HEAD >list &&
+	test_cmp_sorted list proper_object_list
+'
+
+test_expect_success 'test rev-list with objects (no order)' '
+	git-rev-list --objects HEAD >list &&
+	test_cmp_sorted list proper_object_list
+'
+
+#verify age limiting
+test_expect_success 'test rev-list date limiting (topo order)' '
+	git-rev-list --topo-order --max-age=$min_date --min-age=$max_date HEAD >list &&
+	test_cmp_sorted list proper_list_date_limited
+'
+
+test_expect_success 'test rev-list date limiting (no order)' '
+	git-rev-list --max-age=$min_date --min-age=$max_date HEAD >list &&
+	test_cmp_sorted list proper_list_date_limited
+'
+
+#check partial cache slice
+test_expect_success 'saving old cache and generating partial slice' '
+	cp ".git/rev-cache/$cache_sha1" .git/rev-cache/.old &&
+	rm ".git/rev-cache/$cache_sha1" .git/rev-cache/index &&
+
+	git-rev-cache add HEAD~2 2>output.err &&
+	grep "final return value: 0" output.err
+'
+
+test_expect_success 'rev-list with wholly interesting partial slice' '
+	git-rev-list --topo-order HEAD >list &&
+	test_cmp list proper_commit_list
+'
+
+test_expect_success 'rev-list with partly uninteresting partial slice' '
+	git-rev-list --topo-order HEAD --not HEAD~3 >list &&
+	test_cmp list proper_commit_list_limited
+'
+
+test_expect_success 'rev-list with wholly uninteresting partial slice' '
+	git-rev-list --topo-order HEAD --not HEAD~2 >list &&
+	test_cmp list proper_commit_list_limited2
+'
+
+#try out index generation and fuse (note that --all == HEAD in this case)
+#probably should make a test for that too...
+test_expect_success 'test (non-)fusion of one slice' '
+	git-rev-cache fuse >output.err &&
+	grep "nothing to fuse" output.err
+'
 
+test_expect_success 'make fresh slice' '
+	git-rev-cache add --all --fresh 2>output.err &&
+	grep "final return value: 0" output.err
+'
+
+test_expect_success 'check dual slices' '
+	git-rev-list --topo-order HEAD~2 HEAD >list &&
+	test_cmp list proper_commit_list
+'
+
+test_expect_success 'regenerate index' '
+	rm .git/rev-cache/index &&
+	git-rev-cache index 2>output.err &&
+	grep "final return value: 0" output.err
+'
+
+test_expect_success 'fuse slices' '
+	test -e .git/rev-cache/.old &&
+	git-rev-cache fuse 2>output.err &&
+	grep "final return value: 0" output.err &&
+	test_cmp .git/rev-cache/$cache_sha1 .git/rev-cache/.old
+'
+
+#make sure we can smoothly handle corrupted caches
+test_expect_success 'corrupt slice' '
+	echo bla >.git/rev-cache/$cache_sha1
+'
+
+test_expect_success 'test rev-list traversal (limited) (corrupt slice)' '
+	git-rev-list --topo-order HEAD --not HEAD~3 >list &&
+	test_cmp list proper_commit_list_limited
+'
+
+test_expect_success 'test rev-list traversal (unlimited) (corrupt slice)' '
+	git-rev-list HEAD >list &&
+	test_cmp_sorted list proper_commit_list
+'
+
+test_expect_success 'corrupt index' '
+	echo blu >.git/rev-cache/index
+'
+
+test_expect_success 'test rev-list traversal (limited) (corrupt index)' '
+	git-rev-list --topo-order HEAD --not HEAD~3 >list &&
+	test_cmp list proper_commit_list_limited
+'
+
+test_expect_success 'test rev-list traversal (unlimited) (corrupt index)' '
+	git-rev-list HEAD >list &&
+	test_cmp_sorted list proper_commit_list
+'
+
+#test --ignore-size in fuse
+rm .git/rev-cache/*
+cache_sha1=`git-rev-cache add HEAD~2 2>output.err`
+
+test_expect_success 'make fragmented slices' '
+	git-rev-cache add HEAD~1 --not HEAD~2 2>>output.err &&
+	git-rev-cache add HEAD --fresh 2>>output.err &&
+	test `grep "final return value: 0" output.err | wc -l` -eq 3
+'
+
+cache_size=`wc -c .git/rev-cache/$cache_sha1 | grep -o "[0-9]*"`
+test_expect_success 'test --ignore-size function in fuse' '
+	git-rev-cache fuse --ignore-size=$cache_size 2>output.err &&
+	grep "final return value: 0" output.err &&
+	test -e .git/rev-cache/$cache_sha1
+'
+
+test_done
-- 
tg: (936d7dc..) t/revcache/integration (depends on: t/revcache/misc)

^ permalink raw reply related

* Re: [PATCH 6/6 (v4)] support for path name caching in rev-cache
From: Johannes Schindelin @ 2009-08-18 11:54 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Nick Edelen, Junio C Hamano, Sam Vilain, Michael J Gruber,
	Jeff King, Shawn O. Pearce, Andreas Ericsson, Christian Couder,
	git@vger.kernel.org
In-Reply-To: <alpine.LFD.2.00.0908172235360.6044@xanadu.home>

Hi,

On Mon, 17 Aug 2009, Nicolas Pitre wrote:

> |$ ls -ld .git/rev-cache/
> |drw-rw-r-- 2 nico nico 4096 2009-08-17 22:47 .git/rev-cache/
> 
> There is no directory execute permission at all.  Indeed, looking at 
> rev-cache.c line 2314, the mode passed to mkdir() is 0x666.  This should 
> rather be 0777.  Which brings the question: how could this ever work for 
> you?  Are you testing your code as root?

No: Nick is on Windows.

Ciao,
Dscho

^ permalink raw reply

* Re: Windows & executable bit
From: Johannes Schindelin @ 2009-08-18 11:55 UTC (permalink / raw)
  To: Thomas Rast; +Cc: Ferry Huberts, msysgit, git
In-Reply-To: <200908181223.48291.trast@student.ethz.ch>


Hi,

On Tue, 18 Aug 2009, Thomas Rast wrote:

> Johannes Schindelin wrote:
> > 
> > git config trust.fileMode false
> 
> Isn't that core.filemode ?

The matching is actually case-insensitive, but I prefer CamelCase here...

Ciao,
Dscho

^ permalink raw reply

* Re: [msysGit] Windows & executable bit
From: Erik Faye-Lund @ 2009-08-18 12:19 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Thomas Rast, Ferry Huberts, msysgit, git
In-Reply-To: <alpine.DEB.1.00.0908181355090.4680@intel-tinevez-2-302>

On Tue, Aug 18, 2009 at 1:55 PM, Johannes
Schindelin<Johannes.Schindelin@gmx.de> wrote:
>> > git config trust.fileMode false
>>
>> Isn't that core.filemode ?
>
> The matching is actually case-insensitive, but I prefer CamelCase here...

I believe the question was about it being in the trust vs the core section...

-- 
Erik "kusma" Faye-Lund
kusmabite@gmail.com
(+47) 986 59 656

^ permalink raw reply

* Re: [PATCH v2] remove ARM and Mozilla SHA1 implementations
From: Nicolas Pitre @ 2009-08-18 12:42 UTC (permalink / raw)
  To: David Aguilar; +Cc: Junio C Hamano, git
In-Reply-To: <20090818054913.GB37966@gmail.com>

On Mon, 17 Aug 2009, David Aguilar wrote:

> 
> On Mon, Aug 17, 2009 at 08:09:56PM -0400, Nicolas Pitre wrote:
> > 
> >  Makefile            |   26 +------
> >
> > -ifneq (,$(findstring arm,$(uname_M)))
> > -	ARM_SHA1 = YesPlease
> > -	NO_MKSTEMPS = YesPlease
> > -endif
> 
> When I added NO_MKSTEMPS I was being conservative when defining
> it on arm (I wasn't able to test that platform).
> Looks like it wasn't needed afterall.

It is a Linux platform after all, which is already taken care of.


Nicolas

^ permalink raw reply

* [RFC PATCH] stash: accept options also when subcommand 'save' is omitted
From: Matthieu Moy @ 2009-08-18 12:46 UTC (permalink / raw)
  To: git; +Cc: Matthieu Moy

This allows in particular 'git stash --keep-index' which is shorter than
'git stash save --keep-index', and not ambiguous.

Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
---
Does this sound right?

I'm so used to 'git stash' (without saying 'save') that I keep typing
'git stash --keep-index', and get a usage string as an error message.

 Documentation/git-stash.txt |    2 +-
 git-stash.sh                |    8 +++++++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 2f5ca7b..6f251e7 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -13,7 +13,7 @@ SYNOPSIS
 'git stash' drop [-q|--quiet] [<stash>]
 'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]
 'git stash' branch <branchname> [<stash>]
-'git stash' [save [--keep-index] [-q|--quiet] [<message>]]
+'git stash' [save] [--keep-index] [-q|--quiet] [<message>]
 'git stash' clear
 'git stash' create
 
diff --git a/git-stash.sh b/git-stash.sh
index 03e589f..2599410 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -7,7 +7,7 @@ USAGE="list [<options>]
    or: $dashless drop [-q|--quiet] [<stash>]
    or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]
    or: $dashless branch <branchname> [<stash>]
-   or: $dashless [save [--keep-index] [-q|--quiet] [<message>]]
+   or: $dashless [save] [--keep-index] [-q|--quiet] [<message>]
    or: $dashless clear"
 
 SUBDIRECTORY_OK=Yes
@@ -302,6 +302,12 @@ apply_to_branch () {
 	drop_stash $stash
 }
 
+case "$1" in
+    -*)
+	set "save" "$@"
+	;;
+esac
+
 # Main command set
 case "$1" in
 list)
-- 
1.6.4.173.g0591

^ permalink raw reply related

* Re: [PATCH] block-sha1: Windows declares ntohl() in winsock2.h
From: Artur Skawina @ 2009-08-18 12:56 UTC (permalink / raw)
  To: Sebastian Schuberth
  Cc: Johannes Sixt, msysGit, Junio C Hamano, Git Mailing List
In-Reply-To: <4A8A8661.5060908@gmail.com>

Sebastian Schuberth wrote:
> As ntohl()/htonl() are function calls (that internally do shifts), I
> doubt they're faster than the shift macros, though I haven't measured
> it. However, I do not suggest to go for the macros on Windows/Intel, but
> to apply the following patch on top of your patch:

> On Windows/Intel, ntohl()/htonl() are function calls that do shifts to
> swap the
> byte order. Using the native bswap instruction boths gets rid of the
> shifts and
> the function call overhead to gain some performance.

Umm, nothing like this should be needed on linux; the compiler/glibc
will choose bswap itself. (see endian.h and bits/byteswap.h).
I did try using __builtin_bswap32 directly and the result was a few
(3 or 4, iirc) differently scheduled instructions, that's all, no
performance difference.

>   * Performance might be improved if the CPU architecture is OK with
> - * unaligned 32-bit loads and a fast ntohl() is available.
> + * unaligned 32-bit loads and a fast ntohl() is available. On Intel,
> + * use the bswap built-in to get rid of the function call overhead.
>   * Otherwise fall back to byte loads and shifts which is portable,
>   * and is faster on architectures with memory alignment issues.
>   */
> 
> -#if defined(__i386__) || defined(__x86_64__) || \
> -    defined(__ppc__) || defined(__ppc64__) || \
> -    defined(__powerpc__) || defined(__powerpc64__) || \
> -    defined(__s390__) || defined(__s390x__)
> +#if defined(__i386__) || defined(__x86_64__)
>
> +#define get_be32(p)    __builtin_bswap32(*(unsigned int *)(p))
> +#define put_be32(p, v)    do { *(unsigned int *)(p) = __builtin_bswap32(v); } while (0)
> +
> +#elif defined(__ppc__) || defined(__ppc64__) || \
> +      defined(__powerpc__) || defined(__powerpc64__) || \
> +      defined(__s390__) || defined(__s390x__)

I'd limit it to windows and any other ia32 platform that doesn't pick the
bswaps itself; as is, it just adds an unnecessary hidden gcc dependency.

Hmm, it's actually a gcc-4.3+ dependency, so it won't even build w/ gcc 4.2;
something like this would be required: "(__GNUC__>=4 && __GNUC_MINOR__>=3)" .

artur

^ permalink raw reply

* [RFC] Enable compilation by Makefile for the MSVC toolchain
From: Marius Storm-Olsen @ 2009-08-18 12:58 UTC (permalink / raw)
  To: Johannes.Schindelin
  Cc: msysgit, git, lznuaa, bonzini, kusmabite, Marius Storm-Olsen
In-Reply-To: <alpine.DEB.1.00.0908172149480.8306@pacific.mpi-cbg.de>

From: Marius Storm-Olsen <mstormo@gmail.com>

By using GNU Make we can also compile with the MSVC toolchain.
This is a rudementary patch, only meant as an RFC for now!!

!! DO NOT COMMIT THIS UPSTREAM !!
---
 So, instead of rely on these vcproj files which *will* go stale, we can
 simply use the same Makefile system which everyone else is using. :)
 After all, we're just compiling with a different compiler. The end result
 will still rely on the *msysGit environment* to function, so we already
 require it. Thus, GNU Make is present, and we can use it.

 This implementation is a quick hack to make it compile (hence the RFC
 subject), so please don't even consider basing anything ontop of it ;)

 But, do point out all the do's and don'ts, and I'll try to polish it up
 to something which we can add to Frank's series..
 

 Makefile      |   97 +++++++++++++++++++++++++++++++++++++++++++++++---------
 compat/msvc.h |   77 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 158 insertions(+), 16 deletions(-)

diff --git a/Makefile b/Makefile
index daf4296..2e14976 100644
--- a/Makefile
+++ b/Makefile
@@ -214,9 +214,13 @@ uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
 
 CFLAGS = -g -O2 -Wall
 LDFLAGS =
+ARFLAGS = rcs\ # whitespace intentional
 ALL_CFLAGS = $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)
 STRIP ?= strip
+COMPFLAG = -c
+COBJFLAG = -o\ # whitespace intended
+LOBJFLAG = -o\ # whitespace intended
 
 # Among the variables below, these:
 #   gitexecdir
@@ -874,6 +878,58 @@ ifneq (,$(findstring CYGWIN,$(uname_S)))
 	COMPAT_OBJS += compat/cygwin.o
 	UNRELIABLE_FSTAT = UnfortunatelyYes
 endif
+ifneq (,$(findstring Microsoft Visual Studio, $(INCLUDE)))
+	pathsep = ;
+	MOZILLA_SHA1 = 1
+	NO_PREAD = YesPlease
+	NO_OPENSSL = YesPlease
+	NO_LIBGEN_H = YesPlease
+	NO_SYMLINK_HEAD = YesPlease
+	NO_IPV6 = YesPlease
+	NO_SETENV = YesPlease
+	NO_UNSETENV = YesPlease
+	NO_STRCASESTR = YesPlease
+	NO_STRLCPY = YesPlease
+	NO_MEMMEM = YesPlease
+	NEEDS_LIBICONV = YesPlease
+	OLD_ICONV = YesPlease
+	NO_C99_FORMAT = YesPlease
+	NO_STRTOUMAX = YesPlease
+	NO_MKDTEMP = YesPlease
+	NO_MKSTEMPS = YesPlease
+	SNPRINTF_RETURNS_BOGUS = YesPlease
+	NO_SVN_TESTS = YesPlease
+	NO_PERL_MAKEMAKER = YesPlease
+	RUNTIME_PREFIX = YesPlease
+	NO_POSIX_ONLY_PROGRAMS = YesPlease
+	NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
+	NO_NSEC = YesPlease
+	USE_WIN32_MMAP = YesPlease
+	UNRELIABLE_FSTAT = UnfortunatelyYes
+	OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
+	NO_REGEX = YesPlease
+
+	NO_CURL = YesPlease
+	NO_PTHREADS = YesPlease
+        
+	CC = cl 
+	COBJFLAG = -Fo
+	LOBJFLAG = -OUT:
+	CFLAGS =
+	BASIC_CFLAGS += -nologo -MT -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE
+	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch
+	COMPAT_OBJS += compat/mingw.o compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o
+	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
+
+	LINK = link
+	BASIC_LDFLAGS += -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib ../zlib/projects/vc9/Win32_LIB_Release/zlib.lib
+	NO_CFLAGS_TO_LINKER = YesPlease
+	EXTLIBS = 
+	AR = lib
+	ARFLAGS = -OUT:
+
+	X = .exe
+else
 ifneq (,$(findstring MINGW,$(uname_S)))
 	pathsep = ;
 	NO_PREAD = YesPlease
@@ -922,6 +978,7 @@ else
 	NO_PTHREADS = YesPlease
 endif
 endif
+endif
 ifneq (,$(findstring arm,$(uname_M)))
 	ARM_SHA1 = YesPlease
 	NO_MKSTEMPS = YesPlease
@@ -1298,6 +1355,14 @@ LIB_OBJS += $(COMPAT_OBJS)
 ALL_CFLAGS += $(BASIC_CFLAGS)
 ALL_LDFLAGS += $(BASIC_LDFLAGS)
 
+ifndef LINK
+LINK = $(CC)
+endif
+
+ifndef NO_CFLAGS_TO_LINKER
+LINKER_CFLAGS += $(ALL_CFLAGS)
+endif
+
 export TAR INSTALL DESTDIR SHELL_PATH
 
 
@@ -1331,14 +1396,14 @@ strip: $(PROGRAMS) git$X
 git.o: git.c common-cmds.h GIT-CFLAGS
 	$(QUIET_CC)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
 		'-DGIT_HTML_PATH="$(htmldir_SQ)"' \
-		$(ALL_CFLAGS) -c $(filter %.c,$^)
+		$(ALL_CFLAGS) $(COMPFLAG) $(COBJFLAG)git.o $(filter %.c,$^)
 
 git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
-	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
+	$(QUIET_LINK)$(LINK) $(LINKER_CFLAGS) $(LOBJFLAG)$@ git.o \
 		$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
 
 builtin-help.o: builtin-help.c common-cmds.h GIT-CFLAGS
-	$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
+	$(QUIET_CC)$(CC) $(COBJFLAG)$*.o $(COMPFLAG) $(ALL_CFLAGS) \
 		'-DGIT_HTML_PATH="$(htmldir_SQ)"' \
 		'-DGIT_MAN_PATH="$(mandir_SQ)"' \
 		'-DGIT_INFO_PATH="$(infodir_SQ)"' $<
@@ -1450,44 +1515,44 @@ git.o git.spec \
 	: GIT-VERSION-FILE
 
 %.o: %.c GIT-CFLAGS
-	$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
+	$(QUIET_CC)$(CC) $(COBJFLAG)$*.o $(COMPFLAG) $(ALL_CFLAGS) $<
 %.s: %.c GIT-CFLAGS
 	$(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
 %.o: %.S
-	$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
+	$(QUIET_CC)$(CC) $(COBJFLAG)$*.o $(COMPFLAG) $(ALL_CFLAGS) $<
 
 exec_cmd.o: exec_cmd.c GIT-CFLAGS
-	$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
+	$(QUIET_CC)$(CC) $(COBJFLAG)$*.o $(COMPFLAG) $(ALL_CFLAGS) \
 		'-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
 		'-DBINDIR="$(bindir_relative_SQ)"' \
 		'-DPREFIX="$(prefix_SQ)"' \
 		$<
 
 builtin-init-db.o: builtin-init-db.c GIT-CFLAGS
-	$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
+	$(QUIET_CC)$(CC) $(COBJFLAG)$*.o $(COMPFLAG) $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
 
 config.o: config.c GIT-CFLAGS
-	$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $<
+	$(QUIET_CC)$(CC) $(COBJFLAG)$*.o $(COMPFLAG) $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $<
 
 http.o: http.c GIT-CFLAGS
-	$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $<
+	$(QUIET_CC)$(CC) $(COBJFLAG)$*.o $(COMPFLAG) $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $<
 
 ifdef NO_EXPAT
 http-walker.o: http-walker.c http.h GIT-CFLAGS
-	$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DNO_EXPAT $<
+	$(QUIET_CC)$(CC) $(COBJFLAG)$*.o $(COMPFLAG) $(ALL_CFLAGS) -DNO_EXPAT $<
 endif
 
 git-%$X: %.o $(GITLIBS)
-	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+	$(QUIET_LINK)$(LINK) $(LINKER_CFLAGS) $(LOBJFLAG)$@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
 git-imap-send$X: imap-send.o $(GITLIBS)
-	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
+	$(QUIET_LINK)$(LINK) $(LINKER_CFLAGS) $(LOBJFLAG)$@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
 
 http.o http-walker.o http-push.o transport.o: http.h
 
 git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
-	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
+	$(QUIET_LINK)$(LINK) $(LINKER_CFLAGS) $(LOBJFLAG)$@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
 
 $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
@@ -1495,7 +1560,7 @@ $(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h)
 builtin-revert.o wt-status.o: wt-status.h
 
 $(LIB_FILE): $(LIB_OBJS)
-	$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
+	$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS)$@ $(LIB_OBJS)
 
 XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
 	xdiff/xmerge.o xdiff/xpatience.o
@@ -1503,7 +1568,7 @@ $(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
 	xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
 
 $(XDIFF_LIB): $(XDIFF_OBJS)
-	$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(XDIFF_OBJS)
+	$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS)$@ $(XDIFF_OBJS)
 
 
 doc:
@@ -1605,7 +1670,7 @@ test-parse-options.o: parse-options.h
 .PRECIOUS: $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
 
 test-%$X: test-%.o $(GITLIBS)
-	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+	$(QUIET_LINK)$(LINK) $(LINKER_CFLAGS) $(LOBJFLAG)$@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
 check-sha1:: test-sha1$X
 	./test-sha1.sh
diff --git a/compat/msvc.h b/compat/msvc.h
index 6071565..a9d5f7f 100644
--- a/compat/msvc.h
+++ b/compat/msvc.h
@@ -10,50 +10,120 @@
 
 /*Configuration*/
 
+#ifndef NO_PREAD
 #define NO_PREAD
+#endif
+#ifndef NO_OPENSSL
 #define NO_OPENSSL
+#endif
+#ifndef NO_LIBGEN_H
 #define NO_LIBGEN_H
+#endif
+#ifndef NO_SYMLINK_HEAD
 #define NO_SYMLINK_HEAD
+#endif
+#ifndef NO_IPV6
 #define NO_IPV6
+#endif
+#ifndef NO_SETENV
 #define NO_SETENV
+#endif
+#ifndef NO_UNSETENV
 #define NO_UNSETENV
+#endif
+#ifndef NO_STRCASESTR
 #define NO_STRCASESTR
+#endif
+#ifndef NO_STRLCPY
 #define NO_STRLCPY
+#endif
+#ifndef NO_MEMMEM
 #define NO_MEMMEM
+#endif
+#ifndef NO_C99_FORMAT
 #define NO_C99_FORMAT
+#endif
+#ifndef NO_STRTOUMAX
 #define NO_STRTOUMAX
+#endif
+#ifndef NO_MKDTEMP
 #define NO_MKDTEMP
+#endif
+#ifndef NO_MKSTEMPS
 #define NO_MKSTEMPS
+#endif
 
+
+#ifndef RUNTIME_PREFIX
 #define RUNTIME_PREFIX
+#endif
+#ifndef NO_ST_BLOCKS_IN_STRUCT_STAT
 #define NO_ST_BLOCKS_IN_STRUCT_STAT
+#endif
+#ifndef NO_NSEC
 #define NO_NSEC
+#endif
+#ifndef USE_WIN32_MMAP
 #define USE_WIN32_MMAP
+#endif
+#ifndef USE_NED_ALLOCATOR
 #define USE_NED_ALLOCATOR
+#endif
+
 
+#ifndef NO_REGEX
 #define NO_REGEX
+#endif
 
+
+#ifndef NO_SYS_SELECT_H
 #define NO_SYS_SELECT_H
+#endif
+#ifndef NO_PTHEADS
 #define NO_PTHEADS
+#endif
+#ifndef HAVE_STRING_H
 #define HAVE_STRING_H 1
+#endif
+#ifndef STDC_HEADERS
 #define STDC_HEADERS
+#endif
+#ifndef NO_ICONV
 #define NO_ICONV
+#endif
+
 
 #define inline __inline
 #define __inline__ __inline
 
+#ifndef SNPRINTF_RETURNS_BOGUS
 #define SNPRINTF_RETURNS_BOGUS
+#endif
 
+
+#ifndef SHA1_HEADER
 #define SHA1_HEADER "mozilla-sha1\\sha1.h"
+#endif
 
+#ifndef ETC_GITCONFIG
 #define ETC_GITCONFIG "%HOME%"
+#endif
+
 
+#ifndef NO_PTHREADS
 #define NO_PTHREADS
+#endif
+#ifndef NO_CURL
 #define NO_CURL
+#endif
 
 
+#ifndef NO_STRTOUMAX
 #define NO_STRTOUMAX
+#endif
+#ifndef REGEX_MALLOC
 #define REGEX_MALLOC
+#endif
 
 
 #define GIT_EXEC_PATH "bin"
@@ -65,9 +135,16 @@
 #define GIT_HTML_PATH "html"
 #define DEFAULT_GIT_TEMPLATE_DIR "templates"
 
+#ifndef NO_STRLCPY
 #define NO_STRLCPY
+#endif
+#ifndef NO_UNSETENV
 #define NO_UNSETENV
+#endif
+#ifndef NO_SETENV
 #define NO_SETENV
+#endif
+
 
 #define strdup _strdup
 #define read _read
-- 
1.6

^ permalink raw reply related

* Re: [msysGit] Windows & executable bit
From: Johannes Schindelin @ 2009-08-18 12:59 UTC (permalink / raw)
  To: Ferry Huberts; +Cc: Thomas Rast, msysgit, git
In-Reply-To: <4262.77.61.241.211.1250594232.squirrel@hupie.xs4all.nl>

Hi,

On Tue, 18 Aug 2009, Ferry Huberts wrote:

> > Isn't that core.filemode ?
> 
> yep. works
> 
> however, the man page says that you'll have to configure it in this way 
> when you're on a broken filesystem like FAT. We're on NTFS however.... 
> NTFS is also broken then?

It is more a question of the ACLs not being properly mappable to POSIX 
permissions.  So we cannot trust the file mode.

Ciao,
Dscho

^ permalink raw reply

* Re: Windows & executable bit
From: Johannes Schindelin @ 2009-08-18 12:59 UTC (permalink / raw)
  To: Erik Faye-Lund; +Cc: Thomas Rast, Ferry Huberts, msysgit, git
In-Reply-To: <40aa078e0908180519u41b28ce7oc851791db1d5f773@mail.gmail.com>


Hi,

On Tue, 18 Aug 2009, Erik Faye-Lund wrote:

> On Tue, Aug 18, 2009 at 1:55 PM, Johannes
> Schindelin<Johannes.Schindelin@gmx.de> wrote:
> >> > git config trust.fileMode false
> >>
> >> Isn't that core.filemode ?
> >
> > The matching is actually case-insensitive, but I prefer CamelCase here...
> 
> I believe the question was about it being in the trust vs the core 
> section...

Bah, you're right.  I let myself fool by the lowercase 'm'.  Sorry.

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH 09/11] Add MSVC porting header files.
From: Johannes Schindelin @ 2009-08-18 13:01 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Frank Li, git, msysgit
In-Reply-To: <7v4os5jtd9.fsf@alter.siamese.dyndns.org>


Hi,

On Tue, 18 Aug 2009, Junio C Hamano wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > As I said earlier, there are common flags, but as I also said, it is 
> > probably better to keep the #define's in a header file for better 
> > visibility and editability, albeit in logically clustered blocks (i.e. 
> > all the NO_* and other #define's that affect what source code is 
> > compiled, all default paths in another cluster, #define's to bow 
> > before Microsoft's C runtime's decision to deprecate the C99 standard 
> > function names, etc)
> 
> ... and that can live in a separate header file to reduce clutter and 
> shield people who do not need to look at MSC related code, no?

Maybe we could call it compat/msvc.h? ;-)

Ciao,
Dscho

^ permalink raw reply

* Re: [RFC] Enable compilation by Makefile for the MSVC toolchain
From: Marius Storm-Olsen @ 2009-08-18 13:01 UTC (permalink / raw)
  To: Johannes.Schindelin; +Cc: msysgit, git, lznuaa, bonzini, kusmabite
In-Reply-To: <1250600335-8642-1-git-send-email-mstormo@gmail.com>

Marius Storm-Olsen said the following on 18.08.2009 14:58:
> This is a rudementary patch, only meant as an RFC for now!!
> 
> !! DO NOT COMMIT THIS UPSTREAM !!

..meaning in this case Frank Li's repo, and obviously not git.git. :p

--
.marius

^ permalink raw reply

* Re: [RFC PATCH] stash: accept options also when subcommand 'save' is omitted
From: Matthieu Moy @ 2009-08-18 13:01 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin
In-Reply-To: <1250599567-31428-1-git-send-email-Matthieu.Moy@imag.fr>

Matthieu Moy <Matthieu.Moy@imag.fr> writes:

> This allows in particular 'git stash --keep-index' which is shorter than
> 'git stash save --keep-index', and not ambiguous.

Hmm, googling a bit, I just noticed that there's already something in
pu:
ea41cfc4f (Make 'git stash -k' a short form for 'git stash save --keep-index')
which also does the trick, while adding a -k alias for --keep-index.

Not sure which hack is best between my

> +case "$1" in
> +    -*)
> +	set "save" "$@"
> +	;;
> +esac
> +

And the proposed

 *)
-	if test $# -eq 0
-	then
-		save_stash &&
+	case $#,"$1" in
+	0,|1,-k|1,--keep-index)
+		save_stash "$@" &&
 		say '(To restore them type "git stash apply")'
-	else
+		;;
+	*)
 		usage
-	fi
+	esac
 	;;
 esac

Mine has at least two advantages:

* It won't require changing the code again when new options are added
  to 'git stash save'.

* It works with 'git stash -k -q' for example, while the other
  proposal checks that $# == 1, which won't work if there are more
  than one option.

But I may have missed its drawbacks ;-)

--
Matthieu

^ permalink raw reply

* Re: [RFC] Enable compilation by Makefile for the MSVC toolchain
From: Erik Faye-Lund @ 2009-08-18 13:09 UTC (permalink / raw)
  To: Marius Storm-Olsen; +Cc: Johannes.Schindelin, msysgit, git, lznuaa, bonzini
In-Reply-To: <1250600335-8642-1-git-send-email-mstormo@gmail.com>

On Tue, Aug 18, 2009 at 2:58 PM, Marius Storm-Olsen<mstormo@gmail.com> wrote:
> @@ -1331,14 +1396,14 @@ strip: $(PROGRAMS) git$X
>  git.o: git.c common-cmds.h GIT-CFLAGS
>        $(QUIET_CC)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
>                '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
> -               $(ALL_CFLAGS) -c $(filter %.c,$^)
> +               $(ALL_CFLAGS) $(COMPFLAG) $(COBJFLAG)git.o $(filter %.c,$^)
>
>  git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
> -       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
> +       $(QUIET_LINK)$(LINK) $(LINKER_CFLAGS) $(LOBJFLAG)$@ git.o \
>                $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
<snip>
>  ifdef NO_EXPAT
>  http-walker.o: http-walker.c http.h GIT-CFLAGS
> -       $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DNO_EXPAT $<
> +       $(QUIET_CC)$(CC) $(COBJFLAG)$*.o $(COMPFLAG) $(ALL_CFLAGS) -DNO_EXPAT $<
>  endif

Perhaps this is the right time to change the make-system to using the
somewhat standard $(COMPLIE.c), $(OUTPUT_OPTION) etc macros?

-- 
Erik "kusma" Faye-Lund
kusmabite@gmail.com
(+47) 986 59 656

^ permalink raw reply

* Re: [PATCH] block-sha1: Windows declares ntohl() in winsock2.h
From: Sebastian Schuberth @ 2009-08-18 13:17 UTC (permalink / raw)
  To: Artur Skawina; +Cc: Johannes Sixt, msysGit, Junio C Hamano, Git Mailing List
In-Reply-To: <4A8AA511.1060205@gmail.com>

On Tue, Aug 18, 2009 at 14:56, Artur Skawina<art.08.09@gmail.com> wrote:

> I did try using __builtin_bswap32 directly and the result was a few
> (3 or 4, iirc) differently scheduled instructions, that's all, no
> performance difference.

[...]

> I'd limit it to windows and any other ia32 platform that doesn't pick the
> bswaps itself; as is, it just adds an unnecessary hidden gcc dependency.
>
> Hmm, it's actually a gcc-4.3+ dependency, so it won't even build w/ gcc 4.2;
> something like this would be required: "(__GNUC__>=4 && __GNUC_MINOR__>=3)" .

So, as you say the code makes no difference under Linux, would you be
OK with just testing for GCC 4.3+, and not for Windows? That would get
rid of the "hidden" GCC dependency and not make the preprocessor
checks overly complex. Moreover, limiting my patch to any "platform
that doesn't pick the bswaps itself" could possibly require
maintenance on compiler / CRT updates.

-- 
Sebastian Schuberth

^ permalink raw reply

* Re: [PATCH] block-sha1: Windows declares ntohl() in winsock2.h
From: Junio C Hamano @ 2009-08-18 13:39 UTC (permalink / raw)
  To: Sebastian Schuberth
  Cc: Artur Skawina, Johannes Sixt, msysGit, Junio C Hamano,
	Linus Torvalds, Nicolas Pitre, Git Mailing List
In-Reply-To: <bdca99240908180617n75dfd0b5nfe069aba6e74b722@mail.gmail.com>

Sebastian Schuberth <sschuberth@gmail.com> writes:

> On Tue, Aug 18, 2009 at 14:56, Artur Skawina<art.08.09@gmail.com> wrote:
> ...
>> I'd limit it to windows and any other ia32 platform that doesn't pick the
>> bswaps itself; as is, it just adds an unnecessary hidden gcc dependency.
>>
>> Hmm, it's actually a gcc-4.3+ dependency, so it won't even build w/ gcc 4.2;
>> something like this would be required: "(__GNUC__>=4 && __GNUC_MINOR__>=3)" .
>
> So, as you say the code makes no difference under Linux, would you be
> OK with just testing for GCC 4.3+, and not for Windows? That would get
> rid of the "hidden" GCC dependency and not make the preprocessor
> checks overly complex. Moreover, limiting my patch to any "platform
> that doesn't pick the bswaps itself" could possibly require
> maintenance on compiler / CRT updates.

I would say that should be fine, but I'd let Linus and Nico to overrule me
on this if they have any input.

^ permalink raw reply

* Re: [RFC] Enable compilation by Makefile for the MSVC toolchain
From: Johannes Schindelin @ 2009-08-18 14:11 UTC (permalink / raw)
  To: Marius Storm-Olsen; +Cc: msysgit, git, lznuaa, bonzini, kusmabite
In-Reply-To: <1250600335-8642-1-git-send-email-mstormo@gmail.com>

Hi,

On Tue, 18 Aug 2009, Marius Storm-Olsen wrote:

>  So, instead of rely on these vcproj files which *will* go stale, we can 
>  simply use the same Makefile system which everyone else is using. :) 
>  After all, we're just compiling with a different compiler. The end 
>  result will still rely on the *msysGit environment* to function, so we 
>  already require it. Thus, GNU Make is present, and we can use it.

We can also use sed or perl to generate/modify the .vcproj files, or run 
CMake (once Pau got it to build), and package the stuff using zip (once I 
got that to build).

> diff --git a/Makefile b/Makefile
> index daf4296..2e14976 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -214,9 +214,13 @@ uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
>  
>  CFLAGS = -g -O2 -Wall
>  LDFLAGS =
> +ARFLAGS = rcs\ # whitespace intentional
>  ALL_CFLAGS = $(CFLAGS)
>  ALL_LDFLAGS = $(LDFLAGS)
>  STRIP ?= strip
> +COMPFLAG = -c
> +COBJFLAG = -o\ # whitespace intended
> +LOBJFLAG = -o\ # whitespace intended

These probably want to go into the Microsoft Visual C++ specific section.

> @@ -874,6 +878,58 @@ ifneq (,$(findstring CYGWIN,$(uname_S)))
>  	COMPAT_OBJS += compat/cygwin.o
>  	UNRELIABLE_FSTAT = UnfortunatelyYes
>  endif
> +ifneq (,$(findstring Microsoft Visual Studio, $(INCLUDE)))
> +	pathsep = ;
> +	MOZILLA_SHA1 = 1
> +	NO_PREAD = YesPlease
> +	NO_OPENSSL = YesPlease
> +	NO_LIBGEN_H = YesPlease
> +	NO_SYMLINK_HEAD = YesPlease
> +	NO_IPV6 = YesPlease
> +	NO_SETENV = YesPlease
> +	NO_UNSETENV = YesPlease
> +	NO_STRCASESTR = YesPlease
> +	NO_STRLCPY = YesPlease
> +	NO_MEMMEM = YesPlease
> +	NEEDS_LIBICONV = YesPlease
> +	OLD_ICONV = YesPlease
> +	NO_C99_FORMAT = YesPlease
> +	NO_STRTOUMAX = YesPlease
> +	NO_MKDTEMP = YesPlease
> +	NO_MKSTEMPS = YesPlease
> +	SNPRINTF_RETURNS_BOGUS = YesPlease
> +	NO_SVN_TESTS = YesPlease
> +	NO_PERL_MAKEMAKER = YesPlease
> +	RUNTIME_PREFIX = YesPlease
> +	NO_POSIX_ONLY_PROGRAMS = YesPlease
> +	NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
> +	NO_NSEC = YesPlease
> +	USE_WIN32_MMAP = YesPlease
> +	UNRELIABLE_FSTAT = UnfortunatelyYes
> +	OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
> +	NO_REGEX = YesPlease
> +
> +	NO_CURL = YesPlease
> +	NO_PTHREADS = YesPlease
> +        
> +	CC = cl 
> +	COBJFLAG = -Fo
> +	LOBJFLAG = -OUT:
> +	CFLAGS =
> +	BASIC_CFLAGS += -nologo -MT -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE
> +	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch
> +	COMPAT_OBJS += compat/mingw.o compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o
> +	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
> +
> +	LINK = link
> +	BASIC_LDFLAGS += -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib ../zlib/projects/vc9/Win32_LIB_Release/zlib.lib
> +	NO_CFLAGS_TO_LINKER = YesPlease
> +	EXTLIBS = 
> +	AR = lib
> +	ARFLAGS = -OUT:
> +
> +	X = .exe
> +else
>  ifneq (,$(findstring MINGW,$(uname_S)))
>  	pathsep = ;
>  	NO_PREAD = YesPlease

This means that gcc is never used when Visual C++ is available?  Hmm.

> diff --git a/compat/msvc.h b/compat/msvc.h
> index 6071565..a9d5f7f 100644
> --- a/compat/msvc.h
> +++ b/compat/msvc.h
> @@ -10,50 +10,120 @@
>  
>  /*Configuration*/
>  
> +#ifndef NO_PREAD
>  #define NO_PREAD
> +#endif

Why?  You now have the stuff in two places.  If you want to keep them in 
compat/msvc.h to be able to generate .vcproj files, I'd rather not have 
them duplicated in the Makefile.

Ciao,
Dscho

^ permalink raw reply

* Re: git find (was: [RFC PATCH v3 8/8] --sparse for porcelains)
From: Nguyen Thai Ngoc Duy @ 2009-08-18 14:35 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: skillzero, Johannes Schindelin, Junio C Hamano, git
In-Reply-To: <200908180825.55289.jnareb@gmail.com>

On Tue, Aug 18, 2009 at 1:25 PM, Jakub Narebski<jnareb@gmail.com> wrote:
> Well, I also think that it would be nice and useful to have "git find"
> in addition to current "git grep".

Can you make a draft on how you want "git find" to be? Except the
"-exec" part, Git allows us to search using various commands
(ls-files, rev-list, log). I don't think a single "git find" can cover
them all. I was thinking about putting more find-options to search
commands we already have. ls-files would support -exec, for example.

A few things that I'd love to have supported:
 - --depth for ls-files (probably all pathspec-as-argument commands)
 - logical combination of search criteria
 - unified blob locator. git-show understands SHA-1:/path/to/blob
syntax. What if git-log can output using similar syntax, then feed
them to git-grep in order to grep through (across commits)?
-- 
Duy

^ permalink raw reply

* Re: [PATCH 01/11] Fix build failure at VC because function declare  use old style at regex.c
From: Frank Li @ 2009-08-18 15:03 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, kusmabite, msysgit
In-Reply-To: <alpine.DEB.1.00.0908171822130.4991@intel-tinevez-2-302>

 - there are a lot more functions with K&R style function definitions than
>  just regerror().
>

I double check it. VC can compile K&R style function. This patch is redundancy

^ permalink raw reply

* Re: [PATCH] block-sha1: Windows declares ntohl() in winsock2.h
From: Linus Torvalds @ 2009-08-18 15:40 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Sebastian Schuberth, Artur Skawina, Johannes Sixt, msysGit,
	Nicolas Pitre, Git Mailing List
In-Reply-To: <7v4os5gs0p.fsf@alter.siamese.dyndns.org>



On Tue, 18 Aug 2009, Junio C Hamano wrote:

> Sebastian Schuberth <sschuberth@gmail.com> writes:
> 
> > On Tue, Aug 18, 2009 at 14:56, Artur Skawina<art.08.09@gmail.com> wrote:
> > ...
> >> I'd limit it to windows and any other ia32 platform that doesn't pick the
> >> bswaps itself; as is, it just adds an unnecessary hidden gcc dependency.
> >>
> >> Hmm, it's actually a gcc-4.3+ dependency, so it won't even build w/ gcc 4.2;
> >> something like this would be required: "(__GNUC__>=4 && __GNUC_MINOR__>=3)" .
> >
> > So, as you say the code makes no difference under Linux, would you be
> > OK with just testing for GCC 4.3+, and not for Windows? That would get
> > rid of the "hidden" GCC dependency and not make the preprocessor
> > checks overly complex. Moreover, limiting my patch to any "platform
> > that doesn't pick the bswaps itself" could possibly require
> > maintenance on compiler / CRT updates.
> 
> I would say that should be fine, but I'd let Linus and Nico to overrule me
> on this if they have any input.

I'd suggest not using a gcc builtin, since if you're using gcc you might 
as well just use inline asm that has been around forever (unlike the 
builtin).

Just do:

	#if defined(__GNUC__)
	#define htonl(x) ({ unsigned int __res; \
		__asm__("bswap %0":"=r" (__res):"0" (x)); \
		__res; })
	#define ntohl(x) htonl(x)
	#endif

or similar in the x86 section that does the rol/ror thing.

			Linus

^ permalink raw reply

* Re: Git User's Survey 2009 partial summary, part 2 - from first 10
From: Nicolas Sebrecht @ 2009-08-18 15:54 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git
In-Reply-To: <200908171224.44686.jnareb@gmail.com>

The 17/08/09, Jakub Narebski wrote:

> Git User's Survey 2009 partial summary, part 2 - git difficulty,
> proficiency, uses, install, OS, editors.

Thanks for these partial summaries.

> 3) Have you found Git easy to learn?
> 4) Have you found Git easy to use?
>    (Choice - Single answer)
> 
> ================================================
> Answer            | to learn [%] |   to use [%]
> ------------------------------------------------
> Very easy         |          4%  |          9%
> Easy              |         20%  |         36%
> Reasonably easy   |         55%  |         45%
> Hard              |         19%  |          8%
> Very hard         |          2%  |          1%
> ------------------------------------------------
> Total respondents |        2942  |        2959
> ================================================

<...>

> What's interesting is comparing (percentage) results for questions
> 3. and 4.; how hard is git to learn versus how hard is to use.  It
> seems like Git is reasonably easy to learn, and reasonably easy to
> easy to use.  So it looks like Git just have somewhat steep learning
> curve, and the difficulty to learn pays in being more powerful to
> use.

I believe it would be interesting to know who (from the question 6.)
think what later. We may expect that people of the grade 4 and 5 ("can
offer advice" and "know it very well") underestimate the difficulty to
learn Git.

Also (and as you said), this "Git's users" survey won't have answers
from unsatisfied users who left Git. We can't rate the number of users
who left Git because they found it too much hard to learn.

> 6) Rate your own proficiency with Git:
>    (Choice - Single answer)
> 
> You can think of it as 1-5 numerical grade of your proficiency in Git.
> 
> ================================================
> Proficiency               | resp [%] | resp [n]
> ------------------------------------------------
> 1. novice                 |       4% |      114
> 2. casual, needs advice   |      17% |      520
> 3. everyday use           |      38% |     1138
> 4. can offer advice       |      34% |     1020
> 5. know it very well      |       6% |      192
> --------------------------+---------------------
> Total respondents         |                2984
> Skipped this question     |                 105
> ================================================

-- 
Nicolas Sebrecht

^ permalink raw reply

* Re: git find (was: [RFC PATCH v3 8/8] --sparse for porcelains)
From: Jakub Narebski @ 2009-08-18 16:00 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: skillzero, Johannes Schindelin, Junio C Hamano, git
In-Reply-To: <fcaeb9bf0908180735s583bfdcajc354723c9faa48@mail.gmail.com>

On Tue, Aug 18, 2009, Nguyen Thai Ngoc Duy wrote:
> On Tue, Aug 18, 2009 at 1:25 PM, Jakub Narebski<jnareb@gmail.com> wrote:
> >
> > Well, I also think that it would be nice and useful to have "git find"
> > in addition to current "git grep".
> 
> Can you make a draft on how you want "git find" to be? Except the
> "-exec" part, Git allows us to search using various commands
> (ls-files, rev-list, log). I don't think a single "git find" can cover
> them all. I was thinking about putting more find-options to search
> commands we already have. ls-files would support -exec, for example.

Both git-rev-list and git-ls-files are plumbing, not porcelain.  Among
tools / commands you have mentioned only git-log is porcelain.

You need to process output of git-ls-files if you want to use more
complicated search criteria. 

> 
> A few things that I'd love to have supported:
>  - --depth for ls-files (probably all pathspec-as-argument commands)
>  - logical combination of search criteria
>  - unified blob locator. git-show understands SHA-1:/path/to/blob
> syntax. What if git-log can output using similar syntax, then feed
> them to git-grep in order to grep through (across commits)?

Draft specification for git-find.  git-find, like git-grep, searches
the filesystem dimension, and not time dimension like git-log.

git-find(1)
===========

NAME
----
git-find - Search for files in a repository

SYNOPSIS
--------
'git find' [--cached] [-z|--null] [(<tree> | <path>)...] [<expression>]

OPTIONS
-------
--cached::
        Instead of searching in the working tree files, check
        the blobs registered in the index file.

EXPRESSIONS
-----------
The expression is made up of options (which affect overall operation rather
than the processing of a specific file, and always return true), tests
(which return a true or false value), and actions (which have side effects
and return a true or false value), all separated by operators. `--and`  is
assumed where the operator is omitted.  If the expression contains no
actions other than `--prune`, `--print` is performed on all files for which
the expression is true.

OPTIONS
~~~~~~~
--max-depth <levels>::
        Descend  at  most levels (a non-negative integer) levels of 
        directories below the command line arguments.   `--max-depth 0`
        means only apply the tests and actions to the command line 
        arguments.

--min-depth <levels>::
        Do not apply any tests or actions at levels less than levels 
        (a non-negative integer).  `--min-depth 1` means process all
        files except the  command line arguments.

TESTS
~~~~~
--false::
        Always false.

--true::
        Always true.

--name <pattern>::
--iname <pattern>::
--path <pattern>::
--ipath <pattern>::
        [Entire] Filename matches glob.

--regex <expr>::
--iregex <expr>::
        Entire file name matches regular expression.

--lname <pattern>::
--ilname <pattern>::
        True if the file is a symbolic link whose contents match glob.

--size <n>[<unit>]::
        True if the file uses N units of space, rounding up.

--empty::
        File is empty and is either a regular file or a directory.

--type <C>::
        True if file is of type C: 'd' for directory, 'f' for regular
        file, 'l' for symbolic link, 's' for submodule, 'x' for 
        executable regular file (replaces `-perm` from 'find').

ACTIONS
~~~~~~~
(--exec | --ok) <command> ;
        Execute command; true if 0 status is returned.

(--execdir | --okdir) <command> ;
        Like `--exec`, but the specified command is run from the 
        subdirectory containing the matched file.

--print::
--print0::
--printf <format>::
--fprint <file>::
--fprint0 <file>::
--fprintf <file> <format>::
        True; print the full file name.

--prune::
        True; if the file is a directory, do not descend into it.

--quit::
        Exit immediately.


OPERATORS
~~~~~~~~~
--and::
--or::
--not::
( ... )::
        Specify how multiple expressions are combined using Boolean
        expressions.  `--and` is the default operator.

-- 
Jakub Narebski
Poland

^ permalink raw reply

* Simple commit mechanism for non-technical users
From: D Sundstrom @ 2009-08-18 16:05 UTC (permalink / raw)
  To: git

I use git to manage all project artifacts, including documentation,
proposals, presentations, and so on.

However, I have a hard time convincing non-technical staff to learn
enough about git or to take the time to go through the effort of
committing changes to a repository.  So the steady stream of email
attachments with "Acme Specification v3" or "final final spemco
proprosal" continues.

I'd hoped there was a simple web interface that would allow a user to
upload and commit a file to a repository, but I've had no luck finding
one.  (I've used cgit for browsing, but it is read-only).

Is anyone aware of a simple way I can have my non-technical users
manage their documents against a git repository?  Ideally this would
involve no installation of software on their machine (unless it were
compelling, for example, the Finder plugin for SVN on the mac was a
great tool for these users; or at least those on a mac...)

-David

^ permalink raw reply

* Re: [PATCH] block-sha1: Windows declares ntohl() in winsock2.h
From: Linus Torvalds @ 2009-08-18 16:08 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Sebastian Schuberth, Artur Skawina, Johannes Sixt, msysGit,
	Nicolas Pitre, Git Mailing List
In-Reply-To: <alpine.LFD.2.01.0908180836440.3162@localhost.localdomain>



On Tue, 18 Aug 2009, Linus Torvalds wrote:
> 
> I'd suggest not using a gcc builtin, since if you're using gcc you might 
> as well just use inline asm that has been around forever (unlike the 
> builtin).

That seems to be what glibc does too.

Here's a patch.

		Linus
---
 block-sha1/sha1.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/block-sha1/sha1.c b/block-sha1/sha1.c
index 464cb25..e6e7170 100644
--- a/block-sha1/sha1.c
+++ b/block-sha1/sha1.c
@@ -22,6 +22,11 @@
 #define SHA_ROL(x,n)	SHA_ASM("rol", x, n)
 #define SHA_ROR(x,n)	SHA_ASM("ror", x, n)
 
+#undef htonl
+#undef ntohl
+#define htonl(x) ({ unsigned int __res; __asm__("bswap %0":"=r" (__res):"0" (x)); __res; })
+#define ntohl(x) htonl(x)
+
 #else
 
 #define SHA_ROT(X,l,r)	(((X) << (l)) | ((X) >> (r)))

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox