summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/config.txt4
-rw-r--r--Documentation/git-merge.txt6
-rw-r--r--Makefile25
-rw-r--r--builtin-add.c52
-rw-r--r--builtin-commit-tree.c13
-rw-r--r--builtin-log.c16
-rw-r--r--builtin-mailinfo.c42
-rw-r--r--cache.h4
-rw-r--r--commit.c100
-rw-r--r--commit.h9
-rw-r--r--config.c8
-rwxr-xr-xcontrib/completion/git-completion.bash1
-rw-r--r--dir.c23
-rw-r--r--dir.h9
-rw-r--r--environment.c3
-rw-r--r--fetch-pack.c84
-rwxr-xr-xgit-am.sh7
-rwxr-xr-xgit-clone.sh21
-rwxr-xr-xgit-fetch.sh35
-rwxr-xr-xgit-merge.sh29
-rwxr-xr-xgit-pull.sh24
-rwxr-xr-xgit-rebase.sh21
-rwxr-xr-xgit-reset.sh3
-rwxr-xr-xgit-sh-setup.sh8
-rwxr-xr-xgit-svn.perl201
-rwxr-xr-xgitweb/gitweb.perl7
-rw-r--r--refs.c3
-rw-r--r--revision.h1
-rw-r--r--shallow.c104
-rw-r--r--t/Makefile3
-rw-r--r--t/README2
-rwxr-xr-xt/t3700-add.sh33
-rwxr-xr-xt/t3900-i18n-commit.sh115
-rw-r--r--t/t3900/1-UTF-8.txt3
-rw-r--r--t/t3900/2-UTF-8.txt4
-rw-r--r--t/t3900/EUCJP.txt4
-rw-r--r--t/t3900/ISO-2022-JP.txt4
-rw-r--r--t/t3900/ISO-8859-1.txt3
-rwxr-xr-xt/t5400-send-pack.sh43
-rwxr-xr-xt/t5500-fetch-pack.sh50
-rw-r--r--t/t6023-merge-file.sh22
-rw-r--r--t/t6024-recursive-merge.sh90
-rwxr-xr-xt/t9200-git-cvsexportcommit.sh10
-rwxr-xr-xt/test-lib.sh101
-rw-r--r--templates/hooks--update2
-rw-r--r--upload-pack.c174
-rw-r--r--utf8.c54
-rw-r--r--utf8.h6
-rw-r--r--xdiff/xmerge.c4
49 files changed, 1131 insertions, 459 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 6452a8be14..178e0e1e20 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -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.
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index e2954aa76e..0f79665ea6 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -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[]
diff --git a/Makefile b/Makefile
index 775ffaac27..93dc4948d3 100644
--- 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
diff --git a/builtin-add.c b/builtin-add.c
index 8ed4a6a9f3..e7a1b4d9ab 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -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");
diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c
index f641787988..146aaffd28 100644
--- a/builtin-commit-tree.c
+++ b/builtin-commit-tree.c
@@ -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)) {
diff --git a/builtin-log.c b/builtin-log.c
index 8df3c1394a..a59b4acef1 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -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)
diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index e6472293d4..a67f3eb90b 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -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 4943056c19..29dd290c92 100644
--- 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);
diff --git a/commit.c b/commit.c
index 3167ce62ac..eb06afbbe0 100644
--- 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;
}
diff --git a/commit.h b/commit.h
index 10eea9f26f..936f8fce30 100644
--- 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 */
diff --git a/config.c b/config.c
index 1662a4626e..fcccf7e2a4 100644
--- 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;
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 234cd0954b..7c7520ea29 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -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 dd188a8c56..0338d6c4e0 100644
--- 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 08c6345472..7233d65bbd 100644
--- 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
diff --git a/environment.c b/environment.c
index f8c7dbcead..a1502c4e87 100644
--- a/environment.c
+++ b/environment.c
@@ -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;
diff --git a/fetch-pack.c b/fetch-pack.c
index 92322cf4da..c527bf9e96 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -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;
}
diff --git a/git-am.sh b/git-am.sh
index 0126a77b92..c3bbd78eab 100755
--- 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
diff --git a/git-clone.sh b/git-clone.sh
index 490f3e48db..3d388de62a 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -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" &&
diff --git a/git-fetch.sh b/git-fetch.sh
index ffbd44f0e1..8bd11f8b60 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -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
diff --git a/git-merge.sh b/git-merge.sh
index 7dd0a11236..ba42260426 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -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
diff --git a/git-pull.sh b/git-pull.sh
index 1703091bbb..28d08195f0 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -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
diff --git a/git-rebase.sh b/git-rebase.sh
index ece31425d0..828c59ce61 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -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"
diff --git a/git-reset.sh b/git-reset.sh
index 2379db082f..a9693701a3 100755
--- a/git-reset.sh
+++ b/git-reset.sh
@@ -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
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 42f9b1c125..87b939c0e4 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -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"
diff --git a/git-svn.perl b/git-svn.perl
index c2cdceb1d1..b28c5bbc72 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -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
}
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index da12be7472..d845e91e20 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -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 8b2a3c1378..e88ed8b2d3 100644
--- 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);
diff --git a/revision.h b/revision.h
index ec991e5c57..8f7907d7ab 100644
--- a/revision.h
+++ b/revision.h
@@ -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
index 0000000000..3d53d17423
--- /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;
+}
+
diff --git a/t/Makefile b/t/Makefile
index 250a19019c..19e38508a7 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -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
diff --git a/t/README b/t/README
index c5db5804df..7abab1dafe 100644
--- 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.
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index c09c53f20b..e98786de32 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -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
index 0000000000..46fd47cb0f
--- /dev/null
+++ b/t/t3900-i18n-commit.sh
@@ -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
index 0000000000..ee31e19738
--- /dev/null
+++ b/t/t3900/1-UTF-8.txt
@@ -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
index 0000000000..63f4f8f121
--- /dev/null
+++ b/t/t3900/2-UTF-8.txt
@@ -0,0 +1,4 @@
+はれひほふ
+
+しているのが、いるので。
+濱浜ほれぷりぽれまびぐりろへ。
diff --git a/t/t3900/EUCJP.txt b/t/t3900/EUCJP.txt
new file mode 100644
index 0000000000..546f2aac01
--- /dev/null
+++ b/t/t3900/EUCJP.txt
@@ -0,0 +1,4 @@
+ϤҤۤ
+
+ƤΤΤǡ
+ͤۤפݤޤӤء
diff --git a/t/t3900/ISO-2022-JP.txt b/t/t3900/ISO-2022-JP.txt
new file mode 100644
index 0000000000..74b533042f
--- /dev/null
+++ b/t/t3900/ISO-2022-JP.txt
@@ -0,0 +1,4 @@
+$B$O$l$R$[$U(B
+
+$B$7$F$$$k$N$,!"$$$k$N$G!#(B
+$B_@IM$[$l$W$j$]$l$^$S$0$j$m$X!#(B
diff --git a/t/t3900/ISO-8859-1.txt b/t/t3900/ISO-8859-1.txt
new file mode 100644
index 0000000000..7cbef0ee6f
--- /dev/null
+++ b/t/t3900/ISO-8859-1.txt
@@ -0,0 +1,3 @@
+
+
+bdfg
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 28744b35e1..2c151912a3 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -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.
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index f7625a6f46..77c3c575d8 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -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
diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh
index 5d9b6f34b8..1c21d8c986 100644
--- a/t/t6023-merge-file.sh
+++ b/t/t6023-merge-file.sh
@@ -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
diff --git a/t/t6024-recursive-merge.sh b/t/t6024-recursive-merge.sh
index 69b18f7d81..31b96257b4 100644
--- a/t/t6024-recursive-merge.sh
+++ b/t/t6024-recursive-merge.sh
@@ -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"
diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh
index ca0513b162..315119abff 100755
--- a/t/t9200-git-cvsexportcommit.sh
+++ b/t/t9200-git-cvsexportcommit.sh
@@ -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 \
diff --git a/t/test-lib.sh b/t/test-lib.sh
index f0f9cd6be0..bf108d4226 100755
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -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
diff --git a/templates/hooks--update b/templates/hooks--update
index 76d5ac2477..9863a800c8 100644
--- a/templates/hooks--update
+++ b/templates/hooks--update
@@ -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
diff --git a/upload-pack.c b/upload-pack.c
index 32b06b2e66..c568ef066c 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -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 8fa62571aa..1eedd8b61a 100644
--- 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 a0d7f591ad..cae2a8e665 100644
--- 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
diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c
index 352207e516..294450b899 100644
--- a/xdiff/xmerge.c
+++ b/xdiff/xmerge.c
@@ -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.