Merge branch 'master' of .
authorJunio C Hamano <junkio@cox.net>
Sun, 18 Sep 2005 08:18:15 +0000 (01:18 -0700)
committerJunio C Hamano <junkio@cox.net>
Sun, 18 Sep 2005 08:18:15 +0000 (01:18 -0700)
49 files changed:
.gitignore
Documentation/Makefile
Documentation/git-build-rev-cache.txt [deleted file]
Documentation/git-fetch.txt
Documentation/git-rev-list.txt
Documentation/git-show-rev-cache.txt [deleted file]
Documentation/git-update-server-info.txt
Documentation/git.txt
Documentation/pull-fetch-param.txt
Documentation/repository-layout.txt
Makefile
build-rev-cache.c [deleted file]
cmd-rename.sh
commit.c
commit.h
convert-objects.c
debian/control
debian/rules
diff-tree.c
diff.c
diffcore-break.c
diffcore-rename.c
diffcore.h
fetch.c
git-bisect.sh
git-branch.sh
git-checkout.sh
git-clone.sh
git-core.spec.in
git-fetch.sh
git-parse-remote.sh
git-pull.sh
git-repack.sh
git-shortlog.perl
http-fetch.c
ident.c
object.c
object.h
rev-cache.c [deleted file]
rev-cache.h [deleted file]
rev-list.c
rsh.c
server-info.c
show-rev-cache.c [deleted file]
ssh-fetch.c
ssh-pull.c [new file with mode: 0644]
ssh-push.c [new file with mode: 0644]
ssh-upload.c
t/t1001-read-tree-m-2way.sh

index 31c03f4..0fd59b9 100644 (file)
@@ -6,7 +6,6 @@ git-applypatch
 git-archimport
 git-bisect
 git-branch
-git-build-rev-cache
 git-cat-file
 git-checkout
 git-checkout-index
@@ -73,13 +72,15 @@ git-rev-list
 git-rev-parse
 git-rev-tree
 git-revert
+git-send-email
 git-send-pack
 git-sh-setup
 git-shortlog
 git-show-branch
 git-show-index
-git-show-rev-cache
 git-ssh-fetch
+git-ssh-pull
+git-ssh-push
 git-ssh-upload
 git-status
 git-stripspace
index b81a6a2..37b7fcb 100644 (file)
@@ -45,7 +45,7 @@ man1: $(DOC_MAN1)
 man7: $(DOC_MAN7)
 
 install:
-       $(INSTALL) -m755 -d $(DESTDIR)/$(man1) $(DESTDIR)/$(man7)
+       $(INSTALL) -d -m755 $(DESTDIR)/$(man1) $(DESTDIR)/$(man7)
        $(INSTALL) $(DOC_MAN1) $(DESTDIR)/$(man1)
        $(INSTALL) $(DOC_MAN7) $(DESTDIR)/$(man7)
 
diff --git a/Documentation/git-build-rev-cache.txt b/Documentation/git-build-rev-cache.txt
deleted file mode 100644 (file)
index 1dbad77..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-git-build-rev-cache(1)
-======================
-
-NAME
-----
-git-build-rev-cache - Create or update a rev-cache file.
-
-SYNOPSIS
---------
-'git-build-rev-cache' [-v] <rev-cache-file> < list-of-heads
-
-DESCRIPTION
------------
-Creates or updates a file that describes the commit ancestry reachable
-from the list-of-head read from stdin. This file is in an append-only
-binary format to make the server side friendly to rsync mirroring
-scheme, and can be read by the git-show-rev-cache command.
-
-OPTIONS
--------
--v::
-       Verbose.
-
-<rev-cache-file>::
-       The rev-cache to operate on.
-
-Author
-------
-Written by Junio C Hamano <junkio@cox.net>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the link:git.html[git] suite
-
index 017f646..8c1cc07 100644 (file)
@@ -26,6 +26,12 @@ OPTIONS
 -------
 include::pull-fetch-param.txt[]
 
+-u, \--update-head-ok::
+       By default 'git-fetch' refuses to update the head which
+       corresponds to the current branch.  This flag disables the
+       check.  Note that fetching into the current branch will not
+       update the index and working directory, so use it with care.
+
 
 Author
 ------
index 35fecf3..32c06a1 100644 (file)
@@ -32,8 +32,11 @@ I have the commit object 'bar', but not 'foo'".
 
 The *--bisect* flag limits output to the one commit object which is
 roughly halfway between the included and excluded commits. Thus,
-if "git-rev-list --bisect foo ^bar ^baz" outputs 'midpoint', the output
-of "git-rev-list foo ^midpoint" and "git-rev-list midpoint ^bar ^baz"
+if 'git-rev-list --bisect foo ^bar
+^baz' outputs 'midpoint', the output
+of 'git-rev-list foo ^midpoint' and 'git-rev-list midpoint
+^bar
+^baz'
 would be of roughly the same length. Finding the change which introduces
 a regression is thus reduced to a binary search: repeatedly generate and
 test new 'midpoint's until the commit chain is of length one.
diff --git a/Documentation/git-show-rev-cache.txt b/Documentation/git-show-rev-cache.txt
deleted file mode 100644 (file)
index 104ecb7..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-git-show-rev-cache(1)
-=====================
-
-NAME
-----
-git-show-rev-cache - Show the contents of a rev-cache file.
-
-SYNOPSIS
---------
-'git-show-rev-cache' <rev-cache-file>
-
-DESCRIPTION
------------
-Show the contents of <rev-cache-file>.
-
-A rev-cache file describes the commit ancestry reachable from references
-supplied as input to get-build-rev-cache. This file is in an
-append-only binary format to make the server side friendly to rsync
-mirroring scheme.
-
-OPTIONS
--------
-<rev-cache-file>::
-       Rev-cache file to display.
-
-Author
-------
-Written by Junio C Hamano <junkio@cox.net>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the link:git.html[git] suite
-
index 74c4364..39222c3 100644 (file)
@@ -38,8 +38,6 @@ of what they are for:
 
 * info/refs
 
-* info/rev-cache
-
 
 BUGS
 ----
index 31dd474..bec562e 100644 (file)
@@ -359,9 +359,6 @@ link:git-tag.html[git-tag]::
 
 Interrogators:
 
-link:git-build-rev-cache.html[git-build-rev-cache]::
-       Create or update a rev-cache file.
-
 link:git-cherry.html[git-cherry]::
        Find commits not merged upstream.
 
@@ -402,9 +399,6 @@ link:git-send-email.html[git-send-email]::
        Send patch e-mails out of "format-patch --mbox" output.
        Previously this command was known as git-send-email-script.
 
-link:git-show-rev-cache.html[git-show-rev-cache]::
-       Show the contents of a rev-cache file.
-
 link:git-stripspace.html[git-stripspace]::
        Filter out empty lines.
 
index 8f6b68c..8642182 100644 (file)
           <ref>: when pulling/fetching, and <ref>:<ref> when
           pushing.  That is, do not store it locally if
           fetching, and update the same name if pushing.
+
+-a, \--append::
+       Append ref names and object names of fetched refs to the
+       existing contents of $GIT_DIR/FETCH_HEAD.  Without this
+       option old data in $GIT_DIR/FETCH_HEAD will be overwritten.
+
+-f, \--force::
+       Usually, the command refuses to update a local ref that is
+       not an ancestor of the remote ref used to overwrite it.
+       This flag disables the check.  What this means is that the
+       local repository can lose commits; use it with care.
index 499b070..d20fa80 100644 (file)
@@ -117,13 +117,6 @@ info/grafts::
        listing their 40-byte hexadecimal object names separated
        by a space and terminated by a newline.
 
-info/rev-cache::
-       No higher-level tool currently takes advantage of this
-       file, but it is generated when `git update-server-info`
-       is run.  It records the commit ancestry information of
-       the commits in this repository in a concise binary
-       format, and can be read with `git-show-rev-cache`.
-
 info/exclude::
        This file, by convention among Porcelains, stores the
        exclude pattern list.  `git status` looks at it, but
index 9725b1a..877e0b8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -92,7 +92,7 @@ SIMPLE_PROGRAMS = \
 
 # ... and all the rest
 PROGRAMS = \
-       git-apply git-build-rev-cache git-cat-file \
+       git-apply git-cat-file \
        git-checkout-index git-clone-pack git-commit-tree \
        git-convert-objects git-diff-files \
        git-diff-helper git-diff-index git-diff-stages \
@@ -103,12 +103,15 @@ PROGRAMS = \
        git-peek-remote git-prune-packed git-read-tree \
        git-receive-pack git-rev-list git-rev-parse \
        git-rev-tree git-send-pack git-show-branch \
-       git-show-index git-show-rev-cache git-ssh-fetch \
+       git-show-index git-ssh-fetch \
        git-ssh-upload git-tar-tree git-unpack-file \
        git-unpack-objects git-update-index git-update-server-info \
        git-upload-pack git-verify-pack git-write-tree \
        $(SIMPLE_PROGRAMS)
 
+# Backward compatibility -- to be removed in 0.99.8
+PROGRAMS += git-ssh-pull git-ssh-push
+
 PYMODULES = \
        gitMergeCommon.py
 
@@ -125,7 +128,7 @@ LIB_FILE=libgit.a
 LIB_H = \
        blob.h cache.h commit.h count-delta.h csum-file.h delta.h \
        diff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \
-       rev-cache.h run-command.h strbuf.h tag.h tree.h
+       run-command.h strbuf.h tag.h tree.h
 
 DIFF_OBJS = \
        diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \
@@ -135,7 +138,7 @@ LIB_OBJS = \
        blob.o commit.o connect.o count-delta.o csum-file.o \
        date.o diff-delta.o entry.o ident.o index.o \
        object.o pack-check.o patch-delta.o path.o pkt-line.o \
-       quote.o read-cache.o refs.o rev-cache.o run-command.o \
+       quote.o read-cache.o refs.o run-command.o \
        server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
        tag.o tree.o usage.o $(DIFF_OBJS)
 
@@ -148,7 +151,8 @@ ifeq ($(shell uname -s),Darwin)
 endif
 ifeq ($(shell uname -s),SunOS)
        NEEDS_SOCKET = YesPlease
-       PLATFORM_DEFINES += -DNO_GETDOMAINNAME=1
+       NEEDS_NSL = YesPlease
+       PLATFORM_DEFINES += -D__EXTENSIONS__
 endif
 
 ifndef SHELL_PATH
@@ -195,6 +199,10 @@ ifdef NEEDS_SOCKET
        LIBS += -lsocket
        SIMPLE_LIB += -lsocket
 endif
+ifdef NEEDS_NSL
+       LIBS += -lnsl
+       SIMPLE_LIB += -lnsl
+endif
 
 DEFINES += '-DSHA1_HEADER=$(SHA1_HEADER)'
 
@@ -250,6 +258,8 @@ git-http-fetch: fetch.o
 git-local-fetch: fetch.o
 git-ssh-fetch: rsh.o fetch.o
 git-ssh-upload: rsh.o
+git-ssh-pull: rsh.o fetch.o
+git-ssh-push: rsh.o
 
 git-http-fetch: LIBS += -lcurl
 git-rev-list: LIBS += $(OPENSSL_LIBSSL)
@@ -288,12 +298,12 @@ check:
 ### Installation rules
 
 install: $(PROGRAMS) $(SCRIPTS)
-       $(INSTALL) -m755 -d $(DESTDIR)$(bindir)
+       $(INSTALL) -d -m755 $(DESTDIR)$(bindir)
        $(INSTALL) $(PROGRAMS) $(SCRIPTS) $(DESTDIR)$(bindir)
        $(INSTALL) git-revert $(DESTDIR)$(bindir)/git-cherry-pick
        sh ./cmd-rename.sh $(DESTDIR)$(bindir)
        $(MAKE) -C templates install
-       $(INSTALL) -m755 -d $(DESTDIR)$(GIT_PYTHON_DIR)
+       $(INSTALL) -d -m755 $(DESTDIR)$(GIT_PYTHON_DIR)
        $(INSTALL) $(PYMODULES) $(DESTDIR)$(GIT_PYTHON_DIR)
 
 install-doc:
diff --git a/build-rev-cache.c b/build-rev-cache.c
deleted file mode 100644 (file)
index 948898b..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "refs.h"
-#include "cache.h"
-#include "commit.h"
-#include "rev-cache.h"
-
-static void process_head_list(int verbose)
-{
-       char buf[512];
-
-       while (fgets(buf, sizeof(buf), stdin)) {
-               unsigned char sha1[20];
-               struct commit *commit;
-
-               if (get_sha1_hex(buf, sha1)) {
-                       error("ignoring: %s", buf);
-                       continue;
-               }
-               if (!(commit = lookup_commit_reference(sha1))) {
-                       error("not a commit: %s", sha1_to_hex(sha1));
-                       continue;
-               }
-               record_rev_cache(commit->object.sha1, verbose ? stderr : NULL);
-       }
-}
-
-
-static const char *build_rev_cache_usage =
-"git-build-rev-cache <rev-cache-file> < list-of-heads";
-
-int main(int ac, char **av)
-{
-       int verbose = 0;
-       const char *path;
-
-       while (1 < ac && av[1][0] == '-') {
-               if (!strcmp(av[1], "-v"))
-                       verbose = 1;
-               else
-                       usage(build_rev_cache_usage);
-               ac--; av++;
-       }
-
-       if (ac != 2)
-               usage(build_rev_cache_usage);
-
-       path = av[1];
-
-       /* read existing rev-cache */
-       read_rev_cache(path, NULL, 0);
-
-       process_head_list(verbose);
-
-       /* update the rev-cache database by appending newly found one to it */
-       write_rev_cache(path, path);
-       return 0;
-}
index 1edb037..ada33fb 100755 (executable)
@@ -42,12 +42,14 @@ git-tag-script      git-tag
 git-verify-tag-script  git-verify-tag
 git-http-pull  git-http-fetch
 git-local-pull git-local-fetch
-git-ssh-pull   git-ssh-fetch
 git-checkout-cache     git-checkout-index
 git-diff-cache git-diff-index
 git-merge-cache        git-merge-index
 git-update-cache       git-update-index
-git-ssh-push   git-ssh-upload
 git-convert-cache      git-convert-objects
 git-fsck-cache git-fsck-objects
 EOF
+
+# These two are a bit more than symlinks now.
+# git-ssh-push git-ssh-upload
+# git-ssh-pull git-ssh-fetch
index 2f73cf3..f735f98 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -3,6 +3,8 @@
 #include "commit.h"
 #include "cache.h"
 
+int save_commit_buffer = 1;
+
 struct sort_node
 {
        /*
@@ -264,7 +266,7 @@ int parse_commit(struct commit *item)
                             sha1_to_hex(item->object.sha1));
        }
        ret = parse_commit_buffer(item, buffer, size);
-       if (!ret) {
+       if (save_commit_buffer && !ret) {
                item->buffer = buffer;
                return 0;
        }
index 9dda2f0..30702ca 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -17,6 +17,7 @@ struct commit {
        char *buffer;
 };
 
+extern int save_commit_buffer;
 extern const char *commit_type;
 
 struct commit *lookup_commit(const unsigned char *sha1);
index 073cab5..9ad0c77 100644 (file)
@@ -1,5 +1,4 @@
 #define _XOPEN_SOURCE /* glibc2 needs this */
-#define __EXTENSIONS__ /* solaris needs this */
 #include <time.h>
 #include <ctype.h>
 #include "cache.h"
index 33a8f85..5d75c32 100644 (file)
@@ -2,13 +2,13 @@ Source: git-core
 Section: devel
 Priority: optional
 Maintainer: Junio C Hamano <junkio@cox.net>
-Build-Depends-Indep: libz-dev, libssl-dev, libcurl3-dev, asciidoc (>= 6.0.3), xmlto, debhelper (>= 4.0.0)
+Build-Depends-Indep: libz-dev, libssl-dev, libcurl3-dev, asciidoc (>= 6.0.3), xmlto, debhelper (>= 4.0.0), bc
 Standards-Version: 3.6.1
 
 Package: git-core
 Architecture: any
 Depends: ${shlibs:Depends}, ${perl:Depends}, ${misc:Depends}, patch, rcs
-Recommends: rsync, curl, ssh, libmail-sendmail-perl, libemail-valid-perl, python (>= 2.4.0)
+Recommends: rsync, curl, ssh, libmail-sendmail-perl, libemail-valid-perl, python (>= 2.4.0), less
 Suggests: cogito
 Conflicts: git, cogito (<< 0.13)
 Description: The git content addressable filesystem
index 1a53ca2..568d430 100755 (executable)
@@ -41,7 +41,7 @@ MAN_DESTDIR := $(DESTDIR)/$(MANDIR)
 build: debian/build-stamp
 debian/build-stamp:
        dh_testdir
-       $(MAKE) prefix=$(PREFIX) PYTHON_PATH=/usr/bin/python2.4 all doc
+       $(MAKE) prefix=$(PREFIX) PYTHON_PATH=/usr/bin/python2.4 all doc test
        touch debian/build-stamp
 
 debian-clean:
index fc87902..e8f5d1b 100644 (file)
@@ -370,6 +370,7 @@ static int diff_tree_commit(const unsigned char *commit, const char *name)
                }
                offset += 48;
        }
+       free(buf);
        return 0;
 }
 
diff --git a/diff.c b/diff.c
index f8e3cbf..d8d20c2 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -214,14 +214,10 @@ struct diff_filespec *alloc_filespec(const char *path)
 {
        int namelen = strlen(path);
        struct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);
+
+       memset(spec, 0, sizeof(*spec));
        spec->path = (char *)(spec + 1);
-       strcpy(spec->path, path);
-       spec->should_free = spec->should_munmap = 0;
-       spec->xfrm_flags = 0;
-       spec->size = 0;
-       spec->data = NULL;
-       spec->mode = 0;
-       memset(spec->sha1, 0, 20);
+       memcpy(spec->path, path, namelen+1);
        return spec;
 }
 
@@ -406,13 +402,14 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
        return 0;
 }
 
-void diff_free_filespec(struct diff_filespec *s)
+void diff_free_filespec_data(struct diff_filespec *s)
 {
        if (s->should_free)
                free(s->data);
        else if (s->should_munmap)
                munmap(s->data, s->size);
-       free(s);
+       s->should_free = s->should_munmap = 0;
+       s->data = NULL;
 }
 
 static void prep_temp_blob(struct diff_tempfile *temp,
@@ -765,14 +762,17 @@ struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
        dp->status = 0;
        dp->source_stays = 0;
        dp->broken_pair = 0;
-       diff_q(queue, dp);
+       if (queue)
+               diff_q(queue, dp);
        return dp;
 }
 
 void diff_free_filepair(struct diff_filepair *p)
 {
-       diff_free_filespec(p->one);
-       diff_free_filespec(p->two);
+       diff_free_filespec_data(p->one);
+       diff_free_filespec_data(p->two);
+       free(p->one);
+       free(p->two);
        free(p);
 }
 
index b0c8461..06f9a7f 100644 (file)
@@ -231,8 +231,8 @@ static void merge_broken(struct diff_filepair *p,
 
        dp = diff_queue(outq, d->one, c->two);
        dp->score = p->score;
-       diff_free_filespec(d->two);
-       diff_free_filespec(c->one);
+       diff_free_filespec_data(d->two);
+       diff_free_filespec_data(c->one);
        free(d);
        free(c);
 }
index dbc8522..092cf68 100644 (file)
@@ -47,7 +47,8 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
        if (first < rename_dst_nr)
                memmove(rename_dst + first + 1, rename_dst + first,
                        (rename_dst_nr - first - 1) * sizeof(*rename_dst));
-       rename_dst[first].two = two;
+       rename_dst[first].two = alloc_filespec(two->path);
+       fill_filespec(rename_dst[first].two, two->sha1, two->mode);
        rename_dst[first].pair = NULL;
        return &(rename_dst[first]);
 }
@@ -201,8 +202,7 @@ static int estimate_similarity(struct diff_filespec *src,
        return score;
 }
 
-static void record_rename_pair(struct diff_queue_struct *renq,
-                              int dst_index, int src_index, int score)
+static void record_rename_pair(int dst_index, int src_index, int score)
 {
        struct diff_filespec *one, *two, *src, *dst;
        struct diff_filepair *dp;
@@ -218,7 +218,7 @@ static void record_rename_pair(struct diff_queue_struct *renq,
        two = alloc_filespec(dst->path);
        fill_filespec(two, dst->sha1, dst->mode);
 
-       dp = diff_queue(renq, one, two);
+       dp = diff_queue(NULL, one, two);
        dp->score = score;
        dp->source_stays = rename_src[src_index].src_path_left;
        rename_dst[dst_index].pair = dp;
@@ -252,15 +252,14 @@ static int compute_stays(struct diff_queue_struct *q,
 void diffcore_rename(int detect_rename, int minimum_score)
 {
        struct diff_queue_struct *q = &diff_queued_diff;
-       struct diff_queue_struct renq, outq;
+       struct diff_queue_struct outq;
        struct diff_score *mx;
-       int i, j;
+       int i, j, rename_count;
        int num_create, num_src, dst_cnt;
 
        if (!minimum_score)
                minimum_score = DEFAULT_RENAME_SCORE;
-       renq.queue = NULL;
-       renq.nr = renq.alloc = 0;
+       rename_count = 0;
 
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
@@ -292,19 +291,19 @@ void diffcore_rename(int detect_rename, int minimum_score)
                        struct diff_filespec *one = rename_src[j].one;
                        if (!is_exact_match(one, two))
                                continue;
-                       record_rename_pair(&renq, i, j, MAX_SCORE);
+                       record_rename_pair(i, j, MAX_SCORE);
+                       rename_count++;
                        break; /* we are done with this entry */
                }
        }
-       diff_debug_queue("done detecting exact", &renq);
 
        /* Have we run out the created file pool?  If so we can avoid
         * doing the delta matrix altogether.
         */
-       if (renq.nr == rename_dst_nr)
+       if (rename_count == rename_dst_nr)
                goto cleanup;
 
-       num_create = (rename_dst_nr - renq.nr);
+       num_create = (rename_dst_nr - rename_count);
        num_src = rename_src_nr;
        mx = xmalloc(sizeof(*mx) * num_create * num_src);
        for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
@@ -330,14 +329,14 @@ void diffcore_rename(int detect_rename, int minimum_score)
                        continue; /* already done, either exact or fuzzy. */
                if (mx[i].score < minimum_score)
                        break; /* there is no more usable pair. */
-               record_rename_pair(&renq, mx[i].dst, mx[i].src, mx[i].score);
+               record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
+               rename_count++;
        }
        free(mx);
-       diff_debug_queue("done detecting fuzzy", &renq);
 
  cleanup:
        /* At this point, we have found some renames and copies and they
-        * are kept in renq.  The original list is still in *q.
+        * are recorded in rename_dst.  The original list is still in *q.
         */
        outq.queue = NULL;
        outq.nr = outq.alloc = 0;
@@ -372,9 +371,9 @@ void diffcore_rename(int detect_rename, int minimum_score)
                         *
                         * (1) this is a broken delete and the counterpart
                         *     broken create remains in the output; or
-                        * (2) this is not a broken delete, and renq does
-                        *     not have a rename/copy to move p->one->path
-                        *     out.
+                        * (2) this is not a broken delete, and rename_dst
+                        *     does not have a rename/copy to move p->one->path
+                        *     out of existence.
                         *
                         * Otherwise, the counterpart broken create
                         * has been turned into a rename-edit; or
@@ -390,11 +389,16 @@ void diffcore_rename(int detect_rename, int minimum_score)
                                        pair_to_free = p;
                        }
                        else {
-                               for (j = 0; j < renq.nr; j++)
-                                       if (!strcmp(renq.queue[j]->one->path,
-                                                   p->one->path))
-                                               break;
-                               if (j < renq.nr)
+                               for (j = 0; j < rename_dst_nr; j++) {
+                                       if (!rename_dst[j].pair)
+                                               continue;
+                                       if (strcmp(rename_dst[j].pair->
+                                                  one->path,
+                                                  p->one->path))
+                                               continue;
+                                       break;
+                               }
+                               if (j < rename_dst_nr)
                                        /* this path remains */
                                        pair_to_free = p;
                        }
@@ -416,7 +420,6 @@ void diffcore_rename(int detect_rename, int minimum_score)
        }
        diff_debug_queue("done copying original", &outq);
 
-       free(renq.queue);
        free(q->queue);
        *q = outq;
        diff_debug_queue("done collapsing", q);
@@ -438,6 +441,11 @@ void diffcore_rename(int detect_rename, int minimum_score)
                }
        }
 
+       for (i = 0; i < rename_dst_nr; i++) {
+               diff_free_filespec_data(rename_dst[i].two);
+               free(rename_dst[i].two);
+       }
+
        free(rename_dst);
        rename_dst = NULL;
        rename_dst_nr = rename_dst_alloc = 0;
index 633d1ae..f1b5ca7 100644 (file)
@@ -43,7 +43,7 @@ extern void fill_filespec(struct diff_filespec *, const unsigned char *,
                          unsigned short);
 
 extern int diff_populate_filespec(struct diff_filespec *, int);
-extern void diff_free_filespec(struct diff_filespec *);
+extern void diff_free_filespec_data(struct diff_filespec *);
 
 struct diff_filepair {
        struct diff_filespec *one;
diff --git a/fetch.c b/fetch.c
index e874538..1d95ce0 100644 (file)
--- a/fetch.c
+++ b/fetch.c
@@ -33,42 +33,51 @@ static void report_missing(const char *what, const unsigned char *missing)
                what, missing_hex, sha1_to_hex(current_commit_sha1));
 }
 
-static int make_sure_we_have_it(const char *what, unsigned char *sha1)
-{
-       int status = 0;
-
-       if (!has_sha1_file(sha1)) {
-               status = fetch(sha1);
-               if (status && what)
-                       report_missing(what, sha1);
-       }
-       return status;
-}
-
 static int process(unsigned char *sha1, const char *type);
 
 static int process_tree(struct tree *tree)
 {
-       struct tree_entry_list *entries;
+       struct tree_entry_list *entry;
 
        if (parse_tree(tree))
                return -1;
 
-       for (entries = tree->entries; entries; entries = entries->next) {
-               if (process(entries->item.any->sha1,
-                           entries->directory ? tree_type : blob_type))
+       entry = tree->entries;
+       tree->entries = NULL;
+       while (entry) {
+               struct tree_entry_list *next = entry->next;
+               if (process(entry->item.any->sha1,
+                           entry->directory ? tree_type : blob_type))
                        return -1;
+               free(entry);
+               entry = next;
        }
        return 0;
 }
 
+#define COMPLETE       1U
+#define TO_FETCH       2U
+#define TO_SCAN                4U
+#define SCANNED                8U
+
+static struct commit_list *complete = NULL;
+
 static int process_commit(struct commit *commit)
 {
        if (parse_commit(commit))
                return -1;
 
+       while (complete && complete->item->date >= commit->date) {
+               pop_most_recent_commit(&complete, COMPLETE);
+       }
+
+       if (commit->object.flags & COMPLETE)
+               return 0;
+
        memcpy(current_commit_sha1, commit->object.sha1, 20);
 
+       pull_say("walk %s\n", sha1_to_hex(commit->object.sha1));
+
        if (get_tree) {
                if (process(commit->tree->object.sha1, tree_type))
                        return -1;
@@ -78,10 +87,7 @@ static int process_commit(struct commit *commit)
        if (get_history) {
                struct commit_list *parents = commit->parents;
                for (; parents; parents = parents->next) {
-                       if (has_sha1_file(parents->item->object.sha1))
-                               continue;
-                       if (process(parents->item->object.sha1,
-                                   commit_type))
+                       if (process(parents->item->object.sha1, commit_type))
                                return -1;
                }
        }
@@ -100,6 +106,10 @@ static struct object_list **process_queue_end = &process_queue;
 
 static int process_object(struct object *obj)
 {
+       if (obj->flags & SCANNED)
+               return 0;
+       obj->flags |= SCANNED;
+
        if (obj->type == commit_type) {
                if (process_commit((struct commit *)obj))
                        return -1;
@@ -126,17 +136,23 @@ static int process_object(struct object *obj)
 static int process(unsigned char *sha1, const char *type)
 {
        struct object *obj = lookup_object_type(sha1, type);
+
        if (has_sha1_file(sha1)) {
                parse_object(sha1);
                /* We already have it, so we should scan it now. */
-               return process_object(obj);
+               if (obj->flags & (SCANNED | TO_SCAN))
+                       return 0;
+               object_list_insert(obj, process_queue_end);
+               process_queue_end = &(*process_queue_end)->next;
+               obj->flags |= TO_SCAN;
+               return 0;
        }
-       if (object_list_contains(process_queue, obj))
+       if (obj->flags & (COMPLETE | TO_FETCH))
                return 0;
        object_list_insert(obj, process_queue_end);
        process_queue_end = &(*process_queue_end)->next;
+       obj->flags |= TO_FETCH;
 
-       //fprintf(stderr, "prefetch %s\n", sha1_to_hex(sha1));
        prefetch(sha1);
                
        return 0;
@@ -144,21 +160,27 @@ static int process(unsigned char *sha1, const char *type)
 
 static int loop(void)
 {
+       struct object_list *elem;
+
        while (process_queue) {
                struct object *obj = process_queue->item;
-               /*
-               fprintf(stderr, "%d objects to pull\n", 
-                       object_list_length(process_queue));
-               */
-               process_queue = process_queue->next;
+               elem = process_queue;
+               process_queue = elem->next;
+               free(elem);
                if (!process_queue)
                        process_queue_end = &process_queue;
 
-               //fprintf(stderr, "fetch %s\n", sha1_to_hex(obj->sha1));
-               
-               if (make_sure_we_have_it(obj->type ? obj->type : "object", 
-                                        obj->sha1))
-                       return -1;
+               /* If we are not scanning this object, we placed it in
+                * the queue because we needed to fetch it first.
+                */
+               if (! (obj->flags & TO_SCAN)) {
+                       if (fetch(obj->sha1)) {
+                               report_missing(obj->type
+                                              ? obj->type
+                                              : "object", obj->sha1);
+                               return -1;
+                       }
+               }
                if (!obj->type)
                        parse_object(obj->sha1);
                if (process_object(obj))
@@ -179,18 +201,30 @@ static int interpret_target(char *target, unsigned char *sha1)
        return -1;
 }
 
+static int mark_complete(const char *path, const unsigned char *sha1)
+{
+       struct commit *commit = lookup_commit_reference_gently(sha1, 1);
+       if (commit) {
+               commit->object.flags |= COMPLETE;
+               insert_by_date(commit, &complete);
+       }
+       return 0;
+}
 
 int pull(char *target)
 {
        unsigned char sha1[20];
        int fd = -1;
 
+       save_commit_buffer = 0;
        if (write_ref && current_ref) {
                fd = lock_ref_sha1(write_ref, current_ref);
                if (fd < 0)
                        return -1;
        }
 
+       for_each_ref(mark_complete);
+
        if (interpret_target(target, sha1))
                return error("Could not interpret %s as something to pull",
                             target);
index a5be3a7..8dc77c9 100755 (executable)
@@ -110,7 +110,7 @@ bisect_next_check() {
 }
 
 bisect_auto_next() {
-       bisect_next_check && bisect_next
+       bisect_next_check && bisect_next || :
 }
 
 bisect_next() {
index 81b9e6c..dcec2a9 100755 (executable)
@@ -3,7 +3,7 @@
 . git-sh-setup || die "Not a git archive"
 
 usage () {
-    echo >&2 "usage: $(basename $0)"' [<branchname> [start-point]]
+    echo >&2 "usage: $(basename $0)"' [-d <branch>] | [<branch> [start-point]]
 
 If no arguments, show available branches and mark current branch with a star.
 If one argument, create a new branch <branchname> based off of current HEAD.
@@ -12,6 +12,59 @@ If two arguments, create a new branch <branchname> based off of <start-point>.
     exit 1
 }
 
+delete_branch () {
+    option="$1" branch_name="$2"
+    headref=$(readlink "$GIT_DIR/HEAD" | sed -e 's|^refs/heads/||')
+    case ",$headref," in
+    ",$branch_name,")
+       die "Cannot delete the branch you are on." ;;
+    ,,)
+       die "What branch are you on anyway?" ;;
+    esac
+    branch=$(cat "$GIT_DIR/refs/heads/$branch_name") &&
+       branch=$(git-rev-parse --verify "$branch^0") ||
+           die "Seriously, what branch are you talking about?"
+    case "$option" in
+    -D)
+       ;;
+    *)
+       mbs=$(git-merge-base -a "$branch" HEAD | tr '\012' ' ')
+       case " $mbs " in
+       *' '$branch' '*)
+           # the merge base of branch and HEAD contains branch --
+           # which means that the HEAD contains everything in the HEAD.
+           ;;
+       *)
+           echo >&2 "The branch '$branch_name' is not a strict subset of your current HEAD.
+If you are sure you want to delete it, run 'git branch -D $branch_name'."
+           exit 1
+           ;;
+       esac
+       ;;
+    esac
+    rm -f "$GIT_DIR/refs/heads/$branch_name"
+    echo "Deleted branch $branch_name."
+    exit 0
+}
+
+while case "$#,$1" in 0,*) break ;; *,-*) ;; *) break ;; esac
+do
+       case "$1" in
+       -d | -D)
+               delete_branch "$1" "$2"
+               exit
+               ;;
+       --)
+               shift
+               break
+               ;;
+       -*)
+               usage
+               ;;
+       esac
+       shift
+done
+
 case "$#" in
 0)
        headref=$(readlink "$GIT_DIR/HEAD" | sed -e 's|^refs/heads/||')
@@ -36,11 +89,6 @@ case "$#" in
 esac
 branchname="$1"
 
-case "$branchname" in
--*)
-       usage;;
-esac
-
 rev=$(git-rev-parse --verify "$head") || exit
 
 [ -e "$GIT_DIR/refs/heads/$branchname" ] && die "$branchname already exists"
index 4a605cd..e02c7af 100755 (executable)
@@ -22,7 +22,8 @@ while [ "$#" != "0" ]; do
                force=1
                ;;
        *)
-               rev=$(git-rev-parse --verify "$arg^0") || exit
+               rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null) ||
+                       die "hey dummy, branch '$arg' doesn't exist."
                if [ -z "$rev" ]; then
                        echo "unknown flag $arg"
                        exit 1
index a21f13a..bfb8fd6 100755 (executable)
@@ -144,8 +144,32 @@ yes,yes)
 *)
        case "$repo" in
        rsync://*)
-               rsync $quiet -avz --ignore-existing "$repo/objects/" "$D/.git/objects/" &&
-               rsync $quiet -avz --ignore-existing "$repo/refs/" "$D/.git/refs/"
+               rsync $quiet -av --ignore-existing  \
+                       --exclude info "$repo/objects/" "$D/.git/objects/" &&
+               rsync $quiet -av --ignore-existing  \
+                       --exclude info "$repo/refs/" "$D/.git/refs/" || exit
+
+               # Look at objects/info/alternates for rsync -- http will
+               # support it natively and git native ones will do it on the
+               # remote end.  Not having that file is not a crime.
+               rsync -q "$repo/objects/info/alternates" "$D/.git/TMP_ALT" ||
+                       rm -f "$D/.git/TMP_ALT"
+               if test -f "$D/.git/TMP_ALT"
+               then
+                   ( cd $D &&
+                     . git-parse-remote &&
+                     resolve_alternates "$repo" <"./.git/TMP_ALT" ) |
+                   while read alt
+                   do
+                       case "$alt" in 'bad alternate: '*) die "$alt";; esac
+                       case "$quiet" in
+                       '')     echo >&2 "Getting alternate: $alt" ;;
+                       esac
+                       rsync $quiet -av --ignore-existing  \
+                           --exclude info "$alt" "$D/.git/objects" || exit
+                   done
+                   rm -f "$D/.git/TMP_ALT"
+               fi
                ;;
        http://*)
                clone_dumb_http "$repo" "$D"
index f98f8db..6c17d52 100644 (file)
@@ -1,16 +1,15 @@
 # Pass --without docs to rpmbuild if you don't want the documetnation
 Name:          git-core
 Version:       @@VERSION@@
-Release:       1
-Vendor:        Junio C Hamano <junkio@cox.net>
+Release:       1%{?dist}
 Summary:       Git core and tools
 License:       GPL
 Group:                 Development/Tools
 URL:           http://kernel.org/pub/software/scm/git/
 Source:        http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz
 BuildRequires: zlib-devel, openssl-devel, curl-devel  %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
-BuildRoot:     %{_tmppath}/%{name}-%{version}-root
-Requires:      sh-utils, curl, diffutils, rsync, rcs, openssh-clients, perl, python >= 2.4, tk
+BuildRoot:     %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+Requires:      rsync, rcs, curl, less, openssh-clients, python >= 2.4, tk
 
 %description
 This is a stupid (but extremely fast) directory content manager.  It
@@ -24,7 +23,7 @@ elsewhere for tools for ordinary humans layered on top of this.
 %setup -q
 
 %build
-make prefix=%{_prefix} all %{!?_without_docs: doc}
+make COPTS="$RPM_OPT_FLAGS" prefix=%{_prefix} all %{!?_without_docs: doc}
 
 %install
 rm -rf $RPM_BUILD_ROOT
@@ -37,17 +36,35 @@ rm -rf $RPM_BUILD_ROOT
 %files
 %defattr(-,root,root)
 %{_bindir}/*
-%{_datadir}/git-core/templates/*
+%{_datadir}/git-core/
 %doc README COPYING Documentation/*.txt
 %{!?_without_docs: %doc Documentation/*.html }
 %{!?_without_docs: %{_mandir}/man1/*.1*}
 %{!?_without_docs: %{_mandir}/man7/*.7*}
 
 %changelog
+* Fri Sep 16 2005 Chris Wright <chrisw@osdl.org> 0.99.6-1
+- update to 0.99.6
+
+* Fri Sep 16 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl>
+- Linus noticed that less is required, added to the dependencies
+
 * Sun Sep 11 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl>
 - Updated dependencies
 - Don't assume manpages are gzipped
 
+* Thu Aug 18 2005 Chris Wright <chrisw@osdl.org> 0.99.4-4
+- drop sh_utils, sh-utils, diffutils, mktemp, and openssl Requires
+- use RPM_OPT_FLAGS in spec file, drop patch0
+
+* Wed Aug 17 2005 Tom "spot" Callaway <tcallawa@redhat.com> 0.99.4-3
+- use dist tag to differentiate between branches
+- use rpm optflags by default (patch0)
+- own %{_datadir}/git-core/
+
+* Mon Aug 15 2005 Chris Wright <chrisw@osdl.org>
+- update spec file to fix Buildroot, Requires, and drop Vendor
+
 * Sun Aug 07 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl>
 - Redid the description
 - Cut overlong make line, loosened changelog a bit
index 2273944..72f17ab 100755 (executable)
@@ -183,12 +183,30 @@ do
        ;;
     rsync://*)
        TMP_HEAD="$GIT_DIR/TMP_HEAD"
-       rsync -L "$remote/$remote_name" "$TMP_HEAD" || exit 1
+       rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
        head=$(git-rev-parse TMP_HEAD)
        rm -f "$TMP_HEAD"
        test "$rsync_slurped_objects" || {
-           rsync -avz --ignore-existing "$remote/objects/" \
-               "$GIT_OBJECT_DIRECTORY/" || exit
+           rsync -av --ignore-existing --exclude info \
+               "$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit
+
+           # Look at objects/info/alternates for rsync -- http will
+           # support it natively and git native ones will do it on the remote
+           # end.  Not having that file is not a crime.
+           rsync -q "$remote/objects/info/alternates" "$GIT_DIR/TMP_ALT" ||
+                   rm -f "$GIT_DIR/TMP_ALT"
+           if test -f "$GIT_DIR/TMP_ALT"
+           then
+               resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" |
+               while read alt
+               do
+                   case "$alt" in 'bad alternate: '*) die "$alt";; esac
+                   echo >&2 "Getting alternate: $alt"
+                   rsync -av --ignore-existing --exclude info \
+                   "$alt" "$GIT_OBJECT_DIRECTORY/" || exit
+               done
+               rm -f "$GIT_DIR/TMP_ALT"
+           fi
            rsync_slurped_objects=t
        }
        ;;
index 3c5d94b..a9db0cd 100755 (executable)
@@ -153,3 +153,24 @@ get_remote_refs_for_fetch () {
            ;;
        esac
 }
+
+resolve_alternates () {
+       # original URL (xxx.git)
+       top_=`expr "$1" : '\([^:]*:/*[^/]*\)/'`
+       while read path
+       do
+               case "$path" in
+               \#* | '')
+                       continue ;;
+               /*)
+                       echo "$top_$path/" ;;
+               ../*)
+                       # relative -- ugly but seems to work.
+                       echo "$1/objects/$path/" ;;
+               *)
+                       # exit code may not be caught by the reader.
+                       echo "bad alternate: $path"
+                       exit 1 ;;
+               esac
+       done
+}
index c1b4474..8cf39e7 100755 (executable)
@@ -25,8 +25,10 @@ then
 fi
 
 merge_head=$(sed -e 's/        .*//' "$GIT_DIR"/FETCH_HEAD | tr '\012' ' ')
-merge_name=$(sed -e 's/^[0-9a-f]*      //' "$GIT_DIR"/FETCH_HEAD |
-        tr '\012' ' ')
+merge_name=$(
+    perl -e 'print join("; ", map { chomp; s/^[0-9a-f]*        //; $_ } <>)' \
+    "$GIT_DIR"/FETCH_HEAD
+)
 
 case "$merge_head" in
 '')
index 064c85c..b395d0e 100755 (executable)
@@ -58,7 +58,15 @@ then
        # all-into-one is used.
        if test "$all_into_one" != '' && test "$existing" != ''
        then
-               ( cd "$PACKDIR" && rm -f $existing )
+               ( cd "$PACKDIR" &&
+                 for e in $existing
+                 do
+                       case "$e" in
+                       ./pack-$name.pack | ./pack-$name.idx) ;;
+                       *)      rm -f $e ;;
+                       esac
+                 done
+               )
        fi
 fi
 
index 107c895..8f0984b 100755 (executable)
@@ -108,7 +108,7 @@ sub changelog_input {
                if ($pstate == 1) {
                        my ($email);
 
-                       next unless /^Author: (.*)<(.*)>.*$/;
+                       next unless /^[Aa]uthor:? (.*)<(.*)>.*$/;
        
                        $n_records++;
        
index 4e564fc..17051fe 100644 (file)
 #endif
 
 static CURL *curl;
+static struct curl_slist *no_pragma_header;
 
-static char *base;
+static char *initial_base;
+
+struct alt_base
+{
+       char *base;
+       int got_indices;
+       struct packed_git *packs;
+       struct alt_base *next;
+};
+
+struct alt_base *alt = NULL;
 
 static SHA_CTX c;
 static z_stream stream;
@@ -71,11 +82,9 @@ void prefetch(unsigned char *sha1)
 {
 }
 
-static int got_indices = 0;
-
-static struct packed_git *packs = NULL;
+static int got_alternates = 0;
 
-static int fetch_index(unsigned char *sha1)
+static int fetch_index(struct alt_base *repo, unsigned char *sha1)
 {
        char *filename;
        char *url;
@@ -89,9 +98,9 @@ static int fetch_index(unsigned char *sha1)
                fprintf(stderr, "Getting index for pack %s\n",
                        sha1_to_hex(sha1));
        
-       url = xmalloc(strlen(base) + 64);
+       url = xmalloc(strlen(repo->base) + 64);
        sprintf(url, "%s/objects/pack/pack-%s.idx",
-               base, sha1_to_hex(sha1));
+               repo->base, sha1_to_hex(sha1));
        
        filename = sha1_pack_index_name(sha1);
        indexfile = fopen(filename, "w");
@@ -102,6 +111,7 @@ static int fetch_index(unsigned char *sha1)
        curl_easy_setopt(curl, CURLOPT_FILE, indexfile);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
        curl_easy_setopt(curl, CURLOPT_URL, url);
+       curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_pragma_header);
        
        if (curl_easy_perform(curl)) {
                fclose(indexfile);
@@ -112,22 +122,92 @@ static int fetch_index(unsigned char *sha1)
        return 0;
 }
 
-static int setup_index(unsigned char *sha1)
+static int setup_index(struct alt_base *repo, unsigned char *sha1)
 {
        struct packed_git *new_pack;
        if (has_pack_file(sha1))
                return 0; // don't list this as something we can get
 
-       if (fetch_index(sha1))
+       if (fetch_index(repo, sha1))
                return -1;
 
        new_pack = parse_pack_index(sha1);
-       new_pack->next = packs;
-       packs = new_pack;
+       new_pack->next = repo->packs;
+       repo->packs = new_pack;
        return 0;
 }
 
-static int fetch_indices(void)
+static int fetch_alternates(char *base)
+{
+       int ret = 0;
+       struct buffer buffer;
+       char *url;
+       char *data;
+       int i = 0;
+       if (got_alternates)
+               return 0;
+       data = xmalloc(4096);
+       buffer.size = 4096;
+       buffer.posn = 0;
+       buffer.buffer = data;
+
+       if (get_verbosely)
+               fprintf(stderr, "Getting alternates list\n");
+       
+       url = xmalloc(strlen(base) + 31);
+       sprintf(url, "%s/objects/info/http-alternates", base);
+
+       curl_easy_setopt(curl, CURLOPT_FILE, &buffer);
+       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
+       curl_easy_setopt(curl, CURLOPT_URL, url);
+
+       if (curl_easy_perform(curl) || !buffer.posn) {
+               sprintf(url, "%s/objects/info/alternates", base);
+               
+               curl_easy_setopt(curl, CURLOPT_FILE, &buffer);
+               curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
+               curl_easy_setopt(curl, CURLOPT_URL, url);
+               
+               if (curl_easy_perform(curl)) {
+                       return 0;
+               }
+       }
+
+       while (i < buffer.posn) {
+               int posn = i;
+               while (posn < buffer.posn && data[posn] != '\n')
+                       posn++;
+               if (data[posn] == '\n') {
+                       if (data[i] == '/') {
+                               int serverlen = strchr(base + 8, '/') - base;
+                               // skip 'objects' at end
+                               char *target = 
+                                       xmalloc(serverlen + posn - i - 6);
+                               struct alt_base *newalt;
+                               strncpy(target, base, serverlen);
+                               strncpy(target + serverlen, data + i,
+                                       posn - i - 7);
+                               target[serverlen + posn - i - 7] = '\0';
+                               if (get_verbosely)
+                                       fprintf(stderr, 
+                                               "Also look at %s\n", target);
+                               newalt = xmalloc(sizeof(*newalt));
+                               newalt->next = alt;
+                               newalt->base = target;
+                               newalt->got_indices = 0;
+                               newalt->packs = NULL;
+                               alt = newalt;
+                               ret++;
+                       }
+               }
+               i = posn + 1;
+       }
+       got_alternates = 1;
+       
+       return ret;
+}
+
+static int fetch_indices(struct alt_base *repo)
 {
        unsigned char sha1[20];
        char *url;
@@ -135,7 +215,7 @@ static int fetch_indices(void)
        char *data;
        int i = 0;
 
-       if (got_indices)
+       if (repo->got_indices)
                return 0;
 
        data = xmalloc(4096);
@@ -146,18 +226,19 @@ static int fetch_indices(void)
        if (get_verbosely)
                fprintf(stderr, "Getting pack list\n");
        
-       url = xmalloc(strlen(base) + 21);
-       sprintf(url, "%s/objects/info/packs", base);
+       url = xmalloc(strlen(repo->base) + 21);
+       sprintf(url, "%s/objects/info/packs", repo->base);
 
        curl_easy_setopt(curl, CURLOPT_FILE, &buffer);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
        curl_easy_setopt(curl, CURLOPT_URL, url);
+       curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
        
        if (curl_easy_perform(curl)) {
                return error("Unable to get pack index %s", url);
        }
 
-       do {
+       while (i < buffer.posn) {
                switch (data[i]) {
                case 'P':
                        i++;
@@ -165,7 +246,7 @@ static int fetch_indices(void)
                            !strncmp(data + i, " pack-", 6) &&
                            !strncmp(data + i + 46, ".pack\n", 6)) {
                                get_sha1_hex(data + i + 6, sha1);
-                               setup_index(sha1);
+                               setup_index(repo, sha1);
                                i += 51;
                                break;
                        }
@@ -174,13 +255,13 @@ static int fetch_indices(void)
                                i++;
                }
                i++;
-       } while (i < buffer.posn);
+       }
 
-       got_indices = 1;
+       repo->got_indices = 1;
        return 0;
 }
 
-static int fetch_pack(unsigned char *sha1)
+static int fetch_pack(struct alt_base *repo, unsigned char *sha1)
 {
        char *url;
        struct packed_git *target;
@@ -188,12 +269,11 @@ static int fetch_pack(unsigned char *sha1)
        FILE *packfile;
        char *filename;
 
-       if (fetch_indices())
+       if (fetch_indices(repo))
                return -1;
-       target = find_sha1_pack(sha1, packs);
+       target = find_sha1_pack(sha1, repo->packs);
        if (!target)
-               return error("Couldn't get %s: not separate or in any pack",
-                            sha1_to_hex(sha1));
+               return -1;
 
        if (get_verbosely) {
                fprintf(stderr, "Getting pack %s\n",
@@ -202,9 +282,9 @@ static int fetch_pack(unsigned char *sha1)
                        sha1_to_hex(sha1));
        }
 
-       url = xmalloc(strlen(base) + 65);
+       url = xmalloc(strlen(repo->base) + 65);
        sprintf(url, "%s/objects/pack/pack-%s.pack",
-               base, sha1_to_hex(target->sha1));
+               repo->base, sha1_to_hex(target->sha1));
 
        filename = sha1_pack_name(target->sha1);
        packfile = fopen(filename, "w");
@@ -215,6 +295,7 @@ static int fetch_pack(unsigned char *sha1)
        curl_easy_setopt(curl, CURLOPT_FILE, packfile);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
        curl_easy_setopt(curl, CURLOPT_URL, url);
+       curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_pragma_header);
        
        if (curl_easy_perform(curl)) {
                fclose(packfile);
@@ -223,7 +304,7 @@ static int fetch_pack(unsigned char *sha1)
 
        fclose(packfile);
 
-       lst = &packs;
+       lst = &repo->packs;
        while (*lst != target)
                lst = &((*lst)->next);
        *lst = (*lst)->next;
@@ -233,7 +314,7 @@ static int fetch_pack(unsigned char *sha1)
        return 0;
 }
 
-int fetch(unsigned char *sha1)
+int fetch_object(struct alt_base *repo, unsigned char *sha1)
 {
        char *hex = sha1_to_hex(sha1);
        char *filename = sha1_file_name(sha1);
@@ -255,10 +336,11 @@ int fetch(unsigned char *sha1)
        curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
        curl_easy_setopt(curl, CURLOPT_FILE, NULL);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
+       curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_pragma_header);
 
-       url = xmalloc(strlen(base) + 50);
-       strcpy(url, base);
-       posn = url + strlen(base);
+       url = xmalloc(strlen(repo->base) + 50);
+       strcpy(url, repo->base);
+       posn = url + strlen(repo->base);
        strcpy(posn, "objects/");
        posn += 8;
        memcpy(posn, hex, 2);
@@ -270,9 +352,7 @@ int fetch(unsigned char *sha1)
 
        if (curl_easy_perform(curl)) {
                unlink(filename);
-               if (fetch_pack(sha1))
-                       return error("Tried %s", url);
-               return 0;
+               return -1;
        }
 
        close(local);
@@ -291,11 +371,30 @@ int fetch(unsigned char *sha1)
        return 0;
 }
 
+int fetch(unsigned char *sha1)
+{
+       struct alt_base *altbase = alt;
+       while (altbase) {
+               if (!fetch_object(altbase, sha1))
+                       return 0;
+               if (!fetch_pack(altbase, sha1))
+                       return 0;
+               if (fetch_alternates(altbase->base) > 0) {
+                       altbase = alt;
+                       continue;
+               }
+               altbase = altbase->next;
+       }
+       return error("Unable to find %s under %s\n", sha1_to_hex(sha1), 
+                    initial_base);
+}
+
 int fetch_ref(char *ref, unsigned char *sha1)
 {
         char *url, *posn;
         char hex[42];
         struct buffer buffer;
+       char *base = initial_base;
         buffer.size = 41;
         buffer.posn = 0;
         buffer.buffer = hex;
@@ -303,6 +402,7 @@ int fetch_ref(char *ref, unsigned char *sha1)
         
         curl_easy_setopt(curl, CURLOPT_FILE, &buffer);
         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
+       curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
 
         url = xmalloc(strlen(base) + 6 + strlen(ref));
         strcpy(url, base);
@@ -354,6 +454,7 @@ int main(int argc, char **argv)
        curl_global_init(CURL_GLOBAL_ALL);
 
        curl = curl_easy_init();
+       no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
 
        curl_ssl_verify = getenv("GIT_SSL_NO_VERIFY") ? 0 : 1;
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, curl_ssl_verify);
@@ -361,11 +462,17 @@ int main(int argc, char **argv)
        curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
 #endif
 
-       base = url;
+       alt = xmalloc(sizeof(*alt));
+       alt->base = url;
+       alt->got_indices = 0;
+       alt->packs = NULL;
+       alt->next = NULL;
+       initial_base = url;
 
        if (pull(commit_id))
                return 1;
 
+       curl_slist_free_all(no_pragma_header);
        curl_global_cleanup();
        return 0;
 }
diff --git a/ident.c b/ident.c
index 0df2d97..a2d241f 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -36,13 +36,11 @@ int setup_ident(void)
        memcpy(real_email, pw->pw_name, len);
        real_email[len++] = '@';
        gethostname(real_email + len, sizeof(real_email) - len);
-#ifndef NO_GETDOMAINNAME
        if (!strchr(real_email+len, '.')) {
                len = strlen(real_email);
                real_email[len++] = '.';
                getdomainname(real_email+len, sizeof(real_email)-len);
        }
-#endif
        /* And set the default date */
        datestamp(real_date, sizeof(real_date));
        return 0;
index 63e6e78..1fdebe0 100644 (file)
--- a/object.c
+++ b/object.c
@@ -9,6 +9,8 @@ struct object **objs;
 int nr_objs;
 static int obj_allocs;
 
+int track_object_refs = 1;
+
 static int find_object(const unsigned char *sha1)
 {
        int first = 0, last = nr_objs;
@@ -67,9 +69,12 @@ void created_object(const unsigned char *sha1, struct object *obj)
 
 void add_ref(struct object *refer, struct object *target)
 {
-       struct object_list **pp = &refer->refs;
-       struct object_list *p;
-       
+       struct object_list **pp, *p;
+
+       if (!track_object_refs)
+               return;
+
+       pp = &refer->refs;
        while ((p = *pp) != NULL) {
                if (p->item == target)
                        return;
@@ -87,6 +92,8 @@ void mark_reachable(struct object *obj, unsigned int mask)
 {
        struct object_list *p = obj->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;
index bf74449..6accda3 100644 (file)
--- a/object.h
+++ b/object.h
@@ -17,6 +17,7 @@ struct object {
        void *util;
 };
 
+extern int track_object_refs;
 extern int nr_objs;
 extern struct object **objs;
 
diff --git a/rev-cache.c b/rev-cache.c
deleted file mode 100644 (file)
index 6344d62..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-#include "refs.h"
-#include "cache.h"
-#include "rev-cache.h"
-
-struct rev_cache **rev_cache;
-int nr_revs, alloc_revs;
-
-static struct rev_list_elem *rle_free;
-
-#define BATCH_SIZE 512
-
-int find_rev_cache(const unsigned char *sha1)
-{
-       int lo = 0, hi = nr_revs;
-       while (lo < hi) {
-               int mi = (lo + hi) / 2;
-               struct rev_cache *ri = rev_cache[mi];
-               int cmp = memcmp(sha1, ri->sha1, 20);
-               if (!cmp)
-                       return mi;
-               if (cmp < 0)
-                       hi = mi;
-               else
-                       lo = mi + 1;
-       }
-       return -lo - 1;
-}
-
-static struct rev_list_elem *alloc_list_elem(void)
-{
-       struct rev_list_elem *rle;
-       if (!rle_free) {
-               int i;
-
-               rle = xmalloc(sizeof(*rle) * BATCH_SIZE);
-               for (i = 0; i < BATCH_SIZE - 1; i++) {
-                       rle[i].ri = NULL;
-                       rle[i].next = &rle[i + 1];
-               }
-               rle[BATCH_SIZE - 1].ri = NULL;
-               rle[BATCH_SIZE - 1].next = NULL;
-               rle_free = rle;
-       }
-       rle = rle_free;
-       rle_free = rle->next;
-       return rle;
-}
-
-static struct rev_cache *create_rev_cache(const unsigned char *sha1)
-{
-       struct rev_cache *ri;
-       int pos = find_rev_cache(sha1);
-
-       if (0 <= pos)
-               return rev_cache[pos];
-       pos = -pos - 1;
-       if (alloc_revs <= ++nr_revs) {
-               alloc_revs = alloc_nr(alloc_revs);
-               rev_cache = xrealloc(rev_cache, sizeof(ri) * alloc_revs);
-       }
-       if (pos < nr_revs)
-               memmove(rev_cache + pos + 1, rev_cache + pos,
-                       (nr_revs - pos - 1) * sizeof(ri));
-       ri = xcalloc(1, sizeof(*ri));
-       memcpy(ri->sha1, sha1, 20);
-       rev_cache[pos] = ri;
-       return ri;
-}
-
-static unsigned char last_sha1[20];
-
-static void write_one_rev_cache(FILE *rev_cache_file, struct rev_cache *ri)
-{
-       unsigned char flag;
-       struct rev_list_elem *rle;
-
-       if (ri->written)
-               return;
-
-       if (ri->parsed) {
-               /* We use last_sha1 compression only for the first parent;
-                * otherwise the resulting rev-cache would lose the parent
-                * order information.
-                */
-               if (ri->parents &&
-                   !memcmp(ri->parents->ri->sha1, last_sha1, 20))
-                       flag = (ri->num_parents - 1) | 0x80;
-               else
-                       flag = ri->num_parents;
-
-               fwrite(ri->sha1, 20, 1, rev_cache_file);
-               fwrite(&flag, 1, 1, rev_cache_file);
-               for (rle = ri->parents; rle; rle = rle->next) {
-                       if (flag & 0x80 && rle == ri->parents)
-                               continue;
-                       fwrite(rle->ri->sha1, 20, 1, rev_cache_file);
-               }
-               memcpy(last_sha1, ri->sha1, 20);
-               ri->written = 1;
-       }
-       /* recursively write children depth first */
-       for (rle = ri->children; rle; rle = rle->next)
-               write_one_rev_cache(rev_cache_file, rle->ri);
-}
-
-void write_rev_cache(const char *newpath, const char *oldpath)
-{
-       /* write the following commit ancestry information in
-        * $GIT_DIR/info/rev-cache.
-        *
-        * The format is:
-        * 20-byte SHA1 (commit ID)
-        * 1-byte flag:
-        * - bit 0-6 records "number of parent commit SHA1s to
-        *   follow" (i.e. up to 127 children can be listed).
-        * - when the bit 7 is on, then "the entry immediately
-        *   before this entry is one of the parents of this
-         *   commit".
-        * N x 20-byte SHA1 (parent commit IDs)
-        */
-       FILE *rev_cache_file;
-       int i;
-       struct rev_cache *ri;
-
-       if (!strcmp(newpath, oldpath)) {
-               /* If we are doing it in place */
-               rev_cache_file = fopen(newpath, "a");
-       }
-       else {
-               char buf[8096];
-               size_t sz;
-               FILE *oldfp = fopen(oldpath, "r");
-               rev_cache_file = fopen(newpath, "w");
-               if (oldfp) {
-                       while (1) {
-                               sz = fread(buf, 1, sizeof(buf), oldfp);
-                               if (sz == 0)
-                                       break;
-                               fwrite(buf, 1, sz, rev_cache_file);
-                       }
-                       fclose(oldfp);
-               }
-       }
-
-       memset(last_sha1, 0, 20);
-
-       /* Go through available rev_cache structures, starting from
-        * parentless ones first, so that we would get most out of
-        * last_sha1 optimization by the depth first behaviour of
-        * write_one_rev_cache().
-        */
-       for (i = 0; i < nr_revs; i++) {
-               ri = rev_cache[i];
-               if (ri->num_parents)
-                       continue;
-               write_one_rev_cache(rev_cache_file, ri);
-       }
-       /* Then the rest */
-       for (i = 0; i < nr_revs; i++) {
-               ri = rev_cache[i];
-               write_one_rev_cache(rev_cache_file, ri);
-       }
-       fclose(rev_cache_file);
-}
-
-static void add_parent(struct rev_cache *child,
-                      const unsigned char *parent_sha1)
-{
-       struct rev_cache *parent = create_rev_cache(parent_sha1);
-       struct rev_list_elem *e = alloc_list_elem();
-
-       /* Keep the parent list ordered in the same way the commit
-        * object records them.
-        */
-       e->ri = parent;
-       e->next = NULL;
-       if (!child->parents_tail)
-               child->parents = e;
-       else
-               child->parents_tail->next = e;
-       child->parents_tail = e;
-       child->num_parents++;
-
-       /* There is no inherent order of the children so we just
-        * LIFO them together.
-        */
-       e = alloc_list_elem();
-       e->next = parent->children;
-       parent->children = e;
-       e->ri = child;
-       parent->num_children++;
-}
-
-int read_rev_cache(const char *path, FILE *dumpfile, int dry_run)
-{
-       unsigned char *map;
-       int fd;
-       struct stat st;
-       unsigned long ofs, len;
-       struct rev_cache *ri = NULL;
-
-       fd = open(path, O_RDONLY);
-       if (fd < 0) {
-               if (dry_run)
-                       return error("cannot open %s", path);
-               if (errno == ENOENT)
-                       return 0;
-               return -1;
-       }
-       if (fstat(fd, &st)) {
-               close(fd);
-               return -1;
-       }
-       map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-       close(fd);
-       if (map == MAP_FAILED)
-               return -1;
-
-       memset(last_sha1, 0, 20);
-       ofs = 0;
-       len = st.st_size;
-       while (ofs < len) {
-               unsigned char sha1[20];
-               int flag, cnt, i;
-               if (len < ofs + 21)
-                       die("rev-cache too short");
-               memcpy(sha1, map + ofs, 20);
-               flag = map[ofs + 20];
-               ofs += 21;
-               cnt = (flag & 0x7f) + ((flag & 0x80) != 0);
-               if (len < ofs + (flag & 0x7f) * 20)
-                       die("rev-cache too short to have %d more parents",
-                           (flag & 0x7f));
-               if (dumpfile)
-                       fprintf(dumpfile, "%s", sha1_to_hex(sha1));
-               if (!dry_run) {
-                       ri = create_rev_cache(sha1);
-                       if (!ri)
-                               die("cannot create rev-cache for %s",
-                                   sha1_to_hex(sha1));
-                       ri->written = ri->parsed = 1;
-               }
-               i = 0;
-               if (flag & 0x80) {
-                       if (!dry_run)
-                               add_parent(ri, last_sha1);
-                       if (dumpfile)
-                               fprintf(dumpfile, " %s",
-                                       sha1_to_hex(last_sha1));
-                       i++;
-               }
-               while (i++ < cnt) {
-                       if (!dry_run)
-                               add_parent(ri, map + ofs);
-                       if (dumpfile)
-                               fprintf(dumpfile, " %s",
-                                       sha1_to_hex(last_sha1));
-                       ofs += 20;
-               }
-               if (dumpfile)
-                       fprintf(dumpfile, "\n");
-               memcpy(last_sha1, sha1, 20);
-       }
-       if (ofs != len)
-               die("rev-cache truncated?");
-       munmap(map, len);
-       return 0;
-}
-
-int record_rev_cache(const unsigned char *sha1, FILE *dumpfile)
-{
-       unsigned char parent[20];
-       char type[20];
-       unsigned long size, ofs;
-       unsigned int cnt, i;
-       void *buf;
-       struct rev_cache *ri;
-
-       buf = read_sha1_file(sha1, type, &size);
-       if (!buf)
-               return error("%s: not found", sha1_to_hex(sha1));
-       if (strcmp(type, "commit")) {
-               free(buf);
-               return error("%s: not a commit but a %s",
-                            sha1_to_hex(sha1), type);
-       }
-       ri = create_rev_cache(sha1);
-       if (ri->parsed)
-               return 0;
-       if (dumpfile)
-               fprintf(dumpfile, "commit %s\n", sha1_to_hex(sha1));
-
-       cnt = 0;
-       ofs = 46; /* "tree " + hex-sha1 + "\n" */
-       while (!memcmp(buf + ofs, "parent ", 7) &&
-              !get_sha1_hex(buf + ofs + 7, parent)) {
-               ofs += 48;
-               cnt++;
-       }
-       if (cnt * 48 + 46 != ofs) {
-               free(buf);
-               die("internal error in record_rev_cache");
-       }
-
-       ri = create_rev_cache(sha1);
-       ri->parsed = 1;
-
-       for (i = 0; i < cnt; i++) {
-               unsigned char parent_sha1[20];
-
-               ofs = 46 + i * 48 + 7;
-               get_sha1_hex(buf + ofs, parent_sha1);
-               add_parent(ri, parent_sha1);
-               record_rev_cache(parent_sha1, dumpfile);
-       }
-       free(buf);
-       return 0;
-}
diff --git a/rev-cache.h b/rev-cache.h
deleted file mode 100644 (file)
index b238ac6..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef REV_CACHE_H
-#define REV_CACHE_H
-
-extern struct rev_cache {
-       struct rev_cache *head_list;
-       struct rev_list_elem *children;
-       struct rev_list_elem *parents;
-       struct rev_list_elem *parents_tail;
-       unsigned short num_parents;
-       unsigned short num_children;
-       unsigned int written : 1;
-       unsigned int parsed : 1;
-       unsigned int work : 30;
-       void *work_ptr;
-       unsigned char sha1[20];
-} **rev_cache;
-extern int nr_revs, alloc_revs;
-
-struct rev_list_elem {
-       struct rev_list_elem *next;
-       struct rev_cache *ri;
-};
-
-extern int find_rev_cache(const unsigned char *);
-extern int read_rev_cache(const char *, FILE *, int);
-extern int record_rev_cache(const unsigned char *, FILE *);
-extern void write_rev_cache(const char *new, const char *old);
-
-#endif
index 2d97cdb..e41d5a0 100644 (file)
@@ -147,11 +147,16 @@ static struct object_list **process_tree(struct tree *tree, struct object_list *
                die("bad tree object %s", sha1_to_hex(obj->sha1));
        obj->flags |= SEEN;
        p = add_object(obj, p, name);
-       for (entry = tree->entries ; entry ; entry = entry->next) {
+       entry = tree->entries;
+       tree->entries = NULL;
+       while (entry) {
+               struct tree_entry_list *next = entry->next;
                if (entry->directory)
                        p = process_tree(entry->item.tree, p, entry->name);
                else
                        p = process_blob(entry->item.blob, p, entry->name);
+               free(entry);
+               entry = next;
        }
        return p;
 }
@@ -218,12 +223,15 @@ static void mark_tree_uninteresting(struct tree *tree)
        if (parse_tree(tree) < 0)
                die("bad tree %s", sha1_to_hex(obj->sha1));
        entry = tree->entries;
+       tree->entries = NULL;
        while (entry) {
+               struct tree_entry_list *next = entry->next;
                if (entry->directory)
                        mark_tree_uninteresting(entry->item.tree);
                else
                        mark_blob_uninteresting(entry->item.blob);
-               entry = entry->next;
+               free(entry);
+               entry = next;
        }
 }
 
@@ -231,8 +239,6 @@ static void mark_parents_uninteresting(struct commit *commit)
 {
        struct commit_list *parents = commit->parents;
 
-       if (tree_objects)
-               mark_tree_uninteresting(commit->tree);
        while (parents) {
                struct commit *commit = parents->item;
                commit->object.flags |= UNINTERESTING;
@@ -272,29 +278,6 @@ static int everybody_uninteresting(struct commit_list *orig)
                        continue;
                return 0;
        }
-
-       /*
-        * Ok, go back and mark all the edge trees uninteresting,
-        * since otherwise we can have situations where a parent
-        * that was marked uninteresting (and we never even had
-        * to look at) had lots of objects that we don't want to
-        * include.
-        *
-        * NOTE! This still doesn't mean that the object list is
-        * "correct", since we may end up listing objects that
-        * even older commits (that we don't list) do actually
-        * reference, but it gets us to a minimal list (or very
-        * close) in practice.
-        */
-       if (!tree_objects)
-               return 1;
-
-       while (orig) {
-               struct commit *commit = orig->item;
-               if (!parse_commit(commit) && commit->tree)
-                       mark_tree_uninteresting(commit->tree);
-               orig = orig->next;
-       }
        return 1;
 }
 
@@ -370,6 +353,19 @@ static struct commit_list *find_bisection(struct commit_list *list)
        return best;
 }
 
+static void mark_edges_uninteresting(struct commit_list *list)
+{
+       for ( ; list; list = list->next) {
+               struct commit_list *parents = list->item->parents;
+
+               for ( ; parents; parents = parents->next) {
+                       struct commit *commit = parents->item;
+                       if (commit->object.flags & UNINTERESTING)
+                               mark_tree_uninteresting(commit->tree);
+               }
+       }
+}
+
 static struct commit_list *limit_list(struct commit_list *list)
 {
        struct commit_list *newlist = NULL;
@@ -388,6 +384,8 @@ static struct commit_list *limit_list(struct commit_list *list)
                }
                p = &commit_list_insert(commit, p)->next;
        }
+       if (tree_objects)
+               mark_edges_uninteresting(newlist);
        if (bisect_list)
                newlist = find_bisection(newlist);
        return newlist;
@@ -563,6 +561,8 @@ int main(int argc, char **argv)
                        struct commit *exclude = NULL;
                        struct commit *include = NULL;
                        *dotdot = 0;
+                       if (!*next)
+                               next = "HEAD";
                        exclude = get_commit_reference(arg, UNINTERESTING);
                        include = get_commit_reference(next, 0);
                        if (exclude && include) {
@@ -571,7 +571,7 @@ int main(int argc, char **argv)
                                handle_one_commit(include, &list);
                                continue;
                        }
-                       *next = '.';
+                       *dotdot = '.';
                }
                if (*arg == '^') {
                        flags = UNINTERESTING;
@@ -582,6 +582,9 @@ int main(int argc, char **argv)
                handle_one_commit(commit, &list);
        }
 
+       save_commit_buffer = verbose_header;
+       track_object_refs = 0;
+
        if (!merge_order) {             
                sort_by_date(&list);
                if (limited)
diff --git a/rsh.c b/rsh.c
index 04cbdf7..1c63686 100644 (file)
--- a/rsh.c
+++ b/rsh.c
@@ -8,6 +8,71 @@
 
 #define COMMAND_SIZE 4096
 
+/*
+ * Write a shell-quoted version of a string into a buffer, and
+ * return bytes that ought to be output excluding final null.
+ */
+static int shell_quote(char *buf, int nmax, const char *str)
+{
+       char ch;
+       int nq;
+       int oc = 0;
+
+       while ( (ch = *str++) ) {
+               nq = 0;
+               if ( strchr(" !\"#$%&\'()*;<=>?[\\]^`{|}", ch) )
+                       nq = 1;
+
+               if ( nq ) {
+                       if ( nmax > 1 ) {
+                               *buf++ = '\\';
+                               nmax--;
+                       }
+                       oc++;
+               }
+
+               if ( nmax > 1 ) {
+                       *buf++ = ch;
+                       nmax--;
+               }
+               oc++;
+       }
+
+       if ( nmax )
+               *buf = '\0';
+
+       return oc;
+}
+                       
+/*
+ * Append a string to a string buffer, with or without quoting.  Return true
+ * if the buffer overflowed.
+ */
+static int add_to_string(char **ptrp, int *sizep, const char *str, int quote)
+{
+       char *p = *ptrp;
+       int size = *sizep;
+       int oc;
+
+       if ( quote ) {
+               oc = shell_quote(p, size, str);
+       } else {
+               oc = strlen(str);
+               memcpy(p, str, (oc >= size) ? size-1 : oc);
+       }
+
+       if ( oc >= size ) {
+               p[size-1] = '\0';
+               *ptrp += size-1;
+               *sizep = 1;
+               return 1;       /* Overflow, string unusable */
+       }
+
+       *ptrp  += oc;
+       *sizep -= oc;
+       return 0;
+}
+
 int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, 
                     char *url, int rmt_argc, char **rmt_argv)
 {
@@ -16,6 +81,8 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog,
        int sv[2];
        char command[COMMAND_SIZE];
        char *posn;
+       int sizen;
+       int of;
        int i;
 
        if (!strcmp(url, "-")) {
@@ -37,24 +104,30 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog,
        if (!path) {
                return error("Bad URL: %s", url);
        }
-       /* ssh <host> 'cd <path>; stdio-pull <arg...> <commit-id>' */
-       snprintf(command, COMMAND_SIZE, 
-                "%s='%s' %s",
-                GIT_DIR_ENVIRONMENT, path, remote_prog);
-       *path = '\0';
-       posn = command + strlen(command);
-       for (i = 0; i < rmt_argc; i++) {
-               *(posn++) = ' ';
-               strncpy(posn, rmt_argv[i], COMMAND_SIZE - (posn - command));
-               posn += strlen(rmt_argv[i]);
-               if (posn - command + 4 >= COMMAND_SIZE) {
-                       return error("Command line too long");
-               }
+       /* $GIT_RSH <host> "env GIR_DIR=<path> <remote_prog> <args...>" */
+       sizen = COMMAND_SIZE;
+       posn = command;
+       of = 0;
+       of |= add_to_string(&posn, &sizen, "env ", 0);
+       of |= add_to_string(&posn, &sizen, GIT_DIR_ENVIRONMENT, 0);
+       of |= add_to_string(&posn, &sizen, "=", 0);
+       of |= add_to_string(&posn, &sizen, path, 1);
+       of |= add_to_string(&posn, &sizen, " ", 0);
+       of |= add_to_string(&posn, &sizen, remote_prog, 1);
+
+       for ( i = 0 ; i < rmt_argc ; i++ ) {
+               of |= add_to_string(&posn, &sizen, " ", 0);
+               of |= add_to_string(&posn, &sizen, rmt_argv[i], 1);
        }
-       strcpy(posn, " -");
-       if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) {
+
+       of |= add_to_string(&posn, &sizen, " -", 0);
+
+       if ( of )
+               return error("Command line too long");
+
+       if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv))
                return error("Couldn't create socket");
-       }
+
        if (!fork()) {
                const char *ssh, *ssh_basename;
                ssh = getenv("GIT_SSH");
index 2b3aeca..a9e5607 100644 (file)
@@ -3,20 +3,9 @@
 #include "object.h"
 #include "commit.h"
 #include "tag.h"
-#include "rev-cache.h"
 
 /* refs */
 static FILE *info_ref_fp;
-static unsigned long info_ref_time;
-static int info_ref_is_stale = 0;
-
-static int stat_ref(const char *path, const unsigned char *sha1)
-{
-       struct stat st;
-       if (!stat(path, &st) && info_ref_time < st.st_mtime)
-               info_ref_is_stale = 1;
-       return 0;
-}
 
 static int add_info_ref(const char *path, const unsigned char *sha1)
 {
@@ -26,7 +15,6 @@ static int add_info_ref(const char *path, const unsigned char *sha1)
 
 static int update_info_refs(int force)
 {
-       struct stat st;
        char *path0 = strdup(git_path("info/refs"));
        int len = strlen(path0);
        char *path1 = xmalloc(len + 2);
@@ -34,21 +22,6 @@ static int update_info_refs(int force)
        strcpy(path1, path0);
        strcpy(path1 + len, "+");
 
-       if (!force) {
-               if (stat(path0, &st)) {
-                       if (errno == ENOENT)
-                               info_ref_is_stale = 1;
-                       else
-                               return error("cannot stat %s", path0);
-               }
-               else {
-                       info_ref_time = st.st_mtime;
-                       for_each_ref(stat_ref);
-               }
-               if (!info_ref_is_stale)
-                       return 0;
-       }
-
        safe_create_leading_directories(path0);
        info_ref_fp = fopen(path1, "w");
        if (!info_ref_fp)
@@ -516,45 +489,6 @@ static int update_info_packs(int force)
        return 0;
 }
 
-/* rev-cache */
-static int record_rev_cache_ref(const char *path, const unsigned char *sha1)
-{
-       struct object *obj = parse_object(sha1);
-
-       if (!obj)
-               return error("ref %s has bad sha %s", path, sha1_to_hex(sha1));
-       while (obj && obj->type == tag_type)
-               obj = parse_object(((struct tag *)obj)->tagged->sha1);
-       if (!obj || obj->type != commit_type)
-               /* tag pointing at a non-commit */
-               return 0;
-       return record_rev_cache(obj->sha1, NULL);
-}
-
-static int update_info_revs(int force)
-{
-       char *path0 = strdup(git_path("info/rev-cache"));
-       int len = strlen(path0);
-       char *path1 = xmalloc(len + 2);
-
-       strcpy(path1, path0);
-       strcpy(path1 + len, "+");
-
-       /* read existing rev-cache */
-       if (!force)
-               read_rev_cache(path0, NULL, 0);
-       safe_create_leading_directories(path0);
-
-       for_each_ref(record_rev_cache_ref);
-
-       /* update the rev-cache database */
-       write_rev_cache(path1, force ? "/dev/null" : path0);
-       rename(path1, path0);
-       free(path1);
-       free(path0);
-       return 0;
-}
-
 /* public */
 int update_server_info(int force)
 {
@@ -566,7 +500,6 @@ int update_server_info(int force)
 
        errs = errs | update_info_refs(force);
        errs = errs | update_info_packs(force);
-       errs = errs | update_info_revs(force);
 
        return errs;
 }
diff --git a/show-rev-cache.c b/show-rev-cache.c
deleted file mode 100644 (file)
index fa92b87..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "cache.h"
-#include "rev-cache.h"
-
-static char *show_rev_cache_usage =
-"git-show-rev-cache <rev-cache-file>";
-
-int main(int ac, char **av)
-{
-       while (1 < ac && av[0][1] == '-') {
-               /* do flags here */
-               break;
-               ac--; av++;
-       }
-       if (ac != 2)
-               usage(show_rev_cache_usage);
-
-       return read_rev_cache(av[1], stdout, 1);
-}
index d8f4368..683a1e4 100644 (file)
@@ -1,3 +1,13 @@
+#ifndef COUNTERPART_ENV_NAME
+#define COUNTERPART_ENV_NAME "GIT_SSH_UPLOAD"
+#endif
+#ifndef COUNTERPART_PROGRAM_NAME
+#define COUNTERPART_PROGRAM_NAME "git-ssh-upload"
+#endif
+#ifndef MY_PROGRAM_NAME
+#define MY_PROGRAM_NAME "git-ssh-fetch"
+#endif
+
 #include "cache.h"
 #include "commit.h"
 #include "rsh.h"
@@ -82,6 +92,9 @@ int fetch_ref(char *ref, unsigned char *sha1)
        return 0;
 }
 
+static const char ssh_fetch_usage[] =
+  MY_PROGRAM_NAME
+  " [-c] [-t] [-a] [-v] [-d] [--recover] [-w ref] commit-id url";
 int main(int argc, char **argv)
 {
        char *commit_id;
@@ -110,7 +123,7 @@ int main(int argc, char **argv)
                arg++;
        }
        if (argc < arg + 2) {
-               usage("git-ssh-fetch [-c] [-t] [-a] [-v] [-d] [--recover] [-w ref] commit-id url");
+               usage(ssh_fetch_usage);
                return 1;
        }
        commit_id = argv[arg];
diff --git a/ssh-pull.c b/ssh-pull.c
new file mode 100644 (file)
index 0000000..868ce4d
--- /dev/null
@@ -0,0 +1,4 @@
+#define COUNTERPART_ENV_NAME "GIT_SSH_PUSH"
+#define COUNTERPART_PROGRAM_NAME "git-ssh-push"
+#define MY_PROGRAM_NAME "git-ssh-pull"
+#include "ssh-fetch.c"
diff --git a/ssh-push.c b/ssh-push.c
new file mode 100644 (file)
index 0000000..a562df1
--- /dev/null
@@ -0,0 +1,4 @@
+#define COUNTERPART_ENV_NAME "GIT_SSH_PULL"
+#define COUNTERPART_PROGRAM_NAME "git-ssh-pull"
+#define MY_PROGRAM_NAME "git-ssh-push"
+#include "ssh-upload.c"
index 10a3687..603abcc 100644 (file)
@@ -1,3 +1,13 @@
+#ifndef COUNTERPART_ENV_NAME
+#define COUNTERPART_ENV_NAME "GIT_SSH_FETCH"
+#endif
+#ifndef COUNTERPART_PROGRAM_NAME
+#define COUNTERPART_PROGRAM_NAME "git-ssh-fetch"
+#endif
+#ifndef MY_PROGRAM_NAME
+#define MY_PROGRAM_NAME "git-ssh-upload"
+#endif
+
 #include "cache.h"
 #include "rsh.h"
 #include "refs.h"
@@ -97,7 +107,7 @@ static void service(int fd_in, int fd_out) {
 }
 
 static const char ssh_push_usage[] =
-       "git-ssh-upload [-c] [-t] [-a] [-w ref] commit-id url";
+       MY_PROGRAM_NAME " [-c] [-t] [-a] [-w ref] commit-id url";
 
 int main(int argc, char **argv)
 {
@@ -109,8 +119,8 @@ int main(int argc, char **argv)
        unsigned char sha1[20];
        char hex[41];
 
-       prog = getenv("GIT_SSH_PULL");
-       if (!prog) prog = "git-ssh-fetch";
+       prog = getenv(COUNTERPART_ENV_NAME);
+       if (!prog) prog = COUNTERPART_PROGRAM_NAME;
        while (arg < argc && argv[arg][0] == '-') {
                if (argv[arg][1] == 'w')
                        arg++;
index 5b69681..d0ed242 100755 (executable)
@@ -11,7 +11,7 @@ There is the head (called H) and another commit (called M), which is
 simply ahead of H.  The index and the work tree contains a state that
 is derived from H, but may also have local changes.  This test checks
 all the combinations described in the two-tree merge "carry forward"
-rules, found in <Documentation/git-rev-tree.txt>.
+rules, found in <Documentation/git-read-tree.txt>.
 
 In the test, these paths are used:
         bozbar  - in H, stays in M, modified from bozbar to gnusto