summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes-1.5.6.txt59
-rw-r--r--Documentation/config.txt6
-rw-r--r--Documentation/git-bisect.txt7
-rw-r--r--Documentation/git-config.txt2
-rw-r--r--Documentation/git-status.txt5
-rw-r--r--Documentation/git-unpack-objects.txt3
-rw-r--r--Documentation/hooks.txt7
-rw-r--r--Documentation/pretty-formats.txt1
-rw-r--r--Makefile4
l---------RelNotes2
-rw-r--r--builtin-apply.c8
-rw-r--r--builtin-commit.c6
-rw-r--r--builtin-config.c28
-rw-r--r--builtin-gc.c31
-rw-r--r--builtin-log.c3
-rw-r--r--builtin-remote.c7
-rw-r--r--builtin-unpack-objects.c177
-rw-r--r--cache.h1
-rw-r--r--commit.h3
-rw-r--r--config.c12
-rwxr-xr-xcontrib/completion/git-completion.bash9
-rw-r--r--contrib/emacs/git.el11
-rw-r--r--contrib/hooks/pre-auto-gc-battery36
-rw-r--r--diff.c83
-rw-r--r--diffcore-rename.c80
-rwxr-xr-xgit-add--interactive.perl49
-rwxr-xr-xgit-bisect.sh12
-rwxr-xr-xgit-rebase.sh52
-rwxr-xr-xgit-send-email.perl20
-rwxr-xr-xgit-submodule.sh16
-rw-r--r--gitweb/INSTALL83
-rw-r--r--gitweb/README59
-rwxr-xr-xgitweb/gitweb.perl7
-rw-r--r--log-tree.c10
-rw-r--r--perl/Git.pm45
-rw-r--r--pretty.c68
-rw-r--r--receive-pack.c36
-rw-r--r--revision.c2
-rw-r--r--revision.h3
-rw-r--r--sha1-lookup.c171
-rw-r--r--sha1-lookup.h9
-rw-r--r--sha1_file.c35
-rwxr-xr-xt/t1300-repo-config.sh58
-rwxr-xr-xt/t3701-add-interactive.sh19
-rwxr-xr-xt/t5300-pack-object.sh95
-rwxr-xr-xt/t7401-submodule-summary.sh13
-rwxr-xr-xt/t7502-status.sh134
-rw-r--r--var.c3
-rw-r--r--wt-status.c41
49 files changed, 1363 insertions, 268 deletions
diff --git a/Documentation/RelNotes-1.5.6.txt b/Documentation/RelNotes-1.5.6.txt
new file mode 100644
index 0000000000..f3256fb82c
--- /dev/null
+++ b/Documentation/RelNotes-1.5.6.txt
@@ -0,0 +1,59 @@
+GIT v1.5.6 Release Notes
+========================
+
+Updates since v1.5.5
+--------------------
+
+(subsystems)
+
+
+(portability)
+
+
+(performance)
+
+* "git rebase --onto $there $from $branch" used to switch to the tip of
+ $branch only to immediately reset back to $from, smudging work tree
+ files unnecessarily. This has been optimized.
+
+(usability, bells and whistles)
+
+* "git add -p" (and the "patch" subcommand of "git add -i") can choose to
+ apply (or not apply) mode changes independently from contents changes.
+
+* "git bisect help" gives longer and more helpful usage information.
+
+* "git diff/log --dirstat" output is consistent between binary and textual
+ changes.
+
+* "git gc --auto" honors a new pre-aut-gc hook to temporarily disable it.
+
+* "git log --pretty=tformat:<custom format>" gives a LF after each entry,
+ instead of giving a LF between each pair of entries which is how
+ "git log --pretty=format:<custom format>" works.
+
+* "git send-email" now can send out messages outside a git repository.
+
+* "git status" can optionally include output from "git submodule
+ summary".
+
+* "gitweb" can read from a system-wide configuration file.
+
+(internal)
+
+* "git unpack-objects" and "git receive-pack" is now more strict about
+ detecting breakage in the objects they receive over the wire.
+
+
+Fixes since v1.5.5
+------------------
+
+All of the fixes in v1.5.5 maintenance series are included in
+this release, unless otherwise noted.
+
+
+--
+exec >/var/tmp/1
+O=v1.5.5-56-g5f0734f
+echo O=`git describe refs/heads/master`
+git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 04c01c5fdc..fe43b12572 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -991,6 +991,12 @@ imap::
The configuration variables in the 'imap' section are described
in linkgit:git-imap-send[1].
+receive.fsckObjects::
+ If it is set to true, git-receive-pack will check all received
+ objects. It will abort in the case of a malformed object or a
+ broken link. The result of an abort are only dangling objects.
+ Defaults to false.
+
receive.unpackLimit::
If the number of objects received in a push is below this
limit then the objects will be unpacked into loose object
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index 96585ae8d9..698ffde7ce 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -15,6 +15,7 @@ DESCRIPTION
The command takes various subcommands, and different options depending
on the subcommand:
+ git bisect help
git bisect start [<bad> [<good>...]] [--] [<paths>...]
git bisect bad [<rev>]
git bisect good [<rev>...]
@@ -29,6 +30,12 @@ This command uses 'git-rev-list --bisect' option to help drive the
binary search process to find which change introduced a bug, given an
old "good" commit object name and a later "bad" commit object name.
+Getting help
+~~~~~~~~~~~~
+
+Use "git bisect" to get a short usage description, and "git bisect
+help" or "git bisect -h" to get a long usage description.
+
Basic bisect commands: start, bad, good
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index fa161718dd..5de5d051b7 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -144,6 +144,8 @@ See also <<FILES>>.
"auto". If `stdout-is-tty` is missing, then checks the standard
output of the command itself, and exits with status 0 if color
is to be used, or exits with status 1 otherwise.
+ When the color setting for `name` is undefined, the command uses
+ `color.ui` as fallback.
--get-color name default::
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 3ea269aa7a..ea4376a17f 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -52,6 +52,11 @@ If the config variable `status.relativePaths` is set to false, then all
paths shown are relative to the repository root, not to the current
directory.
+If `status.submodulesummary` is set to a non zero number or true (identical
+to -1 or an unlimited number), the submodule summary will be enabled and a
+summary of commits for modified submodules will be shown (see --summary-limit
+option of linkgit:git-submodule[1]).
+
See Also
--------
linkgit:gitignore[5]
diff --git a/Documentation/git-unpack-objects.txt b/Documentation/git-unpack-objects.txt
index b79be3fd4c..3697896a06 100644
--- a/Documentation/git-unpack-objects.txt
+++ b/Documentation/git-unpack-objects.txt
@@ -40,6 +40,9 @@ OPTIONS
and make the best effort to recover as many objects as
possible.
+--strict::
+ Don't write objects with broken content or links.
+
Author
------
diff --git a/Documentation/hooks.txt b/Documentation/hooks.txt
index 76b8d77460..44fbe58f20 100644
--- a/Documentation/hooks.txt
+++ b/Documentation/hooks.txt
@@ -276,3 +276,10 @@ probably enable this hook.
Both standard output and standard error output are forwarded to
`git-send-pack` on the other end, so you can simply `echo` messages
for the user.
+
+pre-auto-gc
+-----------
+
+This hook is invoked by `git-gc --auto`. It takes no parameter, and
+exiting with non-zero status from this script causes the `git-gc --auto`
+to abort.
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 0193c3ce58..e8bea3e18e 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -123,3 +123,4 @@ The placeholders are:
- '%Creset': reset color
- '%m': left, right or boundary mark
- '%n': newline
+- '%x00': print a byte from a hex code
diff --git a/Makefile b/Makefile
index 7c70b00b82..9d84c8d799 100644
--- a/Makefile
+++ b/Makefile
@@ -189,6 +189,7 @@ ETC_GITCONFIG = $(sysconfdir)/gitconfig
# default configuration for gitweb
GITWEB_CONFIG = gitweb_config.perl
+GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
GITWEB_HOME_LINK_STR = projects
GITWEB_SITENAME =
GITWEB_PROJECTROOT = /pub/git
@@ -365,6 +366,7 @@ LIB_H += refs.h
LIB_H += remote.h
LIB_H += revision.h
LIB_H += run-command.h
+LIB_H += sha1-lookup.h
LIB_H += sideband.h
LIB_H += strbuf.h
LIB_H += tag.h
@@ -445,6 +447,7 @@ LIB_OBJS += run-command.o
LIB_OBJS += server-info.o
LIB_OBJS += setup.o
LIB_OBJS += sha1_file.o
+LIB_OBJS += sha1-lookup.o
LIB_OBJS += sha1_name.o
LIB_OBJS += shallow.o
LIB_OBJS += sideband.o
@@ -1034,6 +1037,7 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl
-e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
-e 's|++GIT_BINDIR++|$(bindir)|g' \
-e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
+ -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
-e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
-e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
-e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
diff --git a/RelNotes b/RelNotes
index 730df98bdc..e29d6504d9 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.5.5.1.txt \ No newline at end of file
+Documentation/RelNotes-1.5.6.txt \ No newline at end of file
diff --git a/builtin-apply.c b/builtin-apply.c
index 30d26e57b3..caa3f2aa0c 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -2981,12 +2981,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
static int git_apply_config(const char *var, const char *value)
{
- if (!strcmp(var, "apply.whitespace")) {
- if (!value)
- return config_error_nonbool(var);
- apply_default_whitespace = xstrdup(value);
- return 0;
- }
+ if (!strcmp(var, "apply.whitespace"))
+ return git_config_string(&apply_default_whitespace, var, value);
return git_default_config(var, value);
}
diff --git a/builtin-commit.c b/builtin-commit.c
index 05dfc6973a..b41d4a3561 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -745,10 +745,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
die("No paths with --include/--only does not make sense.");
if (argc == 0 && only && amend)
only_include_assumed = "Clever... amending the last one with dirty index.";
- if (argc > 0 && !also && !only) {
+ if (argc > 0 && !also && !only)
only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths...";
- also = 0;
- }
if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE;
else if (!strcmp(cleanup_arg, "verbatim"))
@@ -810,7 +808,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
rev.verbose_header = 1;
rev.show_root_diff = 1;
- rev.commit_format = get_commit_format("format:%h: %s");
+ get_commit_format("format:%h: %s", &rev);
rev.always_show_header = 0;
rev.diffopt.detect_rename = 1;
rev.diffopt.rename_limit = 100;
diff --git a/builtin-config.c b/builtin-config.c
index c34bc8b6a6..8ee01bdecd 100644
--- a/builtin-config.c
+++ b/builtin-config.c
@@ -3,7 +3,7 @@
#include "color.h"
static const char git_config_set_usage[] =
-"git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]";
+"git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]";
static char *key;
static regex_t *key_regexp;
@@ -16,7 +16,7 @@ static int seen;
static char delim = '=';
static char key_delim = ' ';
static char term = '\n';
-static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
+static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW;
static int show_all_config(const char *key_, const char *value_)
{
@@ -53,6 +53,14 @@ static int show_config(const char* key_, const char* value_)
sprintf(value, "%d", git_config_int(key_, value_?value_:""));
else if (type == T_BOOL)
vptr = git_config_bool(key_, value_) ? "true" : "false";
+ else if (type == T_BOOL_OR_INT) {
+ int is_bool, v;
+ v = git_config_bool_or_int(key_, value_, &is_bool);
+ if (is_bool)
+ vptr = v ? "true" : "false";
+ else
+ sprintf(value, "%d", v);
+ }
else
vptr = value_?value_:"";
seen++;
@@ -157,6 +165,14 @@ char *normalize_value(const char *key, const char *value)
else if (type == T_BOOL)
sprintf(normalized, "%s",
git_config_bool(key, value) ? "true" : "false");
+ else if (type == T_BOOL_OR_INT) {
+ int is_bool, v;
+ v = git_config_bool_or_int(key, value, &is_bool);
+ if (!is_bool)
+ sprintf(normalized, "%d", v);
+ else
+ sprintf(normalized, "%s", v ? "true" : "false");
+ }
}
return normalized;
@@ -224,6 +240,10 @@ static int git_get_colorbool_config(const char *var, const char *value)
get_diff_color_found =
git_config_colorbool(var, value, stdout_is_tty);
}
+ if (!strcmp(var, "color.ui")) {
+ git_use_color_default = git_config_colorbool(var, value, stdout_is_tty);
+ return 0;
+ }
return 0;
}
@@ -251,7 +271,7 @@ static int get_colorbool(int argc, const char **argv)
if (!strcmp(get_color_slot, "color.diff"))
get_colorbool_found = get_diff_color_found;
if (get_colorbool_found < 0)
- get_colorbool_found = 0;
+ get_colorbool_found = git_use_color_default;
}
if (argc == 1) {
@@ -273,6 +293,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
type = T_INT;
else if (!strcmp(argv[1], "--bool"))
type = T_BOOL;
+ else if (!strcmp(argv[1], "--bool-or-int"))
+ type = T_BOOL_OR_INT;
else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
if (argc != 2)
usage(git_config_set_usage);
diff --git a/builtin-gc.c b/builtin-gc.c
index 8cef36f6a4..f99ebc7926 100644
--- a/builtin-gc.c
+++ b/builtin-gc.c
@@ -157,6 +157,34 @@ static int too_many_packs(void)
return gc_auto_pack_limit <= cnt;
}
+static int run_hook(void)
+{
+ const char *argv[2];
+ struct child_process hook;
+ int ret;
+
+ argv[0] = git_path("hooks/pre-auto-gc");
+ argv[1] = NULL;
+
+ if (access(argv[0], X_OK) < 0)
+ return 0;
+
+ memset(&hook, 0, sizeof(hook));
+ hook.argv = argv;
+ hook.no_stdin = 1;
+ hook.stdout_to_stderr = 1;
+
+ ret = start_command(&hook);
+ if (ret) {
+ warning("Could not spawn %s", argv[0]);
+ return ret;
+ }
+ ret = finish_command(&hook);
+ if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
+ warning("%s exited due to uncaught signal", argv[0]);
+ return ret;
+}
+
static int need_to_gc(void)
{
/*
@@ -176,6 +204,9 @@ static int need_to_gc(void)
append_option(argv_repack, "-A", MAX_ADD);
else if (!too_many_loose_objects())
return 0;
+
+ if (run_hook())
+ return 0;
return 1;
}
diff --git a/builtin-log.c b/builtin-log.c
index 5c00725f03..1670d0b334 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -56,7 +56,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
rev->abbrev = DEFAULT_ABBREV;
rev->commit_format = CMIT_FMT_DEFAULT;
if (fmt_pretty)
- rev->commit_format = get_commit_format(fmt_pretty);
+ get_commit_format(fmt_pretty, rev);
rev->verbose_header = 1;
DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
rev->show_root_diff = default_show_root;
@@ -400,6 +400,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
* allow us to set a different default.
*/
rev.commit_format = CMIT_FMT_ONELINE;
+ rev.use_terminator = 1;
rev.always_show_header = 1;
/*
diff --git a/builtin-remote.c b/builtin-remote.c
index 8fe31dbd9a..a3ee1ac393 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -19,6 +19,8 @@ static const char * const builtin_remote_usage[] = {
static int verbose;
+static int show_all(void);
+
static inline int postfixcmp(const char *string, const char *postfix)
{
int len1 = strlen(string), len2 = strlen(postfix);
@@ -384,8 +386,11 @@ static int show_or_prune(int argc, const char **argv, int prune)
argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
- if (argc < 1)
+ if (argc < 1) {
+ if (!prune)
+ return show_all();
usage_with_options(builtin_remote_usage, options);
+ }
memset(&states, 0, sizeof(states));
for (; argc; argc--, argv++) {
diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c
index 50e07faa12..fecf0be779 100644
--- a/builtin-unpack-objects.c
+++ b/builtin-unpack-objects.c
@@ -7,11 +7,13 @@
#include "commit.h"
#include "tag.h"
#include "tree.h"
+#include "tree-walk.h"
#include "progress.h"
#include "decorate.h"
+#include "fsck.h"
-static int dry_run, quiet, recover, has_errors;
-static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file";
+static int dry_run, quiet, recover, has_errors, strict;
+static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
/* We always read in 4kB chunks. */
static unsigned char buffer[4096];
@@ -19,6 +21,11 @@ static unsigned int offset, len;
static off_t consumed_bytes;
static SHA_CTX ctx;
+/*
+ * When running under --strict mode, objects whose reachability are
+ * suspect are kept in core without getting written in the object
+ * store.
+ */
struct obj_buffer {
char *buffer;
unsigned long size;
@@ -31,6 +38,16 @@ static struct obj_buffer *lookup_object_buffer(struct object *base)
return lookup_decoration(&obj_decorate, base);
}
+static void add_object_buffer(struct object *object, char *buffer, unsigned long size)
+{
+ struct obj_buffer *obj;
+ obj = xcalloc(1, sizeof(struct obj_buffer));
+ obj->buffer = buffer;
+ obj->size = size;
+ if (add_decoration(&obj_decorate, object, obj))
+ die("object %s tried to add buffer twice!", sha1_to_hex(object->sha1));
+}
+
/*
* Make sure at least "min" bytes are available in the buffer, and
* return the pointer to the buffer.
@@ -134,19 +151,110 @@ static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1,
struct obj_info {
off_t offset;
unsigned char sha1[20];
+ struct object *obj;
};
+#define FLAG_OPEN (1u<<20)
+#define FLAG_WRITTEN (1u<<21)
+
static struct obj_info *obj_list;
+unsigned nr_objects;
+
+/*
+ * Called only from check_object() after it verified this object
+ * is Ok.
+ */
+static void write_cached_object(struct object *obj)
+{
+ unsigned char sha1[20];
+ struct obj_buffer *obj_buf = lookup_object_buffer(obj);
+ if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0)
+ die("failed to write object %s", sha1_to_hex(obj->sha1));
+ obj->flags |= FLAG_WRITTEN;
+}
+
+/*
+ * At the very end of the processing, write_rest() scans the objects
+ * that have reachability requirements and calls this function.
+ * Verify its reachability and validity recursively and write it out.
+ */
+static int check_object(struct object *obj, int type, void *data)
+{
+ if (!obj)
+ return 0;
+
+ if (obj->flags & FLAG_WRITTEN)
+ return 1;
+
+ if (type != OBJ_ANY && obj->type != type)
+ die("object type mismatch");
+
+ if (!(obj->flags & FLAG_OPEN)) {
+ unsigned long size;
+ int type = sha1_object_info(obj->sha1, &size);
+ if (type != obj->type || type <= 0)
+ die("object of unexpected type");
+ obj->flags |= FLAG_WRITTEN;
+ return 1;
+ }
+
+ if (fsck_object(obj, 1, fsck_error_function))
+ die("Error in object");
+ if (!fsck_walk(obj, check_object, 0))
+ die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
+ write_cached_object(obj);
+ return 1;
+}
+
+static void write_rest(void)
+{
+ unsigned i;
+ for (i = 0; i < nr_objects; i++)
+ check_object(obj_list[i].obj, OBJ_ANY, 0);
+}
static void added_object(unsigned nr, enum object_type type,
void *data, unsigned long size);
+/*
+ * Write out nr-th object from the list, now we know the contents
+ * of it. Under --strict, this buffers structured objects in-core,
+ * to be checked at the end.
+ */
static void write_object(unsigned nr, enum object_type type,
void *buf, unsigned long size)
{
- if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
- die("failed to write object");
- added_object(nr, type, buf, size);
+ if (!strict) {
+ if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
+ die("failed to write object");
+ added_object(nr, type, buf, size);
+ free(buf);
+ obj_list[nr].obj = NULL;
+ } else if (type == OBJ_BLOB) {
+ struct blob *blob;
+ if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
+ die("failed to write object");
+ added_object(nr, type, buf, size);
+ free(buf);
+
+ blob = lookup_blob(obj_list[nr].sha1);
+ if (blob)
+ blob->object.flags |= FLAG_WRITTEN;
+ else
+ die("invalid blob object");
+ obj_list[nr].obj = NULL;
+ } else {
+ struct object *obj;
+ int eaten;
+ hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
+ added_object(nr, type, buf, size);
+ obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
+ if (!obj)
+ die("invalid %s", typename(type));
+ add_object_buffer(obj, buf, size);
+ obj->flags |= FLAG_OPEN;
+ obj_list[nr].obj = obj;
+ }
}
static void resolve_delta(unsigned nr, enum object_type type,
@@ -163,9 +271,12 @@ static void resolve_delta(unsigned nr, enum object_type type,
die("failed to apply delta");
free(delta);
write_object(nr, type, result, result_size);
- free(result);
}
+/*
+ * We now know the contents of an object (which is nr-th in the pack);
+ * resolve all the deltified objects that are based on it.
+ */
static void added_object(unsigned nr, enum object_type type,
void *data, unsigned long size)
{
@@ -193,7 +304,24 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
if (!dry_run && buf)
write_object(nr, type, buf, size);
- free(buf);
+ else
+ free(buf);
+}
+
+static int resolve_against_held(unsigned nr, const unsigned char *base,
+ void *delta_data, unsigned long delta_size)
+{
+ struct object *obj;
+ struct obj_buffer *obj_buffer;
+ obj = lookup_object(base);
+ if (!obj)
+ return 0;
+ obj_buffer = lookup_object_buffer(obj);
+ if (!obj_buffer)
+ return 0;
+ resolve_delta(nr, obj->type, obj_buffer->buffer,
+ obj_buffer->size, delta_data, delta_size);
+ return 1;
}
static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
@@ -202,7 +330,6 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
void *delta_data, *base;
unsigned long base_size;
unsigned char base_sha1[20];
- struct object *obj;
if (type == OBJ_REF_DELTA) {
hashcpy(base_sha1, fill(20));
@@ -212,7 +339,13 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
free(delta_data);
return;
}
- if (!has_sha1_file(base_sha1)) {
+ if (ha