aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/config.txt6
-rw-r--r--Documentation/git-bisect.txt7
-rw-r--r--Documentation/git-unpack-objects.txt3
-rw-r--r--Documentation/pretty-formats.txt1
-rw-r--r--Makefile2
-rw-r--r--builtin-apply.c8
-rw-r--r--builtin-commit.c4
-rw-r--r--builtin-config.c22
-rw-r--r--builtin-unpack-objects.c177
-rw-r--r--cache.h1
-rw-r--r--config.c12
-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
-rw-r--r--gitweb/INSTALL6
-rw-r--r--gitweb/README9
-rwxr-xr-xgitweb/gitweb.perl7
-rw-r--r--log-tree.c6
-rw-r--r--perl/Git.pm45
-rw-r--r--pretty.c11
-rw-r--r--receive-pack.c36
-rwxr-xr-xt/t1300-repo-config.sh58
-rwxr-xr-xt/t3701-add-interactive.sh19
-rwxr-xr-xt/t5300-pack-object.sh95
-rw-r--r--var.c3
27 files changed, 619 insertions, 132 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 04c01c5fd..fe43b1257 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 96585ae8d..698ffde7c 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-unpack-objects.txt b/Documentation/git-unpack-objects.txt
index b79be3fd4..3697896a0 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/pretty-formats.txt b/Documentation/pretty-formats.txt
index 0193c3ce5..e8bea3e18 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 7c70b00b8..78b773862 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
@@ -1034,6 +1035,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/builtin-apply.c b/builtin-apply.c
index 30d26e57b..caa3f2aa0 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 05dfc6973..bcb7aaaa9 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"))
diff --git a/builtin-config.c b/builtin-config.c
index c34bc8b6a..10447a704 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;
@@ -273,6 +289,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-unpack-objects.c b/builtin-unpack-objects.c
index 50e07faa1..fecf0be77 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 (has_sha1_file(base_sha1))
+ ; /* Ok we have this one */
+ else if (resolve_against_held(nr, base_sha1,
+ delta_data, delta_size))
+ return; /* we are done */
+ else {
+ /* cannot resolve yet --- queue it */
hashcpy(obj_list[nr].sha1, null_sha1);
add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
return;
@@ -258,22 +391,18 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
}
}
if (!base_found) {
- /* The delta base object is itself a delta that
- has not been resolved yet. */
+ /*
+ * The delta base object is itself a delta that
+ * has not been resolved yet.
+ */
hashcpy(obj_list[nr].sha1, null_sha1);
add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
return;
}
}
- obj = lookup_object(base_sha1);
- if (obj) {
- struct obj_buffer *obj_buf = lookup_object_buffer(obj);
- if (obj_buf) {
- resolve_delta(nr, obj->type, obj_buf->buffer, obj_buf->size, delta_data, delta_size);
- return;
- }
- }
+ if (resolve_against_held(nr, base_sha1, delta_data, delta_size))
+ return;
base = read_sha1_file(base_sha1, &type, &base_size);
if (!base) {
@@ -336,7 +465,8 @@ static void unpack_all(void)
int i;
struct progress *progress = NULL;
struct pack_header *hdr = fill(sizeof(struct pack_header));
- unsigned nr_objects = ntohl(hdr->hdr_entries);
+
+ nr_objects = ntohl(hdr->hdr_entries);
if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE)
die("bad pack file");
@@ -347,6 +477,7 @@ static void unpack_all(void)
if (!quiet)
progress = start_progress("Unpacking objects", nr_objects);
obj_list = xmalloc(nr_objects * sizeof(*obj_list));
+ memset(obj_list, 0, nr_objects * sizeof(*obj_list));
for (i = 0; i < nr_objects; i++) {
unpack_one(i);
display_progress(progress, i + 1);
@@ -382,6 +513,10 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
recover = 1;
continue;
}
+ if (!strcmp(arg, "--strict")) {
+ strict = 1;
+ continue;
+ }
if (!prefixcmp(arg, "--pack_header=")) {
struct pack_header *hdr;
char *c;
@@ -407,6 +542,8 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
unpack_all();
SHA1_Update(&ctx, buffer, offset);
SHA1_Final(sha1, &ctx);
+ if (strict)
+ write_rest();
if (hashcmp(fill(20), sha1))
die("final sha1 did not match");
use(20);
diff --git a/cache.h b/cache.h
index 2a1e7ec6b..50b28fad0 100644
--- a/cache.h
+++ b/cache.h
@@ -692,6 +692,7 @@ extern int git_parse_long(const char *, long *);
extern int git_parse_ulong(const char *, unsigned long *);
extern int git_config_int(const char *, const char *);
extern unsigned long git_config_ulong(const char *, const char *);
+extern int git_config_bool_or_int(const char *, const char *, int *);
extern int git_config_bool(const char *, const char *);
extern int git_config_string(const char **, const char *, const char *);
extern int git_config_set(const char *, const char *);
diff --git a/config.c b/config.c
index 062449459..b0ada515b 100644
--- a/config.c
+++ b/config.c
@@ -303,8 +303,9 @@ unsigned long git_config_ulong(const char *name, const char *value)
return ret;
}
-int git_config_bool(const char *name, const char *value)
+int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
{
+ *is_bool = 1;
if (!value)
return 1;
if (!*value)
@@ -313,7 +314,14 @@ int git_config_bool(const char *name, const char *value)
return 1;
if (!strcasecmp(value, "false") || !strcasecmp(value, "no"))
return 0;
- return git_config_int(name, value) != 0;
+ *is_bool = 0;
+ return git_config_int(name, value);
+}
+
+int git_config_bool(const char *name, const char *value)
+{
+ int discard;
+ return !!git_config_bool_or_int(name, value, &discard);
}
int git_config_string(const char **dest, const char *var, const char *value)
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 31941bcbb..1369a5ec4 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -112,8 +112,8 @@ static int basename_same(struct diff_filespec *src, struct diff_filespec *dst)
struct diff_score {
int src; /* index in rename_src */
int dst; /* index in rename_dst */
- int score;
- int name_score;
+ unsigned short score;
+ short name_score;
};
static int estimate_similarity(struct diff_filespec *src,
@@ -223,6 +223,12 @@ static int score_compare(const void *a_, const void *b_)
{
const struct diff_score *a = a_, *b = b_;
+ /* sink the unused ones to the bottom */
+ if (a->dst < 0)
+ return (0 <= b->dst);
+ else if (b->dst < 0)
+ return -1;
+
if (a->score == b->score)
return b->name_score - a->name_score;
@@ -387,6 +393,22 @@ static int find_exact_renames(void)
return i;
}
+#define NUM_CANDIDATE_PER_DST 4
+static void record_if_better(struct diff_score m[], struct diff_score *o)
+{
+ int i, worst;
+
+ /* find the worst one */
+ worst = 0;
+ for (i = 1; i < NUM_CANDIDATE_PER_DST; i++)
+ if (score_compare(&m[i], &m[worst]) > 0)
+ worst = i;
+
+ /* is it better than the worst one? */
+ if (score_compare(&m[worst], o) > 0)
+ m[worst] = *o;
+}
+
void diffcore_rename(struct diff_options *options)
{
int detect_rename = options->detect_rename;
@@ -474,47 +496,61 @@ void diffcore_rename(struct diff_options *options)
goto cleanup;
}
- mx = xmalloc(sizeof(*mx) * num_create * num_src);
+ mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));
for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
- int base = dst_cnt * num_src;
struct diff_filespec *two = rename_dst[i].two;
+ struct diff_score *m;
+
if (rename_dst[i].pair)
continue; /* dealt with exact match already. */
+
+ m = &mx[dst_cnt * NUM_CANDIDATE_PER_DST];
+ for (j = 0; j < NUM_CANDIDATE_PER_DST; j++)
+ m[j].dst = -1;
+
for (j = 0; j < rename_src_nr; j++) {
struct diff_filespec *one = rename_src[j].one;
- struct diff_score *m = &mx[base+j];
- m->src = j;
- m->dst = i;
- m->score = estimate_similarity(one, two,
- minimum_score);
- m->name_score = basename_same(one, two);
+ struct diff_score this_src;
+ this_src.score = estimate_similarity(one, two,
+ minimum_score);
+ this_src.name_score = basename_same(one, two);
+ this_src.dst = i;
+ this_src.src = j;
+ record_if_better(m, &this_src);
diff_free_filespec_blob(one);
}
/* We do not need the text anymore */
diff_free_filespec_blob(two);
dst_cnt++;
}
+
/* cost matrix sorted by most to least similar pair */
- qsort(mx, num_create * num_src, sizeof(*mx), score_compare);
- for (i = 0; i < num_create * num_src; i++) {
- struct diff_rename_dst *dst = &rename_dst[mx[i].dst];
- struct diff_filespec *src;
+ qsort(mx, dst_cnt * NUM_CANDIDATE_PER_DST, sizeof(*mx), score_compare);
+
+ for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
+ struct diff_rename_dst *dst;
+
+ if ((mx[i].dst < 0) ||
+ (mx[i].score < minimum_score))
+ break; /* there is no more usable pair. */
+ dst = &rename_dst[mx[i].dst];
if (dst->pair)
continue; /* already done, either exact or fuzzy. */
- if (mx[i].score < minimum_score)
- break; /* there is no more usable pair. */
- src = rename_src[mx[i].src].one;
- if (src->rename_used)
+ if (rename_src[mx[i].src].one->rename_used)
continue;
record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
rename_count++;
}
- for (i = 0; i < num_create * num_src; i++) {
- struct diff_rename_dst *dst = &rename_dst[mx[i].dst];
+
+ for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
+ struct diff_rename_dst *dst;
+
+ if ((mx[i].dst < 0) ||
+ (mx[i].score < minimum_score))
+ break; /* there is no more usable pair. */
+ dst = &rename_dst[mx[i].dst];
if (dst->pair)
continue; /* already done, either exact or fuzzy. */
- if (mx[i].score < minimum_score)
- break; /* there is no more usable pair. */
record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
rename_count++;
}
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index a0a81f134..903953e68 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -550,6 +550,21 @@ sub parse_diff {
return @hunk;
}
+sub parse_diff_header {
+ my $src = shift;
+
+ my $head = { TEXT => [], DISPLAY => [] };
+ my $mode = { TEXT => [], DISPLAY => [] };
+
+ for (my $i = 0; $i < @{$src->{TEXT}}; $i++) {
+ my $dest = $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ?
+ $mode : $head;
+ push @{$dest->{TEXT}}, $src->{TEXT}->[$i];
+ push @{$dest->{DISPLAY}}, $src->{DISPLAY}->[$i];
+ }
+ return ($head, $mode);
+}
+
sub hunk_splittable {
my ($text) = @_;
@@ -795,9 +810,40 @@ sub patch_update_file {
my ($ix, $num);
my $path = shift;
my ($head, @hunk) = parse_diff($path);
+ ($head, my $mode) = parse_diff_header($head);
for (@{$head->{DISPLAY}}) {
print;
}
+
+ if (@{$mode->{TEXT}}) {
+ while (1) {
+ print @{$mode->{DISPLAY}};
+ print colored $prompt_color,
+ "Stage mode change [y/n/a/d/?]? ";
+ my $line = <STDIN>;
+ if ($line =~ /^y/i) {
+ $mode->{USE} = 1;
+ last;
+ }
+ elsif ($line =~ /^n/i) {
+ $mode->{USE} = 0;
+ last;
+ }
+ elsif ($line =~ /^a/i) {
+ $_->{USE} = 1 foreach ($mode, @hunk);
+ last;
+ }
+ elsif ($line =~ /^d/i) {
+ $_->{USE} = 0 foreach ($mode, @hunk);
+ last;
+ }
+ else {
+ help_patch_cmd('');
+ next;
+ }
+ }
+ }
+
$num = scalar @hunk;
$ix = 0;
@@ -920,6 +966,9 @@ sub patch_update_file {
my $n_lofs = 0;
my @result = ();
+ if ($mode->{USE}) {
+ push @result, @{$mode->{TEXT}};
+ }
for (@hunk) {
my $text = $_->{TEXT};
my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) =
diff --git a/git-bisect.sh b/git-bisect.sh
index 8e57e9a75..d8d9bfde4 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -1,7 +1,9 @@
#!/bin/sh
-USAGE='[start|bad|good|skip|next|reset|visualize|replay|log|run]'
-LONG_USAGE='git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
+USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'
+LONG_USAGE='git bisect help
+ print this long help message.
+git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
reset bisect state and start bisection.
git bisect bad [<rev>]
mark <rev> a known-bad revision.
@@ -20,7 +22,9 @@ git bisect replay <logfile>
git bisect log
show bisect log.
git bisect run <cmd>...
- use <cmd>... to automatically bisect.'
+ use <cmd>... to automatically bisect.
+
+Please use "git help bisect" to get the full man page.'
OPTIONS_SPEC=
. git-sh-setup
@@ -467,6 +471,8 @@ case "$#" in
cmd="$1"
shift
case "$cmd" in
+ help)
+ git bisect -h ;;
start)
bisect_start "$@" ;;
bad|good|skip)
diff --git a/git-rebase.sh b/git-rebase.sh
index 60c458f20..9b13b833c 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -309,22 +309,42 @@ then
}
fi
-# If the branch to rebase is given, first switch to it.
+# If the branch to rebase is given, that is the branch we will rebase
+# $branch_name -- branch being rebased, or HEAD (already detached)
+# $orig_head -- commit object name of tip of the branch before rebasing
+# $head_name -- refs/heads/<that-branch> or "detached HEAD"
+switch_to=
case "$#" in
2)
+ # Is it "rebase other $branchname" or "rebase other $commit"?
branch_name="$2"
- git-checkout "$2" || usage
+ switch_to="$2"
+
+ if git show-ref --verify --quiet -- "refs/heads/$2" &&
+ branch=$(git rev-parse --verify "refs/heads/$2" 2>/dev/null)
+ then
+ head_name="refs/heads/$2"
+ elif branch=$(git rev-parse --verify "$2" 2>/dev/null)
+ then
+ head_name="detached HEAD"
+ else
+ usage
+ fi
;;
*)
+ # Do not need to switch branches, we are already on it.
if branch_name=`git symbolic-ref -q HEAD`
then
+ head_name=$branch_name
branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
else
+ head_name="detached HEAD"
branch_name=HEAD ;# detached
fi
+ branch=$(git rev-parse --verify "${branch_name}^0") || exit
;;
esac
-branch=$(git rev-parse --verify "${branch_name}^0") || exit
+orig_head=$branch
# Now we are rebasing commits $upstream..$branch on top of $onto
@@ -335,6 +355,8 @@ if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
# linear history?
! git rev-list --parents "$onto".."$branch" | grep " .* " > /dev/null
then
+ # Lazily switch to the target branch if needed...
+ test -z "$switch_to" || git checkout "$switch_to"
echo >&2 "Current branch $branch_name is up to date."
exit 0
fi
@@ -346,22 +368,11 @@ then
GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
fi
-# move to a detached HEAD
-orig_head=$(git rev-parse HEAD^0)
-head_name=$(git symbolic-ref HEAD 2> /dev/null)
-case "$head_name" in
-'')
- head_name="detached HEAD"
- ;;
-*)
- git checkout "$orig_head" > /dev/null 2>&1 ||
- die "could not detach HEAD"
- ;;
-esac
-
-# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
+# Detach HEAD and reset the tree
echo "First, rewinding head to replay your work on top of it..."
-git-reset --hard "$onto"
+git checkout "$onto^0" >/dev/null 2>&1 ||
+ die "could not detach HEAD"
+# git reset --hard "$onto^0"
# If the $onto is a proper descendant of the tip of the branch, then
# we just fast forwarded.
@@ -374,7 +385,8 @@ fi
if test -z "$do_merge"
then
- git format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
+ git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+ "$upstream..$orig_head" |
git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
ret=$?
@@ -397,7 +409,7 @@ echo "$orig_head" > "$dotest/orig-head"
echo "$head_name" > "$dotest/head-name"
msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$upstream"..ORIG_HEAD`
+for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
do
msgnum=$(($msgnum + 1))
echo "$cmt" > "$dotest/cmt.$msgnum"
diff --git a/git-send-email.perl b/git-send-email.perl
index be4a20d7c..9e568bf9c 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -168,7 +168,8 @@ my $envelope_sender;
# Example reply to:
#$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
-my $repo = Git->repository();
+my $repo = eval { Git->repository() };
+my @repo = $repo ? ($repo) : ();
my $term = eval {
$ENV{"GIT_SEND_EMAIL_NOTTY"}
? new Term::ReadLine 'git-send-email', \*STDIN, \*STDOUT
@@ -271,25 +272,25 @@ sub read_config {
foreach my $setting (keys %config_bool_settings) {
my $target = $config_bool_settings{$setting}->[0];
- $$target = $repo->config_bool("$prefix.$setting") unless (defined $$target);
+ $$target = Git::config_bool(@repo, "$prefix.$setting") unless (defined $$target);
}
foreach my $setting (keys %config_settings) {
my $target = $config_settings{$setting};
if (ref($target) eq "ARRAY") {
unless (@$target) {
- my @values = $repo->config("$prefix.$setting");
+ my @values = Git::config(@repo, "$prefix.$setting");
@$target = @values if (@values && defined $values[0]);
}
}
else {
- $$target = $repo->config("$prefix.$setting") unless (defined $$target);
+ $$target = Git::config(@repo, "$prefix.$setting") unless (defined $$target);
}
}
}
# read configuration from [sendemail "$identity"], fall back on [sendemail]
-$identity = $repo->config("sendemail.identity") unless (defined $identity);
+$identity = Git::config(@repo, "sendemail.identity") unless (defined $identity);
read_config("sendemail.$identity") if (defined $identity);
read_config("sendemail");
@@ -327,8 +328,9 @@ if (0) {
}
}
-my ($repoauthor) = $repo->ident_person('author');
-my ($repocommitter) = $repo->ident_person('committer');
+my ($repoauthor, $repocommitter);
+($repoauthor) = Git::ident_person(@repo, 'author');
+($repocommitter) = Git::ident_person(@repo, 'committer');
# Verify the user input
@@ -415,7 +417,7 @@ if (@files) {
my $prompting = 0;
if (!defined $sender) {
- $sender = $repoauthor || $repocommitter;
+ $sender = $repoauthor || $repocommitter || '';
while (1) {
$_ = $term->readline("Who should the emails appear to be from? [$sender] ");
@@ -509,7 +511,7 @@ GIT: for the patch you are writing.
EOT
close(C);
- my $editor = $ENV{GIT_EDITOR} || $repo->config("core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
+ my $editor = $ENV{GIT_EDITOR} || Git::config(@repo, "core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
system('sh', '-c', '$0 $@', $editor, $compose_filename);
open(C2,">",$compose_filename . ".final")
diff --git a/gitweb/INSTALL b/gitweb/INSTALL
index 9cd5b0a2b..743f2d444 100644
--- a/gitweb/INSTALL
+++ b/gitweb/INSTALL
@@ -95,7 +95,11 @@ for gitweb (in gitweb/README).
by default it is file named gitweb_config.perl in the same place as
gitweb.cgi script. You can control default place for config file
using GITWEB_CONFIG build configuration variable, and you can set it
- using GITWEB_CONFIG environmental variable.
+ using GITWEB_CONFIG environmental variable. If this file does not
+ exist, gitweb looks for a system-wide configuration file, normally
+ /etc/gitweb.conf. You can change the default using the
+ GITWEB_CONFIG_SYSTEM build configuration variable, and override it
+ through GITWEB_CONFIG_SYSTEM environmental variable.
- Gitweb config file is [fragment] of perl code. You can set variables
using "our $variable = value"; text from "#" character until the end
diff --git a/gitweb/README b/gitweb/README
index 216307104..8dfe335f7 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -100,13 +100,20 @@ You can specify the following configuration variables when building GIT:
is set when gitweb.cgi is executed, then the file specified in the
environment variable will be loaded instead of the file specified
when gitweb.cgi was created. [Default: gitweb_config.perl]
+ * GITWEB_CONFIG_SYSTEM
+ This Perl file will be loaded using 'do' as a fallback if GITWEB_CONFIG
+ does not exist. If the environment variable GITWEB_CONFIG_SYSTEM is set
+ when gitweb.cgi is executed, then the file specified in the environment
+ variable will be loaded instead of the file specified when gitweb.cgi was
+ created. [Default: /etc/gitweb.conf]
Runtime gitweb configuration
----------------------------
You can adjust gitweb behaviour using the file specified in `GITWEB_CONFIG`
-(defaults to 'gitweb_config.perl' in the same directory as the CGI).
+(defaults to 'gitweb_config.perl' in the same directory as the CGI), and
+as a fallback `GITWEB_CONFIG_SYSTEM` (defaults to /etc/gitweb.conf).
The most notable thing that is not configurable at compile time are the
optional features, stored in the '%features' variable.
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 73d098a43..e69d7fd07 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -369,7 +369,12 @@ sub filter_snapshot_fmts {
}
our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
-do $GITWEB_CONFIG if -e $GITWEB_CONFIG;
+if (-e $GITWEB_CONFIG) {
+ do $GITWEB_CONFIG;
+} else {
+ our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
+ do $GITWEB_CONFIG_SYSTEM if -e $GITWEB_CONFIG_SYSTEM;
+}
# version of the core git binary
our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
diff --git a/log-tree.c b/log-tree.c
index 5b2963998..9d5406160 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -317,8 +317,10 @@ void show_log(struct rev_info *opt, const char *sep)
if (opt->show_log_size)
printf("log size %i\n", (int)msgbuf.len);
- if (msgbuf.len)
- printf("%s%s%s", msgbuf.buf, extra, sep);
+ if (msgbuf.len) {
+ fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+ printf("%s%s", extra, sep);
+ }
strbuf_release(&msgbuf);
}
diff --git a/perl/Git.pm b/perl/Git.pm
index a2812ea61..2e7f896ba 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -487,22 +487,20 @@ does. In scalar context requires the variable to be set only one time
(exception is thrown otherwise), in array context returns allows the
variable to be set multiple times and returns all the values.
-Must be called on a repository instance.
-
This currently wraps command('config') so it is not so fast.
=cut
sub config {
- my ($self, $var) = @_;
- $self->repo_path()
- or throw Error::Simple("not a repository");
+ my ($self, $var) = _maybe_self(@_);
try {
+ my @cmd = ('config');
+ unshift @cmd, $self if $self;
if (wantarray) {
- return $self->command('config', '--get-all', $var);
+ return command(@cmd, '--get-all', $var);
} else {
- return $self->command_oneline('config', '--get', $var);
+ return command_oneline(@cmd, '--get', $var);
}
} catch Git::Error::Command with {
my $E = shift;
@@ -522,20 +520,17 @@ Retrieve the bool configuration C<VARIABLE>. The return value
is usable as a boolean in perl (and C<undef> if it's not defined,
of course).
-Must be called on a repository instance.
-
This currently wraps command('config') so it is not so fast.
=cut
sub config_bool {
- my ($self, $var) = @_;
- $self->repo_path()
- or throw Error::Simple("not a repository");
+ my ($self, $var) = _maybe_self(@_);
try {
- my $val = $self->command_oneline('config', '--bool', '--get',
- $var);
+ my @cmd = ('config', '--bool', '--get', $var);
+ unshift @cmd, $self if $self;
+ my $val = command_oneline(@cmd);
return undef unless defined $val;
return $val eq 'true';
} catch Git::Error::Command with {
@@ -557,19 +552,17 @@ or 'g' in the config file will cause the value to be multiplied
by 1024, 1048576 (1024^2), or 1073741824 (1024^3) prior to output.
It would return C<undef> if configuration variable is not defined,
-Must be called on a repository instance.
-
This currently wraps command('config') so it is not so fast.
=cut
sub config_int {
- my ($self, $var) = @_;
- $self->repo_path()
- or throw Error::Simple("not a repository");
+ my ($self, $var) = _maybe_self(@_);
try {
- return $self->command_oneline('config', '--int', '--get', $var);
+ my @cmd = ('config', '--int', '--get', $var);
+ unshift @cmd, $self if $self;
+ return command_oneline(@cmd);
} catch Git::Error::Command with {
my $E = shift;
if ($E->value() == 1) {
@@ -639,15 +632,15 @@ The synopsis is like:
"$name <$email>" eq ident_person($name);
$time_tz =~ /^\d+ [+-]\d{4}$/;
-Both methods must be called on a repository instance.
-
=cut
sub ident {
- my ($self, $type) = @_;
+ my ($self, $type) = _maybe_self(@_);
my $identstr;
if (lc $type eq lc 'committer' or lc $type eq lc 'author') {
- $identstr = $self->command_oneline('var', 'GIT_'.uc($type).'_IDENT');
+ my @cmd = ('var', 'GIT_'.uc($type).'_IDENT');
+ unshift @cmd, $self if $self;
+ $identstr = command_oneline(@cmd);
} else {
$identstr = $type;
}
@@ -659,8 +652,8 @@ sub ident {
}
sub ident_person {
- my ($self, @ident) = @_;
- $#ident == 0 and @ident = $self->ident($ident[0]);
+ my ($self, @ident) = _maybe_self(@_);
+ $#ident == 0 and @ident = $self ? $self->ident($ident[0]) : ident($ident[0]);
return "$ident[0] <$ident[1]>";
}
diff --git a/pretty.c b/pretty.c
index 16bfb86cd..6c04176cb 100644
--- a/pretty.c
+++ b/pretty.c
@@ -457,6 +457,7 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
const struct commit *commit = c->commit;
const char *msg = commit->buffer;
struct commit_list *p;
+ int h1, h2;
/* these are independent of the commit */
switch (placeholder[0]) {
@@ -478,6 +479,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
case 'n': /* newline */
strbuf_addch(sb, '\n');
return 1;
+ case 'x':
+ /* %x00 == NUL, %x0a == LF, etc. */
+ if (0 <= (h1 = hexval_table[0xff & placeholder[1]]) &&
+ h1 <= 16 &&
+ 0 <= (h2 = hexval_table[0xff & placeholder[2]]) &&
+ h2 <= 16) {
+ strbuf_addch(sb, (h1<<4)|h2);
+ return 3;
+ } else
+ return 0;
}
/* these depend on the commit */
diff --git a/receive-pack.c b/receive-pack.c
index f83ae87e1..828d49001 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -10,6 +10,7 @@
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
static int deny_non_fast_forwards = 0;
+static int receive_fsck_objects;
static int receive_unpack_limit = -1;
static int transfer_unpack_limit = -1;
static int unpack_limit = 100;
@@ -35,6 +36,11 @@ static int receive_pack_config(const char *var, const char *value)
return 0;
}
+ if (strcmp(var, "receive.fsckobjects") == 0) {
+ receive_fsck_objects = git_config_bool(var, value);
+ return 0;
+ }
+
return git_default_config(var, value);
}
@@ -368,11 +374,13 @@ static const char *unpack(void)
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
if (ntohl(hdr.hdr_entries) < unpack_limit) {
- int code;
- const char *unpacker[3];
- unpacker[0] = "unpack-objects";
- unpacker[1] = hdr_arg;
- unpacker[2] = NULL;
+ int code, i = 0;
+ const char *unpacker[4];
+ unpacker[i++] = "unpack-objects";
+ if (receive_fsck_objects)
+ unpacker[i++] = "--strict";
+ unpacker[i++] = hdr_arg;
+ unpacker[i++] = NULL;
code = run_command_v_opt(unpacker, RUN_GIT_CMD);
switch (code) {
case 0:
@@ -393,8 +401,8 @@ static const char *unpack(void)
return "unpacker exited with error code";
}
} else {
- const char *keeper[6];
- int s, status;
+ const char *keeper[7];
+ int s, status, i = 0;
char keep_arg[256];
struct child_process ip;
@@ -402,12 +410,14 @@ static const char *unpack(void)
if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
strcpy(keep_arg + s, "localhost");
- keeper[0] = "index-pack";
- keeper[1] = "--stdin";
- keeper[2] = "--fix-thin";
- keeper[3] = hdr_arg;
- keeper[4] = keep_arg;
- keeper[5] = NULL;
+ keeper[i++] = "index-pack";
+ keeper[i++] = "--stdin";
+ if (receive_fsck_objects)
+ keeper[i++] = "--strict";
+ keeper[i++] = "--fix-thin";
+ keeper[i++] = hdr_arg;
+ keeper[i++] = keep_arg;
+ keeper[i++] = NULL;
memset(&ip, 0, sizeof(ip));
ip.argv = keeper;
ip.out = -1;
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index b36a9012e..a675cbb51 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -595,6 +595,64 @@ test_expect_success 'set --int' '
rm .git/config
+cat >expect <<\EOF
+[bool]
+ true1 = true
+ true2 = true
+ false1 = false
+ false2 = false
+[int]
+ int1 = 0
+ int2 = 1
+ int3 = -1
+EOF
+
+test_expect_success 'get --bool-or-int' '
+ (
+ echo "[bool]"
+ echo true1
+ echo true2 = true
+ echo false = false
+ echo "[int]"
+ echo int1 = 0
+ echo int2 = 1
+ echo int3 = -1
+ ) >>.git/config &&
+ test $(git config --bool-or-int bool.true1) = true &&
+ test $(git config --bool-or-int bool.true2) = true &&
+ test $(git config --bool-or-int bool.false) = false &&
+ test $(git config --bool-or-int int.int1) = 0 &&
+ test $(git config --bool-or-int int.int2) = 1 &&
+ test $(git config --bool-or-int int.int3) = -1
+
+'
+
+rm .git/config
+cat >expect <<\EOF
+[bool]
+ true1 = true
+ false1 = false
+ true2 = true
+ false2 = false
+[int]
+ int1 = 0
+ int2 = 1
+ int3 = -1
+EOF
+
+test_expect_success 'set --bool-or-int' '
+ git config --bool-or-int bool.true1 true &&
+ git config --bool-or-int bool.false1 false &&
+ git config --bool-or-int bool.true2 yes &&
+ git config --bool-or-int bool.false2 no &&
+ git config --bool-or-int int.int1 0 &&
+ git config --bool-or-int int.int2 1 &&
+ git config --bool-or-int int.int3 -1 &&
+ test_cmp expect .git/config
+'
+
+rm .git/config
+
git config quote.leading " test"
git config quote.ending "test "
git config quote.semicolon "test;test"
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index 77c90f6fa..f15be93e7 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -66,4 +66,23 @@ test_expect_success 'revert works (commit)' '
grep "unchanged *+3/-0 file" output
'
+test_expect_success 'patch does not affect mode' '
+ git reset --hard &&
+ echo content >>file &&
+ chmod +x file &&
+ printf "n\\ny\\n" | git add -p &&
+ git show :file | grep content &&
+ git diff file | grep "new mode"
+'
+
+test_expect_success 'stage mode but not hunk' '
+ git reset --hard &&
+ echo content >>file &&
+ chmod +x file &&
+ printf "y\\nn\\n" | git add -p &&
+ git diff --cached file | grep "new mode" &&
+ git diff file | grep "+content"
+'
+
+
test_done
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index c955fe44f..983a39398 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -274,4 +274,99 @@ test_expect_success \
packname_4=$(git pack-objects test-4 <obj-list) &&
test 3 = $(ls test-4-*.pack | wc -l)'
+test_expect_success 'unpacking with --strict' '
+
+ git config --unset pack.packsizelimit &&
+ for j in a b c d e f g
+ do
+ for i in 0 1 2 3 4 5 6 7 8 9
+ do
+ o=$(echo $j$i | git hash-object -w --stdin) &&
+ echo "100644 $o 0 $j$i"
+ done
+ done >LIST &&
+ rm -f .git/index &&
+ git update-index --index-info <LIST &&
+ LIST=$(git write-tree) &&
+ rm -f .git/index &&
+ head -n 10 LIST | git update-index --index-info &&
+ LI=$(git write-tree) &&
+ rm -f .git/index &&
+ tail -n 10 LIST | git update-index --index-info &&
+ ST=$(git write-tree) &&
+ PACK5=$( git rev-list --objects "$LIST" "$LI" "$ST" | \
+ git pack-objects test-5 ) &&
+ PACK6=$( (
+ echo "$LIST"
+ echo "$LI"
+ echo "$ST"
+ ) | git pack-objects test-6 ) &&
+ test_create_repo test-5 &&
+ (
+ cd test-5 &&
+ git unpack-objects --strict <../test-5-$PACK5.pack &&
+ git ls-tree -r $LIST &&
+ git ls-tree -r $LI &&
+ git ls-tree -r $ST
+ ) &&
+ test_create_repo test-6 &&
+ (
+ # tree-only into empty repo -- many unreachables
+ cd test-6 &&
+ test_must_fail git unpack-objects --strict <../test-6-$PACK6.pack
+ ) &&
+ (
+ # already populated -- no unreachables
+ cd test-5 &&
+ git unpack-objects --strict <../test-6-$PACK6.pack
+ )
+'
+
+test_expect_success 'index-pack with --strict' '
+
+ for j in a b c d e f g
+ do
+ for i in 0 1 2 3 4 5 6 7 8 9
+ do
+ o=$(echo $j$i | git hash-object -w --stdin) &&
+ echo "100644 $o 0 $j$i"
+ done
+ done >LIST &&
+ rm -f .git/index &&
+ git update-index --index-info <LIST &&
+ LIST=$(git write-tree) &&
+ rm -f .git/index &&
+ head -n 10 LIST | git update-index --index-info &&
+ LI=$(git write-tree) &&
+ rm -f .git/index &&
+ tail -n 10 LIST | git update-index --index-info &&
+ ST=$(git write-tree) &&
+ PACK5=$( git rev-list --objects "$LIST" "$LI" "$ST" | \
+ git pack-objects test-5 ) &&
+ PACK6=$( (
+ echo "$LIST"
+ echo "$LI"
+ echo "$ST"
+ ) | git pack-objects test-6 ) &&
+ test_create_repo test-7 &&
+ (
+ cd test-7 &&
+ git index-pack --strict --stdin <../test-5-$PACK5.pack &&
+ git ls-tree -r $LIST &&
+ git ls-tree -r $LI &&
+ git ls-tree -r $ST
+ ) &&
+ test_create_repo test-8 &&
+ (
+ # tree-only into empty repo -- many unreachables
+ cd test-8 &&
+ test_must_fail git index-pack --strict --stdin <../test-6-$PACK6.pack
+ ) &&
+ (
+ # already populated -- no unreachables
+ cd test-7 &&
+ git index-pack --strict --stdin <../test-6-$PACK6.pack
+ )
+'
+
test_done
diff --git a/var.c b/var.c
index 0de0efa2a..c20ac919b 100644
--- a/var.c
+++ b/var.c
@@ -51,11 +51,12 @@ static int show_config(const char *var, const char *value)
int main(int argc, char **argv)
{
const char *val;
+ int nongit;
if (argc != 2) {
usage(var_usage);
}
- setup_git_directory();
+ setup_git_directory_gently(&nongit);
val = NULL;
if (strcmp(argv[1], "-l") == 0) {