summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/config.txt6
-rw-r--r--Documentation/git-branch.txt11
-rw-r--r--Documentation/git-clone.txt24
-rw-r--r--Documentation/git-diff-tree.txt5
-rw-r--r--Documentation/git-log.txt4
-rw-r--r--Documentation/git-rev-list.txt6
-rw-r--r--Documentation/git-show.txt5
-rw-r--r--Documentation/pretty-formats.txt78
-rw-r--r--Documentation/tutorial.txt2
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--archive-zip.c24
-rw-r--r--builtin-apply.c6
-rw-r--r--builtin-archive.c2
-rw-r--r--builtin-branch.c103
-rw-r--r--builtin-log.c20
-rw-r--r--builtin-pack-objects.c4
-rw-r--r--builtin-prune.c9
-rw-r--r--builtin-update-index.c6
-rw-r--r--connect.c47
-rwxr-xr-xgit-clone.sh14
-rwxr-xr-xgit-cvsimport.perl54
-rwxr-xr-xgit-svn.perl179
-rw-r--r--read-cache.c6
-rwxr-xr-xt/t3700-add.sh14
-rwxr-xr-xt/t4013-diff-various.sh1
-rw-r--r--upload-pack.c101
-rw-r--r--xdiff/xemit.c2
27 files changed, 625 insertions, 110 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 9d3c71c3b8..9090762819 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -219,6 +219,12 @@ 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'.
+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.
+ Tools like gitlink:git-log[1] or gitlink:git-whatchanged[1], which
+ normally hide the root commit will now show it. True by default.
+
merge.summary::
Whether to include summaries of merged commits in newly created
merge commit messages. False by default.
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index d43ef1dec4..5376760813 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -8,14 +8,16 @@ git-branch - List, create, or delete branches.
SYNOPSIS
--------
[verse]
-'git-branch' [-r]
+'git-branch' [-r] [-a]
'git-branch' [-l] [-f] <branchname> [<start-point>]
'git-branch' (-d | -D) <branchname>...
DESCRIPTION
-----------
-With no arguments given (or just `-r`) a list of available branches
+With no arguments given a list of existing branches
will be shown, the current branch will be highlighted with an asterisk.
+Option `-r` causes the remote-tracking branches to be listed,
+and option `-a` shows both.
In its second form, a new branch named <branchname> will be created.
It will start out with a head equal to the one given as <start-point>.
@@ -45,7 +47,10 @@ OPTIONS
a branch that already exists with the same name.
-r::
- List only the "remote" branches.
+ List the remote-tracking branches.
+
+-a::
+ List both remote-tracking branches and local branches.
<branchname>::
The name of the branch to create or delete.
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 86060472ad..4cb42237b5 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -11,7 +11,8 @@ SYNOPSIS
[verse]
'git-clone' [--template=<template_directory>] [-l [-s]] [-q] [-n] [--bare]
[-o <name>] [-u <upload-pack>] [--reference <repository>]
- [--use-separate-remote] <repository> [<directory>]
+ [--use-separate-remote | --use-immingled-remote] <repository>
+ [<directory>]
DESCRIPTION
-----------
@@ -71,9 +72,13 @@ OPTIONS
Make a 'bare' GIT repository. That is, instead of
creating `<directory>` and placing the administrative
files in `<directory>/.git`, make the `<directory>`
- itself the `$GIT_DIR`. This implies `-n` option. When
- this option is used, neither the `origin` branch nor the
- default `remotes/origin` file is created.
+ itself the `$GIT_DIR`. This obviously implies the `-n`
+ because there is nowhere to check out the working tree.
+ Also the branch heads at the remote are copied directly
+ to corresponding local branch heads, without mapping
+ them to `refs/remotes/origin/`. When this option is
+ used, neither the `origin` branch nor the default
+ `remotes/origin` file is created.
--origin <name>::
-o <name>::
@@ -97,8 +102,15 @@ OPTIONS
--use-separate-remote::
Save remotes heads under `$GIT_DIR/remotes/origin/` instead
- of `$GIT_DIR/refs/heads/`. Only the master branch is saved
- in the latter.
+ of `$GIT_DIR/refs/heads/`. Only the local master branch is
+ saved in the latter. This is the default.
+
+--use-immingled-remote::
+ Save remotes heads in the same namespace as the local
+ heads, `$GIT_DIR/refs/heads/'. In regular repositories,
+ this is a legacy setup git-clone created by default in
+ older Git versions, and will be removed before the next
+ major release.
<repository>::
The (possibly remote) repository to clone from. It can
diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt
index f7e8ff2968..5d6e9dc751 100644
--- a/Documentation/git-diff-tree.txt
+++ b/Documentation/git-diff-tree.txt
@@ -73,10 +73,7 @@ separated with a single space are given.
This flag causes "git-diff-tree --stdin" to also show
the commit message before the differences.
---pretty[=(raw|medium|short)]::
- This is used to control "pretty printing" format of the
- commit message. Without "=<style>", it defaults to
- medium.
+include::pretty-formats.txt[]
--no-commit-id::
git-diff-tree outputs a line with the commit ID when
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index c9ffff734c..79643ac928 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -24,8 +24,8 @@ This manual page describes only the most frequently used options.
OPTIONS
-------
---pretty=<format>::
- Controls the way the commit log is formatted.
+
+include::pretty-formats.txt[]
--max-count=<n>::
Limits the number of commits to show.
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 00a95e249f..ec43c0b3a8 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -79,11 +79,7 @@ Using these options, gitlink:git-rev-list[1] will act similar to the
more specialized family of commit log tools: gitlink:git-log[1],
gitlink:git-show[1], and gitlink:git-whatchanged[1]
---pretty[='<format>']::
-
- Pretty print the contents of the commit logs in a given format,
- where '<format>' can be one of 'raw', 'medium', 'short', 'full',
- and 'oneline'. When left out the format default to 'medium'.
+include::pretty-formats.txt[]
--relative-date::
diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt
index 2b4df3f96f..4c880a8717 100644
--- a/Documentation/git-show.txt
+++ b/Documentation/git-show.txt
@@ -26,10 +26,7 @@ OPTIONS
<commitid>::
ID of the commit to show.
---pretty=<format>::
- Controls the output format for the commit logs.
- <format> can be one of 'raw', 'medium', 'short', 'full',
- and 'oneline'.
+include::pretty-formats.txt[]
Author
------
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
new file mode 100644
index 0000000000..996f628903
--- /dev/null
+++ b/Documentation/pretty-formats.txt
@@ -0,0 +1,78 @@
+--pretty[='<format>']::
+
+ Pretty-prints the details of a commit. `--pretty`
+ without an explicit `=<format>` defaults to 'medium'.
+ If the commit is a merge, and if the pretty-format
+ is not 'oneline', 'email' or 'raw', an additional line is
+ inserted before the 'Author:' line. This line begins with
+ "Merge: " and the sha1s of ancestral commits are printed,
+ separated by spaces. Note that the listed commits may not
+ necessarily be the list of the *direct* parent commits if you
+ have limited your view of history: for example, if you are
+ only interested in changes related to a certain directory or
+ file. Here are some additional details for each format:
+
+ * 'oneline'
+
+ <sha1> <title line>
++
+This is designed to be as compact as possible.
+
+ * 'short'
+
+ commit <sha1>
+ Author: <author>
+
+ <title line>
+
+ * 'medium'
+
+ commit <sha1>
+ Author: <author>
+ Date: <date>
+
+ <title line>
+
+ <full commit message>
+
+ * 'full'
+
+ commit <sha1>
+ Author: <author>
+ Commit: <committer>
+
+ <title line>
+
+ <full commit message>
+
+ * 'fuller'
+
+ commit <sha1>
+ Author: <author>
+ AuthorDate: <date & time>
+ Commit: <committer>
+ CommitDate: <date & time>
+
+ <title line>
+
+ <full commit message>
+
+
+ * 'email'
+
+ From <sha1> <date>
+ From: <author>
+ Date: <date & time>
+ Subject: [PATCH] <title line>
+
+ full commit message>
+
+
+ * 'raw'
++
+The 'raw' format shows the entire commit exactly as
+stored in the commit object. Notably, the SHA1s are
+displayed in full, regardless of whether --abbrev or
+--no-abbrev are used, and 'parents' information show the
+true parent commits, without taking grafts nor history
+simplification into account.
diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt
index 554ee0af91..1e4ddfbd11 100644
--- a/Documentation/tutorial.txt
+++ b/Documentation/tutorial.txt
@@ -141,7 +141,7 @@ $ git commit -a
------------------------------------------------
at this point the two branches have diverged, with different changes
-made in each. To merge the changes made in the two branches, run
+made in each. To merge the changes made in experimental into master, run
------------------------------------------------
$ git pull . experimental
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index eca1ff2175..4eac314f3a 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.4.4.GIT
+DEF_VER=v1.4.4.1.GIT
LF='
'
diff --git a/archive-zip.c b/archive-zip.c
index ae5572ae20..36e922a1f2 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -35,6 +35,7 @@ struct zip_local_header {
unsigned char size[4];
unsigned char filename_length[2];
unsigned char extra_length[2];
+ unsigned char _end[1];
};
struct zip_dir_header {
@@ -55,6 +56,7 @@ struct zip_dir_header {
unsigned char attr1[2];
unsigned char attr2[4];
unsigned char offset[4];
+ unsigned char _end[1];
};
struct zip_dir_trailer {
@@ -66,8 +68,18 @@ struct zip_dir_trailer {
unsigned char size[4];
unsigned char offset[4];
unsigned char comment_length[2];
+ unsigned char _end[1];
};
+/*
+ * On ARM, padding is added at the end of the struct, so a simple
+ * sizeof(struct ...) reports two bytes more than the payload size
+ * we're interested in.
+ */
+#define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end)
+#define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end)
+#define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end)
+
static void copy_le16(unsigned char *dest, unsigned int n)
{
dest[0] = 0xff & n;
@@ -211,7 +223,7 @@ static int write_zip_entry(const unsigned char *sha1,
}
/* make sure we have enough free space in the dictionary */
- direntsize = sizeof(struct zip_dir_header) + pathlen;
+ direntsize = ZIP_DIR_HEADER_SIZE + pathlen;
while (zip_dir_size < zip_dir_offset + direntsize) {
zip_dir_size += ZIP_DIRECTORY_MIN_SIZE;
zip_dir = xrealloc(zip_dir, zip_dir_size);
@@ -234,8 +246,8 @@ static int write_zip_entry(const unsigned char *sha1,
copy_le16(dirent.attr1, 0);
copy_le32(dirent.attr2, attr2);
copy_le32(dirent.offset, zip_offset);
- memcpy(zip_dir + zip_dir_offset, &dirent, sizeof(struct zip_dir_header));
- zip_dir_offset += sizeof(struct zip_dir_header);
+ memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE);
+ zip_dir_offset += ZIP_DIR_HEADER_SIZE;
memcpy(zip_dir + zip_dir_offset, path, pathlen);
zip_dir_offset += pathlen;
zip_dir_entries++;
@@ -251,8 +263,8 @@ static int write_zip_entry(const unsigned char *sha1,
copy_le32(header.size, uncompressed_size);
copy_le16(header.filename_length, pathlen);
copy_le16(header.extra_length, 0);
- write_or_die(1, &header, sizeof(struct zip_local_header));
- zip_offset += sizeof(struct zip_local_header);
+ write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE);
+ zip_offset += ZIP_LOCAL_HEADER_SIZE;
write_or_die(1, path, pathlen);
zip_offset += pathlen;
if (compressed_size > 0) {
@@ -282,7 +294,7 @@ static void write_zip_trailer(const unsigned char *sha1)
copy_le16(trailer.comment_length, sha1 ? 40 : 0);
write_or_die(1, zip_dir, zip_dir_offset);
- write_or_die(1, &trailer, sizeof(struct zip_dir_trailer));
+ write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE);
if (sha1)
write_or_die(1, sha1_to_hex(sha1), 40);
}
diff --git a/builtin-apply.c b/builtin-apply.c
index 61f047fd45..436d9e1880 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -2119,7 +2119,11 @@ static void numstat_patch_list(struct patch *patch)
for ( ; patch; patch = patch->next) {
const char *name;
name = patch->new_name ? patch->new_name : patch->old_name;
- printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
+ if (patch->is_binary)
+ printf("-\t-\t");
+ else
+ printf("%d\t%d\t",
+ patch->lines_added, patch->lines_deleted);
if (line_termination && quote_c_style(name, NULL, NULL, 0))
quote_c_style(name, NULL, stdout, 0);
else
diff --git a/builtin-archive.c b/builtin-archive.c
index 2df1a84b85..a8a1f079bf 100644
--- a/builtin-archive.c
+++ b/builtin-archive.c
@@ -249,7 +249,7 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
if (remote)
return run_remote_archiver(remote, argc, argv);
- setlinebuf(stderr);
+ setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
memset(&ar, 0, sizeof(ar));
tree_idx = parse_archive_args(argc, argv, &ar);
diff --git a/builtin-branch.c b/builtin-branch.c
index 368b68ec91..22e3285a4c 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -11,7 +11,7 @@
#include "builtin.h"
static const char builtin_branch_usage[] =
-"git-branch (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | [-r]";
+"git-branch (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | [-r] | [-a]";
static const char *head;
@@ -79,46 +79,100 @@ static void delete_branches(int argc, const char **argv, int force)
}
}
-static int ref_index, ref_alloc;
-static char **ref_list;
+#define REF_UNKNOWN_TYPE 0x00
+#define REF_LOCAL_BRANCH 0x01
+#define REF_REMOTE_BRANCH 0x02
+#define REF_TAG 0x04
-static int append_ref(const char *refname, const unsigned char *sha1, int flags,
- void *cb_data)
+struct ref_item {
+ char *name;
+ unsigned int kind;
+};
+
+struct ref_list {
+ int index, alloc;
+ struct ref_item *list;
+ int kinds;
+};
+
+static int append_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
{
- if (ref_index >= ref_alloc) {
- ref_alloc = alloc_nr(ref_alloc);
- ref_list = xrealloc(ref_list, ref_alloc * sizeof(char *));
+ struct ref_list *ref_list = (struct ref_list*)(cb_data);
+ struct ref_item *newitem;
+ int kind = REF_UNKNOWN_TYPE;
+
+ /* Detect kind */
+ if (!strncmp(refname, "refs/heads/", 11)) {
+ kind = REF_LOCAL_BRANCH;
+ refname += 11;
+ } else if (!strncmp(refname, "refs/remotes/", 13)) {
+ kind = REF_REMOTE_BRANCH;
+ refname += 13;
+ } else if (!strncmp(refname, "refs/tags/", 10)) {
+ kind = REF_TAG;
+ refname += 10;
+ }
+
+ /* Don't add types the caller doesn't want */
+ if ((kind & ref_list->kinds) == 0)
+ return 0;
+
+ /* Resize buffer */
+ if (ref_list->index >= ref_list->alloc) {
+ ref_list->alloc = alloc_nr(ref_list->alloc);
+ ref_list->list = xrealloc(ref_list->list,
+ ref_list->alloc * sizeof(struct ref_item));
}
- ref_list[ref_index++] = xstrdup(refname);
+ /* Record the new item */
+ newitem = &(ref_list->list[ref_list->index++]);
+ newitem->name = xstrdup(refname);
+ newitem->kind = kind;
return 0;
}
+static void free_ref_list(struct ref_list *ref_list)
+{
+ int i;
+
+ for (i = 0; i < ref_list->index; i++)
+ free(ref_list->list[i].name);
+ free(ref_list->list);
+}
+
static int ref_cmp(const void *r1, const void *r2)
{
- return strcmp(*(char **)r1, *(char **)r2);
+ struct ref_item *c1 = (struct ref_item *)(r1);
+ struct ref_item *c2 = (struct ref_item *)(r2);
+
+ if (c1->kind != c2->kind)
+ return c1->kind - c2->kind;
+ return strcmp(c1->name, c2->name);
}
-static void print_ref_list(int remote_only)
+static void print_ref_list(int kinds)
{
int i;
char c;
+ struct ref_list ref_list;
- if (remote_only)
- for_each_remote_ref(append_ref, NULL);
- else
- for_each_branch_ref(append_ref, NULL);
+ memset(&ref_list, 0, sizeof(ref_list));
+ ref_list.kinds = kinds;
+ for_each_ref(append_ref, &ref_list);
- qsort(ref_list, ref_index, sizeof(char *), ref_cmp);
+ qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
- for (i = 0; i < ref_index; i++) {
+ for (i = 0; i < ref_list.index; i++) {
c = ' ';
- if (!strcmp(ref_list[i], head))
+ if (ref_list.list[i].kind == REF_LOCAL_BRANCH &&
+ !strcmp(ref_list.list[i].name, head))
c = '*';
- printf("%c %s\n", c, ref_list[i]);
+ printf("%c %s\n", c, ref_list.list[i].name);
}
+
+ free_ref_list(&ref_list);
}
static void create_branch(const char *name, const char *start,
@@ -160,8 +214,9 @@ static void create_branch(const char *name, const char *start,
int cmd_branch(int argc, const char **argv, const char *prefix)
{
- int delete = 0, force_delete = 0, force_create = 0, remote_only = 0;
+ int delete = 0, force_delete = 0, force_create = 0;
int reflog = 0;
+ int kinds = REF_LOCAL_BRANCH;
int i;
git_config(git_default_config);
@@ -189,7 +244,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "-r")) {
- remote_only = 1;
+ kinds = REF_REMOTE_BRANCH;
+ continue;
+ }
+ if (!strcmp(arg, "-a")) {
+ kinds = REF_REMOTE_BRANCH | REF_LOCAL_BRANCH;
continue;
}
if (!strcmp(arg, "-l")) {
@@ -209,7 +268,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (delete)
delete_branches(argc - i, argv + i, force_delete);
else if (i == argc)
- print_ref_list(remote_only);
+ print_ref_list(kinds);
else if (i == argc - 1)
create_branch(argv[i], head, force_create, reflog);
else if (i == argc - 2)
diff --git a/builtin-log.c b/builtin-log.c
index fedb0137bc..7acf5d3b0c 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -13,6 +13,8 @@
#include <time.h>
#include <sys/time.h>
+static int default_show_root = 1;
+
/* this is in builtin-diff.c */
void add_head(struct rev_info *revs);
@@ -22,6 +24,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
rev->abbrev = DEFAULT_ABBREV;
rev->commit_format = CMIT_FMT_DEFAULT;
rev->verbose_header = 1;
+ rev->show_root_diff = default_show_root;
argc = setup_revisions(argc, argv, rev, "HEAD");
if (rev->diffopt.pickaxe || rev->diffopt.filter)
rev->always_show_header = 0;
@@ -44,11 +47,20 @@ static int cmd_log_walk(struct rev_info *rev)
return 0;
}
+static int git_log_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "log.showroot")) {
+ default_show_root = git_config_bool(var, value);
+ return 0;
+ }
+ return git_diff_ui_config(var, value);
+}
+
int cmd_whatchanged(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
- git_config(git_diff_ui_config);
+ git_config(git_log_config);
init_revisions(&rev, prefix);
rev.diff = 1;
rev.diffopt.recursive = 1;
@@ -63,7 +75,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
- git_config(git_diff_ui_config);
+ git_config(git_log_config);
init_revisions(&rev, prefix);
rev.diff = 1;
rev.diffopt.recursive = 1;
@@ -80,7 +92,7 @@ int cmd_log(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
- git_config(git_diff_ui_config);
+ git_config(git_log_config);
init_revisions(&rev, prefix);
rev.always_show_header = 1;
cmd_log_init(argc, argv, prefix, &rev);
@@ -109,7 +121,7 @@ static int git_format_config(const char *var, const char *value)
if (!strcmp(var, "diff.color")) {
return 0;
}
- return git_diff_ui_config(var, value);
+ return git_log_config(var, value);
}
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 69e5dd39ca..753bcd57b0 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -1176,7 +1176,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
* on an earlier try, but only when reusing delta data.
*/
if (!no_reuse_delta && trg_entry->in_pack &&
- trg_entry->in_pack == src_entry->in_pack)
+ trg_entry->in_pack == src_entry->in_pack &&
+ trg_entry->in_pack_type != OBJ_REF_DELTA &&
+ trg_entry->in_pack_type != OBJ_OFS_DELTA)
return 0;
/*
diff --git a/builtin-prune.c b/builtin-prune.c
index d853902c51..8591d28b8e 100644
--- a/builtin-prune.c
+++ b/builtin-prune.c
@@ -16,8 +16,15 @@ static struct rev_info revs;
static int prune_object(char *path, const char *filename, const unsigned char *sha1)
{
+ char buf[20];
+ const char *type;
+
if (show_only) {
- printf("would prune %s/%s\n", path, filename);
+ if (sha1_object_info(sha1, buf, NULL))
+ type = "unknown";
+ else
+ type = buf;
+ printf("%s %s\n", sha1_to_hex(sha1), type);
return 0;
}
unlink(mkpath("%s/%s", path, filename));
diff --git a/builtin-update-index.c b/builtin-update-index.c
index 7f9c638466..182331d341 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -112,13 +112,13 @@ static int add_file_to_cache(const char *path)
ce->ce_mode = create_ce_mode(st.st_mode);
if (!trust_executable_bit) {
/* If there is an existing entry, pick the mode bits
- * from it, otherwise force to 644.
+ * from it, otherwise assume unexecutable.
*/
int pos = cache_name_pos(path, namelen);
if (0 <= pos)
ce->ce_mode = active_cache[pos]->ce_mode;
- else
- ce->ce_mode = create_ce_mode(S_IFREG | 0644);
+ else if (S_ISREG(st.st_mode))
+ ce->ce_mode = create_ce_mode(S_IFREG | 0666);
}
if (index_path(ce->sha1, path, &st, !info_only))
diff --git a/connect.c b/connect.c
index c55a20a4aa..b9666cc0d8 100644
--- a/connect.c
+++ b/connect.c
@@ -174,21 +174,58 @@ static int count_refspec_match(const char *pattern,
struct ref *refs,
struct ref **matched_ref)
{
- int match;
int patlen = strlen(pattern);
+ struct ref *matched_weak = NULL;
+ struct ref *matched = NULL;
+ int weak_match = 0;
+ int match = 0;
- for (match = 0; refs; refs = refs->next) {
+ for (weak_match = match = 0; refs; refs = refs->next) {
char *name = refs->name;
int namelen = strlen(name);
+ int weak_match;
+
if (namelen < patlen ||
memcmp(name + namelen - patlen, pattern, patlen))
continue;
if (namelen != patlen && name[namelen - patlen - 1] != '/')
continue;
- match++;
- *matched_ref = refs;
+
+ /* A match is "weak" if it is with refs outside
+ * heads or tags, and did not specify the pattern
+ * in full (e.g. "refs/remotes/origin/master") or at
+ * least from the toplevel (e.g. "remotes/origin/master");
+ * otherwise "git push $URL master" would result in
+ * ambiguity between remotes/origin/master and heads/master
+ * at the remote site.
+ */
+ if (namelen != patlen &&
+ patlen != namelen - 5 &&
+ strncmp(name, "refs/heads/", 11) &&
+ strncmp(name, "refs/tags/", 10)) {
+ /* We want to catch the case where only weak
+ * matches are found and there are multiple
+ * matches, and where more than one strong
+ * matches are found, as ambiguous. One
+ * strong match with zero or more weak matches
+ * are acceptable as a unique match.
+ */
+ matched_weak = refs;
+ weak_match++;
+ }
+ else {
+ matched = refs;
+ match++;
+ }
+ }
+ if (!matched) {
+ *matched_ref = matched_weak;
+ return weak_match;
+ }
+ else {
+ *matched_ref = matched;
+ return match;
}
- return match;
}
static void link_dst_tail(struct ref *ref, struct ref ***tail)
diff --git a/git-clone.sh b/git-clone.sh
index 3f006d1a77..9ed4135544 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -14,7 +14,7 @@ die() {
}
usage() {
- die "Usage: $0 [--template=<template_directory>] [--use-separate-remote] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [-n] <repo> [<dir>]"
+ die "Usage: $0 [--template=<template_directory>] [--use-immingled-remote] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [-n] <repo> [<dir>]"
}
get_repo_base() {
@@ -115,7 +115,7 @@ bare=
reference=
origin=
origin_override=
-use_separate_remote=
+use_separate_remote=t
while
case "$#,$1" in
0,*) break ;;
@@ -134,7 +134,10 @@ while
template="$1" ;;
*,-q|*,--quiet) quiet=-q ;;
*,--use-separate-remote)
+ # default
use_separate_remote=t ;;
+ *,--use-immingled-remote)
+ use_separate_remote= ;;
1,--reference) usage ;;
*,--reference)
shift; reference="$1" ;;
@@ -169,18 +172,15 @@ repo="$1"
test -n "$repo" ||
die 'you must specify a repository to clone.'
-# --bare implies --no-checkout
+# --bare implies --no-checkout and --use-immingled-remote
if test yes = "$bare"
then
if test yes = "$origin_override"
then
die '--bare and --origin $origin options are incompatible.'
fi
- if test t = "$use_separate_remote"
- then
- die '--bare and --use-separate-remote options are incompatible.'
- fi
no_checkout=yes
+ use_separate_remote=
fi
if test -z "$origin"
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index b54a9486d2..4310dea132 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -161,8 +161,22 @@ sub new {
sub conn {
my $self = shift;
my $repo = $self->{'fullrep'};
- if($repo =~ s/^:pserver:(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?//) {
- my($user,$pass,$serv,$port) = ($1,$2,$3,$4);
+ if($repo =~ s/^:pserver(?:([^:]*)):(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?//) {
+ my($param,$user,$pass,$serv,$port) = ($1,$2,$3,$4,$5);
+
+ my($proxyhost,$proxyport);
+ if($param && ($param =~ m/proxy=([^;]+)/)) {
+ $proxyhost = $1;
+ # Default proxyport, if not specified, is 8080.
+ $proxyport = 8080;
+ if($ENV{"CVS_PROXY_PORT"}) {
+ $proxyport = $ENV{"CVS_PROXY_PORT"};
+ }
+ if($param =~ m/proxyport=([^;]+)/){
+ $proxyport = $1;
+ }
+ }
+
$user="anonymous" unless defined $user;
my $rr2 = "-";
unless($port) {
@@ -187,13 +201,43 @@ sub conn {
}
$pass="A" unless $pass;
- my $s = IO::Socket::INET->new(PeerHost => $serv, PeerPort => $port);
- die "Socket to $serv: $!\n" unless defined $s;
+ my ($s, $rep);
+ if($proxyhost) {
+
+ # Use a HTTP Proxy. Only works for HTTP proxies that
+ # don't require user authentication
+ #
+ # See: http://www.ietf.org/rfc/rfc2817.txt
+
+ $s = IO::Socket::INET->new(PeerHost => $proxyhost, PeerPort => $proxyport);
+ die "Socket to $proxyhost: $!\n" unless defined $s;
+ $s->write("CONNECT $serv:$port HTTP/1.1\r\nHost: $serv:$port\r\n\r\n")
+ or die "Write to $proxyhost: $!\n";
+ $s->flush();
+
+ $rep = <$s>;
+
+ # The answer should look like 'HTTP/1.x 2yy ....'
+ if(!($rep =~ m#^HTTP/1\.. 2[0-9][0-9]#)) {
+ die "Proxy connect: $rep\n";
+ }
+ # Skip up to the empty line of the proxy server output
+ # including the response headers.
+ while ($rep = <$s>) {
+ last if (!defined $rep ||
+ $rep eq "\n" ||
+ $rep eq "\r\n");
+ }
+ } else {
+ $s = IO::Socket::INET->new(PeerHost => $serv, PeerPort => $port);
+ die "Socket to $serv: $!\n" unless defined $s;
+ }
+
$s->write("BEGIN AUTH REQUEST\n$repo\n$user\n$pass\nEND AUTH REQUEST\n")
or die "Write to $serv: $!\n";
$s->flush();
- my $rep = <$s>;
+ $rep = <$s>;
if($rep ne "I LOVE YOU\n") {
$rep="<unknown>" unless $rep;
diff --git a/git-svn.perl b/git-svn.perl
index 80b7b87f0f..47cd3e27fe 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -39,7 +39,7 @@ memoize('revisions_eq');
memoize('cmt_metadata');
memoize('get_commit_time');
-my ($SVN_PATH, $SVN, $SVN_LOG, $_use_lib);
+my ($SVN_PATH, $SVN, $SVN_LOG, $_use_lib, $AUTH_BATON, $AUTH_CALLBACKS);
sub nag_lib {
print STDERR <<EOF;
@@ -66,7 +66,8 @@ my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
$_template, $_shared, $_no_default_regex, $_no_graft_copy,
$_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,
$_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m,
- $_merge, $_strategy, $_dry_run, $_ignore_nodate, $_non_recursive);
+ $_merge, $_strategy, $_dry_run, $_ignore_nodate, $_non_recursive,
+ $_username, $_config_dir, $_no_auth_cache);
my (@_branch_from, %tree_map, %users, %rusers, %equiv);
my ($_svn_co_url_revs, $_svn_pg_peg_revs);
my @repo_path_split_cache;
@@ -79,6 +80,9 @@ my %fc_opts = ( 'no-ignore-externals' => \$_no_ignore_ext,
'repack:i' => \$_repack,
'no-metadata' => \$_no_metadata,
'quiet|q' => \$_q,
+ 'username=s' => \$_username,
+ 'config-dir=s' => \$_config_dir,
+ 'no-auth-cache' => \$_no_auth_cache,
'ignore-nodate' => \$_ignore_nodate,
'repack-flags|repack-args|repack-opts=s' => \$_repack_flags);
@@ -232,7 +236,7 @@ sub rebuild {
my @commit = grep(/^git-svn-id: /,`git-cat-file commit $c`);
next if (!@commit); # skip merges
my ($url, $rev, $uuid) = extract_metadata($commit[$#commit]);
- if (!$rev || !$uuid) {
+ if (!defined $rev || !$uuid) {
croak "Unable to extract revision or UUID from ",
"$c, $commit[$#commit]\n";
}
@@ -589,6 +593,13 @@ sub dcommit {
chomp(my @refs = safe_qx(qw/git-rev-list --no-merges/, "$gs..HEAD"));
my $last_rev;
foreach my $d (reverse @refs) {
+ if (quiet_run('git-rev-parse','--verify',"$d~1") != 0) {
+ die "Commit $d\n",
+ "has no parent commit, and therefore ",
+ "nothing to diff against.\n",
+ "You should be working from a repository ",
+ "originally created by git-svn\n";
+ }
unless (defined $last_rev) {
(undef, $last_rev, undef) = cmt_metadata("$d~1");
unless (defined $last_rev) {
@@ -616,7 +627,7 @@ sub dcommit {
} else {
print "No changes between current HEAD and $gs\n",
"Hard resetting to the latest $gs\n";
- @finish = qw/reset --hard/;
+ @finish = qw/reset --mixed/;
}
sys('git', @finish, $gs);
}
@@ -825,8 +836,14 @@ sub commit_diff {
print STDERR "Needed URL or usable git-svn id command-line\n";
commit_diff_usage();
}
- my $r = shift || $_revision;
- die "-r|--revision is a required argument\n" unless (defined $r);
+ my $r = shift;
+ unless (defined $r) {
+ if (defined $_revision) {
+ $r = $_revision
+ } else {
+ die "-r|--revision is a required argument\n";
+ }
+ }
if (defined $_message && defined $_file) {
print STDERR "Both --message/-m and --file/-F specified ",
"for the commit message.\n",
@@ -2486,7 +2503,7 @@ sub extract_metadata {
my $id = shift or return (undef, undef, undef);
my ($url, $rev, $uuid) = ($id =~ /^git-svn-id:\s(\S+?)\@(\d+)
\s([a-f\d\-]+)$/x);
- if (!$rev || !$uuid || !$url) {
+ if (!defined $rev || !$uuid || !$url) {
# some of the original repositories I made had
# identifiers like this:
($rev, $uuid) = ($id =~/^git-svn-id:\s(\d+)\@([a-f\d\-]+)/);
@@ -2670,18 +2687,154 @@ sub libsvn_load {
my $kill_stupid_warnings = $SVN::Node::none.$SVN::Node::file.
$SVN::Node::dir.$SVN::Node::unknown.
$SVN::Node::none.$SVN::Node::file.
- $SVN::Node::dir.$SVN::Node::unknown;
+ $SVN::Node::dir.$SVN::Node::unknown.
+ $SVN::Auth::SSL::CNMISMATCH.
+ $SVN::Auth::SSL::NOTYETVALID.
+ $SVN::Auth::SSL::EXPIRED.
+ $SVN::Auth::SSL::UNKNOWNCA.
+ $SVN::Auth::SSL::OTHER;
1;
};
}
+sub _simple_prompt {
+ my ($cred, $realm, $default_username, $may_save, $pool) = @_;
+ $may_save = undef if $_no_auth_cache;
+ $default_username = $_username if defined $_username;
+ if (defined $default_username && length $default_username) {
+ if (defined $realm && length $realm) {
+ print "Authentication realm: $realm\n";
+ }
+ $cred->username($default_username);
+ } else {
+ _username_prompt($cred, $realm, $may_save, $pool);
+ }
+ $cred->password(_read_password("Password for '" .
+ $cred->username . "': ", $realm));
+ $cred->may_save($may_save);
+ $SVN::_Core::SVN_NO_ERROR;
+}
+
+sub _ssl_server_trust_prompt {
+ my ($cred, $realm, $failures, $cert_info, $may_save, $pool) = @_;
+ $may_save = undef if $_no_auth_cache;
+ print "Error validating server certificate for '$realm':\n";
+ if ($failures & $SVN::Auth::SSL::UNKNOWNCA) {
+ print " - The certificate is not issued by a trusted ",
+ "authority. Use the\n",
+ " fingerprint to validate the certificate manually!\n";
+ }
+ if ($failures & $SVN::Auth::SSL::CNMISMATCH) {
+ print " - The certificate hostname does not match.\n";
+ }
+ if ($failures & $SVN::Auth::SSL::NOTYETVALID) {
+ print " - The certificate is not yet valid.\n";
+ }
+ if ($failures & $SVN::Auth::SSL::EXPIRED) {
+ print " - The certificate has expired.\n";
+ }
+ if ($failures & $SVN::Auth::SSL::OTHER) {
+ print " - The certificate has an unknown error.\n";
+ }
+ printf( "Certificate information:\n".
+ " - Hostname: %s\n".
+ " - Valid: from %s until %s\n".
+ " - Issuer: %s\n".
+ " - Fingerprint: %s\n",
+ map $cert_info->$_, qw(hostname valid_from valid_until
+ issuer_dname fingerprint) );
+ my $choice;
+prompt:
+ print $may_save ?
+ "(R)eject, accept (t)emporarily or accept (p)ermanently? " :
+ "(R)eject or accept (t)emporarily? ";
+ $choice = lc(substr(<STDIN> || 'R', 0, 1));
+ if ($choice =~ /^t$/i) {
+ $cred->may_save(undef);
+ } elsif ($choice =~ /^r$/i) {
+ return -1;
+ } elsif ($may_save && $choice =~ /^p$/i) {
+ $cred->may_save($may_save);
+ } else {
+ goto prompt;
+ }
+ $cred->accepted_failures($failures);
+ $SVN::_Core::SVN_NO_ERROR;
+}
+
+sub _ssl_client_cert_prompt {
+ my ($cred, $realm, $may_save, $pool) = @_;
+ $may_save = undef if $_no_auth_cache;
+ print "Client certificate filename: ";
+ chomp(my $filename = <STDIN>);
+ $cred->cert_file($filename);
+ $cred->may_save($may_save);
+ $SVN::_Core::SVN_NO_ERROR;
+}
+
+sub _ssl_client_cert_pw_prompt {
+ my ($cred, $realm, $may_save, $pool) = @_;
+ $may_save = undef if $_no_auth_cache;
+ $cred->password(_read_password("Password: ", $realm));
+ $cred->may_save($may_save);
+ $SVN::_Core::SVN_NO_ERROR;
+}
+
+sub _username_prompt {
+ my ($cred, $realm, $may_save, $pool) = @_;
+ $may_save = undef if $_no_auth_cache;
+ if (defined $realm && length $realm) {
+ print "Authentication realm: $realm\n";
+ }
+ my $username;
+ if (defined $_username) {
+ $username = $_username;
+ } else {
+ print "Username: ";
+ chomp($username = <STDIN>);
+ }
+ $cred->username($username);
+ $cred->may_save($may_save);
+ $SVN::_Core::SVN_NO_ERROR;
+}
+
+sub _read_password {
+ my ($prompt, $realm) = @_;
+ print $prompt;
+ require Term::ReadKey;
+ Term::ReadKey::ReadMode('noecho');
+ my $password = '';
+ while (defined(my $key = Term::ReadKey::ReadKey(0))) {
+ last if $key =~ /[\012\015]/; # \n\r
+ $password .= $key;
+ }
+ Term::ReadKey::ReadMode('restore');
+ print "\n";
+ $password;
+}
+
sub libsvn_connect {
my ($url) = @_;
- my $auth = SVN::Core::auth_open([SVN::Client::get_simple_provider(),
- SVN::Client::get_ssl_server_trust_file_provider(),
- SVN::Client::get_username_provider()]);
- my $s = eval { SVN::Ra->new(url => $url, auth => $auth) };
- return $s;
+ if (!$AUTH_BATON || !$AUTH_CALLBACKS) {
+ SVN::_Core::svn_config_ensure($_config_dir, undef);
+ ($AUTH_BATON, $AUTH_CALLBACKS) = SVN::Core::auth_open_helper([
+ SVN::Client::get_simple_provider(),
+ SVN::Client::get_ssl_server_trust_file_provider(),
+ SVN::Client::get_simple_prompt_provider(
+ \&_simple_prompt, 2),
+ SVN::Client::get_ssl_client_cert_prompt_provider(
+ \&_ssl_client_cert_prompt, 2),
+ SVN::Client::get_ssl_client_cert_pw_prompt_provider(
+ \&_ssl_client_cert_pw_prompt, 2),
+ SVN::Client::get_username_provider(),
+ SVN::Client::get_ssl_server_trust_prompt_provider(
+ \&_ssl_server_trust_prompt),
+ SVN::Client::get_username_prompt_provider(
+ \&_username_prompt, 2),
+ ]);
+ }
+ SVN::Ra->new(url => $url, auth => $AUTH_BATON,
+ auth_provider_callbacks => $AUTH_CALLBACKS);
}
sub libsvn_get_file {
diff --git a/read-cache.c b/read-cache.c
index 0f5fb5bc33..eae4745d28 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -347,13 +347,13 @@ int add_file_to_index(const char *path, int verbose)
ce->ce_mode = create_ce_mode(st.st_mode);
if (!trust_executable_bit) {
/* If there is an existing entry, pick the mode bits
- * from it, otherwise force to 644.
+ * from it, otherwise assume unexecutable.
*/
int pos = cache_name_pos(path, namelen);
if (pos >= 0)
ce->ce_mode = active_cache[pos]->ce_mode;
- else
- ce->ce_mode = create_ce_mode(S_IFREG | 0644);
+ else if (S_ISREG(st.st_mode))
+ ce->ce_mode = create_ce_mode(S_IFREG | 0666);
}
if (index_path(ce->sha1, path, &st, 1))
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index c20e4c29fc..c09c53f20b 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -27,7 +27,7 @@ test_expect_success \
git-add xfoo1 &&
case "`git-ls-files --stage xfoo1`" in
100644" "*xfoo1) echo ok;;
- *) echo fail; git-ls-files --stage xfoo1; exit 1;;
+ *) echo fail; git-ls-files --stage xfoo1; (exit 1);;
esac'
test_expect_success \
@@ -38,7 +38,17 @@ test_expect_success \
git-update-index --add xfoo2 &&
case "`git-ls-files --stage xfoo2`" in
100644" "*xfoo2) echo ok;;
- *) echo fail; git-ls-files --stage xfoo2; exit 1;;
+ *) echo fail; git-ls-files --stage xfoo2; (exit 1);;
+ esac'
+
+test_expect_success \
+ 'git-update-index --add: Test that executable bit is not used...' \
+ 'git repo-config core.filemode 0 &&
+ ln -s xfoo2 xfoo3 &&
+ git-update-index --add xfoo3 &&
+ case "`git-ls-files --stage xfoo3`" in
+ 120000" "*xfoo3) echo ok;;
+ *) echo fail; git-ls-files --stage xfoo3; (exit 1);;
esac'
test_done
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 71c454356f..ed37141b6e 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -73,6 +73,7 @@ test_expect_success setup '
for i in 1 2; do echo $i; done >>dir/sub &&
git update-index file0 dir/sub &&
+ git repo-config log.showroot false &&
git commit --amend &&
git show-branch
'
diff --git a/upload-pack.c b/upload-pack.c
index ddaa72f0a9..4572fff07c 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -12,9 +12,15 @@
static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] <dir>";
-#define THEY_HAVE (1U << 0)
-#define OUR_REF (1U << 1)
-#define WANTED (1U << 2)
+/* bits #0..7 in revision.h, #8..10 in commit.c */
+#define THEY_HAVE (1u << 11)
+#define OUR_REF (1u << 12)
+#define WANTED (1u << 13)
+#define COMMON_KNOWN (1u << 14)
+#define REACHABLE (1u << 15)
+
+static unsigned long oldest_have;
+
static int multi_ack, nr_our_refs;
static int use_thin_pack, use_ofs_delta;
static struct object_array have_obj;
@@ -303,11 +309,12 @@ static void create_pack_file(void)
static int got_sha1(char *hex, unsigned char *sha1)
{
struct object *o;
+ int we_knew_they_have = 0;
if (get_sha1_hex(hex, sha1))
die("git-upload-pack: expected SHA1 object, got '%s'", hex);
if (!has_sha1_file(sha1))
- return 0;
+ return -1;
o = lookup_object(sha1);
if (!(o && o->parsed))
@@ -316,15 +323,84 @@ static int got_sha1(char *hex, unsigned char *sha1)
die("oops (%s)", sha1_to_hex(sha1));
if (o->type == OBJ_COMMIT) {
struct commit_list *parents;
+ struct commit *commit = (struct commit *)o;
if (o->flags & THEY_HAVE)
- return 0;
- o->flags |= THEY_HAVE;
- for (parents = ((struct commit*)o)->parents;
+ we_knew_they_have = 1;
+ else
+ o->flags |= THEY_HAVE;
+ if (!oldest_have || (commit->date < oldest_have))
+ oldest_have = commit->date;
+ for (parents = commit->parents;
parents;
parents = parents->next)
parents->item->object.flags |= THEY_HAVE;
}
- add_object_array(o, NULL, &have_obj);
+ if (!we_knew_they_have) {
+ add_object_array(o, NULL, &have_obj);
+ return 1;
+ }
+ return 0;
+}
+
+static int reachable(struct commit *want)
+{
+ struct commit_list *work = NULL;
+
+ insert_by_date(want, &work);
+ while (work) {
+ struct commit_list *list = work->next;
+ struct commit *commit = work->item;
+ free(work);
+ work = list;
+
+ if (commit->object.flags & THEY_HAVE) {
+ want->object.flags |= COMMON_KNOWN;
+ break;
+ }
+ if (!commit->object.parsed)
+ parse_object(commit->object.sha1);
+ if (commit->object.flags & REACHABLE)
+ continue;
+ commit->object.flags |= REACHABLE;
+ if (commit->date < oldest_have)
+ continue;
+ for (list = commit->parents; list; list = list->next) {
+ struct commit *parent = list->item;
+ if (!(parent->object.flags & REACHABLE))
+ insert_by_date(parent, &work);
+ }
+ }
+ want->object.flags |= REACHABLE;
+ clear_commit_marks(want, REACHABLE);
+ free_commit_list(work);
+ return (want->object.flags & COMMON_KNOWN);
+}
+
+static int ok_to_give_up(void)
+{
+ int i;
+
+ if (!have_obj.nr)
+ return 0;
+
+ for (i = 0; i < want_obj.nr; i++) {
+ struct object *want = want_obj.objects[i].item;
+
+ if (want->flags & COMMON_KNOWN)
+ continue;
+ want = deref_tag(want, "a want line", 0);
+ if (!want || want->type != OBJ_COMMIT) {
+ /* no way to tell if this is reachable by
+ * looking at the ancestry chain alone, so
+ * leave a note to ourselves not to worry about
+ * this object anymore.
+ */
+ want_obj.objects[i].item->flags |= COMMON_KNOWN;
+ continue;
+ }
+ if (!reachable((struct commit *)want))
+ return 0;
+ }
return 1;
}
@@ -349,7 +425,13 @@ static int get_common_commits(void)
}
len = strip(line, len);
if (!strncmp(line, "have ", 5)) {
- if (got_sha1(line+5, sha1)) {
+ switch (got_sha1(line+5, sha1)) {
+ case -1: /* they have what we do not */
+ if (multi_ack && ok_to_give_up())
+ packet_write(1, "ACK %s continue\n",
+ sha1_to_hex(sha1));
+ break;
+ default:
memcpy(hex, sha1_to_hex(sha1), 41);
if (multi_ack) {
const char *msg = "ACK %s continue\n";
@@ -358,6 +440,7 @@ static int get_common_commits(void)
}
else if (have_obj.nr == 1)
packet_write(1, "ACK %s\n", hex);
+ break;
}
continue;
}
diff --git a/xdiff/xemit.c b/xdiff/xemit.c
index 07995ec33e..e291dc7608 100644
--- a/xdiff/xemit.c
+++ b/xdiff/xemit.c
@@ -118,7 +118,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
xdemitconf_t const *xecfg) {
long s1, s2, e1, e2, lctx;
xdchange_t *xch, *xche;
- char funcbuf[40];
+ char funcbuf[80];
long funclen = 0;
if (xecfg->flags & XDL_EMIT_COMMON)