Merge branch 'maint'
authorJunio C Hamano <gitster@pobox.com>
Sun, 28 Feb 2010 19:41:57 +0000 (11:41 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 28 Feb 2010 19:41:57 +0000 (11:41 -0800)
* maint:
  Git 1.7.0.1
  Remove reference to GREP_COLORS from documentation
  sha1_name: fix segfault caused by invalid index access

42 files changed:
Documentation/RelNotes-1.7.1.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/git-fast-import.txt
Documentation/technical/api-run-command.txt
Makefile
RelNotes
advice.c
advice.h
builtin-checkout.c
builtin-fetch-pack.c
builtin-grep.c
builtin-receive-pack.c
builtin-send-pack.c
compat/mingw.c
compat/mingw.h
convert.c
fast-import.c
git-parse-remote.sh [changed mode: 0755->0644]
git-request-pull.sh
git-sh-setup.sh [changed mode: 0755->0644]
git-svn.perl
git.c
gitweb/gitweb.perl
imap-send.c
path.c
remote-curl.c
run-command.c
run-command.h
setup.c
t/lib-patch-mode.sh [changed mode: 0755->0644]
t/t5401-update-hooks.sh
t/t5510-fetch.sh
t/t6000lib.sh [changed mode: 0755->0644]
t/t6023-merge-file.sh
t/t7002-grep.sh
t/t7201-co.sh
t/t9151-svn-mergeinfo.sh
t/t9151/make-svnmerge-dump
t/t9151/svn-mergeinfo.dump
transport.c
transport.h
upload-pack.c

diff --git a/Documentation/RelNotes-1.7.1.txt b/Documentation/RelNotes-1.7.1.txt
new file mode 100644 (file)
index 0000000..8c18ca5
--- /dev/null
@@ -0,0 +1,20 @@
+Git v1.7.1 Release Notes
+========================
+
+Updates since v1.7.0
+--------------------
+
+ * "git grep" learned "--no-index" option, to search inside contents that
+   are not managed by git.
+
+Fixes since v1.7.0
+------------------
+
+All of the fixes in v1.7.0.X maintenance series are included in this
+release, unless otherwise noted.
+
+---
+exec >/var/tmp/1
+echo O=$(git describe)
+O=v1.7.0-36-gfaa3b47
+git shortlog --no-merges ^maint $O..
index 2dc3a05..7103172 100644 (file)
@@ -138,6 +138,11 @@ advice.*::
                Advice on how to set your identity configuration when
                your information is guessed from the system username and
                domain name. Default: true.
+
+       detachedHead::
+               Advice shown when you used linkgit::git-checkout[1] to
+               move to the detach HEAD state, to instruct how to create
+               a local branch after the fact.  Default: true.
 --
 
 core.fileMode::
index 6764ff1..19082b0 100644 (file)
@@ -45,10 +45,7 @@ OPTIONS
 
 --max-pack-size=<n>::
        Maximum size of each output packfile.
-       The default is 4 GiB as that is the maximum allowed
-       packfile size (due to file format limitations). Some
-       importers may wish to lower this, such as to ensure the
-       resulting packfiles fit on CDs.
+       The default is unlimited.
 
 --big-file-threshold=<n>::
        Maximum size of a blob that fast-import will attempt to
index 68bf4ca..44876fa 100644 (file)
@@ -64,8 +64,8 @@ The functions above do the following:
 `start_async`::
 
        Run a function asynchronously. Takes a pointer to a `struct
-       async` that specifies the details and returns a pipe FD
-       from which the caller reads. See below for details.
+       async` that specifies the details and returns a set of pipe FDs
+       for communication with the function. See below for details.
 
 `finish_async`::
 
@@ -135,7 +135,7 @@ stderr as follows:
 
        .in: The FD must be readable; it becomes child's stdin.
        .out: The FD must be writable; it becomes child's stdout.
-       .err > 0 is not supported.
+       .err: The FD must be writable; it becomes child's stderr.
 
   The specified FD is closed by start_command(), even if it fails to
   run the sub-process!
@@ -180,17 +180,47 @@ The caller:
    struct async variable;
 2. initializes .proc and .data;
 3. calls start_async();
-4. processes the data by reading from the fd in .out;
-5. closes .out;
+4. processes communicates with proc through .in and .out;
+5. closes .in and .out;
 6. calls finish_async().
 
+The members .in, .out are used to provide a set of fd's for
+communication between the caller and the callee as follows:
+
+. Specify 0 to have no file descriptor passed.  The callee will
+  receive -1 in the corresponding argument.
+
+. Specify < 0 to have a pipe allocated; start_async() replaces
+  with the pipe FD in the following way:
+
+       .in: Returns the writable pipe end into which the caller
+       writes; the readable end of the pipe becomes the function's
+       in argument.
+
+       .out: Returns the readable pipe end from which the caller
+       reads; the writable end of the pipe becomes the function's
+       out argument.
+
+  The caller of start_async() must close the returned FDs after it
+  has completed reading from/writing from them.
+
+. Specify a file descriptor > 0 to be used by the function:
+
+       .in: The FD must be readable; it becomes the function's in.
+       .out: The FD must be writable; it becomes the function's out.
+
+  The specified FD is closed by start_async(), even if it fails to
+  run the function.
+
 The function pointer in .proc has the following signature:
 
-       int proc(int fd, void *data);
+       int proc(int in, int out, void *data);
 
-. fd specifies a writable file descriptor to which the function must
-  write the data that it produces. The function *must* close this
-  descriptor before it returns.
+. in, out specifies a set of file descriptors to which the function
+  must read/write the data that it needs/produces.  The function
+  *must* close these descriptors before it returns.  A descriptor
+  may be -1 if the caller did not configure a descriptor for that
+  direction.
 
 . data is the value that the caller has specified in the .data member
   of struct async.
@@ -205,8 +235,8 @@ because this facility is implemented by a pipe to a forked process on
 UNIX, but by a thread in the same address space on Windows:
 
 . It cannot change the program's state (global variables, environment,
-  etc.) in a way that the caller notices; in other words, .out is the
-  only communication channel to the caller.
+  etc.) in a way that the caller notices; in other words, .in and .out
+  are the only communication channels to the caller.
 
 . It must not change the program's state that the caller of the
   facility also uses.
index 7bf2fca..afedb54 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -315,6 +315,7 @@ PROGRAMS =
 SCRIPT_PERL =
 SCRIPT_PYTHON =
 SCRIPT_SH =
+SCRIPT_LIB =
 TEST_PROGRAMS =
 
 SCRIPT_SH += git-am.sh
@@ -326,20 +327,21 @@ SCRIPT_SH += git-merge-octopus.sh
 SCRIPT_SH += git-merge-one-file.sh
 SCRIPT_SH += git-merge-resolve.sh
 SCRIPT_SH += git-mergetool.sh
-SCRIPT_SH += git-mergetool--lib.sh
 SCRIPT_SH += git-notes.sh
-SCRIPT_SH += git-parse-remote.sh
 SCRIPT_SH += git-pull.sh
 SCRIPT_SH += git-quiltimport.sh
 SCRIPT_SH += git-rebase--interactive.sh
 SCRIPT_SH += git-rebase.sh
 SCRIPT_SH += git-repack.sh
 SCRIPT_SH += git-request-pull.sh
-SCRIPT_SH += git-sh-setup.sh
 SCRIPT_SH += git-stash.sh
 SCRIPT_SH += git-submodule.sh
 SCRIPT_SH += git-web--browse.sh
 
+SCRIPT_LIB += git-mergetool--lib
+SCRIPT_LIB += git-parse-remote
+SCRIPT_LIB += git-sh-setup
+
 SCRIPT_PERL += git-add--interactive.perl
 SCRIPT_PERL += git-difftool.perl
 SCRIPT_PERL += git-archimport.perl
@@ -1411,7 +1413,7 @@ export TAR INSTALL DESTDIR SHELL_PATH
 
 SHELL = $(SHELL_PATH)
 
-all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
+all:: shell_compatibility_test $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
 ifneq (,$X)
        $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
 endif
@@ -1462,17 +1464,25 @@ common-cmds.h: ./generate-cmdlist.sh command-list.txt
 common-cmds.h: $(wildcard Documentation/git-*.txt)
        $(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@
 
+define cmd_munge_script
+$(RM) $@ $@+ && \
+sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
+    -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
+    -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
+    -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
+    -e $(BROKEN_PATH_FIX) \
+    $@.sh >$@+
+endef
+
 $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
-       $(QUIET_GEN)$(RM) $@ $@+ && \
-       sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-           -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
-           -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
-           -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
-           -e $(BROKEN_PATH_FIX) \
-           $@.sh >$@+ && \
+       $(QUIET_GEN)$(cmd_munge_script) && \
        chmod +x $@+ && \
        mv $@+ $@
 
+$(SCRIPT_LIB) : % : %.sh
+       $(QUIET_GEN)$(cmd_munge_script) && \
+       mv $@+ $@
+
 ifndef NO_PERL
 $(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
 
@@ -1805,6 +1815,7 @@ install: all
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+       $(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'
        $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
 ifndef NO_PERL
@@ -1924,7 +1935,7 @@ distclean: clean
 clean:
        $(RM) *.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \
                $(LIB_FILE) $(XDIFF_LIB)
-       $(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
+       $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
        $(RM) $(TEST_PROGRAMS)
        $(RM) -r bin-wrappers
        $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
@@ -1956,7 +1967,7 @@ endif
 ### Check documentation
 #
 check-docs::
-       @(for v in $(ALL_PROGRAMS) $(BUILT_INS) git gitk; \
+       @(for v in $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk; \
        do \
                case "$$v" in \
                git-merge-octopus | git-merge-ours | git-merge-recursive | \
@@ -1999,9 +2010,12 @@ check-docs::
                documented,gitrepository-layout | \
                documented,gittutorial | \
                documented,gittutorial-2 | \
+               documented,git-bisect-lk2009 | \
+               documented.git-remote-helpers | \
+               documented,gitworkflows | \
                sentinel,not,matching,is,ok ) continue ;; \
                esac; \
-               case " $(ALL_PROGRAMS) $(BUILT_INS) git gitk " in \
+               case " $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk " in \
                *" $$cmd "*)    ;; \
                *) echo "removed but $$how: $$cmd" ;; \
                esac; \
index 9fadb0a..00e7722 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.7.0.1.txt
\ No newline at end of file
+Documentation/RelNotes-1.7.1.txt
\ No newline at end of file
index 936d98b..0be4b5f 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -5,6 +5,7 @@ int advice_status_hints = 1;
 int advice_commit_before_merge = 1;
 int advice_resolve_conflict = 1;
 int advice_implicit_identity = 1;
+int advice_detached_head = 1;
 
 static struct {
        const char *name;
@@ -15,6 +16,7 @@ static struct {
        { "commitbeforemerge", &advice_commit_before_merge },
        { "resolveconflict", &advice_resolve_conflict },
        { "implicitidentity", &advice_implicit_identity },
+       { "detachedhead", &advice_detached_head },
 };
 
 int git_default_advice_config(const char *var, const char *value)
index 9b7a3ad..3244ebb 100644 (file)
--- a/advice.h
+++ b/advice.h
@@ -8,6 +8,7 @@ extern int advice_status_hints;
 extern int advice_commit_before_merge;
 extern int advice_resolve_conflict;
 extern int advice_implicit_identity;
+extern int advice_detached_head;
 
 int git_default_advice_config(const char *var, const char *value);
 
index 5277817..c5ab783 100644 (file)
@@ -488,6 +488,20 @@ static void report_tracking(struct branch_info *new)
        strbuf_release(&sb);
 }
 
+static void detach_advice(const char *old_path, const char *new_name)
+{
+       const char fmt[] =
+       "Note: checking out '%s'.\n\n"
+       "You are in 'detached HEAD' state. You can look around, make experimental\n"
+       "changes and commit them, and you can discard any commits you make in this\n"
+       "state without impacting any branches by performing another checkout.\n\n"
+       "If you want to create a new branch to retain commits you create, you may\n"
+       "do so (now or later) by using -b with the checkout command again. Example:\n\n"
+       "  git checkout -b new_branch_name\n\n";
+
+       fprintf(stderr, fmt, new_name);
+}
+
 static void update_refs_for_switch(struct checkout_opts *opts,
                                   struct branch_info *old,
                                   struct branch_info *new)
@@ -522,8 +536,8 @@ static void update_refs_for_switch(struct checkout_opts *opts,
                update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
                           REF_NODEREF, DIE_ON_ERR);
                if (!opts->quiet) {
-                       if (old->path)
-                               fprintf(stderr, "Note: moving to '%s' which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n  git checkout -b <new_branch_name>\n", new->name);
+                       if (old->path && advice_detached_head)
+                               detach_advice(old->path, new->name);
                        describe_detached_head("HEAD is now at", new->commit);
                }
        }
index 8ed4a6f..dbd8b7b 100644 (file)
@@ -586,12 +586,12 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
        return retval;
 }
 
-static int sideband_demux(int fd, void *data)
+static int sideband_demux(int in, int out, void *data)
 {
        int *xd = data;
 
-       int ret = recv_sideband("fetch-pack", xd[0], fd);
-       close(fd);
+       int ret = recv_sideband("fetch-pack", xd[0], out);
+       close(out);
        return ret;
 }
 
@@ -613,6 +613,7 @@ static int get_pack(int xd[2], char **pack_lockfile)
                 */
                demux.proc = sideband_demux;
                demux.data = xd;
+               demux.out = -1;
                if (start_async(&demux))
                        die("fetch-pack: unable to fork off sideband"
                            " demultiplexer");
index 2697957..552ef1f 100644 (file)
@@ -14,6 +14,7 @@
 #include "userdiff.h"
 #include "grep.h"
 #include "quote.h"
+#include "dir.h"
 
 #ifndef NO_PTHREADS
 #include "thread-utils.h"
@@ -652,6 +653,24 @@ static int grep_object(struct grep_opt *opt, const char **paths,
        die("unable to grep from object of type %s", typename(obj->type));
 }
 
+static int grep_directory(struct grep_opt *opt, const char **paths)
+{
+       struct dir_struct dir;
+       int i, hit = 0;
+
+       memset(&dir, 0, sizeof(dir));
+       setup_standard_excludes(&dir);
+
+       fill_directory(&dir, paths);
+       for (i = 0; i < dir.nr; i++) {
+               hit |= grep_file(opt, dir.entries[i]->name);
+               if (hit && opt->status_only)
+                       break;
+       }
+       free_grep_patterns(opt);
+       return hit;
+}
+
 static int context_callback(const struct option *opt, const char *arg,
                            int unset)
 {
@@ -746,9 +765,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        const char **paths = NULL;
        int i;
        int dummy;
+       int nongit = 0, use_index = 1;
        struct option options[] = {
                OPT_BOOLEAN(0, "cached", &cached,
                        "search in index instead of in the work tree"),
+               OPT_BOOLEAN(0, "index", &use_index,
+                       "--no-index finds in contents not managed by git"),
                OPT_GROUP(""),
                OPT_BOOLEAN('v', "invert-match", &opt.invert,
                        "show non-matching lines"),
@@ -831,6 +853,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                OPT_END()
        };
 
+       prefix = setup_git_directory_gently(&nongit);
+
        /*
         * 'git grep -h', unlike 'git grep -h <pattern>', is a request
         * to show usage information and exit.
@@ -868,6 +892,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                             PARSE_OPT_STOP_AT_NON_OPTION |
                             PARSE_OPT_NO_INTERNAL_HELP);
 
+       if (use_index && nongit)
+               /* die the same way as if we did it at the beginning */
+               setup_git_directory();
+
        /*
         * skip a -- separator; we know it cannot be
         * separating revisions from pathnames if
@@ -939,6 +967,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                paths[1] = NULL;
        }
 
+       if (!use_index) {
+               int hit;
+               if (cached)
+                       die("--cached cannot be used with --no-index.");
+               if (list.nr)
+                       die("--no-index cannot be used with revs.");
+               hit = grep_directory(&opt, paths);
+               if (use_threads)
+                       hit |= wait_all();
+               return !hit;
+       }
+
        if (!list.nr) {
                int hit;
                if (!cached)
index 4320c93..0559fcc 100644 (file)
@@ -2,6 +2,7 @@
 #include "pack.h"
 #include "refs.h"
 #include "pkt-line.h"
+#include "sideband.h"
 #include "run-command.h"
 #include "exec_cmd.h"
 #include "commit.h"
@@ -27,11 +28,12 @@ static int receive_unpack_limit = -1;
 static int transfer_unpack_limit = -1;
 static int unpack_limit = 100;
 static int report_status;
+static int use_sideband;
 static int prefer_ofs_delta = 1;
 static int auto_update_server_info;
 static int auto_gc = 1;
 static const char *head_name;
-static char *capabilities_to_send;
+static int sent_capabilities;
 
 static enum deny_action parse_deny_action(const char *var, const char *value)
 {
@@ -105,19 +107,21 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
 
 static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
-       if (!capabilities_to_send)
+       if (sent_capabilities)
                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
        else
-               packet_write(1, "%s %s%c%s\n",
-                            sha1_to_hex(sha1), path, 0, capabilities_to_send);
-       capabilities_to_send = NULL;
+               packet_write(1, "%s %s%c%s%s\n",
+                            sha1_to_hex(sha1), path, 0,
+                            " report-status delete-refs side-band-64k",
+                            prefer_ofs_delta ? " ofs-delta" : "");
+       sent_capabilities = 1;
        return 0;
 }
 
 static void write_head_info(void)
 {
        for_each_ref(show_ref, NULL);
-       if (capabilities_to_send)
+       if (!sent_capabilities)
                show_ref("capabilities^{}", null_sha1, 0, NULL);
 
 }
@@ -135,11 +139,61 @@ static struct command *commands;
 static const char pre_receive_hook[] = "hooks/pre-receive";
 static const char post_receive_hook[] = "hooks/post-receive";
 
+static void rp_error(const char *err, ...) __attribute__((format (printf, 1, 2)));
+static void rp_warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
+
+static void report_message(const char *prefix, const char *err, va_list params)
+{
+       int sz = strlen(prefix);
+       char msg[4096];
+
+       strncpy(msg, prefix, sz);
+       sz += vsnprintf(msg + sz, sizeof(msg) - sz, err, params);
+       if (sz > (sizeof(msg) - 1))
+               sz = sizeof(msg) - 1;
+       msg[sz++] = '\n';
+
+       if (use_sideband)
+               send_sideband(1, 2, msg, sz, use_sideband);
+       else
+               xwrite(2, msg, sz);
+}
+
+static void rp_warning(const char *err, ...)
+{
+       va_list params;
+       va_start(params, err);
+       report_message("warning: ", err, params);
+       va_end(params);
+}
+
+static void rp_error(const char *err, ...)
+{
+       va_list params;
+       va_start(params, err);
+       report_message("error: ", err, params);
+       va_end(params);
+}
+
+static int copy_to_sideband(int in, int out, void *arg)
+{
+       char data[128];
+       while (1) {
+               ssize_t sz = xread(in, data, sizeof(data));
+               if (sz <= 0)
+                       break;
+               send_sideband(1, 2, data, sz, use_sideband);
+       }
+       close(in);
+       return 0;
+}
+
 static int run_receive_hook(const char *hook_name)
 {
        static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4];
        struct command *cmd;
        struct child_process proc;
+       struct async muxer;
        const char *argv[2];
        int have_input = 0, code;
 
@@ -159,9 +213,23 @@ static int run_receive_hook(const char *hook_name)
        proc.in = -1;
        proc.stdout_to_stderr = 1;
 
+       if (use_sideband) {
+               memset(&muxer, 0, sizeof(muxer));
+               muxer.proc = copy_to_sideband;
+               muxer.in = -1;
+               code = start_async(&muxer);
+               if (code)
+                       return code;
+               proc.err = muxer.in;
+       }
+
        code = start_command(&proc);
-       if (code)
+       if (code) {
+               if (use_sideband)
+                       finish_async(&muxer);
                return code;
+       }
+
        for (cmd = commands; cmd; cmd = cmd->next) {
                if (!cmd->error_string) {
                        size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
@@ -173,6 +241,8 @@ static int run_receive_hook(const char *hook_name)
                }
        }
        close(proc.in);
+       if (use_sideband)
+               finish_async(&muxer);
        return finish_command(&proc);
 }
 
@@ -180,6 +250,8 @@ static int run_update_hook(struct command *cmd)
 {
        static const char update_hook[] = "hooks/update";
        const char *argv[5];
+       struct child_process proc;
+       int code;
 
        if (access(update_hook, X_OK) < 0)
                return 0;
@@ -190,8 +262,18 @@ static int run_update_hook(struct command *cmd)
        argv[3] = sha1_to_hex(cmd->new_sha1);
        argv[4] = NULL;
 
-       return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN |
-                                       RUN_COMMAND_STDOUT_TO_STDERR);
+       memset(&proc, 0, sizeof(proc));
+       proc.no_stdin = 1;
+       proc.stdout_to_stderr = 1;
+       proc.err = use_sideband ? -1 : 0;
+       proc.argv = argv;
+
+       code = start_command(&proc);
+       if (code)
+               return code;
+       if (use_sideband)
+               copy_to_sideband(proc.err, -1, NULL);
+       return finish_command(&proc);
 }
 
 static int is_ref_checked_out(const char *ref)
@@ -224,7 +306,7 @@ static void refuse_unconfigured_deny(void)
 {
        int i;
        for (i = 0; i < ARRAY_SIZE(refuse_unconfigured_deny_msg); i++)
-               error("%s", refuse_unconfigured_deny_msg[i]);
+               rp_error("%s", refuse_unconfigured_deny_msg[i]);
 }
 
 static char *refuse_unconfigured_deny_delete_current_msg[] = {
@@ -244,7 +326,7 @@ static void refuse_unconfigured_deny_delete_current(void)
        for (i = 0;
             i < ARRAY_SIZE(refuse_unconfigured_deny_delete_current_msg);
             i++)
-               error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
+               rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
 }
 
 static const char *update(struct command *cmd)
@@ -256,7 +338,7 @@ static const char *update(struct command *cmd)
 
        /* only refs/... are allowed */
        if (prefixcmp(name, "refs/") || check_ref_format(name + 5)) {
-               error("refusing to create funny ref '%s' remotely", name);
+               rp_error("refusing to create funny ref '%s' remotely", name);
                return "funny refname";
        }
 
@@ -265,11 +347,11 @@ static const char *update(struct command *cmd)
                case DENY_IGNORE:
                        break;
                case DENY_WARN:
-                       warning("updating the current branch");
+                       rp_warning("updating the current branch");
                        break;
                case DENY_REFUSE:
                case DENY_UNCONFIGURED:
-                       error("refusing to update checked out branch: %s", name);
+                       rp_error("refusing to update checked out branch: %s", name);
                        if (deny_current_branch == DENY_UNCONFIGURED)
                                refuse_unconfigured_deny();
                        return "branch is currently checked out";
@@ -284,7 +366,7 @@ static const char *update(struct command *cmd)
 
        if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) {
                if (deny_deletes && !prefixcmp(name, "refs/heads/")) {
-                       error("denying ref deletion for %s", name);
+                       rp_error("denying ref deletion for %s", name);
                        return "deletion prohibited";
                }
 
@@ -293,13 +375,13 @@ static const char *update(struct command *cmd)
                        case DENY_IGNORE:
                                break;
                        case DENY_WARN:
-                               warning("deleting the current branch");
+                               rp_warning("deleting the current branch");
                                break;
                        case DENY_REFUSE:
                        case DENY_UNCONFIGURED:
                                if (deny_delete_current == DENY_UNCONFIGURED)
                                        refuse_unconfigured_deny_delete_current();
-                               error("refusing to delete the current branch: %s", name);
+                               rp_error("refusing to delete the current branch: %s", name);
                                return "deletion of the current branch prohibited";
                        }
                }
@@ -329,23 +411,23 @@ static const char *update(struct command *cmd)
                                break;
                free_commit_list(bases);
                if (!ent) {
-                       error("denying non-fast-forward %s"
-                             " (you should pull first)", name);
+                       rp_error("denying non-fast-forward %s"
+                                " (you should pull first)", name);
                        return "non-fast-forward";
                }
        }
        if (run_update_hook(cmd)) {
-               error("hook declined to update %s", name);
+               rp_error("hook declined to update %s", name);
                return "hook declined";
        }
 
        if (is_null_sha1(new_sha1)) {
                if (!parse_object(old_sha1)) {
-                       warning ("Allowing deletion of corrupt ref.");
+                       rp_warning("Allowing deletion of corrupt ref.");
                        old_sha1 = NULL;
                }
                if (delete_ref(name, old_sha1, 0)) {
-                       error("failed to delete %s", name);
+                       rp_error("failed to delete %s", name);
                        return "failed to delete";
                }
                return NULL; /* good */
@@ -353,7 +435,7 @@ static const char *update(struct command *cmd)
        else {
                lock = lock_any_ref_for_update(name, old_sha1, 0);
                if (!lock) {
-                       error("failed to lock %s", name);
+                       rp_error("failed to lock %s", name);
                        return "failed to lock";
                }
                if (write_ref_sha1(lock, new_sha1, "push")) {
@@ -368,8 +450,9 @@ static char update_post_hook[] = "hooks/post-update";
 static void run_update_post_hook(struct command *cmd)
 {
        struct command *cmd_p;
-       int argc, status;
+       int argc;
        const char **argv;
+       struct child_process proc;
 
        for (argc = 0, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
                if (cmd_p->error_string)
@@ -391,8 +474,18 @@ static void run_update_post_hook(struct command *cmd)
                argc++;
        }
        argv[argc] = NULL;
-       status = run_command_v_opt(argv, RUN_COMMAND_NO_STDIN
-                       | RUN_COMMAND_STDOUT_TO_STDERR);
+
+       memset(&proc, 0, sizeof(proc));
+       proc.no_stdin = 1;
+       proc.stdout_to_stderr = 1;
+       proc.err = use_sideband ? -1 : 0;
+       proc.argv = argv;
+
+       if (!start_command(&proc)) {
+               if (use_sideband)
+                       copy_to_sideband(proc.err, -1, NULL);
+               finish_command(&proc);
+       }
 }
 
 static void execute_commands(const char *unpacker_error)
@@ -452,6 +545,8 @@ static void read_head_info(void)
                if (reflen + 82 < len) {
                        if (strstr(refname + reflen + 1, "report-status"))
                                report_status = 1;
+                       if (strstr(refname + reflen + 1, "side-band-64k"))
+                               use_sideband = LARGE_PACKET_MAX;
                }
                cmd = xmalloc(sizeof(struct command) + len - 80);
                hashcpy(cmd->old_sha1, old_sha1);
@@ -551,17 +646,25 @@ static const char *unpack(void)
 static void report(const char *unpack_status)
 {
        struct command *cmd;
-       packet_write(1, "unpack %s\n",
-                    unpack_status ? unpack_status : "ok");
+       struct strbuf buf = STRBUF_INIT;
+
+       packet_buf_write(&buf, "unpack %s\n",
+                        unpack_status ? unpack_status : "ok");
        for (cmd = commands; cmd; cmd = cmd->next) {
                if (!cmd->error_string)
-                       packet_write(1, "ok %s\n",
-                                    cmd->ref_name);
+                       packet_buf_write(&buf, "ok %s\n",
+                                        cmd->ref_name);
                else
-                       packet_write(1, "ng %s %s\n",
-                                    cmd->ref_name, cmd->error_string);
+                       packet_buf_write(&buf, "ng %s %s\n",
+                                        cmd->ref_name, cmd->error_string);
        }
-       packet_flush(1);
+       packet_buf_flush(&buf);
+
+       if (use_sideband)
+               send_sideband(1, 1, buf.buf, buf.len, use_sideband);
+       else
+               safe_write(1, buf.buf, buf.len);
+       strbuf_release(&buf);
 }
 
 static int delete_only(struct command *cmd)
@@ -658,10 +761,6 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
        else if (0 <= receive_unpack_limit)
                unpack_limit = receive_unpack_limit;
 
-       capabilities_to_send = (prefer_ofs_delta) ?
-               " report-status delete-refs ofs-delta " :
-               " report-status delete-refs ";
-
        if (advertise_refs || !stateless_rpc) {
                add_alternate_refs();
                write_head_info();
@@ -695,5 +794,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                if (auto_update_server_info)
                        update_server_info(0);
        }
+       if (use_sideband)
+               packet_flush(1);
        return 0;
 }
index 76c7206..2183a47 100644 (file)
@@ -372,6 +372,14 @@ static void print_helper_status(struct ref *ref)
        strbuf_release(&buf);
 }
 
+static int sideband_demux(int in, int out, void *data)
+{
+       int *fd = data;
+       int ret = recv_sideband("send-pack", fd[0], out);
+       close(out);
+       return ret;
+}
+
 int send_pack(struct send_pack_args *args,
              int fd[], struct child_process *conn,
              struct ref *remote_refs,
@@ -382,18 +390,22 @@ int send_pack(struct send_pack_args *args,
        struct strbuf req_buf = STRBUF_INIT;
        struct ref *ref;
        int new_refs;
-       int ask_for_status_report = 0;
        int allow_deleting_refs = 0;
-       int expect_status_report = 0;
+       int status_report = 0;
+       int use_sideband = 0;
+       unsigned cmds_sent = 0;
        int ret;
+       struct async demux;
 
        /* Does the other end support the reporting? */
        if (server_supports("report-status"))
-               ask_for_status_report = 1;
+               status_report = 1;
        if (server_supports("delete-refs"))
                allow_deleting_refs = 1;
        if (server_supports("ofs-delta"))
                args->use_ofs_delta = 1;
+       if (server_supports("side-band-64k"))
+               use_sideband = 1;
 
        if (!remote_refs) {
                fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
@@ -426,28 +438,30 @@ int send_pack(struct send_pack_args *args,
                if (!ref->deletion)
                        new_refs++;
 
-               if (!args->dry_run) {
+               if (args->dry_run) {
+                       ref->status = REF_STATUS_OK;
+               } else {
                        char *old_hex = sha1_to_hex(ref->old_sha1);
                        char *new_hex = sha1_to_hex(ref->new_sha1);
 
-                       if (ask_for_status_report) {
-                               packet_buf_write(&req_buf, "%s %s %s%c%s",
+                       if (!cmds_sent && (status_report || use_sideband)) {
+                               packet_buf_write(&req_buf, "%s %s %s%c%s%s",
                                        old_hex, new_hex, ref->name, 0,
-                                       "report-status");
-                               ask_for_status_report = 0;
-                               expect_status_report = 1;
+                                       status_report ? " report-status" : "",
+                                       use_sideband ? " side-band-64k" : "");
                        }
                        else
                                packet_buf_write(&req_buf, "%s %s %s",
                                        old_hex, new_hex, ref->name);
+                       ref->status = status_report ?
+                               REF_STATUS_EXPECTING_REPORT :
+                               REF_STATUS_OK;
+                       cmds_sent++;
                }
-               ref->status = expect_status_report ?
-                       REF_STATUS_EXPECTING_REPORT :
-                       REF_STATUS_OK;
        }
 
        if (args->stateless_rpc) {
-               if (!args->dry_run) {
+               if (!args->dry_run && cmds_sent) {
                        packet_buf_flush(&req_buf);
                        send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
                }
@@ -457,23 +471,43 @@ int send_pack(struct send_pack_args *args,
        }
        strbuf_release(&req_buf);
 
-       if (new_refs && !args->dry_run) {
+       if (use_sideband && cmds_sent) {
+               memset(&demux, 0, sizeof(demux));
+               demux.proc = sideband_demux;
+               demux.data = fd;
+               demux.out = -1;
+               if (start_async(&demux))
+                       die("receive-pack: unable to fork off sideband demultiplexer");
+               in = demux.out;
+       }
+
+       if (new_refs && cmds_sent) {
                if (pack_objects(out, remote_refs, extra_have, args) < 0) {
                        for (ref = remote_refs; ref; ref = ref->next)
                                ref->status = REF_STATUS_NONE;
+                       if (use_sideband)
+                               finish_async(&demux);
                        return -1;
                }
        }
-       if (args->stateless_rpc && !args->dry_run)
+       if (args->stateless_rpc && cmds_sent)
                packet_flush(out);
 
-       if (expect_status_report)
+       if (status_report && cmds_sent)
                ret = receive_status(in, remote_refs);
        else
                ret = 0;
        if (args->stateless_rpc)
                packet_flush(out);
 
+       if (use_sideband && cmds_sent) {
+               if (finish_async(&demux)) {
+                       error("error in sideband demultiplexer");
+                       ret = -1;
+               }
+               close(demux.out);
+       }
+
        if (ret < 0)
                return ret;
        for (ref = remote_refs; ref; ref = ref->next) {
index ab65f77..c5bfb39 100644 (file)
@@ -140,6 +140,22 @@ int mingw_open (const char *filename, int oflags, ...)
        return fd;
 }
 
+#undef fopen
+FILE *mingw_fopen (const char *filename, const char *otype)
+{
+       if (!strcmp(filename, "/dev/null"))
+               filename = "nul";
+       return fopen(filename, otype);
+}
+
+#undef freopen
+FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
+{
+       if (filename && !strcmp(filename, "/dev/null"))
+               filename = "nul";
+       return freopen(filename, otype, stream);
+}
+
 /*
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
index e254fb4..e81e752 100644 (file)
@@ -170,6 +170,12 @@ int link(const char *oldpath, const char *newpath);
 int mingw_open (const char *filename, int oflags, ...);
 #define open mingw_open
 
+FILE *mingw_fopen (const char *filename, const char *otype);
+#define fopen mingw_fopen
+
+FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
+#define freopen mingw_freopen
+
 char *mingw_getcwd(char *pointer, int len);
 #define getcwd mingw_getcwd
 
index 27acce5..4f8fcb7 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -241,7 +241,7 @@ struct filter_params {
        const char *cmd;
 };
 
-static int filter_buffer(int fd, void *data)
+static int filter_buffer(int in, int out, void *data)
 {
        /*
         * Spawn cmd and feed the buffer contents through its stdin.
@@ -255,7 +255,7 @@ static int filter_buffer(int fd, void *data)
        child_process.argv = argv;
        child_process.use_shell = 1;
        child_process.in = -1;
-       child_process.out = fd;
+       child_process.out = out;
 
        if (start_command(&child_process))
                return error("cannot fork to run external filter %s", params->cmd);
@@ -292,6 +292,7 @@ static int apply_filter(const char *path, const char *src, size_t len,
        memset(&async, 0, sizeof(async));
        async.proc = filter_buffer;
        async.data = &params;
+       async.out = -1;
        params.src = src;
        params.size = len;
        params.cmd = cmd;
index b477dc6..74f08bd 100644 (file)
@@ -164,12 +164,11 @@ Format of STDIN stream:
 
 struct object_entry
 {
+       struct pack_idx_entry idx;
        struct object_entry *next;
-       uint32_t offset;
        uint32_t type : TYPE_BITS,
                pack_id : PACK_ID_BITS,
                depth : DEPTH_BITS;
-       unsigned char sha1[20];
 };
 
 struct object_entry_pool
@@ -192,7 +191,7 @@ struct mark_set
 struct last_object
 {
        struct strbuf data;
-       uint32_t offset;
+       off_t offset;
        unsigned int depth;
        unsigned no_swap : 1;
 };
@@ -280,7 +279,7 @@ struct recent_command
 
 /* Configured limits on output */
 static unsigned long max_depth = 10;
-static off_t max_packsize = (1LL << 32) - 1;
+static off_t max_packsize;
 static uintmax_t big_file_threshold = 512 * 1024 * 1024;
 static int force_update;
 static int pack_compression_level = Z_DEFAULT_COMPRESSION;
@@ -313,9 +312,10 @@ static struct atom_str **atom_table;
 
 /* The .pack file being generated */
 static unsigned int pack_id;
+static struct sha1file *pack_file;
 static struct packed_git *pack_data;
 static struct packed_git **all_packs;
-static unsigned long pack_size;
+static off_t pack_size;
 
 /* Table of objects we've written. */
 static unsigned int object_entry_alloc = 5000;
@@ -521,7 +521,7 @@ static struct object_entry *new_object(unsigned char *sha1)
                alloc_objects(object_entry_alloc);
 
        e = blocks->next_free++;
-       hashcpy(e->sha1, sha1);
+       hashcpy(e->idx.sha1, sha1);
        return e;
 }
 
@@ -530,7 +530,7 @@ static struct object_entry *find_object(unsigned char *sha1)
        unsigned int h = sha1[0] << 8 | sha1[1];
        struct object_entry *e;
        for (e = object_table[h]; e; e = e->next)
-               if (!hashcmp(sha1, e->sha1))
+               if (!hashcmp(sha1, e->idx.sha1))
                        return e;
        return NULL;
 }
@@ -542,7 +542,7 @@ static struct object_entry *insert_object(unsigned char *sha1)
        struct object_entry *p = NULL;
 
        while (e) {
-               if (!hashcmp(sha1, e->sha1))
+               if (!hashcmp(sha1, e->idx.sha1))
                        return e;
                p = e;
                e = e->next;
@@ -550,7 +550,7 @@ static struct object_entry *insert_object(unsigned char *sha1)
 
        e = new_object(sha1);
        e->next = NULL;
-       e->offset = 0;
+       e->idx.offset = 0;
        if (p)
                p->next = e;
        else
@@ -839,11 +839,12 @@ static void start_packfile(void)
        p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2);
        strcpy(p->pack_name, tmpfile);
        p->pack_fd = pack_fd;
+       pack_file = sha1fd(pack_fd, p->pack_name);
 
        hdr.hdr_signature = htonl(PACK_SIGNATURE);
        hdr.hdr_version = htonl(2);
        hdr.hdr_entries = 0;
-       write_or_die(p->pack_fd, &hdr, sizeof(hdr));
+       sha1write(pack_file, &hdr, sizeof(hdr));
 
        pack_data = p;
        pack_size = sizeof(hdr);
@@ -853,67 +854,30 @@ static void start_packfile(void)
        all_packs[pack_id] = p;
 }
 
-static int oecmp (const void *a_, const void *b_)
-{
-       struct object_entry *a = *((struct object_entry**)a_);
-       struct object_entry *b = *((struct object_entry**)b_);
-       return hashcmp(a->sha1, b->sha1);
-}
-
-static char *create_index(void)
+static const char *create_index(void)
 {
-       static char tmpfile[PATH_MAX];
-       git_SHA_CTX ctx;
-       struct sha1file *f;
-       struct object_entry **idx, **c, **last, *e;
+       const char *tmpfile;
+       struct pack_idx_entry **idx, **c, **last;
+       struct object_entry *e;
        struct object_entry_pool *o;
-       uint32_t array[256];
-       int i, idx_fd;
 
-       /* Build the sorted table of object IDs. */
-       idx = xmalloc(object_count * sizeof(struct object_entry*));
+       /* Build the table of object IDs. */
+       idx = xmalloc(object_count * sizeof(*idx));
        c = idx;
        for (o = blocks; o; o = o->next_pool)
                for (e = o->next_free; e-- != o->entries;)
                        if (pack_id == e->pack_id)
-                               *c++ = e;
+                               *c++ = &e->idx;
        last = idx + object_count;
        if (c != last)
                die("internal consistency error creating the index");
-       qsort(idx, object_count, sizeof(struct object_entry*), oecmp);
 
-       /* Generate the fan-out array. */
-       c = idx;
-       for (i = 0; i < 256; i++) {
-               struct object_entry **next = c;
-               while (next < last) {
-                       if ((*next)->sha1[0] != i)
-                               break;
-                       next++;
-               }
-               array[i] = htonl(next - idx);
-               c = next;
-       }
-
-       idx_fd = odb_mkstemp(tmpfile, sizeof(tmpfile),
-                            "pack/tmp_idx_XXXXXX");
-       f = sha1fd(idx_fd, tmpfile);
-       sha1write(f, array, 256 * sizeof(int));
-       git_SHA1_Init(&ctx);
-       for (c = idx; c != last; c++) {
-               uint32_t offset = htonl((*c)->offset);
-               sha1write(f, &offset, 4);
-               sha1write(f, (*c)->sha1, sizeof((*c)->sha1));
-               git_SHA1_Update(&ctx, (*c)->sha1, 20);
-       }
-       sha1write(f, pack_data->sha1, sizeof(pack_data->sha1));
-       sha1close(f, NULL, CSUM_FSYNC);
+       tmpfile = write_idx_file(NULL, idx, object_count, pack_data->sha1);
        free(idx);
-       git_SHA1_Final(pack_data->sha1, &ctx);
        return tmpfile;
 }
 
-static char *keep_pack(char *curr_index_name)
+static char *keep_pack(const char *curr_index_name)
 {
        static char name[PATH_MAX];
        static const char *keep_msg = "fast-import";
@@ -935,6 +899,7 @@ static char *keep_pack(char *curr_index_name)
                 get_object_directory(), sha1_to_hex(pack_data->sha1));
        if (move_temp_to_file(curr_index_name, name))
                die("cannot store index file");
+       free((void *)curr_index_name);
        return name;
 }
 
@@ -957,15 +922,17 @@ static void end_packfile(void)
 
        clear_delta_base_cache();
        if (object_count) {
+               unsigned char cur_pack_sha1[20];
                char *idx_name;
                int i;
                struct branch *b;
                struct tag *t;
 
                close_pack_windows(pack_data);
+               sha1close(pack_file, cur_pack_sha1, 0);
                fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1,
                                    pack_data->pack_name, object_count,
-                                   NULL, 0);
+                                   cur_pack_sha1, pack_size);
                close(pack_data->pack_fd);
                idx_name = keep_pack(create_index());
 
@@ -1063,25 +1030,21 @@ static int store_object(
        e = insert_object(sha1);
        if (mark)
                insert_mark(mark, e);
-       if (e->offset) {
+       if (e->idx.offset) {
                duplicate_count_by_type[type]++;
                return 1;
        } else if (find_sha1_pack(sha1, packed_git)) {
                e->type = type;
                e->pack_id = MAX_PACK_ID;
-               e->offset = 1; /* just not zero! */
+               e->idx.offset = 1; /* just not zero! */
                duplicate_count_by_type[type]++;
                return 1;
        }
 
-       if (last && last->data.buf && last->depth < max_depth) {
+       if (last && last->data.buf && last->depth < max_depth && dat->len > 20) {
                delta = diff_delta(last->data.buf, last->data.len,
                        dat->buf, dat->len,
-                       &deltalen, 0);
-               if (delta && deltalen >= dat->len) {
-                       free(delta);
-                       delta = NULL;
-               }
+                       &deltalen, dat->len - 20);
        } else
                delta = NULL;
 
@@ -1101,7 +1064,7 @@ static int store_object(
        deflateEnd(&s);
 
        /* Determine if we should auto-checkpoint. */
-       if ((pack_size + 60 + s.total_out) > max_packsize
+       if ((max_packsize && (pack_size + 60 + s.total_out) > max_packsize)
                || (pack_size + 60 + s.total_out) < pack_size) {
 
                /* This new object needs to *not* have the current pack_id. */
@@ -1127,36 +1090,40 @@ static int store_object(
 
        e->type = type;
        e->pack_id = pack_id;
-       e->offset = pack_size;
+       e->idx.offset = pack_size;
        object_count++;
        object_count_by_type[type]++;
 
+       crc32_begin(pack_file);
+
        if (delta) {
-               unsigned long ofs = e->offset - last->offset;
+               off_t ofs = e->idx.offset - last->offset;
                unsigned pos = sizeof(hdr) - 1;
 
                delta_count_by_type[type]++;
                e->depth = last->depth + 1;
 
                hdrlen = encode_header(OBJ_OFS_DELTA, deltalen, hdr);
-               write_or_die(pack_data->pack_fd, hdr, hdrlen);
+               sha1write(pack_file, hdr, hdrlen);
                pack_size += hdrlen;
 
                hdr[pos] = ofs & 127;
                while (ofs >>= 7)
                        hdr[--pos] = 128 | (--ofs & 127);
-               write_or_die(pack_data->pack_fd, hdr + pos, sizeof(hdr) - pos);
+               sha1write(pack_file, hdr + pos, sizeof(hdr) - pos);
                pack_size += sizeof(hdr) - pos;
        } else {
                e->depth = 0;
                hdrlen = encode_header(type, dat->len, hdr);
-               write_or_die(pack_data->pack_fd, hdr, hdrlen);
+               sha1write(pack_file, hdr, hdrlen);
                pack_size += hdrlen;
        }
 
-       write_or_die(pack_data->pack_fd, out, s.total_out);
+       sha1write(pack_file, out, s.total_out);
        pack_size += s.total_out;
 
+       e->idx.crc32 = crc32_end(pack_file);
+
        free(out);
        free(delta);
        if (last) {
@@ -1165,18 +1132,23 @@ static int store_object(
                } else {
                        strbuf_swap(&last->data, dat);
                }
-               last->offset = e->offset;
+               last->offset = e->idx.offset;
                last->depth = e->depth;
        }
        return 0;
 }
 
-static void truncate_pack(off_t to)
+static void truncate_pack(off_t to, git_SHA_CTX *ctx)
 {
        if (ftruncate(pack_data->pack_fd, to)
         || lseek(pack_data->pack_fd, to, SEEK_SET) != to)
                die_errno("cannot truncate pack to skip duplicate");
        pack_size = to;
+
+       /* yes this is a layering violation */
+       pack_file->total = to;
+       pack_file->offset = 0;
+       pack_file->ctx = *ctx;
 }
 
 static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
@@ -1189,16 +1161,21 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
        unsigned long hdrlen;
        off_t offset;
        git_SHA_CTX c;
+       git_SHA_CTX pack_file_ctx;
        z_stream s;
        int status = Z_OK;
 
        /* Determine if we should auto-checkpoint. */
-       if ((pack_size + 60 + len) > max_packsize
+       if ((max_packsize && (pack_size + 60 + len) > max_packsize)
                || (pack_size + 60 + len) < pack_size)
                cycle_packfile();
 
        offset = pack_size;
 
+       /* preserve the pack_file SHA1 ctx in case we have to truncate later */
+       sha1flush(pack_file);
+       pack_file_ctx = pack_file->ctx;
+
        hdrlen = snprintf((char *)out_buf, out_sz, "blob %" PRIuMAX, len) + 1;
        if (out_sz <= hdrlen)
                die("impossibly large object header");
@@ -1206,6 +1183,8 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
        git_SHA1_Init(&c);
        git_SHA1_Update(&c, out_buf, hdrlen);
 
+       crc32_begin(pack_file);
+
        memset(&s, 0, sizeof(s));
        deflateInit(&s, pack_compression_level);
 
@@ -1233,7 +1212,7 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
 
                if (!s.avail_out || status == Z_STREAM_END) {
                        size_t n = s.next_out - out_buf;
-                       write_or_die(pack_data->pack_fd, out_buf, n);
+                       sha1write(pack_file, out_buf, n);
                        pack_size += n;
                        s.next_out = out_buf;
                        s.avail_out = out_sz;
@@ -1259,22 +1238,23 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
        if (mark)
                insert_mark(mark, e);
 
-       if (e->offset) {
+       if (e->idx.offset) {
                duplicate_count_by_type[OBJ_BLOB]++;
-               truncate_pack(offset);
+               truncate_pack(offset, &pack_file_ctx);
 
        } else if (find_sha1_pack(sha1, packed_git)) {
                e->type = OBJ_BLOB;
                e->pack_id = MAX_PACK_ID;
-               e->offset = 1; /* just not zero! */
+               e->idx.offset = 1; /* just not zero! */
                duplicate_count_by_type[OBJ_BLOB]++;
-               truncate_pack(offset);
+               truncate_pack(offset, &pack_file_ctx);
 
        } else {
                e->depth = 0;
                e->type = OBJ_BLOB;
                e->pack_id = pack_id;
-               e->offset = offset;
+               e->idx.offset = offset;
+               e->idx.crc32 = crc32_end(pack_file);
                object_count++;
                object_count_by_type[OBJ_BLOB]++;
        }
@@ -1317,6 +1297,7 @@ static void *gfi_unpack_entry(
                 * the newly written data.
                 */
                close_pack_windows(p);
+               sha1flush(pack_file);
 
                /* We have to offer 20 bytes additional on the end of
                 * the packfile as the core unpacker code assumes the
@@ -1326,7 +1307,7 @@ static void *gfi_unpack_entry(
                 */
                p->pack_size = pack_size + 20;
        }
-       return unpack_entry(p, oe->offset, &type, sizep);
+       return unpack_entry(p, oe->idx.offset, &type, sizep);
 }
 
 static const char *get_mode(const char *str, uint16_t *modep)
@@ -1457,7 +1438,7 @@ static void store_tree(struct tree_entry *root)
        if (S_ISDIR(root->versions[0].mode) && le && le->pack_id == pack_id) {
                mktree(t, 0, &old_tree);
                lo.data = old_tree;
-               lo.offset = le->offset;
+               lo.offset = le->idx.offset;
                lo.depth = t->delta_depth;
        }
 
@@ -1715,7 +1696,7 @@ static void dump_marks_helper(FILE *f,
                for (k = 0; k < 1024; k++) {
                        if (m->data.marked[k])
                                fprintf(f, ":%" PRIuMAX " %s\n", base + k,
-                                       sha1_to_hex(m->data.marked[k]->sha1));
+                                       sha1_to_hex(m->data.marked[k]->idx.sha1));
                }
        }
 }
@@ -1798,7 +1779,7 @@ static void read_marks(void)
                        e = insert_object(sha1);
                        e->type = type;
                        e->pack_id = MAX_PACK_ID;
-                       e->offset = 1; /* just not zero! */
+                       e->idx.offset = 1; /* just not zero! */
                }
                insert_mark(mark, e);
        }
@@ -2183,7 +2164,7 @@ static void file_change_m(struct branch *b)
        if (*p == ':') {
                char *x;
                oe = find_mark(strtoumax(p + 1, &x, 10));
-               hashcpy(sha1, oe->sha1);
+               hashcpy(sha1, oe->idx.sha1);
                p = x;
        } else if (!prefixcmp(p, "inline")) {
                inline_data = 1;
@@ -2316,7 +2297,7 @@ static void note_change_n(struct branch *b, unsigned char old_fanout)
        if (*p == ':') {
                char *x;
                oe = find_mark(strtoumax(p + 1, &x, 10));
-               hashcpy(sha1, oe->sha1);
+               hashcpy(sha1, oe->idx.sha1);
                p = x;
        } else if (!prefixcmp(p, "inline")) {
                inline_data = 1;
@@ -2339,7 +2320,7 @@ static void note_change_n(struct branch *b, unsigned char old_fanout)
                struct object_entry *commit_oe = find_mark(commit_mark);
                if (commit_oe->type != OBJ_COMMIT)
                        die("Mark :%" PRIuMAX " not a commit", commit_mark);
-               hashcpy(commit_sha1, commit_oe->sha1);
+               hashcpy(commit_sha1, commit_oe->idx.sha1);
        } else if (!get_sha1(p, commit_sha1)) {
                unsigned long size;
                char *buf = read_object_with_reference(commit_sha1,
@@ -2446,7 +2427,7 @@ static int parse_from(struct branch *b)
                struct object_entry *oe = find_mark(idnum);
                if (oe->type != OBJ_COMMIT)
                        die("Mark :%" PRIuMAX " not a commit", idnum);
-               hashcpy(b->sha1, oe->sha1);
+               hashcpy(b->sha1, oe->idx.sha1);
                if (oe->pack_id != MAX_PACK_ID) {
                        unsigned long size;
                        char *buf = gfi_unpack_entry(oe, &size);
@@ -2481,7 +2462,7 @@ static struct hash_list *parse_merge(unsigned int *count)
                        struct object_entry *oe = find_mark(idnum);
                        if (oe->type != OBJ_COMMIT)
                                die("Mark :%" PRIuMAX " not a commit", idnum);
-                       hashcpy(n->sha1, oe->sha1);
+                       hashcpy(n->sha1, oe->idx.sha1);
                } else if (!get_sha1(from, n->sha1)) {
                        unsigned long size;
                        char *buf = read_object_with_reference(n->sha1,
@@ -2639,7 +2620,7 @@ static void parse_new_tag(void)
                from_mark = strtoumax(from + 1, NULL, 10);
                oe = find_mark(from_mark);
                type = oe->type;
-               hashcpy(sha1, oe->sha1);
+               hashcpy(sha1, oe->idx.sha1);
        } else if (!get_sha1(from, sha1)) {
                unsigned long size;
                char *buf;
@@ -2891,6 +2872,17 @@ static int git_pack_config(const char *k, const char *v, void *cb)
                pack_compression_seen = 1;
                return 0;
        }
+       if (!strcmp(k, "pack.indexversion")) {
+               pack_idx_default_version = git_config_int(k, v);
+               if (pack_idx_default_version > 2)
+                       die("bad pack.indexversion=%"PRIu32,
+                           pack_idx_default_version);
+               return 0;
+       }
+       if (!strcmp(k, "pack.packsizelimit")) {
+               max_packsize = git_config_ulong(k, v);
+               return 0;
+       }
        if (!strcmp(k, "core.bigfilethreshold")) {
                long n = git_config_int(k, v);
                big_file_threshold = 0 < n ? n : 0;
old mode 100755 (executable)
new mode 100644 (file)
index 630cedd..8fd15f6 100755 (executable)
@@ -65,11 +65,11 @@ if [ -z "$branch" ]; then
        status=1
 fi
 
-echo "The following changes since commit $baserev:"
-git shortlog --max-count=1 $baserev | sed -e 's/^\(.\)/  \1/'
+git show -s --format='The following changes since commit %H:
 
-echo "are available in the git repository at:"
-echo
+  %s (%ci)
+
+are available in the git repository at:' $baserev
 echo "  $url $branch"
 echo
 
old mode 100755 (executable)
new mode 100644 (file)
index 265852f..49dd649 100755 (executable)
@@ -36,11 +36,13 @@ $ENV{TZ} = 'UTC';
 $| = 1; # unbuffer STDOUT
 
 sub fatal (@) { print STDERR "@_\n"; exit 1 }
-require SVN::Core; # use()-ing this causes segfaults for me... *shrug*
-require SVN::Ra;
-require SVN::Delta;
-if ($SVN::Core::VERSION lt '1.1.0') {
-       fatal "Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)";
+sub _req_svn {
+       require SVN::Core; # use()-ing this causes segfaults for me... *shrug*
+       require SVN::Ra;
+       require SVN::Delta;
+       if ($SVN::Core::VERSION lt '1.1.0') {
+               fatal "Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)";
+       }
 }
 my $can_compress = eval { require Compress::Zlib; 1};
 push @Git::SVN::Ra::ISA, 'SVN::Ra';
@@ -730,6 +732,8 @@ sub cmd_branch {
                $src=~s/^http:/https:/;
        }
 
+       ::_req_svn();
+
        my $ctx = SVN::Client->new(
                auth    => Git::SVN::Ra::_auth_providers(),
                log_msg => sub {
@@ -3273,7 +3277,7 @@ sub find_extra_svn_parents {
                                        "$new_parents[$i]..$new_parents[$j]",
                                       );
                                if ( !$revs ) {
-                                       undef($new_parents[$i]);
+                                       undef($new_parents[$j]);
                                }
                        }
                }
@@ -4859,6 +4863,8 @@ sub new {
        $url =~ s!/+$!!;
        return $RA if ($RA && $RA->{url} eq $url);
 
+       ::_req_svn();
+
        SVN::_Core::svn_config_ensure($config_dir, undef);
        my ($baton, $callbacks) = SVN::Core::auth_open_helper(_auth_providers);
        my $config = SVN::Core::config_get_config($config_dir);
diff --git a/git.c b/git.c
index c445d7b..90c6daf 100644 (file)
--- a/git.c
+++ b/git.c
@@ -317,7 +317,7 @@ static void handle_internal_command(int argc, const char **argv)
                { "fsck-objects", cmd_fsck, RUN_SETUP },
                { "gc", cmd_gc, RUN_SETUP },
                { "get-tar-commit-id", cmd_get_tar_commit_id },
-               { "grep", cmd_grep, RUN_SETUP | USE_PAGER },
+               { "grep", cmd_grep, USE_PAGER },
                { "hash-object", cmd_hash_object },
                { "help", cmd_help },
                { "index-pack", cmd_index_pack },
index 1f6978a..3c879b8 100755 (executable)
@@ -1143,6 +1143,7 @@ sub validate_refname {
 # in utf-8 thanks to "binmode STDOUT, ':utf8'" at beginning
 sub to_utf8 {
        my $str = shift;
+       return undef unless defined $str;
        if (utf8::valid($str)) {
                utf8::decode($str);
                return $str;
@@ -1155,6 +1156,7 @@ sub to_utf8 {
 # correct, but quoted slashes look too horrible in bookmarks
 sub esc_param {
        my $str = shift;
+       return undef unless defined $str;
        $str =~ s/([^A-Za-z0-9\-_.~()\/:@ ]+)/CGI::escape($1)/eg;
        $str =~ s/ /\+/g;
        return $str;
@@ -1163,6 +1165,7 @@ sub esc_param {
 # quote unsafe chars in whole URL, so some charactrs cannot be quoted
 sub esc_url {
        my $str = shift;
+       return undef unless defined $str;
        $str =~ s/([^A-Za-z0-9\-_.~();\/;?:@&=])/sprintf("%%%02X", ord($1))/eg;
        $str =~ s/\+/%2B/g;
        $str =~ s/ /\+/g;
@@ -1174,6 +1177,8 @@ sub esc_html {
        my $str = shift;
        my %opts = @_;
 
+       return undef unless defined $str;
+
        $str = to_utf8($str);
        $str = $cgi->escapeHTML($str);
        if ($opts{'-nbsp'}) {
@@ -1188,6 +1193,8 @@ sub esc_path {
        my $str = shift;
        my %opts = @_;
 
+       return undef unless defined $str;
+
        $str = to_utf8($str);
        $str = $cgi->escapeHTML($str);
        if ($opts{'-nbsp'}) {
@@ -3372,7 +3379,7 @@ sub git_footer_html {
              "</html>";
 }
 
-# die_error(<http_status_code>, <error_message>)
+# die_error(<http_status_code>, <error_message>[, <detailed_html_description>])
 # Example: die_error(404, 'Hash not found')
 # By convention, use the following status codes (as defined in RFC 2616):
 # 400: Invalid or missing CGI parameters, or
@@ -3387,7 +3394,7 @@ sub git_footer_html {
 #      or down for maintenance).  Generally, this is a temporary state.
 sub die_error {
        my $status = shift || 500;
-       my $error = shift || "Internal server error";
+       my $error = esc_html(shift) || "Internal Server Error";
        my $extra = shift;
 
        my %http_responses = (
index ba72fa4..5631930 100644 (file)
@@ -91,7 +91,6 @@ struct msg_data {
        char *data;
        int len;
        unsigned char flags;
-       unsigned int crlf:1;
 };
 
 static const char imap_send_usage[] = "git imap-send < <mbox>";
@@ -1162,6 +1161,44 @@ static int imap_make_flags(int flags, char *buf)
        return d;
 }
 
+static void lf_to_crlf(struct msg_data *msg)
+{
+       char *new;
+       int i, j, lfnum = 0;
+
+       if (msg->data[0] == '\n')
+               lfnum++;
+       for (i = 1; i < msg->len; i++) {
+               if (msg->data[i - 1] != '\r' && msg->data[i] == '\n')
+                       lfnum++;
+       }
+
+       new = xmalloc(msg->len + lfnum);
+       if (msg->data[0] == '\n') {
+               new[0] = '\r';
+               new[1] = '\n';
+               i = 1;
+               j = 2;
+       } else {
+               new[0] = msg->data[0];
+               i = 1;
+               j = 1;
+       }
+       for ( ; i < msg->len; i++) {
+               if (msg->data[i] != '\n') {
+                       new[j++] = msg->data[i];
+                       continue;
+               }
+               if (msg->data[i - 1] != '\r')
+                       new[j++] = '\r';
+               /* otherwise it already had CR before */
+               new[j++] = '\n';
+       }
+       msg->len += lfnum;
+       free(msg->data);
+       msg->data = new;
+}
+
 static int imap_store_msg(struct store *gctx, struct msg_data *data)
 {
        struct imap_store *ctx = (struct imap_store *)gctx;
@@ -1171,6 +1208,7 @@ static int imap_store_msg(struct store *gctx, struct msg_data *data)
        int ret, d;
        char flagstr[128];
 
+       lf_to_crlf(data);
        memset(&cb, 0, sizeof(cb));
 
        cb.dlen = data->len;
diff --git a/path.c b/path.c
index e166d53..d1fccbd 100644 (file)
--- a/path.c
+++ b/path.c
@@ -336,7 +336,7 @@ char *enter_repo(char *path, int strict)
 
        if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
            validate_headref("HEAD") == 0) {
-               setenv(GIT_DIR_ENVIRONMENT, ".", 1);
+               set_git_dir(".");
                check_repository_format();
                return path;
        }
index a904164..d388120 100644 (file)
@@ -184,13 +184,13 @@ static struct discovery* discover_refs(const char *service)
        return last;
 }
 
-static int write_discovery(int fd, void *data)
+static int write_discovery(int in, int out, void *data)
 {
        struct discovery *heads = data;
        int err = 0;
-       if (write_in_full(fd, heads->buf, heads->len) != heads->len)
+       if (write_in_full(out, heads->buf, heads->len) != heads->len)
                err = 1;
-       close(fd);
+       close(out);
        return err;
 }
 
@@ -202,6 +202,7 @@ static struct ref *parse_git_refs(struct discovery *heads)
        memset(&async, 0, sizeof(async));
        async.proc = write_discovery;
        async.data = heads;
+       async.out = -1;
 
        if (start_async(&async))
                die("cannot start thread to parse advertised refs");
index 2feb493..0cd7f02 100644 (file)
@@ -233,6 +233,9 @@ fail_pipe:
                else if (need_err) {
                        dup2(fderr[1], 2);
                        close_pair(fderr);
+               } else if (cmd->err > 1) {
+                       dup2(cmd->err, 2);
+                       close(cmd->err);
                }
 
                if (cmd->no_stdout)
@@ -325,6 +328,8 @@ fail_pipe:
                fherr = open("/dev/null", O_RDWR);
        else if (need_err)
                fherr = dup(fderr[1]);
+       else if (cmd->err > 2)
+               fherr = dup(cmd->err);
 
        if (cmd->no_stdout)
                fhout = open("/dev/null", O_RDWR);
@@ -394,6 +399,8 @@ fail_pipe:
 
        if (need_err)
                close(fderr[1]);
+       else if (cmd->err)
+               close(cmd->err);
 
        return 0;
 }
@@ -444,17 +451,51 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
 static unsigned __stdcall run_thread(void *data)
 {
        struct async *async = data;
-       return async->proc(async->fd_for_proc, async->data);
+       return async->proc(async->proc_in, async->proc_out, async->data);
 }
 #endif
 
 int start_async(struct async *async)
 {
-       int pipe_out[2];
+       int need_in, need_out;
+       int fdin[2], fdout[2];
+       int proc_in, proc_out;
 
-       if (pipe(pipe_out) < 0)
-               return error("cannot create pipe: %s", strerror(errno));
-       async->out = pipe_out[0];
+       need_in = async->in < 0;
+       if (need_in) {
+               if (pipe(fdin) < 0) {
+                       if (async->out > 0)
+                               close(async->out);
+                       return error("cannot create pipe: %s", strerror(errno));
+               }
+               async->in = fdin[1];
+       }
+
+       need_out = async->out < 0;
+       if (need_out) {
+               if (pipe(fdout) < 0) {
+                       if (need_in)
+                               close_pair(fdin);
+                       else if (async->in)
+                               close(async->in);
+                       return error("cannot create pipe: %s", strerror(errno));
+               }
+               async->out = fdout[0];
+       }
+
+       if (need_in)
+               proc_in = fdin[0];
+       else if (async->in)
+               proc_in = async->in;
+       else
+               proc_in = -1;
+
+       if (need_out)
+               proc_out = fdout[1];
+       else if (async->out)
+               proc_out = async->out;
+       else
+               proc_out = -1;
 
 #ifndef WIN32
        /* Flush stdio before fork() to avoid cloning buffers */
@@ -463,24 +504,47 @@ int start_async(struct async *async)
        async->pid = fork();
        if (async->pid < 0) {
                error("fork (async) failed: %s", strerror(errno));
-               close_pair(pipe_out);
-               return -1;
+               goto error;
        }
        if (!async->pid) {
-               close(pipe_out[0]);
-               exit(!!async->proc(pipe_out[1], async->data));
+               if (need_in)
+                       close(fdin[1]);
+               if (need_out)
+                       close(fdout[0]);
+               exit(!!async->proc(proc_in, proc_out, async->data));
        }
-       close(pipe_out[1]);
+
+       if (need_in)
+               close(fdin[0]);
+       else if (async->in)
+               close(async->in);
+
+       if (need_out)
+               close(fdout[1]);
+       else if (async->out)
+               close(async->out);
 #else
-       async->fd_for_proc = pipe_out[1];
+       async->proc_in = proc_in;
+       async->proc_out = proc_out;
        async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL);
        if (!async->tid) {
                error("cannot create thread: %s", strerror(errno));
-               close_pair(pipe_out);
-               return -1;
+               goto error;
        }
 #endif
        return 0;
+
+error:
+       if (need_in)
+               close_pair(fdin);
+       else if (async->in)
+               close(async->in);
+
+       if (need_out)
+               close_pair(fdout);
+       else if (async->out)
+               close(async->out);
+       return -1;
 }
 
 int finish_async(struct async *async)
index 967ba8c..94619f5 100644 (file)
@@ -18,7 +18,7 @@ struct child_process {
         * - Specify > 0 to set a channel to a particular FD as follows:
         *     .in: a readable FD, becomes child's stdin
         *     .out: a writable FD, becomes child's stdout/stderr
-        *     .err > 0 not supported
+        *     .err: a writable FD, becomes child's stderr
         *   The specified FD is closed by start_command(), even in case
         *   of errors!
         */
@@ -66,17 +66,20 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
  */
 struct async {
        /*
-        * proc writes to fd and closes it;
+        * proc reads from in; closes it before return
+        * proc writes to out; closes it before return
         * returns 0 on success, non-zero on failure
         */
-       int (*proc)(int fd, void *data);
+       int (*proc)(int in, int out, void *data);
        void *data;
+       int in;         /* caller writes here and closes it */
        int out;        /* caller reads from here and closes it */
 #ifndef WIN32
        pid_t pid;
 #else
        HANDLE tid;
-       int fd_for_proc;
+       int proc_in;
+       int proc_out;
 #endif
 };
 
diff --git a/setup.c b/setup.c
index fac34f7..0717a98 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -404,9 +404,9 @@ const char *setup_git_directory_gently(int *nongit_ok)
                                inside_work_tree = 0;
                        if (offset != len) {
                                cwd[offset] = '\0';
-                               setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
+                               set_git_dir(cwd);
                        } else
-                               setenv(GIT_DIR_ENVIRONMENT, ".", 1);
+                               set_git_dir(".");
                        check_repository_format_gently(nongit_ok);
                        return NULL;
                }
old mode 100755 (executable)
new mode 100644 (file)
index 75a3ee2..ce36f34
@@ -1,3 +1,5 @@
+: included from t2016 and others
+
 . ./test-lib.sh
 
 if ! test_have_prereq PERL; then
index 325714e..17bcb0b 100755 (executable)
@@ -17,23 +17,22 @@ test_expect_success setup '
        commit1=$(echo modify | git commit-tree $tree1 -p $commit0) &&
        git update-ref refs/heads/master $commit0 &&
        git update-ref refs/heads/tofail $commit1 &&
-       git clone ./. victim &&
-       GIT_DIR=victim/.git git config receive.denyCurrentBranch warn &&
-       GIT_DIR=victim/.git git update-ref refs/heads/tofail $commit1 &&
+       git clone --bare ./. victim.git &&
+       GIT_DIR=victim.git git update-ref refs/heads/tofail $commit1 &&
        git update-ref refs/heads/master $commit1 &&
        git update-ref refs/heads/tofail $commit0
 '
 
-cat >victim/.git/hooks/pre-receive <<'EOF'
+cat >victim.git/hooks/pre-receive <<'EOF'
 #!/bin/sh
 printf %s "$@" >>$GIT_DIR/pre-receive.args
 cat - >$GIT_DIR/pre-receive.stdin
 echo STDOUT pre-receive
 echo STDERR pre-receive >&2
 EOF
-chmod u+x victim/.git/hooks/pre-receive
+chmod u+x victim.git/hooks/pre-receive
 
-cat >victim/.git/hooks/update <<'EOF'
+cat >victim.git/hooks/update <<'EOF'
 #!/bin/sh
 echo "$@" >>$GIT_DIR/update.args
 read x; printf %s "$x" >$GIT_DIR/update.stdin
@@ -41,77 +40,77 @@ echo STDOUT update $1
 echo STDERR update $1 >&2
 test "$1" = refs/heads/master || exit
 EOF
-chmod u+x victim/.git/hooks/update
+chmod u+x victim.git/hooks/update
 
-cat >victim/.git/hooks/post-receive <<'EOF'
+cat >victim.git/hooks/post-receive <<'EOF'
 #!/bin/sh
 printf %s "$@" >>$GIT_DIR/post-receive.args
 cat - >$GIT_DIR/post-receive.stdin
 echo STDOUT post-receive
 echo STDERR post-receive >&2
 EOF
-chmod u+x victim/.git/hooks/post-receive
+chmod u+x victim.git/hooks/post-receive
 
-cat >victim/.git/hooks/post-update <<'EOF'
+cat >victim.git/hooks/post-update <<'EOF'
 #!/bin/sh
 echo "$@" >>$GIT_DIR/post-update.args
 read x; printf %s "$x" >$GIT_DIR/post-update.stdin
 echo STDOUT post-update
 echo STDERR post-update >&2
 EOF
-chmod u+x victim/.git/hooks/post-update
+chmod u+x victim.git/hooks/post-update
 
 test_expect_success push '
-       test_must_fail git send-pack --force ./victim/.git \
+       test_must_fail git send-pack --force ./victim.git \
                master tofail >send.out 2>send.err
 '
 
 test_expect_success 'updated as expected' '
-       test $(GIT_DIR=victim/.git git rev-parse master) = $commit1 &&
-       test $(GIT_DIR=victim/.git git rev-parse tofail) = $commit1
+       test $(GIT_DIR=victim.git git rev-parse master) = $commit1 &&
+       test $(GIT_DIR=victim.git git rev-parse tofail) = $commit1
 '
 
 test_expect_success 'hooks ran' '
-       test -f victim/.git/pre-receive.args &&
-       test -f victim/.git/pre-receive.stdin &&
-       test -f victim/.git/update.args &&
-       test -f victim/.git/update.stdin &&
-       test -f victim/.git/post-receive.args &&
-       test -f victim/.git/post-receive.stdin &&
-       test -f victim/.git/post-update.args &&
-       test -f victim/.git/post-update.stdin
+       test -f victim.git/pre-receive.args &&
+       test -f victim.git/pre-receive.stdin &&
+       test -f victim.git/update.args &&
+       test -f victim.git/update.stdin &&
+       test -f victim.git/post-receive.args &&
+       test -f victim.git/post-receive.stdin &&
+       test -f victim.git/post-update.args &&
+       test -f victim.git/post-update.stdin
 '
 
 test_expect_success 'pre-receive hook input' '
        (echo $commit0 $commit1 refs/heads/master;
         echo $commit1 $commit0 refs/heads/tofail
-       ) | test_cmp - victim/.git/pre-receive.stdin
+       ) | test_cmp - victim.git/pre-receive.stdin
 '
 
 test_expect_success 'update hook arguments' '
        (echo refs/heads/master $commit0 $commit1;
         echo refs/heads/tofail $commit1 $commit0
-       ) | test_cmp - victim/.git/update.args
+       ) | test_cmp - victim.git/update.args
 '
 
 test_expect_success 'post-receive hook input' '
        echo $commit0 $commit1 refs/heads/master |
-       test_cmp - victim/.git/post-receive.stdin
+       test_cmp - victim.git/post-receive.stdin
 '
 
 test_expect_success 'post-update hook arguments' '
        echo refs/heads/master |
-       test_cmp - victim/.git/post-update.args
+       test_cmp - victim.git/post-update.args
 '
 
 test_expect_success 'all hook stdin is /dev/null' '
-       ! test -s victim/.git/update.stdin &&
-       ! test -s victim/.git/post-update.stdin
+       ! test -s victim.git/update.stdin &&
+       ! test -s victim.git/post-update.stdin
 '
 
 test_expect_success 'all *-receive hook args are empty' '
-       ! test -s victim/.git/pre-receive.args &&
-       ! test -s victim/.git/post-receive.args
+       ! test -s victim.git/pre-receive.args &&
+       ! test -s victim.git/post-receive.args
 '
 
 test_expect_success 'send-pack produced no output' '
@@ -119,20 +118,21 @@ test_expect_success 'send-pack produced no output' '
 '
 
 cat <<EOF >expect
-STDOUT pre-receive
-STDERR pre-receive
-STDOUT update refs/heads/master
-STDERR update refs/heads/master
-STDOUT update refs/heads/tofail
-STDERR update refs/heads/tofail
-STDOUT post-receive
-STDERR post-receive
-STDOUT post-update
-STDERR post-update
+remote: STDOUT pre-receive
+remote: STDERR pre-receive
+remote: STDOUT update refs/heads/master
+remote: STDERR update refs/heads/master
+remote: STDOUT update refs/heads/tofail
+remote: STDERR update refs/heads/tofail
+remote: error: hook declined to update refs/heads/tofail
+remote: STDOUT post-receive
+remote: STDERR post-receive
+remote: STDOUT post-update
+remote: STDERR post-update
 EOF
 test_expect_success 'send-pack stderr contains hook messages' '
-       grep ^STD send.err >actual &&
-       test_cmp - actual <expect
+       grep ^remote: send.err | sed "s/ *\$//" >actual &&
+       test_cmp expect actual
 '
 
 test_done
index 169af1e..721821e 100755 (executable)
@@ -341,6 +341,13 @@ test_expect_success 'fetch into the current branch with --update-head-ok' '
 
 '
 
+test_expect_success 'fetch --dry-run' '
+
+       rm -f .git/FETCH_HEAD &&
+       git fetch --dry-run . &&
+       ! test -f .git/FETCH_HEAD
+'
+
 test_expect_success "should be able to fetch with duplicate refspecs" '
         mkdir dups &&
         cd dups &&
old mode 100755 (executable)
new mode 100644 (file)
index f55627b..985d517
@@ -1,3 +1,5 @@
+: included from 6002 and others
+
 [ -d .git/refs/tags ] || mkdir -p .git/refs/tags
 
 :> sed.script
index 6291307..d605024 100755 (executable)
@@ -64,6 +64,10 @@ cp new1.txt test.txt
 test_expect_success "merge without conflict" \
        "git merge-file test.txt orig.txt new2.txt"
 
+cp new1.txt test.txt
+test_expect_success "merge without conflict (--quiet)" \
+       "git merge-file --quiet test.txt orig.txt new2.txt"
+
 cp new1.txt test2.txt
 test_expect_success "merge without conflict (missing LF at EOF)" \
        "git merge-file test2.txt orig.txt new2.txt"
index 0b583cb..ebae152 100755 (executable)
@@ -434,6 +434,58 @@ test_expect_success 'grep -Fi' '
        test_cmp expected actual
 '
 
+test_expect_success 'outside of git repository' '
+       rm -fr non &&
+       mkdir -p non/git/sub &&
+       echo hello >non/git/file1 &&
+       echo world >non/git/sub/file2 &&
+       echo ".*o*" >non/git/.gitignore &&
+       {
+               echo file1:hello &&
+               echo sub/file2:world
+       } >non/expect.full &&
+       echo file2:world >non/expect.sub
+       (
+               GIT_CEILING_DIRECTORIES="$(pwd)/non/git" &&
+               export GIT_CEILING_DIRECTORIES &&
+               cd non/git &&
+               test_must_fail git grep o &&
+               git grep --no-index o >../actual.full &&
+               test_cmp ../expect.full ../actual.full
+               cd sub &&
+               test_must_fail git grep o &&
+               git grep --no-index o >../../actual.sub &&
+               test_cmp ../../expect.sub ../../actual.sub
+       )
+'
+
+test_expect_success 'inside git repository but with --no-index' '
+       rm -fr is &&
+       mkdir -p is/git/sub &&
+       echo hello >is/git/file1 &&
+       echo world >is/git/sub/file2 &&
+       echo ".*o*" >is/git/.gitignore &&
+       {
+               echo file1:hello &&
+               echo sub/file2:world
+       } >is/expect.full &&
+       : >is/expect.empty &&
+       echo file2:world >is/expect.sub
+       (
+               cd is/git &&
+               git init &&
+               test_must_fail git grep o >../actual.full &&
+               test_cmp ../expect.empty ../actual.full &&
+               git grep --no-index o >../actual.full &&
+               test_cmp ../expect.full ../actual.full &&
+               cd sub &&
+               test_must_fail git grep o >../../actual.sub &&
+               test_cmp ../../expect.empty ../../actual.sub &&
+               git grep --no-index o >../../actual.sub &&
+               test_cmp ../../expect.sub ../../actual.sub
+       )
+'
+
 test_expect_success 'setup double-dash tests' '
 cat >double-dash <<EOF &&
 --
index 6442f71..d20ed61 100755 (executable)
@@ -166,19 +166,31 @@ test_expect_success 'checkout -m with merge conflict' '
        ! test -s current
 '
 
-test_expect_success 'checkout to detach HEAD' '
+test_expect_success 'checkout to detach HEAD (with advice declined)' '
 
+       git config advice.detachedHead false &&
        git checkout -f renamer && git clean -f &&
        git checkout renamer^ 2>messages &&
-       (cat >messages.expect <<EOF
-Note: moving to '\''renamer^'\'' which isn'\''t a local branch
-If you want to create a new branch from this checkout, you may do so
-(now or later) by using -b with the checkout command again. Example:
-  git checkout -b <new_branch_name>
-HEAD is now at 7329388... Initial A one, A two
-EOF
-) &&
-       test_cmp messages.expect messages &&
+       grep "HEAD is now at 7329388" messages &&
+       test 1 -eq $(wc -l <messages) &&
+       H=$(git rev-parse --verify HEAD) &&
+       M=$(git show-ref -s --verify refs/heads/master) &&
+       test "z$H" = "z$M" &&
+       if git symbolic-ref HEAD >/dev/null 2>&1
+       then
+               echo "OOPS, HEAD is still symbolic???"
+               false
+       else
+               : happy
+       fi
+'
+
+test_expect_success 'checkout to detach HEAD' '
+       git config advice.detachedHead true &&
+       git checkout -f renamer && git clean -f &&
+       git checkout renamer^ 2>messages &&
+       grep "HEAD is now at 7329388" messages &&
+       test 1 -lt $(wc -l <messages) &&
        H=$(git rev-parse --verify HEAD) &&
        M=$(git show-ref -s --verify refs/heads/master) &&
        test "z$H" = "z$M" &&
index 3569c62..1640824 100755 (executable)
@@ -33,6 +33,21 @@ test_expect_success 'svn non-merge merge commits did not become git merge commit
        [ -z "$bad_non_merges" ]
        '
 
+test_expect_success 'commit made to merged branch is reachable from the merge' '
+       before_commit=$(git rev-list --all --grep="trunk commit before merging trunk to b2")
+       merge_commit=$(git rev-list --all --grep="Merge trunk to b2")
+       not_reachable=$(git rev-list -1 $before_commit --not $merge_commit)
+       [ -z "$not_reachable" ]
+       '
+
+test_expect_success 'merging two branches in one commit is detected correctly' '
+       f1_commit=$(git rev-list --all --grep="make f1 branch from trunk")
+       f2_commit=$(git rev-list --all --grep="make f2 branch from trunk")
+       merge_commit=$(git rev-list --all --grep="Merge f1 and f2 to trunk")
+       not_reachable=$(git rev-list -1 $f1_commit $f2_commit --not $merge_commit)
+       [ -z "$not_reachable" ]
+       '
+
 test_expect_failure 'everything got merged in the end' '
        unmerged=$(git rev-list --all --not master)
        [ -z "$unmerged" ]
index 3d73f14..e1e138c 100644 (file)
@@ -156,6 +156,89 @@ svn merge ../branches/right --accept postpone
 i=$(commit $i "non-merge right to trunk 2")
 cd ..
 
+say "Branching b1 from trunk"
+svn update
+svn cp trunk branches/b1
+i=$(commit $i "make b1 branch from trunk")
+
+say "Branching b2 from trunk"
+svn update
+svn cp trunk branches/b2
+i=$(commit $i "make b2 branch from trunk")
+
+say "Make a commit to b2"
+svn update
+cd branches/b2
+echo "b2" > b2file
+svn add b2file
+i=$(commit $i "b2 update 1")
+cd ../..
+
+say "Make a commit to b1"
+svn update
+cd branches/b1
+echo "b1" > b1file
+svn add b1file
+i=$(commit $i "b1 update 1")
+cd ../..
+
+say "Merge b1 to trunk"
+svn update
+cd trunk
+svn merge ../branches/b1/ --accept postpone
+i=$(commit $i "Merge b1 to trunk")
+cd ..
+
+say "Make a commit to trunk before merging trunk to b2"
+svn update
+cd trunk
+echo "trunk" > trunkfile
+svn add trunkfile
+i=$(commit $i "trunk commit before merging trunk to b2")
+cd ..
+
+say "Merge trunk to b2"
+svn update
+cd branches/b2
+svn merge ../../trunk/ --accept postpone
+i=$(commit $i "Merge trunk to b2")
+cd ../..
+
+say "Merge b2 to trunk"
+svn update
+cd trunk
+svn merge ../branches/b2/ --accept postpone
+svn resolved b1file
+svn resolved trunkfile
+i=$(commit $i "Merge b2 to trunk")
+cd ..
+
+say "Creating f1 from trunk with a new file"
+svn update
+svn cp trunk branches/f1
+cd branches/f1
+echo "f1" > f1file
+svn add f1file
+cd ../..
+i=$(commit $i "make f1 branch from trunk with a new file")
+
+say "Creating f2 from trunk with a new file"
+svn update
+svn cp trunk branches/f2
+cd branches/f2
+echo "f2" > f2file
+svn add f2file
+cd ../..
+i=$(commit $i "make f2 branch from trunk with a new file")
+
+say "Merge f1 and f2 to trunk in one go"
+svn update
+cd trunk
+svn merge ../branches/f1/ --accept postpone
+svn merge ../branches/f2/ --accept postpone
+i=$(commit $i "Merge f1 and f2 to trunk")
+cd ..
+
 say "Adding subdirectory to LEFT"
 svn update
 cd branches/left
@@ -174,8 +257,8 @@ cd ..
 
 say "Make PARTIAL branch"
 svn update
-i=$(commit $i "make partial branch")
 svn cp trunk/subdir branches/partial
+i=$(commit $i "make partial branch")
 
 say "Make a commit to PARTIAL"
 svn update
@@ -194,13 +277,13 @@ cd ../../
 
 say "Tagging trunk"
 svn update
-i=$(commit $i "tagging v1.0")
 svn cp trunk tags/v1.0
+i=$(commit $i "tagging v1.0")
 
 say "Branching BUGFIX from v1.0"
 svn update
-i=$(commit $i "make bugfix branch from tag")
 svn cp tags/v1.0 branches/bugfix
+i=$(commit $i "make bugfix branch from tag")
 
 say "Make a commit to BUGFIX"
 svn update
index ebf386e..47cafcf 100644 (file)
@@ -1633,13 +1633,427 @@ PROPS-END
 
 
 Revision-number: 25
+Prop-content-length: 129
+Content-length: 129
+
+K 7
+svn:log
+V 31
+(r25) make b1 branch from trunk
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:18:56.084589Z
+PROPS-END
+
+Node-path: branches/b1
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 24
+Node-copyfrom-path: trunk
+
+
+Revision-number: 26
+Prop-content-length: 129
+Content-length: 129
+
+K 7
+svn:log
+V 31
+(r26) make b2 branch from trunk
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:18:59.076940Z
+PROPS-END
+
+Node-path: branches/b2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 25
+Node-copyfrom-path: trunk
+
+
+Revision-number: 27
+Prop-content-length: 115
+Content-length: 115
+
+K 7
+svn:log
+V 17
+(r27) b2 update 1
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:01.095762Z
+PROPS-END
+
+Node-path: branches/b2/b2file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 3
+Text-content-md5: 5edbdd57cba621eb3c6e601bf563b4dc
+Text-content-sha1: 9d4b38049776bd0a2074d67cad23f8eaed35a3b3
+Content-length: 13
+
+PROPS-END
+b2
+
+
+Revision-number: 28
+Prop-content-length: 115
+Content-length: 115
+
+K 7
+svn:log
+V 17
+(r28) b1 update 1
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:03.097465Z
+PROPS-END
+
+Node-path: branches/b1/b1file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 3
+Text-content-md5: 08778dfd9ac4f603231896aba7aad523
+Text-content-sha1: b551771aa4ad5b14123fc3bd98d89db2bc0edd4f
+Content-length: 13
+
+PROPS-END
+b1
+
+
+Revision-number: 29
+Prop-content-length: 121
+Content-length: 121
+
+K 7
+svn:log
+V 23
+(r29) Merge b1 to trunk
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:06.073175Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 118
+Content-length: 118
+
+K 13
+svn:mergeinfo
+V 83
+/branches/b1:25-28
+/branches/left:2-22
+/branches/left-sub:4-19
+/branches/right:2-22
+PROPS-END
+
+
+Node-path: trunk/b1file
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 28
+Node-copyfrom-path: branches/b1/b1file
+Text-copy-source-md5: 08778dfd9ac4f603231896aba7aad523
+Text-copy-source-sha1: b551771aa4ad5b14123fc3bd98d89db2bc0edd4f
+
+
+Revision-number: 30
+Prop-content-length: 143
+Content-length: 143
+
+K 7
+svn:log
+V 45
+(r30) trunk commit before merging trunk to b2
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:08.096353Z
+PROPS-END
+
+Node-path: trunk/trunkfile
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 6
+Text-content-md5: edf45fe5c98c5367733b39bbb2bb20d9
+Text-content-sha1: 7361d1685e5c86dfc523620cfaf598f196f86239
+Content-length: 16
+
+PROPS-END
+trunk
+
+
+Revision-number: 31
+Prop-content-length: 121
+Content-length: 121
+
+K 7
+svn:log
+V 23
+(r31) Merge trunk to b2
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:11.081541Z
+PROPS-END
+
+Node-path: branches/b2
+Node-kind: dir
+Node-action: change
+Prop-content-length: 131
+Content-length: 131
+
+K 13
+svn:mergeinfo
+V 96
+/branches/b1:25-28
+/branches/left:2-22
+/branches/left-sub:4-19
+/branches/right:2-22
+/trunk:26-30
+PROPS-END
+
+
+Node-path: branches/b2/b1file
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 30
+Node-copyfrom-path: trunk/b1file
+Text-copy-source-md5: 08778dfd9ac4f603231896aba7aad523
+Text-copy-source-sha1: b551771aa4ad5b14123fc3bd98d89db2bc0edd4f
+
+
+Node-path: branches/b2/trunkfile
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 30
+Node-copyfrom-path: trunk/trunkfile
+Text-copy-source-md5: edf45fe5c98c5367733b39bbb2bb20d9
+Text-copy-source-sha1: 7361d1685e5c86dfc523620cfaf598f196f86239
+
+
+Revision-number: 32
+Prop-content-length: 121
+Content-length: 121
+
+K 7
+svn:log
+V 23
+(r32) Merge b2 to trunk
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:14.117939Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 138
+Content-length: 138
+
+K 13
+svn:mergeinfo
+V 102
+/branches/b1:25-28
+/branches/b2:26-31
+/branches/left:2-22
+/branches/left-sub:4-19
+/branches/right:2-22
+PROPS-END
+
+
+Node-path: trunk/b2file
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 31
+Node-copyfrom-path: branches/b2/b2file
+Text-copy-source-md5: 5edbdd57cba621eb3c6e601bf563b4dc
+Text-copy-source-sha1: 9d4b38049776bd0a2074d67cad23f8eaed35a3b3
+
+
+Revision-number: 33
+Prop-content-length: 145
+Content-length: 145
+
+K 7
+svn:log
+V 47
+(r33) make f1 branch from trunk with a new file
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:17.105832Z
+PROPS-END
+
+Node-path: branches/f1
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 32
+Node-copyfrom-path: trunk
+
+
+Node-path: branches/f1/f1file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 3
+Text-content-md5: 2b1abc6b6c5c0018851f9f8e6475563b
+Text-content-sha1: aece6dfba588900e00d95601d22b4408d49580af
+Content-length: 13
+
+PROPS-END
+f1
+
+
+Revision-number: 34
+Prop-content-length: 145
+Content-length: 145
+
+K 7
+svn:log
+V 47
+(r34) make f2 branch from trunk with a new file
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:20.110057Z
+PROPS-END
+
+Node-path: branches/f2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 33
+Node-copyfrom-path: trunk
+
+
+Node-path: branches/f2/f2file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 3
+Text-content-md5: 575c5638d60271457e54ab7d07309502
+Text-content-sha1: 1c49a440c352f3473efa9512255033b94dc7def0
+Content-length: 13
+
+PROPS-END
+f2
+
+
+Revision-number: 35
+Prop-content-length: 128
+Content-length: 128
+
+K 7
+svn:log
+V 30
+(r35) Merge f1 and f2 to trunk
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:24.081490Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 173
+Content-length: 173
+
+K 13
+svn:mergeinfo
+V 137
+/branches/b1:25-28
+/branches/b2:26-31
+/branches/f1:33-34
+/branches/f2:34
+/branches/left:2-22
+/branches/left-sub:4-19
+/branches/right:2-22
+PROPS-END
+
+
+Node-path: trunk/f1file
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 34
+Node-copyfrom-path: branches/f1/f1file
+Text-copy-source-md5: 2b1abc6b6c5c0018851f9f8e6475563b
+Text-copy-source-sha1: aece6dfba588900e00d95601d22b4408d49580af
+
+
+Node-path: trunk/f2file
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 34
+Node-copyfrom-path: branches/f2/f2file
+Text-copy-source-md5: 575c5638d60271457e54ab7d07309502
+Text-copy-source-sha1: 1c49a440c352f3473efa9512255033b94dc7def0
+
+
+Revision-number: 36
 Prop-content-length: 135
 Content-length: 135
 
 K 7
 svn:log
 V 37
-(r25) add subdirectory to left branch
+(r36) add subdirectory to left branch
 K 10
 svn:author
 V 3
@@ -1647,7 +2061,7 @@ adm
 K 8
 svn:date
 V 27
-2010-01-19T04:14:46.052649Z
+2010-02-22T06:19:26.113516Z
 PROPS-END
 
 Node-path: branches/left/subdir
@@ -1672,14 +2086,14 @@ PROPS-END
 Yeehaw
 
 
-Revision-number: 26
+Revision-number: 37
 Prop-content-length: 123
 Content-length: 123
 
 K 7
 svn:log
 V 25
-(r26) merge left to trunk
+(r37) merge left to trunk
 K 10
 svn:author
 V 3
@@ -1687,19 +2101,23 @@ adm
 K 8
 svn:date
 V 27
-2010-01-19T04:14:49.040783Z
+2010-02-22T06:19:29.073699Z
 PROPS-END
 
 Node-path: trunk
 Node-kind: dir
 Node-action: change
-Prop-content-length: 99
-Content-length: 99
+Prop-content-length: 173
+Content-length: 173
 
 K 13
 svn:mergeinfo
-V 64
-/branches/left:2-25
+V 137
+/branches/b1:25-28
+/branches/b2:26-31
+/branches/f1:33-34
+/branches/f2:34
+/branches/left:2-36
 /branches/left-sub:4-19
 /branches/right:2-22
 PROPS-END
@@ -1708,18 +2126,18 @@ PROPS-END
 Node-path: trunk/subdir
 Node-kind: dir
 Node-action: add
-Node-copyfrom-rev: 25
+Node-copyfrom-rev: 36
 Node-copyfrom-path: branches/left/subdir
 
 
-Revision-number: 27
-Prop-content-length: 118
-Content-length: 118
+Revision-number: 38
+Prop-content-length: 123
+Content-length: 123
 
 K 7
 svn:log
-V 20
-(r28) partial update
+V 25
+(r38) make partial branch
 K 10
 svn:author
 V 3
@@ -1727,16 +2145,34 @@ adm
 K 8
 svn:date
 V 27
-2010-01-19T04:14:53.049037Z
+2010-02-22T06:19:32.072243Z
 PROPS-END
 
 Node-path: branches/partial
 Node-kind: dir
 Node-action: add
-Node-copyfrom-rev: 26
+Node-copyfrom-rev: 37
 Node-copyfrom-path: trunk/subdir
 
 
+Revision-number: 39
+Prop-content-length: 118
+Content-length: 118
+
+K 7
+svn:log
+V 20
+(r39) partial update
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:34.097961Z
+PROPS-END
+
 Node-path: branches/partial/palindromes
 Node-kind: file
 Node-action: add
@@ -1750,14 +2186,14 @@ PROPS-END
 racecar
 
 
-Revision-number: 28
+Revision-number: 40
 Prop-content-length: 126
 Content-length: 126
 
 K 7
 svn:log
 V 28
-(r29) merge partial to trunk
+(r40) merge partial to trunk
 K 10
 svn:author
 V 3
@@ -1765,21 +2201,25 @@ adm
 K 8
 svn:date
 V 27
-2010-01-19T04:14:56.041526Z
+2010-02-22T06:19:37.080211Z
 PROPS-END
 
 Node-path: trunk/subdir
 Node-kind: dir
 Node-action: change
-Prop-content-length: 142
-Content-length: 142
+Prop-content-length: 246
+Content-length: 246
 
 K 13
 svn:mergeinfo
-V 106
-/branches/left/subdir:2-25
+V 210
+/branches/b1/subdir:25-28
+/branches/b2/subdir:26-31
+/branches/f1/subdir:33-34
+/branches/f2/subdir:34
+/branches/left/subdir:2-36
 /branches/left-sub/subdir:4-19
-/branches/partial:27
+/branches/partial:38-39
 /branches/right/subdir:2-22
 PROPS-END
 
@@ -1787,20 +2227,20 @@ PROPS-END
 Node-path: trunk/subdir/palindromes
 Node-kind: file
 Node-action: add
-Node-copyfrom-rev: 27
+Node-copyfrom-rev: 39
 Node-copyfrom-path: branches/partial/palindromes
 Text-copy-source-md5: 5d1c2024fb5efc4eef812856df1b080c
 Text-copy-source-sha1: 5f8509ddd14c91a52864dd1447344e706f9bbc69
 
 
-Revision-number: 29
-Prop-content-length: 131
-Content-length: 131
+Revision-number: 41
+Prop-content-length: 116
+Content-length: 116
 
 K 7
 svn:log
-V 33
-(r31) make bugfix branch from tag
+V 18
+(r41) tagging v1.0
 K 10
 svn:author
 V 3
@@ -1808,24 +2248,24 @@ adm
 K 8
 svn:date
 V 27
-2010-01-19T04:15:00.039761Z
+2010-02-22T06:19:40.083460Z
 PROPS-END
 
 Node-path: tags/v1.0
 Node-kind: dir
 Node-action: add
-Node-copyfrom-rev: 28
+Node-copyfrom-rev: 40
 Node-copyfrom-path: trunk
 
 
-Revision-number: 30
-Prop-content-length: 120
-Content-length: 120
+Revision-number: 42
+Prop-content-length: 131
+Content-length: 131
 
 K 7
 svn:log
-V 22
-(r32) commit to bugfix
+V 33
+(r42) make bugfix branch from tag
 K 10
 svn:author
 V 3
@@ -1833,16 +2273,34 @@ adm
 K 8
 svn:date
 V 27
-2010-01-19T04:15:03.043218Z
+2010-02-22T06:19:43.118075Z
 PROPS-END
 
 Node-path: branches/bugfix
 Node-kind: dir
 Node-action: add
-Node-copyfrom-rev: 29
+Node-copyfrom-rev: 41
 Node-copyfrom-path: tags/v1.0
 
 
+Revision-number: 43
+Prop-content-length: 120
+Content-length: 120
+
+K 7
+svn:log
+V 22
+(r43) commit to bugfix
+K 10
+svn:author
+V 3
+adm
+K 8
+svn:date
+V 27
+2010-02-22T06:19:45.079536Z
+PROPS-END
+
 Node-path: branches/bugfix/subdir/palindromes
 Node-kind: file
 Node-action: change
@@ -1855,14 +2313,14 @@ racecar
 kayak
 
 
-Revision-number: 31
+Revision-number: 44
 Prop-content-length: 125
 Content-length: 125
 
 K 7
 svn:log
 V 27
-(r33) Merge BUGFIX to TRUNK
+(r44) Merge BUGFIX to TRUNK
 K 10
 svn:author
 V 3
@@ -1870,41 +2328,49 @@ adm
 K 8
 svn:date
 V 27
-2010-01-19T04:15:06.043723Z
+2010-02-22T06:19:48.078914Z
 PROPS-END
 
 Node-path: trunk
 Node-kind: dir
 Node-action: change
-Prop-content-length: 133
-Content-length: 133
+Prop-content-length: 210
+Content-length: 210
 
 K 13
 svn:mergeinfo
-V 98
-/branches/bugfix:30
-/branches/left:2-25
+V 174
+/branches/b1:25-28
+/branches/b2:26-31
+/branches/bugfix:42-43
+/branches/f1:33-34
+/branches/f2:34
+/branches/left:2-36
 /branches/left-sub:4-19
 /branches/right:2-22
-/tags/v1.0:29
+/tags/v1.0:41
 PROPS-END
 
 
 Node-path: trunk/subdir
 Node-kind: dir
 Node-action: change
-Prop-content-length: 190
-Content-length: 190
+Prop-content-length: 297
+Content-length: 297
 
 K 13
 svn:mergeinfo
-V 154
-/branches/bugfix/subdir:30
-/branches/left/subdir:2-25
+V 261
+/branches/b1/subdir:25-28
+/branches/b2/subdir:26-31
+/branches/bugfix/subdir:42-43
+/branches/f1/subdir:33-34
+/branches/f2/subdir:34
+/branches/left/subdir:2-36
 /branches/left-sub/subdir:4-19
-/branches/partial:27
+/branches/partial:38-39
 /branches/right/subdir:2-22
-/tags/v1.0/subdir:29
+/tags/v1.0/subdir:41
 PROPS-END
 
 
index 3846aac..08e4fa0 100644 (file)
@@ -918,6 +918,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
        if (!remote)
                die("No remote provided to transport_get()");
 
+       ret->got_remote_refs = 0;
        ret->remote = remote;
        helper = remote->foreign_vcs;
 
@@ -1079,8 +1080,10 @@ int transport_push(struct transport *transport,
 
 const struct ref *transport_get_remote_refs(struct transport *transport)
 {
-       if (!transport->remote_refs)
+       if (!transport->got_remote_refs) {
                transport->remote_refs = transport->get_refs_list(transport, 0);
+               transport->got_remote_refs = 1;
+       }
 
        return transport->remote_refs;
 }
index 7cea5cc..6dd9ae1 100644 (file)
@@ -19,6 +19,12 @@ struct transport {
        void *data;
        const struct ref *remote_refs;
 
+       /**
+        * Indicates whether we already called get_refs_list(); set by
+        * transport.c::transport_get_remote_refs().
+        */
+       unsigned got_remote_refs : 1;
+
        /**
         * Returns 0 if successful, positive if the option is not
         * recognized or is inapplicable, and negative if the option
index df15181..dc464d7 100644 (file)
@@ -105,12 +105,12 @@ static void show_edge(struct commit *commit)
        fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1));
 }
 
-static int do_rev_list(int fd, void *create_full_pack)
+static int do_rev_list(int in, int out, void *create_full_pack)
 {
        int i;
        struct rev_info revs;
 
-       pack_pipe = xfdopen(fd, "w");
+       pack_pipe = xfdopen(out, "w");
        init_revisions(&revs, NULL);
        revs.tag_objects = 1;
        revs.tree_objects = 1;
@@ -162,8 +162,9 @@ static void create_pack_file(void)
        int arg = 0;
 
        if (shallow_nr) {
+               memset(&rev_list, 0, sizeof(rev_list));
                rev_list.proc = do_rev_list;
-               rev_list.data = 0;
+               rev_list.out = -1;
                if (start_async(&rev_list))
                        die("git upload-pack: unable to fork git-rev-list");
                argv[arg++] = "pack-objects";