summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-tar-tree.txt15
-rw-r--r--Makefile4
-rw-r--r--builtin-tar-tree.c47
-rw-r--r--fsck-objects.c5
-rw-r--r--object-refs.c142
-rw-r--r--object.c70
-rw-r--r--object.h4
-rw-r--r--ppc/sha1.c2
-rw-r--r--t/annotate-tests.sh4
9 files changed, 182 insertions, 111 deletions
diff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt
index 831537b6ff..f2675c4193 100644
--- a/Documentation/git-tar-tree.txt
+++ b/Documentation/git-tar-tree.txt
@@ -39,19 +39,24 @@ OPTIONS
Examples
--------
-git tar-tree HEAD | (cd /var/tmp/ && mkdir junk && tar Cxf junk -)::
+git tar-tree HEAD junk | (cd /var/tmp/ && tar xf -)::
Create a tar archive that contains the contents of the
latest commit on the current branch, and extracts it in
`/var/tmp/junk` directory.
-git tar-tree v2.6.17 linux-2.6.17 | gzip >linux-2.6.17.tar.gz
+git tar-tree v1.4.0 git-1.4.0 | gzip >git-1.4.0.tar.gz::
- Create a tarball for v2.6.17 release.
+ Create a tarball for v1.4.0 release.
-git tar-tree --remote=example.com:git.git v0.99 >git-0.99.tar
+git tar-tree v1.4.0{caret}\{tree\} git-1.4.0 | gzip >git-1.4.0.tar.gz::
- Get a tarball v0.99 from example.com.
+ Create a tarball for v1.4.0 release, but without a
+ global extended pax header.
+
+git tar-tree --remote=example.com:git.git v1.4.0 >git-1.4.0.tar::
+
+ Get a tarball v1.4.0 from example.com.
Author
------
diff --git a/Makefile b/Makefile
index 2a1e6392dd..5598f48ba3 100644
--- a/Makefile
+++ b/Makefile
@@ -212,7 +212,7 @@ LIB_OBJS = \
blob.o commit.o connect.o csum-file.o cache-tree.o base85.o \
date.o diff-delta.o entry.o exec_cmd.o ident.o lockfile.o \
object.o pack-check.o patch-delta.o path.o pkt-line.o \
- quote.o read-cache.o refs.o run-command.o dir.o \
+ quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
@@ -667,7 +667,7 @@ git.spec: git.spec.in
GIT_TARNAME=git-$(GIT_VERSION)
dist: git.spec git-tar-tree
- ./git-tar-tree HEAD $(GIT_TARNAME) > $(GIT_TARNAME).tar
+ ./git-tar-tree HEAD^{tree} $(GIT_TARNAME) > $(GIT_TARNAME).tar
@mkdir -p $(GIT_TARNAME)
@cp git.spec $(GIT_TARNAME)
@echo $(GIT_VERSION) > $(GIT_TARNAME)/version
diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c
index f6310b9032..39a61b6293 100644
--- a/builtin-tar-tree.c
+++ b/builtin-tar-tree.c
@@ -22,8 +22,10 @@ static unsigned long offset;
static time_t archive_time;
/* tries hard to write, either succeeds or dies in the attempt */
-static void reliable_write(void *buf, unsigned long size)
+static void reliable_write(const void *data, unsigned long size)
{
+ const char *buf = data;
+
while (size > 0) {
long ret = xwrite(1, buf, size);
if (ret < 0) {
@@ -47,37 +49,13 @@ static void write_if_needed(void)
}
}
-/* acquire the next record from the buffer; user must call write_if_needed() */
-static char *get_record(void)
-{
- char *p = block + offset;
- memset(p, 0, RECORDSIZE);
- offset += RECORDSIZE;
- return p;
-}
-
-/*
- * The end of tar archives is marked by 1024 nul bytes and after that
- * follows the rest of the block (if any).
- */
-static void write_trailer(void)
-{
- get_record();
- write_if_needed();
- get_record();
- write_if_needed();
- while (offset) {
- get_record();
- write_if_needed();
- }
-}
-
/*
* queues up writes, so that all our write(2) calls write exactly one
* full block; pads writes to RECORDSIZE
*/
-static void write_blocked(void *buf, unsigned long size)
+static void write_blocked(const void *data, unsigned long size)
{
+ const char *buf = data;
unsigned long tail;
if (offset) {
@@ -107,6 +85,21 @@ static void write_blocked(void *buf, unsigned long size)
write_if_needed();
}
+/*
+ * The end of tar archives is marked by 2*512 nul bytes and after that
+ * follows the rest of the block (if any).
+ */
+static void write_trailer(void)
+{
+ int tail = BLOCKSIZE - offset;
+ memset(block + offset, 0, tail);
+ reliable_write(block, BLOCKSIZE);
+ if (tail < 2 * RECORDSIZE) {
+ memset(block, 0, offset);
+ reliable_write(block, BLOCKSIZE);
+ }
+}
+
static void strbuf_append_string(struct strbuf *sb, const char *s)
{
int slen = strlen(s);
diff --git a/fsck-objects.c b/fsck-objects.c
index 2b1aab488f..769bb2a6a7 100644
--- a/fsck-objects.c
+++ b/fsck-objects.c
@@ -64,6 +64,7 @@ static void check_connectivity(void)
/* Look up all the requirements, warn about missing objects.. */
for (i = 0; i < obj_allocs; i++) {
+ const struct object_refs *refs;
struct object *obj = objs[i];
if (!obj)
@@ -78,8 +79,8 @@ static void check_connectivity(void)
continue;
}
- if (obj->refs) {
- const struct object_refs *refs = obj->refs;
+ refs = lookup_object_refs(obj);
+ if (refs) {
unsigned j;
for (j = 0; j < refs->count; j++) {
struct object *ref = refs->ref[j];
diff --git a/object-refs.c b/object-refs.c
new file mode 100644
index 0000000000..8afa2276fb
--- /dev/null
+++ b/object-refs.c
@@ -0,0 +1,142 @@
+#include "cache.h"
+#include "object.h"
+
+int track_object_refs = 0;
+
+static unsigned int refs_hash_size, nr_object_refs;
+static struct object_refs **refs_hash;
+
+static unsigned int hash_obj(struct object *obj, unsigned int n)
+{
+ unsigned int hash = *(unsigned int *)obj->sha1;
+ return hash % n;
+}
+
+static void grow_refs_hash(void)
+{
+ int i;
+ int new_hash_size = (refs_hash_size + 1000) * 3 / 2;
+ struct object_refs **new_hash;
+
+ new_hash = calloc(new_hash_size, sizeof(struct object_refs *));
+ for (i = 0; i < refs_hash_size; i++) {
+ int j;
+ struct object_refs *ref = refs_hash[i];
+ if (!ref)
+ continue;
+ j = hash_obj(ref->base, new_hash_size);
+ new_hash[j] = ref;
+ }
+ free(refs_hash);
+ refs_hash = new_hash;
+ refs_hash_size = new_hash_size;
+}
+
+static void insert_ref_hash(struct object_refs *ref)
+{
+ int j = hash_obj(ref->base, refs_hash_size);
+
+ while (refs_hash[j]) {
+ j++;
+ if (j >= refs_hash_size)
+ j = 0;
+ }
+ refs_hash[j] = ref;
+}
+
+static void add_object_refs(struct object *obj, struct object_refs *ref)
+{
+ int nr = nr_object_refs + 1;
+
+ if (nr > refs_hash_size * 2 / 3)
+ grow_refs_hash();
+ ref->base = obj;
+ insert_ref_hash(ref);
+ nr_object_refs = nr;
+}
+
+struct object_refs *lookup_object_refs(struct object *obj)
+{
+ int j = hash_obj(obj, refs_hash_size);
+ struct object_refs *ref;
+
+ while ((ref = refs_hash[j]) != NULL) {
+ if (ref->base == obj)
+ break;
+ j++;
+ if (j >= refs_hash_size)
+ j = 0;
+ }
+ return ref;
+}
+
+struct object_refs *alloc_object_refs(unsigned count)
+{
+ struct object_refs *refs;
+ size_t size = sizeof(*refs) + count*sizeof(struct object *);
+
+ refs = xcalloc(1, size);
+ refs->count = count;
+ return refs;
+}
+
+static int compare_object_pointers(const void *a, const void *b)
+{
+ const struct object * const *pa = a;
+ const struct object * const *pb = b;
+ if (*pa == *pb)
+ return 0;
+ else if (*pa < *pb)
+ return -1;
+ else
+ return 1;
+}
+
+void set_object_refs(struct object *obj, struct object_refs *refs)
+{
+ unsigned int i, j;
+
+ /* Do not install empty list of references */
+ if (refs->count < 1) {
+ free(refs);
+ return;
+ }
+
+ /* Sort the list and filter out duplicates */
+ qsort(refs->ref, refs->count, sizeof(refs->ref[0]),
+ compare_object_pointers);
+ for (i = j = 1; i < refs->count; i++) {
+ if (refs->ref[i] != refs->ref[i - 1])
+ refs->ref[j++] = refs->ref[i];
+ }
+ if (j < refs->count) {
+ /* Duplicates were found - reallocate list */
+ size_t size = sizeof(*refs) + j*sizeof(struct object *);
+ refs->count = j;
+ refs = xrealloc(refs, size);
+ }
+
+ for (i = 0; i < refs->count; i++)
+ refs->ref[i]->used = 1;
+ add_object_refs(obj, refs);
+}
+
+void mark_reachable(struct object *obj, unsigned int mask)
+{
+ const struct object_refs *refs;
+
+ if (!track_object_refs)
+ die("cannot do reachability with object refs turned off");
+ /* If we've been here already, don't bother */
+ if (obj->flags & mask)
+ return;
+ obj->flags |= mask;
+ refs = lookup_object_refs(obj);
+ if (refs) {
+ unsigned i;
+ for (i = 0; i < refs->count; i++)
+ mark_reachable(refs->ref[i], mask);
+ }
+}
+
+
diff --git a/object.c b/object.c
index 0f70890a45..e26e319ccd 100644
--- a/object.c
+++ b/object.c
@@ -13,8 +13,6 @@ const char *type_names[] = {
"none", "blob", "tree", "commit", "bad"
};
-int track_object_refs = 0;
-
static int hashtable_index(const unsigned char *sha1)
{
unsigned int i;
@@ -55,7 +53,6 @@ void created_object(const unsigned char *sha1, struct object *obj)
obj->parsed = 0;
memcpy(obj->sha1, sha1, 20);
obj->type = TYPE_NONE;
- obj->refs = NULL;
obj->used = 0;
if (obj_allocs - 1 <= nr_objs * 2) {
@@ -84,73 +81,6 @@ void created_object(const unsigned char *sha1, struct object *obj)
nr_objs++;
}
-struct object_refs *alloc_object_refs(unsigned count)
-{
- struct object_refs *refs;
- size_t size = sizeof(*refs) + count*sizeof(struct object *);
-
- refs = xcalloc(1, size);
- refs->count = count;
- return refs;
-}
-
-static int compare_object_pointers(const void *a, const void *b)
-{
- const struct object * const *pa = a;
- const struct object * const *pb = b;
- if (*pa == *pb)
- return 0;
- else if (*pa < *pb)
- return -1;
- else
- return 1;
-}
-
-void set_object_refs(struct object *obj, struct object_refs *refs)
-{
- unsigned int i, j;
-
- /* Do not install empty list of references */
- if (refs->count < 1) {
- free(refs);
- return;
- }
-
- /* Sort the list and filter out duplicates */
- qsort(refs->ref, refs->count, sizeof(refs->ref[0]),
- compare_object_pointers);
- for (i = j = 1; i < refs->count; i++) {
- if (refs->ref[i] != refs->ref[i - 1])
- refs->ref[j++] = refs->ref[i];
- }
- if (j < refs->count) {
- /* Duplicates were found - reallocate list */
- size_t size = sizeof(*refs) + j*sizeof(struct object *);
- refs->count = j;
- refs = xrealloc(refs, size);
- }
-
- for (i = 0; i < refs->count; i++)
- refs->ref[i]->used = 1;
- obj->refs = refs;
-}
-
-void mark_reachable(struct object *obj, unsigned int mask)
-{
- if (!track_object_refs)
- die("cannot do reachability with object refs turned off");
- /* If we've been here already, don't bother */
- if (obj->flags & mask)
- return;
- obj->flags |= mask;
- if (obj->refs) {
- const struct object_refs *refs = obj->refs;
- unsigned i;
- for (i = 0; i < refs->count; i++)
- mark_reachable(refs->ref[i], mask);
- }
-}
-
struct object *lookup_object_type(const unsigned char *sha1, const char *type)
{
if (!type) {
diff --git a/object.h b/object.h
index f4ee2e55ba..c537b4b72a 100644
--- a/object.h
+++ b/object.h
@@ -9,6 +9,7 @@ struct object_list {
struct object_refs {
unsigned count;
+ struct object *base;
struct object *ref[FLEX_ARRAY]; /* more */
};
@@ -28,7 +29,6 @@ struct object {
unsigned type : TYPE_BITS;
unsigned flags : FLAG_BITS;
unsigned char sha1[20];
- struct object_refs *refs;
};
extern int track_object_refs;
@@ -41,6 +41,8 @@ static inline const char *typename(unsigned int type)
return type_names[type > TYPE_TAG ? TYPE_BAD : type];
}
+extern struct object_refs *lookup_object_refs(struct object *);
+
/** Internal only **/
struct object *lookup_object(const unsigned char *sha1);
diff --git a/ppc/sha1.c b/ppc/sha1.c
index 5ba4fc5259..0820398b00 100644
--- a/ppc/sha1.c
+++ b/ppc/sha1.c
@@ -30,7 +30,7 @@ int SHA1_Update(SHA_CTX *c, const void *ptr, unsigned long n)
unsigned long nb;
const unsigned char *p = ptr;
- c->len += n << 3;
+ c->len += (uint64_t) n << 3;
while (n != 0) {
if (c->cnt || n < 64) {
nb = 64 - c->cnt;
diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh
index 114938c3ff..c04f0e1540 100644
--- a/t/annotate-tests.sh
+++ b/t/annotate-tests.sh
@@ -111,9 +111,7 @@ test_expect_success \
test_expect_success \
'some edit' \
- 'mv file file1 &&
- sed -e 1d -e "5s/3A/99/" file1 >file &&
- rm -f file1 &&
+ 'perl -pi -e "s/^1A.*\n$//; s/^3A/99/" file &&
GIT_AUTHOR_NAME="D" git commit -a -m "edit"'
test_expect_success \