Merge branch 'jc/curl'
authorJunio C Hamano <junkio@cox.net>
Fri, 29 Dec 2006 19:36:21 +0000 (11:36 -0800)
committerJunio C Hamano <junkio@cox.net>
Fri, 29 Dec 2006 19:36:21 +0000 (11:36 -0800)
* jc/curl:
  Work around http-fetch built with cURL 7.16.0

49 files changed:
Documentation/config.txt
Documentation/git-merge.txt
Makefile
builtin-add.c
builtin-commit-tree.c
builtin-log.c
builtin-mailinfo.c
cache.h
commit.c
commit.h
config.c
contrib/completion/git-completion.bash
dir.c
dir.h
environment.c
fetch-pack.c
git-am.sh
git-clone.sh
git-fetch.sh
git-merge.sh
git-pull.sh
git-rebase.sh
git-reset.sh
git-sh-setup.sh
git-svn.perl
gitweb/gitweb.perl
refs.c
revision.h
shallow.c [new file with mode: 0644]
t/Makefile
t/README
t/t3700-add.sh
t/t3900-i18n-commit.sh [new file with mode: 0755]
t/t3900/1-UTF-8.txt [new file with mode: 0644]
t/t3900/2-UTF-8.txt [new file with mode: 0644]
t/t3900/EUCJP.txt [new file with mode: 0644]
t/t3900/ISO-2022-JP.txt [new file with mode: 0644]
t/t3900/ISO-8859-1.txt [new file with mode: 0644]
t/t5400-send-pack.sh
t/t5500-fetch-pack.sh
t/t6023-merge-file.sh
t/t6024-recursive-merge.sh
t/t9200-git-cvsexportcommit.sh
t/test-lib.sh
templates/hooks--update
upload-pack.c
utf8.c
utf8.h
xdiff/xmerge.c

index 6452a8be144f92f9140fb133acda4d9fd32f2b15..178e0e1e209e066ad220d6ba95be0728c2db5e99 100644 (file)
@@ -267,6 +267,10 @@ i18n.commitEncoding::
        browser (and possibly at other places in the future or in other
        porcelains). See e.g. gitlink:git-mailinfo[1]. Defaults to 'utf-8'.
 
+i18n.logOutputEncoding::
+       Character encoding the commit messages are converted to when
+       running `git-log` and friends.
+
 log.showroot::
        If true, the initial commit will be shown as a big creation event.
        This is equivalent to a diff against an empty tree.
index e2954aa76eef46101f38683eb346bd31bf711a40..0f79665ea6e6bf1ffd4ff67f7aee2fcbddec0555 100644 (file)
@@ -10,7 +10,6 @@ SYNOPSIS
 --------
 [verse]
 'git-merge' [-n] [--no-commit] [--squash] [-s <strategy>]...
-       [--reflog-action=<action>]
        -m=<msg> <remote> <remote>...
 
 DESCRIPTION
@@ -37,11 +36,6 @@ include::merge-options.txt[]
        least one <remote>.  Specifying more than one <remote>
        obviously means you are trying an Octopus.
 
---reflog-action=<action>::
-       This is used internally when `git-pull` calls this command
-       to record that the merge was created by `pull` command
-       in the `ref-log` entry that results from the merge.
-
 include::merge-strategies.txt[]
 
 
index 775ffaac27d7382df9db84d226603854295045d6..93dc4948d3cd6b655c2e0c630892e67b9ae656eb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -79,6 +79,10 @@ all:
 #
 # Define NO_ICONV if your libc does not properly support iconv.
 #
+# Define NO_R_TO_GCC if your gcc does not like "-R/path/lib" that
+# tells runtime paths to dynamic libraries; "-Wl,-rpath=/path/lib"
+# is used instead.
+#
 # Define USE_NSEC below if you want git to care about sub-second file mtimes
 # and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
 # it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
@@ -250,8 +254,7 @@ LIB_OBJS = \
        revision.o pager.o tree-walk.o xdiff-interface.o \
        write_or_die.o trace.o list-objects.o grep.o \
        alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
-       color.o wt-status.o archive-zip.o archive-tar.o \
-       utf8.o
+       color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o
 
 BUILTIN_OBJS = \
        builtin-add.o \
@@ -422,11 +425,19 @@ ifeq ($(uname_S),Darwin)
        endif
 endif
 
+ifdef NO_R_TO_GCC_LINKER
+       # Some gcc does not accept and pass -R to the linker to specify
+       # the runtime dynamic library path.
+       CC_LD_DYNPATH = -Wl,-rpath=
+else
+       CC_LD_DYNPATH = -R
+endif
+
 ifndef NO_CURL
        ifdef CURLDIR
-               # This is still problematic -- gcc does not always want -R.
+               # Try "-Wl,-rpath=$(CURLDIR)/lib" in such a case.
                BASIC_CFLAGS += -I$(CURLDIR)/include
-               CURL_LIBCURL = -L$(CURLDIR)/lib -R$(CURLDIR)/lib -lcurl
+               CURL_LIBCURL = -L$(CURLDIR)/lib $(CC_LD_DYNPATH)$(CURLDIR)/lib -lcurl
        else
                CURL_LIBCURL = -lcurl
        endif
@@ -445,9 +456,8 @@ endif
 ifndef NO_OPENSSL
        OPENSSL_LIBSSL = -lssl
        ifdef OPENSSLDIR
-               # Again this may be problematic -- gcc does not always want -R.
                BASIC_CFLAGS += -I$(OPENSSLDIR)/include
-               OPENSSL_LINK = -L$(OPENSSLDIR)/lib -R$(OPENSSLDIR)/lib
+               OPENSSL_LINK = -L$(OPENSSLDIR)/lib $(CC_LD_DYNPATH)$(OPENSSLDIR)/lib
        else
                OPENSSL_LINK =
        endif
@@ -463,9 +473,8 @@ else
 endif
 ifdef NEEDS_LIBICONV
        ifdef ICONVDIR
-               # Again this may be problematic -- gcc does not always want -R.
                BASIC_CFLAGS += -I$(ICONVDIR)/include
-               ICONV_LINK = -L$(ICONVDIR)/lib -R$(ICONVDIR)/lib
+               ICONV_LINK = -L$(ICONVDIR)/lib $(CC_LD_DYNPATH)$(ICONVDIR)/lib
        else
                ICONV_LINK =
        endif
index 8ed4a6a9f32b9cd0f71289af2296cacf79864448..e7a1b4d9ab43cbb7de48b099c3afb721903f516b 100644 (file)
@@ -26,18 +26,9 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
        i = dir->nr;
        while (--i >= 0) {
                struct dir_entry *entry = *src++;
-               int how = match_pathspec(pathspec, entry->name, entry->len,
-                                        prefix, seen);
-               /*
-                * ignored entries can be added with exact match,
-                * but not with glob nor recursive.
-                */
-               if (!how ||
-                   (entry->ignored_entry && how != MATCHED_EXACTLY)) {
-                       free(entry);
-                       continue;
-               }
-               *dst++ = entry;
+               if (match_pathspec(pathspec, entry->name, entry->len,
+                                  prefix, seen))
+                       *dst++ = entry;
        }
        dir->nr = dst - dir->entries;
 
@@ -47,10 +38,20 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
                if (seen[i])
                        continue;
 
-               /* Existing file? We must have ignored it */
                match = pathspec[i];
-               if (!match[0] || !lstat(match, &st))
+               if (!match[0])
                        continue;
+
+               /* Existing file? We must have ignored it */
+               if (!lstat(match, &st)) {
+                       struct dir_entry *ent;
+
+                       ent = dir_add_name(dir, match, strlen(match));
+                       ent->ignored = 1;
+                       if (S_ISDIR(st.st_mode))
+                               ent->ignored_dir = 1;
+                       continue;
+               }
                die("pathspec '%s' did not match any files", match);
        }
 }
@@ -62,8 +63,6 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec)
 
        /* Set up the default git porcelain excludes */
        memset(dir, 0, sizeof(*dir));
-       if (pathspec)
-               dir->show_both = 1;
        dir->exclude_per_dir = ".gitignore";
        path = git_path("info/exclude");
        if (!access(path, R_OK))
@@ -154,7 +153,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        if (show_only) {
                const char *sep = "", *eof = "";
                for (i = 0; i < dir.nr; i++) {
-                       if (!ignored_too && dir.entries[i]->ignored_entry)
+                       if (!ignored_too && dir.entries[i]->ignored)
                                continue;
                        printf("%s%s", sep, dir.entries[i]->name);
                        sep = " ";
@@ -168,16 +167,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)
                die("index file corrupt");
 
        if (!ignored_too) {
-               int has_ignored = -1;
-               for (i = 0; has_ignored < 0 && i < dir.nr; i++)
-                       if (dir.entries[i]->ignored_entry)
-                               has_ignored = i;
-               if (0 <= has_ignored) {
+               int has_ignored = 0;
+               for (i = 0; i < dir.nr; i++)
+                       if (dir.entries[i]->ignored)
+                               has_ignored = 1;
+               if (has_ignored) {
                        fprintf(stderr, ignore_warning);
-                       for (i = has_ignored; i < dir.nr; i++) {
-                               if (!dir.entries[i]->ignored_entry)
+                       for (i = 0; i < dir.nr; i++) {
+                               if (!dir.entries[i]->ignored)
                                        continue;
-                               fprintf(stderr, "%s\n", dir.entries[i]->name);
+                               fprintf(stderr, "%s", dir.entries[i]->name);
+                               if (dir.entries[i]->ignored_dir)
+                                       fprintf(stderr, " (directory)");
+                               fputc('\n', stderr);
                        }
                        fprintf(stderr,
                                "Use -f if you really want to add them.\n");
index f641787988e197209f097cbc9d1b260a2cb6d9d8..146aaffd282987454c0910477cfe7a047f478e94 100644 (file)
@@ -92,6 +92,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
        char comment[1000];
        char *buffer;
        unsigned int size;
+       int encoding_is_utf8;
 
        setup_ident();
        git_config(git_default_config);
@@ -117,6 +118,10 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                        parents++;
        }
 
+       /* Not having i18n.commitencoding is the same as having utf-8 */
+       encoding_is_utf8 = (!git_commit_encoding ||
+                           !strcmp(git_commit_encoding, "utf-8"));
+
        init_buffer(&buffer, &size);
        add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1));
 
@@ -130,7 +135,11 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 
        /* Person/date information */
        add_buffer(&buffer, &size, "author %s\n", git_author_info(1));
-       add_buffer(&buffer, &size, "committer %s\n\n", git_committer_info(1));
+       add_buffer(&buffer, &size, "committer %s\n", git_committer_info(1));
+       if (!encoding_is_utf8)
+               add_buffer(&buffer, &size,
+                               "encoding %s\n", git_commit_encoding);
+       add_buffer(&buffer, &size, "\n");
 
        /* And add the comment */
        while (fgets(comment, sizeof(comment), stdin) != NULL)
@@ -138,7 +147,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 
        /* And check the encoding */
        buffer[size] = '\0';
-       if (!strcmp(git_commit_encoding, "utf-8") && !is_utf8(buffer))
+       if (encoding_is_utf8 && !is_utf8(buffer))
                fprintf(stderr, commit_utf8_warn);
 
        if (!write_sha1_file(buffer, size, commit_type, commit_sha1)) {
index 8df3c1394a0b70548708137bfe20126fbea01709..a59b4acef1bc45f07f15e10c0501aa23de3eed7d 100644 (file)
@@ -20,6 +20,8 @@ void add_head(struct rev_info *revs);
 static void cmd_log_init(int argc, const char **argv, const char *prefix,
                      struct rev_info *rev)
 {
+       int i;
+
        rev->abbrev = DEFAULT_ABBREV;
        rev->commit_format = CMIT_FMT_DEFAULT;
        rev->verbose_header = 1;
@@ -27,8 +29,18 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
        argc = setup_revisions(argc, argv, rev, "HEAD");
        if (rev->diffopt.pickaxe || rev->diffopt.filter)
                rev->always_show_header = 0;
-       if (argc > 1)
-               die("unrecognized argument: %s", argv[1]);
+       for (i = 1; i < argc; i++) {
+               const char *arg = argv[i];
+               if (!strncmp(arg, "--encoding=", 11)) {
+                       arg += 11;
+                       if (strcmp(arg, "none"))
+                               git_log_output_encoding = strdup(arg);
+                       else
+                               git_log_output_encoding = "";
+               }
+               else
+                       die("unrecognized argument: %s", arg);
+       }
 }
 
 static int cmd_log_walk(struct rev_info *rev)
index e6472293d47611d415276f6057227d9c93788f63..a67f3eb90b6f715714c6fa7bb931044630c74111 100644 (file)
@@ -4,6 +4,7 @@
  */
 #include "cache.h"
 #include "builtin.h"
+#include "utf8.h"
 
 static FILE *cmitmsg, *patchfile, *fin, *fout;
 
@@ -510,40 +511,18 @@ static int decode_b_segment(char *in, char *ot, char *ep)
 
 static void convert_to_utf8(char *line, char *charset)
 {
-#ifndef NO_ICONV
-       char *in, *out;
-       size_t insize, outsize, nrc;
-       char outbuf[4096]; /* cheat */
        static char latin_one[] = "latin1";
        char *input_charset = *charset ? charset : latin_one;
-       iconv_t conv = iconv_open(metainfo_charset, input_charset);
-
-       if (conv == (iconv_t) -1) {
-               static int warned_latin1_once = 0;
-               if (input_charset != latin_one) {
-                       fprintf(stderr, "cannot convert from %s to %s\n",
-                               input_charset, metainfo_charset);
-                       *charset = 0;
-               }
-               else if (!warned_latin1_once) {
-                       warned_latin1_once = 1;
-                       fprintf(stderr, "tried to convert from %s to %s, "
-                               "but your iconv does not work with it.\n",
-                               input_charset, metainfo_charset);
-               }
+       char *out = reencode_string(line, metainfo_charset, input_charset);
+
+       if (!out) {
+               fprintf(stderr, "cannot convert from %s to %s\n",
+                       input_charset, metainfo_charset);
+               *charset = 0;
                return;
        }
-       in = line;
-       insize = strlen(in);
-       out = outbuf;
-       outsize = sizeof(outbuf);
-       nrc = iconv(conv, &in, &insize, &out, &outsize);
-       iconv_close(conv);
-       if (nrc == (size_t) -1)
-               return;
-       *out = 0;
-       strcpy(line, outbuf);
-#endif
+       strcpy(line, out);
+       free(out);
 }
 
 static int decode_header_bq(char *it)
@@ -827,7 +806,8 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
                if (!strcmp(argv[1], "-k"))
                        keep_subject = 1;
                else if (!strcmp(argv[1], "-u"))
-                       metainfo_charset = git_commit_encoding;
+                       metainfo_charset = (git_commit_encoding
+                                           ? git_commit_encoding : "utf-8");
                else if (!strncmp(argv[1], "--encoding=", 11))
                        metainfo_charset = argv[1] + 11;
                else
diff --git a/cache.h b/cache.h
index 4943056c19ffb72a7cfb994daaa788ec1b01d60b..29dd290c9253bd96f086432e24d98cb0b43fa096 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -416,8 +416,8 @@ extern int check_repository_format_version(const char *var, const char *value);
 extern char git_default_email[MAX_GITNAME];
 extern char git_default_name[MAX_GITNAME];
 
-#define MAX_ENCODING_LENGTH 64
-extern char git_commit_encoding[MAX_ENCODING_LENGTH];
+extern char *git_commit_encoding;
+extern char *git_log_output_encoding;
 
 extern int copy_fd(int ifd, int ofd);
 extern void write_or_die(int fd, const void *buf, size_t count);
index 3167ce62acd5eb1076a4c089b54f2b37f821130b..eb06afbbe0f00ac4f553e37c50eca290418a7907 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -1,6 +1,8 @@
 #include "cache.h"
 #include "tag.h"
 #include "commit.h"
+#include "pkt-line.h"
+#include "utf8.h"
 
 int save_commit_buffer = 1;
 
@@ -221,6 +223,8 @@ static void prepare_commit_graft(void)
                return;
        graft_file = get_graft_file();
        read_graft_file(graft_file);
+       /* make sure shallows are read */
+       is_repository_shallow();
        commit_graft_prepared = 1;
 }
 
@@ -234,6 +238,37 @@ static struct commit_graft *lookup_commit_graft(const unsigned char *sha1)
        return commit_graft[pos];
 }
 
+int write_shallow_commits(int fd, int use_pack_protocol)
+{
+       int i, count = 0;
+       for (i = 0; i < commit_graft_nr; i++)
+               if (commit_graft[i]->nr_parent < 0) {
+                       const char *hex =
+                               sha1_to_hex(commit_graft[i]->sha1);
+                       count++;
+                       if (use_pack_protocol)
+                               packet_write(fd, "shallow %s", hex);
+                       else {
+                               write(fd, hex,  40);
+                               write(fd, "\n", 1);
+                       }
+               }
+       return count;
+}
+
+int unregister_shallow(const unsigned char *sha1)
+{
+       int pos = commit_graft_pos(sha1);
+       if (pos < 0)
+               return -1;
+       if (pos + 1 < commit_graft_nr)
+               memcpy(commit_graft + pos, commit_graft + pos + 1,
+                               sizeof(struct commit_graft *)
+                               * (commit_graft_nr - pos - 1));
+       commit_graft_nr--;
+       return 0;
+}
+
 int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
 {
        char *tail = buffer;
@@ -563,10 +598,61 @@ static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *com
        return offset;
 }
 
-unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
-                                 unsigned long len, char *buf, unsigned long space,
+static char *get_header(const struct commit *commit, const char *key)
+{
+       int key_len = strlen(key);
+       const char *line = commit->buffer;
+
+       for (;;) {
+               const char *eol = strchr(line, '\n'), *next;
+
+               if (line == eol)
+                       return NULL;
+               if (!eol) {
+                       eol = line + strlen(line);
+                       next = NULL;
+               } else
+                       next = eol + 1;
+               if (!strncmp(line, key, key_len) && line[key_len] == ' ') {
+                       int len = eol - line - key_len;
+                       char *ret = xmalloc(len);
+                       memcpy(ret, line + key_len + 1, len - 1);
+                       ret[len - 1] = '\0';
+                       return ret;
+               }
+               line = next;
+       }
+}
+
+static char *logmsg_reencode(const struct commit *commit)
+{
+       char *encoding;
+       char *out;
+       char *output_encoding = (git_log_output_encoding
+                                ? git_log_output_encoding
+                                : git_commit_encoding);
+
+       if (!output_encoding)
+               return NULL;
+       encoding = get_header(commit, "encoding");
+       if (!encoding || !strcmp(encoding, output_encoding)) {
+               free(encoding);
+               return NULL;
+       }
+       out = reencode_string(commit->buffer, output_encoding, encoding);
+       free(encoding);
+       if (!out)
+               return NULL;
+       return out;
+}
+
+unsigned long pretty_print_commit(enum cmit_fmt fmt,
+                                 const struct commit *commit,
+                                 unsigned long len,
+                                 char *buf, unsigned long space,
                                  int abbrev, const char *subject,
-                                 const char *after_subject, int relative_date)
+                                 const char *after_subject,
+                                 int relative_date)
 {
        int hdr = 1, body = 0;
        unsigned long offset = 0;
@@ -574,6 +660,10 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit
        int parents_shown = 0;
        const char *msg = commit->buffer;
        int plain_non_ascii = 0;
+       char *reencoded = logmsg_reencode(commit);
+
+       if (reencoded)
+               msg = reencoded;
 
        if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
                indent = 0;
@@ -590,7 +680,7 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit
                for (in_body = i = 0; (ch = msg[i]) && i < len; i++) {
                        if (!in_body) {
                                /* author could be non 7-bit ASCII but
-                                * the log may so; skip over the
+                                * the log may be so; skip over the
                                 * header part first.
                                 */
                                if (ch == '\n' &&
@@ -721,6 +811,8 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit
        if (fmt == CMIT_FMT_EMAIL && !body)
                buf[offset++] = '\n';
        buf[offset] = '\0';
+
+       free(reencoded);
        return offset;
 }
 
index 10eea9f26ff5db9df82245756c9c8bff0f6be3f6..936f8fce301672b5b78352a217403cc319ab3f07 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -97,7 +97,7 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
 
 struct commit_graft {
        unsigned char sha1[20];
-       int nr_parent;
+       int nr_parent; /* < 0 if shallow commit */
        unsigned char parent[FLEX_ARRAY][20]; /* more */
 };
 
@@ -107,5 +107,12 @@ int read_graft_file(const char *graft_file);
 
 extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
 
+extern int register_shallow(const unsigned char *sha1);
+extern int unregister_shallow(const unsigned char *sha1);
+extern int write_shallow_commits(int fd, int use_pack_protocol);
+extern int is_repository_shallow();
+extern struct commit_list *get_shallow_commits(struct object_array *heads,
+               int depth, int shallow_flag, int not_shallow_flag);
+
 int in_merge_bases(struct commit *rev1, struct commit *rev2);
 #endif /* COMMIT_H */
index 1662a4626e569b07d96c622b357928216a24538c..fcccf7e2a4f3b7487af10d4f7b505c7ef492b9e8 100644 (file)
--- a/config.c
+++ b/config.c
@@ -309,10 +309,16 @@ int git_default_config(const char *var, const char *value)
        }
 
        if (!strcmp(var, "i18n.commitencoding")) {
-               strlcpy(git_commit_encoding, value, sizeof(git_commit_encoding));
+               git_commit_encoding = strdup(value);
                return 0;
        }
 
+       if (!strcmp(var, "i18n.logoutputencoding")) {
+               git_log_output_encoding = strdup(value);
+               return 0;
+       }
+
+
        if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
                pager_use_color = git_config_bool(var,value);
                return 0;
index 234cd0954b888d814d8d4d86bb41983b80fddade..7c7520ea29dfb26ffafc355ea739046b6d821e28 100755 (executable)
@@ -711,6 +711,7 @@ _git_repo_config ()
                core.compression
                core.legacyHeaders
                i18n.commitEncoding
+               i18n.logOutputEncoding
                diff.color
                color.diff
                diff.renameLimit
diff --git a/dir.c b/dir.c
index dd188a8c56c02e1bbe2c8fc0cfb9ce67cdeb948d..0338d6c4e0ab4409d6023db96f5298d292692099 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -260,13 +260,12 @@ int excluded(struct dir_struct *dir, const char *pathname)
        return 0;
 }
 
-static void add_name(struct dir_struct *dir, const char *pathname, int len,
-                    int ignored_entry)
+struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
 {
        struct dir_entry *ent;
 
        if (cache_name_pos(pathname, len) >= 0)
-               return;
+               return NULL;
 
        if (dir->nr == dir->alloc) {
                int alloc = alloc_nr(dir->alloc);
@@ -274,11 +273,12 @@ static void add_name(struct dir_struct *dir, const char *pathname, int len,
                dir->entries = xrealloc(dir->entries, alloc*sizeof(ent));
        }
        ent = xmalloc(sizeof(*ent) + len + 1);
-       ent->ignored_entry = ignored_entry;
+       ent->ignored = ent->ignored_dir = 0;
        ent->len = len;
        memcpy(ent->name, pathname, len);
        ent->name[len] = 0;
        dir->entries[dir->nr++] = ent;
+       return ent;
 }
 
 static int dir_exists(const char *dirname, int len)
@@ -316,7 +316,6 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
 
                while ((de = readdir(fdir)) != NULL) {
                        int len;
-                       int ignored_entry;
 
                        if ((de->d_name[0] == '.') &&
                            (de->d_name[1] == 0 ||
@@ -325,12 +324,11 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
                                continue;
                        len = strlen(de->d_name);
                        memcpy(fullname + baselen, de->d_name, len+1);
-                       ignored_entry = excluded(dir, fullname);
-
-                       if (!dir->show_both &&
-                           (ignored_entry != dir->show_ignored) &&
-                           (!dir->show_ignored || DTYPE(de) != DT_DIR))
-                               continue;
+                       if (excluded(dir, fullname) != dir->show_ignored) {
+                               if (!dir->show_ignored || DTYPE(de) != DT_DIR) {
+                                       continue;
+                               }
+                       }
 
                        switch (DTYPE(de)) {
                        struct stat st;
@@ -368,8 +366,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
                        if (check_only)
                                goto exit_early;
                        else
-                               add_name(dir, fullname, baselen + len,
-                                        ignored_entry);
+                               dir_add_name(dir, fullname, baselen + len);
                }
 exit_early:
                closedir(fdir);
diff --git a/dir.h b/dir.h
index 08c634547229fc1353fd092fb226293ed07368c3..7233d65bbd393f1d34d75538dd0e39e4a86383f2 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -13,8 +13,9 @@
 
 
 struct dir_entry {
-       unsigned ignored_entry : 1;
-       unsigned int len : 15;
+       unsigned int ignored : 1;
+       unsigned int ignored_dir : 1;
+       unsigned int len : 30;
        char name[FLEX_ARRAY]; /* more */
 };
 
@@ -30,8 +31,7 @@ struct exclude_list {
 
 struct dir_struct {
        int nr, alloc;
-       unsigned int show_both: 1,
-                    show_ignored:1,
+       unsigned int show_ignored:1,
                     show_other_directories:1,
                     hide_empty_directories:1;
        struct dir_entry **entries;
@@ -57,5 +57,6 @@ extern void add_excludes_from_file(struct dir_struct *, const char *fname);
 extern void add_exclude(const char *string, const char *base,
                        int baselen, struct exclude_list *which);
 extern int file_exists(const char *);
+extern struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len);
 
 #endif
index f8c7dbceadf2190997816f9a21b211a6a97efe48..a1502c4e87c0067c8cc276006317005a0da21a49 100644 (file)
@@ -18,7 +18,8 @@ int prefer_symlink_refs;
 int log_all_ref_updates;
 int warn_ambiguous_refs = 1;
 int repository_format_version;
-char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
+char *git_commit_encoding;
+char *git_log_output_encoding;
 int shared_repository = PERM_UMASK;
 const char *apply_default_whitespace;
 int zlib_compression_level = Z_DEFAULT_COMPRESSION;
index 92322cf4da39434d44e4aa52fa0c3f735b22d752..c527bf9e9621519f72e1039313666a03ee12c586 100644 (file)
@@ -10,8 +10,9 @@ static int keep_pack;
 static int quiet;
 static int verbose;
 static int fetch_all;
+static int depth;
 static const char fetch_pack_usage[] =
-"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory <refs>...";
+"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [--depth=<n>] [host:]directory <refs>...";
 static const char *exec = "git-upload-pack";
 
 #define COMPLETE       (1U << 0)
@@ -179,10 +180,41 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                        packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
                fetching++;
        }
+       if (is_repository_shallow())
+               write_shallow_commits(fd[1], 1);
+       if (depth > 0)
+               packet_write(fd[1], "deepen %d", depth);
        packet_flush(fd[1]);
        if (!fetching)
                return 1;
 
+       if (depth > 0) {
+               char line[1024];
+               unsigned char sha1[20];
+               int len;
+
+               while ((len = packet_read_line(fd[0], line, sizeof(line)))) {
+                       if (!strncmp("shallow ", line, 8)) {
+                               if (get_sha1_hex(line + 8, sha1))
+                                       die("invalid shallow line: %s", line);
+                               register_shallow(sha1);
+                               continue;
+                       }
+                       if (!strncmp("unshallow ", line, 10)) {
+                               if (get_sha1_hex(line + 10, sha1))
+                                       die("invalid unshallow line: %s", line);
+                               if (!lookup_object(sha1))
+                                       die("object not found: %s", line);
+                               /* make sure that it is parsed as shallow */
+                               parse_object(sha1);
+                               if (unregister_shallow(sha1))
+                                       die("no shallow found: %s", line);
+                               continue;
+                       }
+                       die("expected shallow/unshallow, got %s", line);
+               }
+       }
+
        flushes = 0;
        retval = -1;
        while ((sha1 = get_rev())) {
@@ -309,7 +341,8 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
                if (!memcmp(ref->name, "refs/", 5) &&
                    check_ref_format(ref->name + 5))
                        ; /* trash */
-               else if (fetch_all) {
+               else if (fetch_all &&
+                        (!depth || strncmp(ref->name, "refs/tags/", 10) )) {
                        *newtail = ref;
                        ref->next = NULL;
                        newtail = &ref->next;
@@ -368,9 +401,11 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
                }
        }
 
-       for_each_ref(mark_complete, NULL);
-       if (cutoff)
-               mark_recent_complete_commits(cutoff);
+       if (!depth) {
+               for_each_ref(mark_complete, NULL);
+               if (cutoff)
+                       mark_recent_complete_commits(cutoff);
+       }
 
        /*
         * Mark all complete remote refs as common refs.
@@ -522,6 +557,8 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
        int status;
 
        get_remote_heads(fd[0], &ref, 0, NULL, 0);
+       if (is_repository_shallow() && !server_supports("shallow"))
+               die("Server does not support shallow clients");
        if (server_supports("multi_ack")) {
                if (verbose)
                        fprintf(stderr, "Server supports multi_ack\n");
@@ -594,6 +631,8 @@ int main(int argc, char **argv)
        char *dest = NULL, **heads;
        int fd[2];
        pid_t pid;
+       struct stat st;
+       struct lock_file lock;
 
        setup_git_directory();
 
@@ -627,6 +666,12 @@ int main(int argc, char **argv)
                                verbose = 1;
                                continue;
                        }
+                       if (!strncmp("--depth=", arg, 8)) {
+                               depth = strtol(arg + 8, NULL, 0);
+                               if (stat(git_path("shallow"), &st))
+                                       st.st_mtime = 0;
+                               continue;
+                       }
                        usage(fetch_pack_usage);
                }
                dest = arg;
@@ -659,5 +704,34 @@ int main(int argc, char **argv)
                        }
        }
 
+       if (!ret && depth > 0) {
+               struct cache_time mtime;
+               char *shallow = git_path("shallow");
+               int fd;
+
+               mtime.sec = st.st_mtime;
+#ifdef USE_NSEC
+               mtime.usec = st.st_mtim.usec;
+#endif
+               if (stat(shallow, &st)) {
+                       if (mtime.sec)
+                               die("shallow file was removed during fetch");
+               } else if (st.st_mtime != mtime.sec
+#ifdef USE_NSEC
+                               || st.st_mtim.usec != mtime.usec
+#endif
+                         )
+                       die("shallow file was changed during fetch");
+
+               fd = hold_lock_file_for_update(&lock, shallow, 1);
+               if (!write_shallow_commits(fd, 0)) {
+                       unlink(shallow);
+                       rollback_lock_file(&lock);
+               } else {
+                       close(fd);
+                       commit_lock_file(&lock);
+               }
+       }
+
        return !!ret;
 }
index 0126a77b924e7f1fe7f3913b84350ab35e6e043a..c3bbd78eabf6f3d5eaa0f31bb0c240a26f28e0c5 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -6,6 +6,7 @@ USAGE='[--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way]
   [--interactive] [--whitespace=<option>] <mbox>...
   or, when resuming [--skip | --resolved]'
 . git-sh-setup
+set_reflog_action am
 
 git var GIT_COMMITTER_IDENT >/dev/null || exit
 
@@ -101,7 +102,6 @@ It does not apply to blobs recorded in its index."
 }
 
 prec=4
-rloga=am
 dotest=.dotest sign= utf8= keep= skip= interactive= resolved= binary= ws= resolvemsg=
 
 while case "$#" in 0) break;; esac
@@ -141,9 +141,6 @@ do
        --resolvemsg=*)
        resolvemsg=$(echo "$1" | sed -e "s/^--resolvemsg=//"); shift ;;
 
-       --reflog-action=*)
-       rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`; shift ;;
-
        --)
        shift; break ;;
        -*)
@@ -452,7 +449,7 @@ do
        parent=$(git-rev-parse --verify HEAD) &&
        commit=$(git-commit-tree $tree -p $parent <"$dotest/final-commit") &&
        echo Committed: $commit &&
-       git-update-ref -m "$rloga: $SUBJECT" HEAD $commit $parent ||
+       git-update-ref -m "$GIT_REFLOG_ACTION: $SUBJECT" HEAD $commit $parent ||
        stop_here $this
 
        if test -x "$GIT_DIR"/hooks/post-applypatch
index 490f3e48db02d01cb480047c011aa7b670c431bc..3d388de62a9ee212c8f54f3a5dc9a8b823bc8934 100755 (executable)
@@ -14,7 +14,7 @@ die() {
 }
 
 usage() {
-       die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [-n] <repo> [<dir>]"
+       die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] <repo> [<dir>]"
 }
 
 get_repo_base() {
@@ -120,6 +120,7 @@ reference=
 origin=
 origin_override=
 use_separate_remote=t
+depth=
 while
        case "$#,$1" in
        0,*) break ;;
@@ -163,6 +164,10 @@ while
        *,-u|*,--upload-pack)
                shift
                upload_pack="--exec=$1" ;;
+       1,--depth) usage;;
+       *,--depth)
+               shift
+               depth="--depth=$1";;
        *,-*) usage ;;
        *) break ;;
        esac
@@ -267,6 +272,10 @@ yes,yes)
 *)
        case "$repo" in
        rsync://*)
+               case "$depth" in
+               "") ;;
+               *) die "shallow over rsync not supported" ;;
+               esac
                rsync $quiet -av --ignore-existing  \
                        --exclude info "$repo/objects/" "$GIT_DIR/objects/" ||
                exit
@@ -295,6 +304,10 @@ yes,yes)
                git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
                ;;
        https://*|http://*|ftp://*)
+               case "$depth" in
+               "") ;;
+               *) die "shallow over http or ftp not supported" ;;
+               esac
                if test -z "@@NO_CURL@@"
                then
                        clone_dumb_http "$repo" "$D"
@@ -304,8 +317,8 @@ yes,yes)
                ;;
        *)
                case "$upload_pack" in
-               '') git-fetch-pack --all -k $quiet "$repo" ;;
-               *) git-fetch-pack --all -k $quiet "$upload_pack" "$repo" ;;
+               '') git-fetch-pack --all -k $quiet $depth "$repo" ;;
+               *) git-fetch-pack --all -k $quiet "$upload_pack" $depth "$repo" ;;
                esac >"$GIT_DIR/CLONE_HEAD" ||
                        die "fetch-pack from '$repo' failed."
                ;;
@@ -375,7 +388,7 @@ then
 
                # Set up the mappings to track the remote branches.
                git-repo-config remote."$origin".fetch \
-                       "refs/heads/*:$remote_top/*" '^$' &&
+                       "+refs/heads/*:$remote_top/*" '^$' &&
                rm -f "refs/remotes/$origin/HEAD"
                git-symbolic-ref "refs/remotes/$origin/HEAD" \
                        "refs/remotes/$origin/$head_points_at" &&
index ffbd44f0e1ab841e6f6a38295860220b01bb26ea..8bd11f8b60c0ffec8a67f59bc7e12e1f63adfc91 100755 (executable)
@@ -4,6 +4,8 @@
 USAGE='<fetch-options> <repository> <refspec>...'
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
+set_reflog_action "fetch $*"
+
 TOP=$(git-rev-parse --show-cdup)
 if test ! -z "$TOP"
 then
@@ -17,7 +19,6 @@ LF='
 '
 IFS="$LF"
 
-rloga=fetch
 no_tags=
 tags=
 append=
@@ -27,6 +28,7 @@ update_head_ok=
 exec=
 upload_pack=
 keep=
+shallow_depth=
 while case "$#" in 0) break ;; esac
 do
        case "$1" in
@@ -59,8 +61,12 @@ do
        -k|--k|--ke|--kee|--keep)
                keep='-k -k'
                ;;
-       --reflog-action=*)
-               rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+       --depth=*)
+               shallow_depth="--depth=`expr "z$1" : 'z-[^=]*=\(.*\)'`"
+               ;;
+       --depth)
+               shift
+               shallow_depth="--depth=$1"
                ;;
        -*)
                usage
@@ -86,9 +92,6 @@ refs=
 rref=
 rsync_slurped_objects=
 
-rloga="$rloga $remote_nick"
-test "$remote_nick" = "$remote" || rloga="$rloga $remote"
-
 if test "" = "$append"
 then
        : >"$GIT_DIR/FETCH_HEAD"
@@ -172,12 +175,12 @@ update_local_ref () {
                else
                        echo >&2 "* $1: updating with $3"
                        echo >&2 "  $label_: $newshort_"
-                       git-update-ref -m "$rloga: updating tag" "$1" "$2"
+                       git-update-ref -m "$GIT_REFLOG_ACTION: updating tag" "$1" "$2"
                fi
        else
                echo >&2 "* $1: storing $3"
                echo >&2 "  $label_: $newshort_"
-               git-update-ref -m "$rloga: storing tag" "$1" "$2"
+               git-update-ref -m "$GIT_REFLOG_ACTION: storing tag" "$1" "$2"
        fi
        ;;
 
@@ -200,7 +203,7 @@ update_local_ref () {
            *,$local)
                echo >&2 "* $1: fast forward to $3"
                echo >&2 "  old..new: $oldshort_..$newshort_"
-               git-update-ref -m "$rloga: fast-forward" "$1" "$2" "$local"
+               git-update-ref -m "$GIT_REFLOG_ACTION: fast-forward" "$1" "$2" "$local"
                ;;
            *)
                false
@@ -210,7 +213,7 @@ update_local_ref () {
                *,t,*)
                        echo >&2 "* $1: forcing update to non-fast forward $3"
                        echo >&2 "  old...new: $oldshort_...$newshort_"
-                       git-update-ref -m "$rloga: forced-update" "$1" "$2" "$local"
+                       git-update-ref -m "$GIT_REFLOG_ACTION: forced-update" "$1" "$2" "$local"
                        ;;
                *)
                        echo >&2 "* $1: not updating to non-fast forward $3"
@@ -222,7 +225,7 @@ update_local_ref () {
        else
            echo >&2 "* $1: storing $3"
            echo >&2 "  $label_: $newshort_"
-           git-update-ref -m "$rloga: storing head" "$1" "$2"
+           git-update-ref -m "$GIT_REFLOG_ACTION: storing head" "$1" "$2"
        fi
        ;;
     esac
@@ -305,6 +308,8 @@ fetch_main () {
       # There are transports that can fetch only one head at a time...
       case "$remote" in
       http://* | https://* | ftp://*)
+         test -n "$shallow_depth" &&
+               die "shallow clone with http not supported"
          proto=`expr "$remote" : '\([^:]*\):'`
          if [ -n "$GIT_SSL_NO_VERIFY" ]; then
              curl_extra_args="-k"
@@ -331,6 +336,8 @@ fetch_main () {
          git-http-fetch -v -a "$head" "$remote/" || exit
          ;;
       rsync://*)
+         test -n "$shallow_depth" &&
+               die "shallow clone with rsync not supported"
          TMP_HEAD="$GIT_DIR/TMP_HEAD"
          rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
          head=$(git-rev-parse --verify TMP_HEAD)
@@ -378,7 +385,7 @@ fetch_main () {
       pack_lockfile=
       IFS="    $LF"
       (
-         git-fetch-pack --thin $exec $keep "$remote" $rref || echo failed "$remote"
+         git-fetch-pack --thin $exec $keep $shallow_depth "$remote" $rref || echo failed "$remote"
       ) |
       while read sha1 remote_name
       do
@@ -451,6 +458,8 @@ case "$no_tags$tags" in
        case "$taglist" in
        '') ;;
        ?*)
+               # do not deepen a shallow tree when following tags
+               shallow_depth=
                fetch_main "$taglist" || exit ;;
        esac
 esac
@@ -465,7 +474,7 @@ case "$orig_head" in
        if test "$curr_head" != "$orig_head"
        then
            git-update-ref \
-                       -m "$rloga: Undoing incorrectly fetched HEAD." \
+                       -m "$GIT_REFLOG_ACTION: Undoing incorrectly fetched HEAD." \
                        HEAD "$orig_head"
                die "Cannot fetch into the current branch."
        fi
index 7dd0a112368a8b3672a98fdfcdb5290146cefeba..ba42260426296b63070a1fbdc22a9b77ea5ac412 100755 (executable)
@@ -3,9 +3,10 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-USAGE='[-n] [--no-commit] [--squash] [-s <strategy>] [--reflog-action=<action>] [-m=<merge-message>] <commit>+'
+USAGE='[-n] [--no-commit] [--squash] [-s <strategy>] [-m=<merge-message>] <commit>+'
 
 . git-sh-setup
+set_reflog_action "merge $*"
 
 LF='
 '
@@ -57,10 +58,10 @@ squash_message () {
 finish () {
        if test '' = "$2"
        then
-               rlogm="$rloga"
+               rlogm="$GIT_REFLOG_ACTION"
        else
                echo "$2"
-               rlogm="$rloga: $2"
+               rlogm="$GIT_REFLOG_ACTION: $2"
        fi
        case "$squash" in
        t)
@@ -109,7 +110,7 @@ merge_name () {
 
 case "$#" in 0) usage ;; esac
 
-rloga= have_message=
+have_message=
 while case "$#" in 0) break ;; esac
 do
        case "$1" in
@@ -139,9 +140,6 @@ do
                        die "available strategies are: $all_strategies" ;;
                esac
                ;;
-       --reflog-action=*)
-               rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-               ;;
        -m=*|--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
                merge_msg=`expr "z$1" : 'z-[^=]*=\(.*\)'`
                have_message=t
@@ -213,7 +211,6 @@ head=$(git-rev-parse --verify "$head_arg"^0) || usage
 
 # All the rest are remote heads
 test "$#" = 0 && usage ;# we need at least one remote head.
-test "$rloga" = '' && rloga="merge: $@"
 
 remoteheads=
 for remote
@@ -230,9 +227,21 @@ case "$use_strategies" in
 '')
        case "$#" in
        1)
-               use_strategies="$default_twohead_strategies" ;;
+               var="`git-repo-config --get pull.twohead`"
+               if test -n "$var"
+               then
+                       use_strategies="$var"
+               else
+                       use_strategies="$default_twohead_strategies"
+               fi ;;
        *)
-               use_strategies="$default_octopus_strategies" ;;
+               var="`git-repo-config --get pull.octopus`"
+               if test -n "$var"
+               then
+                       use_strategies="$var"
+               else
+                       use_strategies="$default_octopus_strategies"
+               fi ;;
        esac
        ;;
 esac
index 1703091bbb988e22f39b2c8d4c70ec7340a2f109..28d08195f0c84b7f3a89a5c5cff9945bb64ddfb3 100755 (executable)
@@ -7,6 +7,7 @@
 USAGE='[-n | --no-summary] [--no-commit] [-s strategy]... [<fetch-options>] <repo> <head>...'
 LONG_USAGE='Fetch one or more remote refs and merge it/them into the current HEAD.'
 . git-sh-setup
+set_reflog_action "pull $*"
 
 strategy_args= no_summary= no_commit= squash=
 while case "$#,$1" in 0) break ;; *,-*) ;; *) break ;; esac
@@ -45,7 +46,7 @@ do
 done
 
 orig_head=$(git-rev-parse --verify HEAD 2>/dev/null)
-git-fetch --update-head-ok --reflog-action=pull "$@" || exit 1
+git-fetch --update-head-ok "$@" || exit 1
 
 curr_head=$(git-rev-parse --verify HEAD 2>/dev/null)
 if test "$curr_head" != "$orig_head"
@@ -89,18 +90,6 @@ case "$merge_head" in
                echo >&2 "Cannot merge multiple branches into empty head"
                exit 1
        fi
-       var=`git-repo-config --get pull.octopus`
-       if test -n "$var"
-       then
-               strategy_default_args="-s $var"
-       fi
-       ;;
-*)
-       var=`git-repo-config --get pull.twohead`
-       if test -n "$var"
-        then
-               strategy_default_args="-s $var"
-       fi
        ;;
 esac
 
@@ -111,13 +100,6 @@ then
        exit
 fi
 
-case "$strategy_args" in
-'')
-       strategy_args=$strategy_default_args
-       ;;
-esac
-
 merge_name=$(git-fmt-merge-msg <"$GIT_DIR/FETCH_HEAD") || exit
-git-merge "--reflog-action=pull $*" \
-       $no_summary $no_commit $squash $strategy_args \
+exec git-merge $no_summary $no_commit $squash $strategy_args \
        "$merge_name" HEAD $merge_head
index ece31425d08a7fc2758b769afac65c37956d20cb..828c59ce61a8317f23ba9113e4de6e09a58e70ce 100755 (executable)
@@ -28,6 +28,7 @@ Example:       git-rebase master~1 topic
   D---E---F---G master          D---E---F---G master
 '
 . git-sh-setup
+set_reflog_action rebase
 
 RESOLVEMSG="
 When you have resolved this problem run \"git rebase --continue\".
@@ -80,10 +81,18 @@ continue_merge () {
 call_merge () {
        cmt="$(cat $dotest/cmt.$1)"
        echo "$cmt" > "$dotest/current"
-       git-merge-$strategy "$cmt^" -- HEAD "$cmt"
+       hd=$(git-rev-parse --verify HEAD)
+       cmt_name=$(git-symbolic-ref HEAD)
+       msgnum=$(cat $dotest/msgnum)
+       end=$(cat $dotest/end)
+       eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
+       eval GITHEAD_$hd='"$(cat $dotest/onto_name)"'
+       export GITHEAD_$cmt GITHEAD_$hd
+       git-merge-$strategy "$cmt^" -- "$hd" "$cmt"
        rv=$?
        case "$rv" in
        0)
+               unset GITHEAD_$cmt GITHEAD_$hd
                return
                ;;
        1)
@@ -132,8 +141,7 @@ do
                        finish_rb_merge
                        exit
                fi
-               git am --resolved --3way --resolvemsg="$RESOLVEMSG" \
-                       --reflog-action=rebase
+               git am --resolved --3way --resolvemsg="$RESOLVEMSG"
                exit
                ;;
        --skip)
@@ -156,8 +164,7 @@ do
                        finish_rb_merge
                        exit
                fi
-               git am -3 --skip --resolvemsg="$RESOLVEMSG" \
-                       --reflog-action=rebase
+               git am -3 --skip --resolvemsg="$RESOLVEMSG"
                exit
                ;;
        --abort)
@@ -306,8 +313,7 @@ fi
 if test -z "$do_merge"
 then
        git-format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
-       git am --binary -3 -k --resolvemsg="$RESOLVEMSG" \
-               --reflog-action=rebase
+       git am --binary -3 -k --resolvemsg="$RESOLVEMSG"
        exit $?
 fi
 
@@ -316,6 +322,7 @@ fi
 
 mkdir -p "$dotest"
 echo "$onto" > "$dotest/onto"
+echo "$onto_name" > "$dotest/onto_name"
 prev_head=`git-rev-parse HEAD^0`
 echo "$prev_head" > "$dotest/prev_head"
 
index 2379db082f956e68a360cfbd667761490ecad5dd..a9693701a34dac623fcddb1943ffe326bdb05405 100755 (executable)
@@ -5,6 +5,7 @@
 USAGE='[--mixed | --soft | --hard]  [<commit-ish>] [ [--] <paths>...]'
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
+set_reflog_action "reset $*"
 
 update= reset_type=--mixed
 unset rev
@@ -81,7 +82,7 @@ then
 else
        rm -f "$GIT_DIR/ORIG_HEAD"
 fi
-git-update-ref -m "reset $reset_type $*" HEAD "$rev"
+git-update-ref -m "$GIT_REFLOG_ACTION" HEAD "$rev"
 update_ref_status=$?
 
 case "$reset_type" in
index 42f9b1c125578a7158392b53ec8792d6c6bbb273..87b939c0e4857ec9c9245c01f609a059788f656a 100755 (executable)
@@ -20,6 +20,14 @@ usage() {
        die "Usage: $0 $USAGE"
 }
 
+set_reflog_action() {
+       if [ -z "${GIT_REFLOG_ACTION:+set}" ]
+       then
+               GIT_REFLOG_ACTION="$*"
+               export GIT_REFLOG_ACTION
+       fi
+}
+
 if [ -z "$LONG_USAGE" ]
 then
        LONG_USAGE="Usage: $0 $USAGE"
index c2cdceb1d1c15eb5e4d2698ceca14bac3e9d3eeb..b28c5bbc7238120d1d98445f1bf0f116dd7a0b8a 100755 (executable)
@@ -69,7 +69,7 @@ my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
        $_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,
        $_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m,
        $_merge, $_strategy, $_dry_run, $_ignore_nodate, $_non_recursive,
-       $_username, $_config_dir, $_no_auth_cache, $_xfer_delta,
+       $_username, $_config_dir, $_no_auth_cache,
        $_pager, $_color);
 my (@_branch_from, %tree_map, %users, %rusers, %equiv);
 my ($_svn_can_do_switch);
@@ -216,7 +216,7 @@ information.
 }
 
 sub version {
-       print "git-svn version $VERSION\n";
+       print "git-svn version $VERSION (svn $SVN::Core::VERSION)\n";
        exit 0;
 }
 
@@ -1098,7 +1098,8 @@ sub read_uuid {
 
 sub verify_ref {
        my ($ref) = @_;
-       eval { command_oneline([ 'rev-parse', $ref ], { STDERR => 0 }) };
+       eval { command_oneline([ 'rev-parse', '--verify', $ref ],
+                              { STDERR => 0 }); };
 }
 
 sub repo_path_split {
@@ -2044,13 +2045,6 @@ sub libsvn_connect {
                              config => $config,
                              pool => SVN::Pool->new,
                              auth_provider_callbacks => $callbacks);
-
-       my $df = $ENV{GIT_SVN_DELTA_FETCH};
-       if (defined $df) {
-               $_xfer_delta = $df;
-       } else {
-               $_xfer_delta = ($url =~ m#^file://#) ? undef : 1;
-       }
        $ra->{svn_path} = $url;
        $ra->{repos_root} = $ra->get_repos_root;
        $ra->{svn_path} =~ s#^\Q$ra->{repos_root}\E/*##;
@@ -2082,49 +2076,6 @@ sub libsvn_dup_ra {
                     auth auth_provider_callbacks repos_root svn_path/);
 }
 
-sub libsvn_get_file {
-       my ($gui, $f, $rev, $chg, $untracked) = @_;
-       $f =~ s#^/##;
-       print "\t$chg\t$f\n" unless $_q;
-
-       my ($hash, $pid, $in, $out);
-       my $pool = SVN::Pool->new;
-       defined($pid = open3($in, $out, '>&STDERR',
-                               qw/git-hash-object -w --stdin/)) or croak $!;
-       # redirect STDOUT for SVN 1.1.x compatibility
-       open my $stdout, '>&', \*STDOUT or croak $!;
-       open STDOUT, '>&', $in or croak $!;
-       my ($r, $props) = $SVN->get_file($f, $rev, \*STDOUT, $pool);
-       $in->flush == 0 or croak $!;
-       open STDOUT, '>&', $stdout or croak $!;
-       close $in or croak $!;
-       close $stdout or croak $!;
-       $pool->clear;
-       chomp($hash = do { local $/; <$out> });
-       close $out or croak $!;
-       waitpid $pid, 0;
-       $hash =~ /^$sha1$/o or die "not a sha1: $hash\n";
-
-       my $mode = exists $props->{'svn:executable'} ? '100755' : '100644';
-       if (exists $props->{'svn:special'}) {
-               $mode = '120000';
-               my $link = `git-cat-file blob $hash`; # no chomping symlinks
-               $link =~ s/^link // or die "svn:special file with contents: <",
-                                               $link, "> is not understood\n";
-               defined($pid = open3($in, $out, '>&STDERR',
-                               qw/git-hash-object -w --stdin/)) or croak $!;
-               print $in $link;
-               $in->flush == 0 or croak $!;
-               close $in or croak $!;
-               chomp($hash = do { local $/; <$out> });
-               close $out or croak $!;
-               waitpid $pid, 0;
-               $hash =~ /^$sha1$/o or die "not a sha1: $hash\n";
-       }
-       %{$untracked->{file_prop}->{$f}} = %$props;
-       print $gui $mode,' ',$hash,"\t",$f,"\0" or croak $!;
-}
-
 sub uri_encode {
        my ($f) = @_;
        $f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg;
@@ -2232,10 +2183,6 @@ sub process_rm {
 }
 
 sub libsvn_fetch {
-       $_xfer_delta ? libsvn_fetch_delta(@_) : libsvn_fetch_full(@_);
-}
-
-sub libsvn_fetch_delta {
        my ($last_commit, $paths, $rev, $author, $date, $msg) = @_;
        my $pool = SVN::Pool->new;
        my $ed = SVN::Git::Fetcher->new({ c => $last_commit, q => $_q });
@@ -2251,66 +2198,6 @@ sub libsvn_fetch_delta {
        libsvn_log_entry($rev, $author, $date, $msg, [$last_commit], $ed);
 }
 
-sub libsvn_fetch_full {
-       my ($last_commit, $paths, $rev, $author, $date, $msg) = @_;
-       my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/);
-       my %amr;
-       my $ut = { empty => {}, dir_prop => {}, file_prop => {} };
-       my $p = $SVN->{svn_path};
-       foreach my $f (keys %$paths) {
-               my $m = $paths->{$f}->action();
-               if (length $p) {
-                       $f =~ s#^/\Q$p\E/##;
-                       next if $f =~ m#^/#;
-               } else {
-                       $f =~ s#^/##;
-               }
-               if ($m =~ /^[DR]$/) {
-                       my $t = process_rm($gui, $last_commit, $f, $_q);
-                       if ($m eq 'D') {
-                               $ut->{empty}->{$f} = 0 if $t == $SVN::Node::dir;
-                               next;
-                       }
-                       # 'R' can be file replacements, too, right?
-               }
-               my $pool = SVN::Pool->new;
-               my $t = $SVN->check_path($f, $rev, $pool);
-               if ($t == $SVN::Node::file) {
-                       if ($m =~ /^[AMR]$/) {
-                               $amr{$f} = $m;
-                       } else {
-                               die "Unrecognized action: $m, ($f r$rev)\n";
-                       }
-               } elsif ($t == $SVN::Node::dir && $m =~ /^[AR]$/) {
-                       my @traversed = ();
-                       libsvn_traverse($gui, '', $f, $rev, \@traversed, $ut);
-                       if (@traversed) {
-                               foreach (@traversed) {
-                                       $amr{$_} = $m;
-                               }
-                       } else {
-                               my ($dir, $file) = ($f =~ m#^(.*?)/?([^/]+)$#);
-                               delete $ut->{empty}->{$dir};
-                               $ut->{empty}->{$f} = 1;
-                       }
-               }
-               $pool->clear;
-       }
-       foreach (keys %amr) {
-               libsvn_get_file($gui, $_, $rev, $amr{$_}, $ut);
-               my ($d) = ($_ =~ m#^(.*?)/?(?:[^/]+)$#);
-               delete $ut->{empty}->{$d};
-       }
-       unless (exists $ut->{dir_prop}->{''}) {
-               my $pool = SVN::Pool->new;
-               my (undef, undef, $props) = $SVN->get_dir('', $rev, $pool);
-               %{$ut->{dir_prop}->{''}} = %$props;
-               $pool->clear;
-       }
-       command_close_pipe($gui, $ctx);
-       libsvn_log_entry($rev, $author, $date, $msg, [$last_commit], $ut);
-}
-
 sub svn_grab_base_rev {
        my $c = eval { command_oneline([qw/rev-parse --verify/,
                                        "refs/remotes/$GIT_SVN^0"],
@@ -2362,41 +2249,6 @@ sub libsvn_parse_revision {
                "Try using the command-line svn client instead\n";
 }
 
-sub libsvn_traverse {
-       my ($gui, $pfx, $path, $rev, $files, $untracked) = @_;
-       my $cwd = length $pfx ? "$pfx/$path" : $path;
-       my $pool = SVN::Pool->new;
-       $cwd =~ s#^\Q$SVN->{svn_path}\E##;
-       my $nr = 0;
-       my ($dirent, $r, $props) = $SVN->get_dir($cwd, $rev, $pool);
-       %{$untracked->{dir_prop}->{$cwd}} = %$props;
-       foreach my $d (keys %$dirent) {
-               my $t = $dirent->{$d}->kind;
-               if ($t == $SVN::Node::dir) {
-                       my $i = libsvn_traverse($gui, $cwd, $d, $rev,
-                                               $files, $untracked);
-                       if ($i) {
-                               $nr += $i;
-                       } else {
-                               $untracked->{empty}->{"$cwd/$d"} = 1;
-                       }
-               } elsif ($t == $SVN::Node::file) {
-                       $nr++;
-                       my $file = "$cwd/$d";
-                       if (defined $files) {
-                               push @$files, $file;
-                       } else {
-                               libsvn_get_file($gui, $file, $rev, 'A',
-                                               $untracked);
-                               my ($dir) = ($file =~ m#^(.*?)/?(?:[^/]+)$#);
-                               delete $untracked->{empty}->{$dir};
-                       }
-               }
-       }
-       $pool->clear;
-       $nr;
-}
-
 sub libsvn_traverse_ignore {
        my ($fh, $path, $r) = @_;
        $path =~ s#^/+##g;
@@ -2488,8 +2340,8 @@ sub libsvn_find_parent_branch {
                print STDERR "Found branch parent: ($GIT_SVN) $parent\n";
                command_noisy('read-tree', $parent);
                unless (libsvn_can_do_switch()) {
-                       return libsvn_fetch_full($parent, $paths, $rev,
-                                               $author, $date, $msg);
+                       return _libsvn_new_tree($paths, $rev, $author, $date,
+                                               $msg, [$parent]);
                }
                # do_switch works with svn/trunk >= r22312, but that is not
                # included with SVN 1.4.2 (the latest version at the moment),
@@ -2514,7 +2366,7 @@ sub libsvn_find_parent_branch {
 
 sub libsvn_get_log {
        my ($ra, @args) = @_;
-       $args[4]-- if $args[4] && $_xfer_delta && ! $_follow_parent;
+       $args[4]-- if $args[4] && ! $_follow_parent;
        if ($SVN::Core::VERSION le '1.2.0') {
                splice(@args, 3, 1);
        }
@@ -2525,28 +2377,23 @@ sub libsvn_new_tree {
        if (my $log_entry = libsvn_find_parent_branch(@_)) {
                return $log_entry;
        }
-       my ($paths, $rev, $author, $date, $msg) = @_;
-       my $ut;
-       if ($_xfer_delta) {
-               my $pool = SVN::Pool->new;
-               my $ed = SVN::Git::Fetcher->new({q => $_q});
-               my $reporter = $SVN->do_update($rev, '', 1, $ed, $pool);
-               my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : ();
-               $reporter->set_path('', $rev, 1, @lock, $pool);
-               $reporter->finish_report($pool);
-               $pool->clear;
-               unless ($ed->{git_commit_ok}) {
-                       die "SVN connection failed somewhere...\n";
-               }
-               $ut = $ed;
-       } else {
-               $ut = { empty => {}, dir_prop => {}, file_prop => {} };
-               my ($gui, $ctx) = command_input_pipe(qw/update-index
-                                                    -z --index-info/);
-               libsvn_traverse($gui, '', $SVN->{svn_path}, $rev, undef, $ut);
-               command_close_pipe($gui, $ctx);
+       my ($paths, $rev, $author, $date, $msg) = @_; # $pool is last
+       _libsvn_new_tree($paths, $rev, $author, $date, $msg, []);
+}
+
+sub _libsvn_new_tree {
+       my ($paths, $rev, $author, $date, $msg, $parents) = @_;
+       my $pool = SVN::Pool->new;
+       my $ed = SVN::Git::Fetcher->new({q => $_q});
+       my $reporter = $SVN->do_update($rev, '', 1, $ed, $pool);
+       my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : ();
+       $reporter->set_path('', $rev, 1, @lock, $pool);
+       $reporter->finish_report($pool);
+       $pool->clear;
+       unless ($ed->{git_commit_ok}) {
+               die "SVN connection failed somewhere...\n";
        }
-       libsvn_log_entry($rev, $author, $date, $msg, [], $ut);
+       libsvn_log_entry($rev, $author, $date, $msg, $parents, $ed);
 }
 
 sub find_graft_path_commit {
@@ -2634,7 +2481,7 @@ sub libsvn_ls_fullurl {
        my $pool = SVN::Pool->new;
        my $r = defined $_revision ? $_revision : $ra->get_latest_revnum;
        my ($dirent, undef, undef) = $ra->get_dir('', $r, $pool);
-       foreach my $d (keys %$dirent) {
+       foreach my $d (sort keys %$dirent) {
                if ($dirent->{$d}->kind == $SVN::Node::dir) {
                        push @ret, "$d/"; # add '/' for compat with cli svn
                }
index da12be747229a7e36148e357da9a14bbf81282f3..d845e91e202233916a91a7095e4a81142687c9c7 100755 (executable)
@@ -18,6 +18,10 @@ use File::Find qw();
 use File::Basename qw(basename);
 binmode STDOUT, ':utf8';
 
+BEGIN {
+       CGI->compile() if $ENV{MOD_PERL};
+}
+
 our $cgi = new CGI;
 our $version = "++GIT_VERSION++";
 our $my_url = $cgi->url();
@@ -1711,6 +1715,7 @@ sub git_header_html {
        }
        print $cgi->header(-type=>$content_type, -charset => 'utf-8',
                           -status=> $status, -expires => $expires);
+       my $mod_perl_version = $ENV{'MOD_PERL'} ? " $ENV{'MOD_PERL'}" : '';
        print <<EOF;
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
@@ -1719,7 +1724,7 @@ sub git_header_html {
 <!-- git core binaries version $git_version -->
 <head>
 <meta http-equiv="content-type" content="$content_type; charset=utf-8"/>
-<meta name="generator" content="gitweb/$version git/$git_version"/>
+<meta name="generator" content="gitweb/$version git/$git_version$mod_perl_version"/>
 <meta name="robots" content="index, nofollow"/>
 <title>$title</title>
 EOF
diff --git a/refs.c b/refs.c
index 8b2a3c13784166e93e15be6f9222d26272a3b78b..e88ed8b2d3f42f48e6859de16f3d6a7f3641a84c 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -925,7 +925,8 @@ static int log_ref_write(struct ref_lock *lock,
        const char *committer;
 
        if (log_all_ref_updates &&
-           !strncmp(lock->ref_name, "refs/heads/", 11)) {
+           (!strncmp(lock->ref_name, "refs/heads/", 11) ||
+            !strncmp(lock->ref_name, "refs/remotes/", 13))) {
                if (safe_create_leading_directories(lock->log_file) < 0)
                        return error("unable to create directory for %s",
                                lock->log_file);
index ec991e5c57039a57af7c63db483e5b108a25ad16..8f7907d7abdb764317612d868f58ab88f7175b59 100644 (file)
@@ -72,6 +72,7 @@ struct rev_info {
        const char      *ref_message_id;
        const char      *add_signoff;
        const char      *extra_headers;
+       const char      *log_reencode;
 
        /* Filter by commit log message */
        struct grep_opt *grep_filter;
diff --git a/shallow.c b/shallow.c
new file mode 100644 (file)
index 0000000..3d53d17
--- /dev/null
+++ b/shallow.c
@@ -0,0 +1,104 @@
+#include "cache.h"
+#include "commit.h"
+#include "tag.h"
+
+static int is_shallow = -1;
+
+int register_shallow(const unsigned char *sha1)
+{
+       struct commit_graft *graft =
+               xmalloc(sizeof(struct commit_graft));
+       struct commit *commit = lookup_commit(sha1);
+
+       hashcpy(graft->sha1, sha1);
+       graft->nr_parent = -1;
+       if (commit && commit->object.parsed)
+               commit->parents = NULL;
+       return register_commit_graft(graft, 0);
+}
+
+int is_repository_shallow()
+{
+       FILE *fp;
+       char buf[1024];
+
+       if (is_shallow >= 0)
+               return is_shallow;
+
+       fp = fopen(git_path("shallow"), "r");
+       if (!fp) {
+               is_shallow = 0;
+               return is_shallow;
+       }
+       is_shallow = 1;
+
+       while (fgets(buf, sizeof(buf), fp)) {
+               unsigned char sha1[20];
+               if (get_sha1_hex(buf, sha1))
+                       die("bad shallow line: %s", buf);
+               register_shallow(sha1);
+       }
+       fclose(fp);
+       return is_shallow;
+}
+
+struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
+               int shallow_flag, int not_shallow_flag)
+{
+       int i = 0, cur_depth = 0;
+       struct commit_list *result = NULL;
+       struct object_array stack = {0, 0, NULL};
+       struct commit *commit = NULL;
+
+       while (commit || i < heads->nr || stack.nr) {
+               struct commit_list *p;
+               if (!commit) {
+                       if (i < heads->nr) {
+                               commit = (struct commit *)
+                                       deref_tag(heads->objects[i++].item, NULL, 0);
+                               if (commit->object.type != OBJ_COMMIT) {
+                                       commit = NULL;
+                                       continue;
+                               }
+                               if (!commit->util)
+                                       commit->util = xmalloc(sizeof(int));
+                               *(int *)commit->util = 0;
+                               cur_depth = 0;
+                       } else {
+                               commit = (struct commit *)
+                                       stack.objects[--stack.nr].item;
+                               cur_depth = *(int *)commit->util;
+                       }
+               }
+               parse_commit(commit);
+               commit->object.flags |= not_shallow_flag;
+               cur_depth++;
+               for (p = commit->parents, commit = NULL; p; p = p->next) {
+                       if (!p->item->util) {
+                               int *pointer = xmalloc(sizeof(int));
+                               p->item->util = pointer;
+                               *pointer =  cur_depth;
+                       } else {
+                               int *pointer = p->item->util;
+                               if (cur_depth >= *pointer)
+                                       continue;
+                               *pointer = cur_depth;
+                       }
+                       if (cur_depth < depth) {
+                               if (p->next)
+                                       add_object_array(&p->item->object,
+                                                       NULL, &stack);
+                               else {
+                                       commit = p->item;
+                                       cur_depth = *(int *)commit->util;
+                               }
+                       } else {
+                               commit_list_insert(p->item, &result);
+                               p->item->object.flags |= shallow_flag;
+                       }
+               }
+       }
+
+       return result;
+}
+
index 250a19019c1f494897c5e43437b93c3f6a80cace..19e38508a70708b78de6467df71ed36373999d6a 100644 (file)
@@ -23,8 +23,7 @@ clean:
 
 # we can test NO_OPTIMIZE_COMMITS independently of LC_ALL
 full-svn-test:
-       $(MAKE) $(TSVN) GIT_SVN_DELTA_FETCH=1 \
-                               GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C
+       $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C
        $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=0 LC_ALL=en_US.UTF-8
 
 .PHONY: $(T) clean
index c5db5804df767bb55d5c9972b18faf4dc35e899c..7abab1dafe83527a5ff84808824057f549a08080 100644 (file)
--- a/t/README
+++ b/t/README
@@ -74,6 +74,8 @@ First digit tells the family:
        5 - the pull and exporting commands
        6 - the revision tree commands (even e.g. merge-base)
        7 - the porcelainish commands concerning the working tree
+       8 - the porcelainish commands concerning forensics
+       9 - the git tools
 
 Second digit tells the particular command we are testing.
 
index c09c53f20bbc04f36d26ff37f060f42233a1c0db..e98786de32ca3139b2587fd5fca29a9f400c81d7 100755 (executable)
@@ -51,4 +51,37 @@ test_expect_success \
         *) echo fail; git-ls-files --stage xfoo3; (exit 1);;
         esac'
 
+test_expect_success '.gitignore test setup' '
+       echo "*.ig" >.gitignore &&
+       mkdir c.if d.ig &&
+       >a.ig && >b.if &&
+       >c.if/c.if && >c.if/c.ig &&
+       >d.ig/d.if && >d.ig/d.ig
+'
+
+test_expect_success '.gitignore is honored' '
+       git-add . &&
+       ! git-ls-files | grep "\\.ig"
+'
+
+test_expect_success 'error out when attempting to add ignored ones without -f' '
+       ! git-add a.?? &&
+       ! git-ls-files | grep "\\.ig"
+'
+
+test_expect_success 'error out when attempting to add ignored ones without -f' '
+       ! git-add d.?? &&
+       ! git-ls-files | grep "\\.ig"
+'
+
+test_expect_success 'add ignored ones with -f' '
+       git-add -f a.?? &&
+       git-ls-files --error-unmatch a.ig
+'
+
+test_expect_success 'add ignored ones with -f' '
+       git-add -f d.??/* &&
+       git-ls-files --error-unmatch d.ig/d.if d.ig/d.ig
+'
+
 test_done
diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh
new file mode 100755 (executable)
index 0000000..46fd47c
--- /dev/null
@@ -0,0 +1,115 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Junio C Hamano
+#
+
+test_description='commit and log output encodings'
+
+. ./test-lib.sh
+
+compare_with () {
+       git-show -s "$1" | sed -e '1,/^$/d' -e 's/^    //' -e '$d' >current &&
+       diff -u current "$2"
+}
+
+test_expect_success setup '
+       : >F &&
+       git-add F &&
+       T=$(git-write-tree) &&
+       C=$(git-commit-tree $T <../t3900/1-UTF-8.txt) &&
+       git-update-ref HEAD $C &&
+       git-tag C0
+'
+
+test_expect_success 'no encoding header for base case' '
+       E=$(git-cat-file commit C0 | sed -ne "s/^encoding //p") &&
+       test z = "z$E"
+'
+
+for H in ISO-8859-1 EUCJP ISO-2022-JP
+do
+       test_expect_success "$H setup" '
+               git-repo-config i18n.commitencoding $H &&
+               git-checkout -b $H C0 &&
+               echo $H >F &&
+               git-commit -a -F ../t3900/$H.txt
+       '
+done
+
+for H in ISO-8859-1 EUCJP ISO-2022-JP
+do
+       test_expect_success "check encoding header for $H" '
+               E=$(git-cat-file commit '$H' | sed -ne "s/^encoding //p") &&
+               test "z$E" = "z'$H'"
+       '
+done
+
+test_expect_success 'repo-config to remove customization' '
+       git-repo-config --unset-all i18n.commitencoding &&
+       if Z=$(git-repo-config --get-all i18n.commitencoding)
+       then
+               echo Oops, should have failed.
+               false
+       else
+               test z = "z$Z"
+       fi &&
+       git-repo-config i18n.commitencoding utf-8
+'
+
+test_expect_success 'ISO-8859-1 should be shown in UTF-8 now' '
+       compare_with ISO-8859-1 ../t3900/1-UTF-8.txt
+'
+
+for H in EUCJP ISO-2022-JP
+do
+       test_expect_success "$H should be shown in UTF-8 now" '
+               compare_with '$H' ../t3900/2-UTF-8.txt
+       '
+done
+
+test_expect_success 'repo-config to add customization' '
+       git-repo-config --unset-all i18n.commitencoding &&
+       if Z=$(git-repo-config --get-all i18n.commitencoding)
+       then
+               echo Oops, should have failed.
+               false
+       else
+               test z = "z$Z"
+       fi
+'
+
+for H in ISO-8859-1 EUCJP ISO-2022-JP
+do
+       test_expect_success "$H should be shown in itself now" '
+               git-repo-config i18n.commitencoding '$H' &&
+               compare_with '$H' ../t3900/'$H'.txt
+       '
+done
+
+test_expect_success 'repo-config to tweak customization' '
+       git-repo-config i18n.logoutputencoding utf-8
+'
+
+test_expect_success 'ISO-8859-1 should be shown in UTF-8 now' '
+       compare_with ISO-8859-1 ../t3900/1-UTF-8.txt
+'
+
+for H in EUCJP ISO-2022-JP
+do
+       test_expect_success "$H should be shown in UTF-8 now" '
+               compare_with '$H' ../t3900/2-UTF-8.txt
+       '
+done
+
+for J in EUCJP ISO-2022-JP
+do
+       git-repo-config i18n.logoutputencoding $J
+       for H in EUCJP ISO-2022-JP
+       do
+               test_expect_success "$H should be shown in $J now" '
+                       compare_with '$H' ../t3900/'$J'.txt
+               '
+       done
+done
+
+test_done
diff --git a/t/t3900/1-UTF-8.txt b/t/t3900/1-UTF-8.txt
new file mode 100644 (file)
index 0000000..ee31e19
--- /dev/null
@@ -0,0 +1,3 @@
+ÄËÑÏÖ
+
+Ábçdèfg
diff --git a/t/t3900/2-UTF-8.txt b/t/t3900/2-UTF-8.txt
new file mode 100644 (file)
index 0000000..63f4f8f
--- /dev/null
@@ -0,0 +1,4 @@
+はれひほふ
+
+しているのが、いるので。
+濱浜ほれぷりぽれまびぐりろへ。
diff --git a/t/t3900/EUCJP.txt b/t/t3900/EUCJP.txt
new file mode 100644 (file)
index 0000000..546f2aa
--- /dev/null
@@ -0,0 +1,4 @@
+¤Ï¤ì¤Ò¤Û¤Õ
+
+¤·¤Æ¤¤¤ë¤Î¤¬¡¢¤¤¤ë¤Î¤Ç¡£
+ßÀÉͤۤì¤×¤ê¤Ý¤ì¤Þ¤Ó¤°¤ê¤í¤Ø¡£
diff --git a/t/t3900/ISO-2022-JP.txt b/t/t3900/ISO-2022-JP.txt
new file mode 100644 (file)
index 0000000..74b5330
--- /dev/null
@@ -0,0 +1,4 @@
+\e$B$O$l$R$[$U\e(B
+
+\e$B$7$F$$$k$N$,!"$$$k$N$G!#\e(B
+\e$B_@IM$[$l$W$j$]$l$^$S$0$j$m$X!#\e(B
diff --git a/t/t3900/ISO-8859-1.txt b/t/t3900/ISO-8859-1.txt
new file mode 100644 (file)
index 0000000..7cbef0e
--- /dev/null
@@ -0,0 +1,3 @@
+ÄËÑÏÖ
+
+Ábçdèfg
index 28744b35e10602cf5076fbf5c62b3e767a847c0c..2c151912a3bcf2c91cfafcbc22f11bc71fedd34d 100755 (executable)
@@ -8,38 +8,63 @@ test_description='See why rewinding head breaks send-pack
 '
 . ./test-lib.sh
 
-touch cpio-test
-test_expect_success 'working cpio' 'echo cpio-test | cpio -o > /dev/null'
-
-cnt='1'
+cnt=64
 test_expect_success setup '
+       test_tick &&
+       mkdir mozart mozart/is &&
+       echo "Commit #0" >mozart/is/pink &&
+       git-update-index --add mozart/is/pink &&
        tree=$(git-write-tree) &&
        commit=$(echo "Commit #0" | git-commit-tree $tree) &&
        zero=$commit &&
        parent=$zero &&
-       for i in $cnt
+       i=0 &&
+       while test $i -le $cnt
        do
-           sleep 1 &&
+           i=$(($i+1)) &&
+           test_tick &&
+           echo "Commit #$i" >mozart/is/pink &&
+           git-update-index --add mozart/is/pink &&
+           tree=$(git-write-tree) &&
            commit=$(echo "Commit #$i" | git-commit-tree $tree -p $parent) &&
+           git-update-ref refs/tags/commit$i $commit &&
            parent=$commit || return 1
        done &&
        git-update-ref HEAD "$commit" &&
-       git-clone -l ./. victim &&
+       git-clone ./. victim &&
        cd victim &&
        git-log &&
        cd .. &&
        git-update-ref HEAD "$zero" &&
        parent=$zero &&
-       for i in $cnt
+       i=0 &&
+       while test $i -le $cnt
        do
-           sleep 1 &&
+           i=$(($i+1)) &&
+           test_tick &&
+           echo "Rebase #$i" >mozart/is/pink &&
+           git-update-index --add mozart/is/pink &&
+           tree=$(git-write-tree) &&
            commit=$(echo "Rebase #$i" | git-commit-tree $tree -p $parent) &&
+           git-update-ref refs/tags/rebase$i $commit &&
            parent=$commit || return 1
        done &&
        git-update-ref HEAD "$commit" &&
        echo Rebase &&
        git-log'
 
+test_expect_success 'pack the source repository' '
+       git repack -a -d &&
+       git prune
+'
+
+test_expect_success 'pack the destination repository' '
+       cd victim &&
+       git repack -a -d &&
+       git prune &&
+       cd ..
+'
+
 test_expect_success \
         'pushing rewound head should not barf but require --force' ' 
        # should not fail but refuse to update.
index f7625a6f4634da4b78c90defdc0a302c8ea4e231..77c3c575d89ad5707ad8f6b22f62b58aef458104 100755 (executable)
@@ -128,4 +128,54 @@ pull_to_client 2nd "B" $((64*3))
 
 pull_to_client 3rd "A" $((1*3)) # old fails
 
+test_expect_success "clone shallow" "git-clone --depth 2 . shallow"
+
+(cd shallow; git-count-objects -v) > count.shallow
+
+test_expect_success "clone shallow object count" \
+       "test \"in-pack: 18\" = \"$(grep in-pack count.shallow)\""
+
+count_output () {
+       sed -e '/^in-pack:/d' -e '/^packs:/d' -e '/: 0$/d' "$1"
+}
+
+test_expect_success "clone shallow object count (part 2)" '
+       test -z "$(count_output count.shallow)"
+'
+
+test_expect_success "fsck in shallow repo" \
+       "(cd shallow; git-fsck-objects --full)"
+
+#test_done; exit
+
+add B66 $B65
+add B67 $B66
+
+test_expect_success "pull in shallow repo" \
+       "(cd shallow; git pull .. B)"
+
+(cd shallow; git-count-objects -v) > count.shallow
+test_expect_success "clone shallow object count" \
+       "test \"count: 6\" = \"$(grep count count.shallow)\""
+
+add B68 $B67
+add B69 $B68
+
+test_expect_success "deepening pull in shallow repo" \
+       "(cd shallow; git pull --depth 4 .. B)"
+
+(cd shallow; git-count-objects -v) > count.shallow
+test_expect_success "clone shallow object count" \
+       "test \"count: 12\" = \"$(grep count count.shallow)\""
+
+test_expect_success "deepening fetch in shallow repo" \
+       "(cd shallow; git fetch --depth 4 .. A:A)"
+
+(cd shallow; git-count-objects -v) > count.shallow
+test_expect_success "clone shallow object count" \
+       "test \"count: 18\" = \"$(grep count count.shallow)\""
+
+test_expect_failure "pull in shallow repo with missing merge base" \
+       "(cd shallow; git pull --depth 4 .. A)"
+
 test_done
index 5d9b6f34b84dd798f180d181aff4a7857bcd93ef..1c21d8c986fba2c287ffab0b883b65a14cb5401f 100644 (file)
@@ -112,5 +112,27 @@ EOF
 test_expect_success "expected conflict markers, with -L" \
        "diff -u test.txt expect.txt"
 
+sed "s/ tu / TU /" < new1.txt > new5.txt
+test_expect_failure "conflict in removed tail" \
+       "git-merge-file -p orig.txt new1.txt new5.txt > out"
+
+cat > expect << EOF
+Dominus regit me,
+et nihil mihi deerit.
+In loco pascuae ibi me collocavit,
+super aquam refectionis educavit me;
+animam meam convertit,
+deduxit me super semitas jusitiae,
+propter nomen suum.
+<<<<<<< orig.txt
+=======
+Nam et si ambulavero in medio umbrae mortis,
+non timebo mala, quoniam TU mecum es:
+virga tua et baculus tuus ipsa me consolata sunt.
+>>>>>>> new5.txt
+EOF
+
+test_expect_success "expected conflict markers" "diff -u expect out"
+
 test_done
 
index 69b18f7d8160d0acb2bf222a9478674cfc21634f..31b96257b454c62ce84c3d883e961c41740ddddd 100644 (file)
@@ -11,50 +11,54 @@ test_description='Test merge without common ancestors'
 #       X   \
 # 2 - C - E - G
 
-export GIT_COMMITTER_DATE="2006-12-12 23:28:00 +0100"
-echo 1 > a1
-git add a1
-GIT_AUTHOR_DATE="2006-12-12 23:00:00" git commit -m 1 a1
-
-git checkout -b A master
-echo A > a1
-GIT_AUTHOR_DATE="2006-12-12 23:00:01" git commit -m A a1
-
-git checkout -b B master
-echo B > a1
-GIT_AUTHOR_DATE="2006-12-12 23:00:02" git commit -m B a1
-
-git checkout -b D A
-git-rev-parse B > .git/MERGE_HEAD
-echo D > a1
-git update-index a1
-GIT_AUTHOR_DATE="2006-12-12 23:00:03" git commit -m D
-
-git symbolic-ref HEAD refs/heads/other
-echo 2 > a1
-GIT_AUTHOR_DATE="2006-12-12 23:00:04" git commit -m 2 a1
-
-git checkout -b C
-echo C > a1
-GIT_AUTHOR_DATE="2006-12-12 23:00:05" git commit -m C a1
-
-git checkout -b E C
-git-rev-parse B > .git/MERGE_HEAD
-echo E > a1
-git update-index a1
-GIT_AUTHOR_DATE="2006-12-12 23:00:06" git commit -m E
-
-git checkout -b G E
-git-rev-parse A > .git/MERGE_HEAD
-echo G > a1
-git update-index a1
-GIT_AUTHOR_DATE="2006-12-12 23:00:07" git commit -m G
-
-git checkout -b F D
-git-rev-parse C > .git/MERGE_HEAD
-echo F > a1
-git update-index a1
+GIT_COMMITTER_DATE="2006-12-12 23:28:00 +0100"
+export GIT_COMMITTER_DATE
+
+test_expect_success "setup tests" '
+echo 1 > a1 &&
+git add a1 &&
+GIT_AUTHOR_DATE="2006-12-12 23:00:00" git commit -m 1 a1 &&
+
+git checkout -b A master &&
+echo A > a1 &&
+GIT_AUTHOR_DATE="2006-12-12 23:00:01" git commit -m A a1 &&
+
+git checkout -b B master &&
+echo B > a1 &&
+GIT_AUTHOR_DATE="2006-12-12 23:00:02" git commit -m B a1 &&
+
+git checkout -b D A &&
+git-rev-parse B > .git/MERGE_HEAD &&
+echo D > a1 &&
+git update-index a1 &&
+GIT_AUTHOR_DATE="2006-12-12 23:00:03" git commit -m D &&
+
+git symbolic-ref HEAD refs/heads/other &&
+echo 2 > a1 &&
+GIT_AUTHOR_DATE="2006-12-12 23:00:04" git commit -m 2 a1 &&
+
+git checkout -b C &&
+echo C > a1 &&
+GIT_AUTHOR_DATE="2006-12-12 23:00:05" git commit -m C a1 &&
+
+git checkout -b E C &&
+git-rev-parse B > .git/MERGE_HEAD &&
+echo E > a1 &&
+git update-index a1 &&
+GIT_AUTHOR_DATE="2006-12-12 23:00:06" git commit -m E &&
+
+git checkout -b G E &&
+git-rev-parse A > .git/MERGE_HEAD &&
+echo G > a1 &&
+git update-index a1 &&
+GIT_AUTHOR_DATE="2006-12-12 23:00:07" git commit -m G &&
+
+git checkout -b F D &&
+git-rev-parse C > .git/MERGE_HEAD &&
+echo F > a1 &&
+git update-index a1 &&
 GIT_AUTHOR_DATE="2006-12-12 23:00:08" git commit -m F
+'
 
 test_expect_failure "combined merge conflicts" "git merge -m final G"
 
index ca0513b1621961f5fd9e589fc62820d42299eccc..315119abff31bfe7cdb85e0d7f2d29f5cf89a8b5 100755 (executable)
@@ -14,16 +14,18 @@ then
     exit
 fi
 
-export CVSROOT=$(pwd)/cvsroot
-export CVSWORK=$(pwd)/cvswork
+CVSROOT=$(pwd)/cvsroot
+CVSWORK=$(pwd)/cvswork
+GIT_DIR=$(pwd)/.git
+export CVSROOT CVSWORK GIT_DIR
+
 rm -rf "$CVSROOT" "$CVSWORK"
 mkdir "$CVSROOT" &&
 cvs init &&
 cvs -Q co -d "$CVSWORK" . &&
-export GIT_DIR=$(pwd)/.git &&
 echo >empty &&
 git add empty &&
-git commit -a -m "Initial" 2>/dev/null ||
+git commit -q -a -m "Initial" 2>/dev/null ||
 exit 1
 
 test_expect_success \
index f0f9cd6be01681c90d1914eaa8a40144e2280adf..bf108d4226fabf847f42420547471dfb3cef8a8e 100755 (executable)
@@ -96,6 +96,17 @@ test_count=0
 
 trap 'echo >&5 "FATAL: Unexpected exit with code $?"; exit 1' exit
 
+test_tick () {
+       if test -z "${test_tick+set}"
+       then
+               test_tick=432630000
+       else
+               test_tick=$(($test_tick + 60))
+       fi
+       GIT_COMMITTER_DATE=$test_tick
+       GIT_AUTHOR_DATE=$test_tick
+       export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
+}
 
 # You are not expected to call test_ok_ and test_failure_ directly, use
 # the text_expect_* functions instead.
@@ -125,16 +136,43 @@ test_run_ () {
        return 0
 }
 
+test_skip () {
+       this_test=$(expr "./$0" : '.*/\(t[0-9]*\)-[^/]*$')
+       this_test="$this_test.$(expr "$test_count" + 1)"
+       to_skip=
+       for skp in $GIT_SKIP_TESTS
+       do
+               case "$this_test" in
+               $skp)
+                       to_skip=t
+               esac
+       done
+       case "$to_skip" in
+       t)
+               say >&3 "skipping test: $@"
+               test_count=$(expr "$test_count" + 1)
+               say "skip $test_count: $1"
+               : true
+               ;;
+       *)
+               false
+               ;;
+       esac
+}
+
 test_expect_failure () {
        test "$#" = 2 ||
        error "bug in the test script: not 2 parameters to test-expect-failure"
-       say >&3 "expecting failure: $2"
-       test_run_ "$2"
-       if [ "$?" = 0 -a "$eval_ret" != 0 -a "$eval_ret" -lt 129 ]
+       if ! test_skip "$@"
        then
-               test_ok_ "$1"
-       else
-               test_failure_ "$@"
+               say >&3 "expecting failure: $2"
+               test_run_ "$2"
+               if [ "$?" = 0 -a "$eval_ret" != 0 -a "$eval_ret" -lt 129 ]
+               then
+                       test_ok_ "$1"
+               else
+                       test_failure_ "$@"
+               fi
        fi
        echo >&3 ""
 }
@@ -142,13 +180,16 @@ test_expect_failure () {
 test_expect_success () {
        test "$#" = 2 ||
        error "bug in the test script: not 2 parameters to test-expect-success"
-       say >&3 "expecting success: $2"
-       test_run_ "$2"
-       if [ "$?" = 0 -a "$eval_ret" = 0 ]
+       if ! test_skip "$@"
        then
-               test_ok_ "$1"
-       else
-               test_failure_ "$@"
+               say >&3 "expecting success: $2"
+               test_run_ "$2"
+               if [ "$?" = 0 -a "$eval_ret" = 0 ]
+               then
+                       test_ok_ "$1"
+               else
+                       test_failure_ "$@"
+               fi
        fi
        echo >&3 ""
 }
@@ -156,13 +197,16 @@ test_expect_success () {
 test_expect_code () {
        test "$#" = 3 ||
        error "bug in the test script: not 3 parameters to test-expect-code"
-       say >&3 "expecting exit code $1: $3"
-       test_run_ "$3"
-       if [ "$?" = 0 -a "$eval_ret" = "$1" ]
+       if ! test_skip "$@"
        then
-               test_ok_ "$2"
-       else
-               test_failure_ "$@"
+               say >&3 "expecting exit code $1: $3"
+               test_run_ "$3"
+               if [ "$?" = 0 -a "$eval_ret" = "$1" ]
+               then
+                       test_ok_ "$2"
+               else
+                       test_failure_ "$@"
+               fi
        fi
        echo >&3 ""
 }
@@ -176,7 +220,7 @@ test_create_repo () {
        repo="$1"
        mkdir "$repo"
        cd "$repo" || error "Cannot setup test environment"
-       "$GIT_EXEC_PATH/git" init-db --template=$GIT_EXEC_PATH/templates/blt/ 2>/dev/null ||
+       "$GIT_EXEC_PATH/git" init-db --template=$GIT_EXEC_PATH/templates/blt/ >/dev/null 2>&1 ||
        error "cannot run git init-db -- have you built things yet?"
        mv .git/hooks .git/hooks-disabled
        cd "$owd"
@@ -223,3 +267,22 @@ test=trash
 rm -fr "$test"
 test_create_repo $test
 cd "$test"
+
+this_test=$(expr "./$0" : '.*/\(t[0-9]*\)-[^/]*$')
+for skp in $GIT_SKIP_TESTS
+do
+       to_skip=
+       for skp in $GIT_SKIP_TESTS
+       do
+               case "$this_test" in
+               $skp)
+                       to_skip=t
+               esac
+       done
+       case "$to_skip" in
+       t)
+               say >&3 "skipping test $this_test altogether"
+               say "skip all tests in $this_test"
+               test_done
+       esac
+done
index 76d5ac2477d669aabfef8108cfbb713fbdfef70a..9863a800c8b945494f284c58112388b9c865ec58 100644 (file)
@@ -19,7 +19,7 @@ ref_type=$(git cat-file -t "$3")
 case "$1","$ref_type" in
 refs/tags/*,commit)
        echo "*** Un-annotated tags are not allowed in this repo" >&2
-       echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate."
+       echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
        exit 1;;
 refs/tags/*,tag)
        echo "### Pushing version '${1##refs/tags/}' to the masses" >&2
index 32b06b2e66099787d621c2557a8a9ee00aec4be6..c568ef066c9e7e0021468cfe7cb904f40ac477f1 100644 (file)
@@ -6,6 +6,9 @@
 #include "object.h"
 #include "commit.h"
 #include "exec_cmd.h"
+#include "diff.h"
+#include "revision.h"
+#include "list-objects.h"
 
 static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] <dir>";
 
@@ -16,6 +19,10 @@ static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=n
 #define COMMON_KNOWN   (1u << 14)
 #define REACHABLE      (1u << 15)
 
+#define SHALLOW                (1u << 16)
+#define NOT_SHALLOW    (1u << 17)
+#define CLIENT_SHALLOW (1u << 18)
+
 static unsigned long oldest_have;
 
 static int multi_ack, nr_our_refs;
@@ -54,6 +61,40 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
        return safe_write(fd, data, sz);
 }
 
+FILE *pack_pipe = NULL;
+static void show_commit(struct commit *commit)
+{
+       if (commit->object.flags & BOUNDARY)
+               fputc('-', pack_pipe);
+       if (fputs(sha1_to_hex(commit->object.sha1), pack_pipe) < 0)
+               die("broken output pipe");
+       fputc('\n', pack_pipe);
+       fflush(pack_pipe);
+       free(commit->buffer);
+       commit->buffer = NULL;
+}
+
+static void show_object(struct object_array_entry *p)
+{
+       /* An object with name "foo\n0000000..." can be used to
+        * confuse downstream git-pack-objects very badly.
+        */
+       const char *ep = strchr(p->name, '\n');
+       if (ep) {
+               fprintf(pack_pipe, "%s %.*s\n", sha1_to_hex(p->item->sha1),
+                      (int) (ep - p->name),
+                      p->name);
+       }
+       else
+               fprintf(pack_pipe, "%s %s\n",
+                               sha1_to_hex(p->item->sha1), p->name);
+}
+
+static void show_edge(struct commit *commit)
+{
+       fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1));
+}
+
 static void create_pack_file(void)
 {
        /* Pipes between rev-list to pack-objects, pack-objects to us
@@ -75,48 +116,40 @@ static void create_pack_file(void)
 
        if (!pid_rev_list) {
                int i;
-               int args;
-               const char **argv;
-               const char **p;
-               char *buf;
+               struct rev_info revs;
 
-               if (create_full_pack) {
-                       args = 10;
-                       use_thin_pack = 0; /* no point doing it */
-               }
-               else
-                       args = have_obj.nr + want_obj.nr + 5;
-               p = xmalloc(args * sizeof(char *));
-               argv = (const char **) p;
-               buf = xmalloc(args * 45);
+               pack_pipe = fdopen(lp_pipe[1], "w");
 
-               dup2(lp_pipe[1], 1);
-               close(0);
-               close(lp_pipe[0]);
-               close(lp_pipe[1]);
-               *p++ = "rev-list";
-               *p++ = use_thin_pack ? "--objects-edge" : "--objects";
                if (create_full_pack)
-                       *p++ = "--all";
-               else {
+                       use_thin_pack = 0; /* no point doing it */
+               init_revisions(&revs, NULL);
+               revs.tag_objects = 1;
+               revs.tree_objects = 1;
+               revs.blob_objects = 1;
+               if (use_thin_pack)
+                       revs.edge_hint = 1;
+
+               if (create_full_pack) {
+                       const char *args[] = {"rev-list", "--all", NULL};
+                       setup_revisions(2, args, &revs, NULL);
+               } else {
                        for (i = 0; i < want_obj.nr; i++) {
                                struct object *o = want_obj.objects[i].item;
-                               *p++ = buf;
-                               memcpy(buf, sha1_to_hex(o->sha1), 41);
-                               buf += 41;
+                               /* why??? */
+                               o->flags &= ~UNINTERESTING;
+                               add_pending_object(&revs, o, NULL);
                        }
-               }
-               if (!create_full_pack)
                        for (i = 0; i < have_obj.nr; i++) {
                                struct object *o = have_obj.objects[i].item;
-                               *p++ = buf;
-                               *buf++ = '^';
-                               memcpy(buf, sha1_to_hex(o->sha1), 41);
-                               buf += 41;
+                               o->flags |= UNINTERESTING;
+                               add_pending_object(&revs, o, NULL);
                        }
-               *p++ = NULL;
-               execv_git_cmd(argv);
-               die("git-upload-pack: unable to exec git-rev-list");
+                       setup_revisions(0, NULL, &revs, NULL);
+               }
+               prepare_revision_walk(&revs);
+               mark_edges_uninteresting(revs.commits, &revs, show_edge);
+               traverse_commit_list(&revs, show_commit, show_object);
+               exit(0);
        }
 
        if (pipe(pu_pipe) < 0)
@@ -456,8 +489,9 @@ static int get_common_commits(void)
 
 static void receive_needs(void)
 {
+       struct object_array shallows = {0, 0, NULL};
        static char line[1000];
-       int len;
+       int len, depth = 0;
 
        for (;;) {
                struct object *o;
@@ -465,8 +499,29 @@ static void receive_needs(void)
                len = packet_read_line(0, line, sizeof(line));
                reset_timeout();
                if (!len)
-                       return;
+                       break;
 
+               if (!strncmp("shallow ", line, 8)) {
+                       unsigned char sha1[20];
+                       struct object *object;
+                       use_thin_pack = 0;
+                       if (get_sha1(line + 8, sha1))
+                               die("invalid shallow line: %s", line);
+                       object = parse_object(sha1);
+                       if (!object)
+                               die("did not find object for %s", line);
+                       object->flags |= CLIENT_SHALLOW;
+                       add_object_array(object, NULL, &shallows);
+                       continue;
+               }
+               if (!strncmp("deepen ", line, 7)) {
+                       char *end;
+                       use_thin_pack = 0;
+                       depth = strtol(line + 7, &end, 0);
+                       if (end == line + 7 || depth <= 0)
+                               die("Invalid deepen: %s", line);
+                       continue;
+               }
                if (strncmp("want ", line, 5) ||
                    get_sha1_hex(line+5, sha1_buf))
                        die("git-upload-pack: protocol error, "
@@ -498,11 +553,58 @@ static void receive_needs(void)
                        add_object_array(o, NULL, &want_obj);
                }
        }
+       if (depth == 0 && shallows.nr == 0)
+               return;
+       if (depth > 0) {
+               struct commit_list *result, *backup;
+               int i;
+               backup = result = get_shallow_commits(&want_obj, depth,
+                       SHALLOW, NOT_SHALLOW);
+               while (result) {
+                       struct object *object = &result->item->object;
+                       if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {
+                               packet_write(1, "shallow %s",
+                                               sha1_to_hex(object->sha1));
+                               register_shallow(object->sha1);
+                       }
+                       result = result->next;
+               }
+               free_commit_list(backup);
+               for (i = 0; i < shallows.nr; i++) {
+                       struct object *object = shallows.objects[i].item;
+                       if (object->flags & NOT_SHALLOW) {
+                               struct commit_list *parents;
+                               packet_write(1, "unshallow %s",
+                                       sha1_to_hex(object->sha1));
+                               object->flags &= ~CLIENT_SHALLOW;
+                               /* make sure the real parents are parsed */
+                               unregister_shallow(object->sha1);
+                               object->parsed = 0;
+                               parse_commit((struct commit *)object);
+                               parents = ((struct commit *)object)->parents;
+                               while (parents) {
+                                       add_object_array(&parents->item->object,
+                                                       NULL, &want_obj);
+                                       parents = parents->next;
+                               }
+                       }
+                       /* make sure commit traversal conforms to client */
+                       register_shallow(object->sha1);
+               }
+               packet_flush(1);
+       } else
+               if (shallows.nr > 0) {
+                       int i;
+                       for (i = 0; i < shallows.nr; i++)
+                               register_shallow(shallows.objects[i].item->sha1);
+               }
+       free(shallows.objects);
 }
 
 static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
-       static const char *capabilities = "multi_ack thin-pack side-band side-band-64k ofs-delta";
+       static const char *capabilities = "multi_ack thin-pack side-band"
+               " side-band-64k ofs-delta shallow";
        struct object *o = parse_object(sha1);
 
        if (!o)
diff --git a/utf8.c b/utf8.c
index 8fa62571aa959897275e694a4370e99c46cccd6a..1eedd8b61aeed9867366df0b70ac849cdef985b9 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -276,3 +276,57 @@ void print_wrapped_text(const char *text, int indent, int indent2, int width)
                }
        }
 }
+
+/*
+ * Given a buffer and its encoding, return it re-encoded
+ * with iconv.  If the conversion fails, returns NULL.
+ */
+#ifndef NO_ICONV
+char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
+{
+       iconv_t conv;
+       size_t insz, outsz, outalloc;
+       char *out, *outpos, *cp;
+
+       if (!in_encoding)
+               return NULL;
+       conv = iconv_open(out_encoding, in_encoding);
+       if (conv == (iconv_t) -1)
+               return NULL;
+       insz = strlen(in);
+       outsz = insz;
+       outalloc = outsz + 1; /* for terminating NUL */
+       out = xmalloc(outalloc);
+       outpos = out;
+       cp = (char *)in;
+
+       while (1) {
+               size_t cnt = iconv(conv, &cp, &insz, &outpos, &outsz);
+
+               if (cnt == -1) {
+                       size_t sofar;
+                       if (errno != E2BIG) {
+                               free(out);
+                               iconv_close(conv);
+                               return NULL;
+                       }
+                       /* insz has remaining number of bytes.
+                        * since we started outsz the same as insz,
+                        * it is likely that insz is not enough for
+                        * converting the rest.
+                        */
+                       sofar = outpos - out;
+                       outalloc = sofar + insz * 2 + 32;
+                       out = xrealloc(out, outalloc);
+                       outpos = out + sofar;
+                       outsz = outalloc - sofar - 1;
+               }
+               else {
+                       *outpos = '\0';
+                       break;
+               }
+       }
+       iconv_close(conv);
+       return out;
+}
+#endif
diff --git a/utf8.h b/utf8.h
index a0d7f591adc3d86e5c813d79059c7c0335b32dc3..cae2a8e665c2cbe7bf31a49deed84250eaa37a33 100644 (file)
--- a/utf8.h
+++ b/utf8.h
@@ -5,4 +5,10 @@ int utf8_width(const char **start);
 int is_utf8(const char *text);
 void print_wrapped_text(const char *text, int indent, int indent2, int len);
 
+#ifndef NO_ICONV
+char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);
+#else
+#define reencode_string(a,b,c) NULL
+#endif
+
 #endif
index 352207e5168135f3c6306968f03a8d191d6ac2bb..294450b89916180ab603d566e7d3f281773a3b92 100644 (file)
@@ -190,6 +190,10 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,
                if (m->mode)
                        continue;
 
+               /* no sense refining a conflict when one side is empty */
+               if (m->chg1 == 0 || m->chg2 == 0)
+                       continue;
+
                /*
                 * This probably does not work outside git, since
                 * we have a very simple mmfile structure.