aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile18
-rw-r--r--builtin-apply.c122
-rw-r--r--builtin-grep.c2
-rw-r--r--builtin-update-index.c4
-rw-r--r--configure.ac2
-rw-r--r--diff.c172
-rw-r--r--diff.h1
-rw-r--r--dir.c27
-rwxr-xr-xgit-checkout.sh9
-rwxr-xr-xgit-merge-recursive-old.py (renamed from git-merge-recursive.py)0
-rwxr-xr-xgit-merge.sh16
-rwxr-xr-xgit-rebase.sh19
-rwxr-xr-xgit-repack.sh14
-rwxr-xr-xgit-svn.perl1
-rwxr-xr-xgitweb/gitweb.perl2
-rw-r--r--grep.c49
-rw-r--r--grep.h1
-rw-r--r--read-cache.c4
-rwxr-xr-xt/t3700-add.sh22
-rwxr-xr-xt/t6001-rev-list-graft.sh113
-rwxr-xr-xt/t7201-co.sh9
-rwxr-xr-xt/test-lib.sh2
23 files changed, 473 insertions, 137 deletions
diff --git a/.gitignore b/.gitignore
index 284db5dff..25eb4637a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,7 @@ git-merge-one-file
git-merge-ours
git-merge-recur
git-merge-recursive
+git-merge-recursive-old
git-merge-resolve
git-merge-stupid
git-mktag
diff --git a/Makefile b/Makefile
index 28091d6be..c888c810b 100644
--- a/Makefile
+++ b/Makefile
@@ -81,8 +81,6 @@ all:
# Define NO_ACCURATE_DIFF if your diff program at least sometimes misses
# a missing newline at the end of the file.
#
-# Define NO_PYTHON if you want to lose all benefits of the recursive merge.
-#
# Define COLLISION_CHECK below if you believe that SHA1's
# 1461501637330902918203684832716283019655932542976 hashes do not give you
# sufficient guarantee that no collisions between objects will ever happen.
@@ -174,7 +172,7 @@ SCRIPT_PERL = \
git-send-email.perl git-svn.perl
SCRIPT_PYTHON = \
- git-merge-recursive.py
+ git-merge-recursive-old.py
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
@@ -199,7 +197,7 @@ PROGRAMS = \
git-upload-pack$X git-verify-pack$X \
git-pack-redundant$X git-var$X \
git-describe$X git-merge-tree$X git-blame$X git-imap-send$X \
- git-merge-recur$X \
+ git-merge-recursive$X \
$(EXTRA_PROGRAMS)
# Empty...
@@ -570,7 +568,8 @@ LIB_OBJS += $(COMPAT_OBJS)
export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
### Build rules
-all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi
+all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi \
+ git-merge-recur$X
all:
$(MAKE) -C templates
@@ -585,6 +584,9 @@ git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) GIT-CFLAGS
help.o: common-cmds.h
+git-merge-recur$X: git-merge-recursive$X
+ rm -f $@ && ln git-merge-recursive$X $@
+
$(BUILT_INS): git$X
rm -f $@ && ln git$X $@
@@ -722,11 +724,6 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
-merge-recursive.o path-list.o: path-list.h
-git-merge-recur$X: merge-recursive.o path-list.o $(GITLIBS)
- $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
- $(LIBS)
-
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
$(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
$(DIFF_OBJS): diffcore.h
@@ -887,6 +884,7 @@ check-docs::
case "$$v" in \
git-merge-octopus | git-merge-ours | git-merge-recursive | \
git-merge-resolve | git-merge-stupid | git-merge-recur | \
+ git-merge-recursive-old | \
git-ssh-pull | git-ssh-push ) continue ;; \
esac ; \
test -f "Documentation/$$v.txt" || \
diff --git a/builtin-apply.c b/builtin-apply.c
index 25e90d8d2..de5f85526 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -854,6 +854,49 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
return -1;
}
+static void check_whitespace(const char *line, int len)
+{
+ const char *err = "Adds trailing whitespace";
+ int seen_space = 0;
+ int i;
+
+ /*
+ * We know len is at least two, since we have a '+' and we
+ * checked that the last character was a '\n' before calling
+ * this function. That is, an addition of an empty line would
+ * check the '+' here. Sneaky...
+ */
+ if (isspace(line[len-2]))
+ goto error;
+
+ /*
+ * Make sure that there is no space followed by a tab in
+ * indentation.
+ */
+ err = "Space in indent is followed by a tab";
+ for (i = 1; i < len; i++) {
+ if (line[i] == '\t') {
+ if (seen_space)
+ goto error;
+ }
+ else if (line[i] == ' ')
+ seen_space = 1;
+ else
+ break;
+ }
+ return;
+
+ error:
+ whitespace_error++;
+ if (squelch_whitespace_errors &&
+ squelch_whitespace_errors < whitespace_error)
+ ;
+ else
+ fprintf(stderr, "%s.\n%s:%d:%.*s\n",
+ err, patch_input_file, linenr, len-2, line+1);
+}
+
+
/*
* Parse a unified diff. Note that this really needs to parse each
* fragment separately, since the only way to know the difference
@@ -904,25 +947,8 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
trailing = 0;
break;
case '+':
- /*
- * We know len is at least two, since we have a '+' and
- * we checked that the last character was a '\n' above.
- * That is, an addition of an empty line would check
- * the '+' here. Sneaky...
- */
- if ((new_whitespace != nowarn_whitespace) &&
- isspace(line[len-2])) {
- whitespace_error++;
- if (squelch_whitespace_errors &&
- squelch_whitespace_errors <
- whitespace_error)
- ;
- else {
- fprintf(stderr, "Adds trailing whitespace.\n%s:%d:%.*s\n",
- patch_input_file,
- linenr, len-2, line+1);
- }
- }
+ if (new_whitespace != nowarn_whitespace)
+ check_whitespace(line, len);
added++;
newlines--;
trailing = 0;
@@ -1494,22 +1520,68 @@ static int apply_line(char *output, const char *patch, int plen)
{
/* plen is number of bytes to be copied from patch,
* starting at patch+1 (patch[0] is '+'). Typically
- * patch[plen] is '\n'.
+ * patch[plen] is '\n', unless this is the incomplete
+ * last line.
*/
+ int i;
int add_nl_to_tail = 0;
- if ((new_whitespace == strip_whitespace) &&
- 1 < plen && isspace(patch[plen-1])) {
+ int fixed = 0;
+ int last_tab_in_indent = -1;
+ int last_space_in_indent = -1;
+ int need_fix_leading_space = 0;
+ char *buf;
+
+ if ((new_whitespace != strip_whitespace) || !whitespace_error) {
+ memcpy(output, patch + 1, plen);
+ return plen;
+ }
+
+ if (1 < plen && isspace(patch[plen-1])) {
if (patch[plen] == '\n')
add_nl_to_tail = 1;
plen--;
while (0 < plen && isspace(patch[plen]))
plen--;
- applied_after_stripping++;
+ fixed = 1;
}
- memcpy(output, patch + 1, plen);
+
+ for (i = 1; i < plen; i++) {
+ char ch = patch[i];
+ if (ch == '\t') {
+ last_tab_in_indent = i;
+ if (0 <= last_space_in_indent)
+ need_fix_leading_space = 1;
+ }
+ else if (ch == ' ')
+ last_space_in_indent = i;
+ else
+ break;
+ }
+
+ buf = output;
+ if (need_fix_leading_space) {
+ /* between patch[1..last_tab_in_indent] strip the
+ * funny spaces, updating them to tab as needed.
+ */
+ for (i = 1; i < last_tab_in_indent; i++, plen--) {
+ char ch = patch[i];
+ if (ch != ' ')
+ *output++ = ch;
+ else if ((i % 8) == 0)
+ *output++ = '\t';
+ }
+ fixed = 1;
+ i = last_tab_in_indent;
+ }
+ else
+ i = 1;
+
+ memcpy(output, patch + i, plen);
if (add_nl_to_tail)
output[plen++] = '\n';
- return plen;
+ if (fixed)
+ applied_after_stripping++;
+ return output + plen - buf;
}
static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof)
diff --git a/builtin-grep.c b/builtin-grep.c
index 671878817..4205e5d38 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -325,6 +325,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
else
hit |= grep_file(opt, ce->name);
}
+ free_grep_patterns(opt);
return hit;
}
@@ -694,5 +695,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (grep_object(&opt, paths, real_obj, list.objects[i].name))
hit = 1;
}
+ free_grep_patterns(&opt);
return !hit;
}
diff --git a/builtin-update-index.c b/builtin-update-index.c
index 0620e779b..a3c0a455a 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -112,11 +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.
+ * from it, otherwise force to 644.
*/
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);
}
if (index_path(ce->sha1, path, &st, !info_only))
diff --git a/configure.ac b/configure.ac
index 511cac93d..b1a5833b4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -75,7 +75,6 @@ GIT_ARG_SET_PATH(shell)
# Define PERL_PATH to provide path to Perl.
GIT_ARG_SET_PATH(perl)
#
-# Define NO_PYTHON if you want to lose all benefits of the recursive merge.
# Define PYTHON_PATH to provide path to Python.
AC_ARG_WITH(python,[AS_HELP_STRING([--with-python=PATH], [provide PATH to python])
AS_HELP_STRING([--without-python], [don't use python scripts])],
@@ -100,7 +99,6 @@ AC_PROG_CC
AC_CHECK_TOOL(AR, ar, :)
AC_CHECK_PROGS(TAR, [gtar tar])
#
-# Define NO_PYTHON if you want to lose all benefits of the recursive merge.
# Define PYTHON_PATH to provide path to Python.
if test -z "$NO_PYTHON"; then
if test -z "$PYTHON_PATH"; then
diff --git a/diff.c b/diff.c
index 443e24861..2464238cc 100644
--- a/diff.c
+++ b/diff.c
@@ -20,12 +20,13 @@ static int diff_use_color_default;
static char diff_colors[][COLOR_MAXLEN] = {
"\033[m", /* reset */
- "", /* normal */
- "\033[1m", /* bold */
- "\033[36m", /* cyan */
- "\033[31m", /* red */
- "\033[32m", /* green */
- "\033[33m" /* yellow */
+ "", /* PLAIN (normal) */
+ "\033[1m", /* METAINFO (bold) */
+ "\033[36m", /* FRAGINFO (cyan) */
+ "\033[31m", /* OLD (red) */
+ "\033[32m", /* NEW (green) */
+ "\033[33m", /* COMMIT (yellow) */
+ "\033[41m", /* WHITESPACE (red background) */
};
static int parse_diff_color_slot(const char *var, int ofs)
@@ -42,6 +43,8 @@ static int parse_diff_color_slot(const char *var, int ofs)
return DIFF_FILE_NEW;
if (!strcasecmp(var+ofs, "commit"))
return DIFF_COMMIT;
+ if (!strcasecmp(var+ofs, "whitespace"))
+ return DIFF_WHITESPACE;
die("bad config variable '%s'", var);
}
@@ -383,9 +386,89 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix)
return "";
}
+static void emit_line(const char *set, const char *reset, const char *line, int len)
+{
+ if (len > 0 && line[len-1] == '\n')
+ len--;
+ fputs(set, stdout);
+ fwrite(line, len, 1, stdout);
+ puts(reset);
+}
+
+static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
+{
+ int col0 = ecbdata->nparents;
+ int last_tab_in_indent = -1;
+ int last_space_in_indent = -1;
+ int i;
+ int tail = len;
+ int need_highlight_leading_space = 0;
+ const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
+ const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
+
+ if (!*ws) {
+ emit_line(set, reset, line, len);
+ return;
+ }
+
+ /* The line is a newly added line. Does it have funny leading
+ * whitespaces? In indent, SP should never precede a TAB.
+ */
+ for (i = col0; i < len; i++) {
+ if (line[i] == '\t') {
+ last_tab_in_indent = i;
+ if (0 <= last_space_in_indent)
+ need_highlight_leading_space = 1;
+ }
+ else if (line[i] == ' ')
+ last_space_in_indent = i;
+ else
+ break;
+ }
+ fputs(set, stdout);
+ fwrite(line, col0, 1, stdout);
+ fputs(reset, stdout);
+ if (((i == len) || line[i] == '\n') && i != col0) {
+ /* The whole line was indent */
+ emit_line(ws, reset, line + col0, len - col0);
+ return;
+ }
+ i = col0;
+ if (need_highlight_leading_space) {
+ while (i < last_tab_in_indent) {
+ if (line[i] == ' ') {
+ fputs(ws, stdout);
+ putchar(' ');
+ fputs(reset, stdout);
+ }
+ else
+ putchar(line[i]);
+ i++;
+ }
+ }
+ tail = len - 1;
+ if (line[tail] == '\n' && i < tail)
+ tail--;
+ while (i < tail) {
+ if (!isspace(line[tail]))
+ break;
+ tail--;
+ }
+ if ((i < tail && line[tail + 1] != '\n')) {
+ /* This has whitespace between tail+1..len */
+ fputs(set, stdout);
+ fwrite(line + i, tail - i + 1, 1, stdout);
+ fputs(reset, stdout);
+ emit_line(ws, reset, line + tail + 1, len - tail - 1);
+ }
+ else
+ emit_line(set, reset, line + i, len - i);
+}
+
static void fn_out_consume(void *priv, char *line, unsigned long len)
{
int i;
+ int color;
struct emit_callback *ecbdata = priv;
const char *set = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);
const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
@@ -403,45 +486,52 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
;
if (2 <= i && i < len && line[i] == ' ') {
ecbdata->nparents = i - 1;
- set = diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO);
+ emit_line(diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO),
+ reset, line, len);
+ return;
}
- else if (len < ecbdata->nparents)
+
+ if (len < ecbdata->nparents) {
set = reset;
- else {
- int nparents = ecbdata->nparents;
- int color = DIFF_PLAIN;
- if (ecbdata->diff_words && nparents != 1)
- /* fall back to normal diff */
- free_diff_words_data(ecbdata);
- if (ecbdata->diff_words) {
- if (line[0] == '-') {
- diff_words_append(line, len,
- &ecbdata->diff_words->minus);
- return;
- } else if (line[0] == '+') {
- diff_words_append(line, len,
- &ecbdata->diff_words->plus);
- return;
- }
- if (ecbdata->diff_words->minus.text.size ||
- ecbdata->diff_words->plus.text.size)
- diff_words_show(ecbdata->diff_words);
- line++;
- len--;
- } else
- for (i = 0; i < nparents && len; i++) {
- if (line[i] == '-')
- color = DIFF_FILE_OLD;
- else if (line[i] == '+')
- color = DIFF_FILE_NEW;
- }
- set = diff_get_color(ecbdata->color_diff, color);
+ emit_line(reset, reset, line, len);
+ return;
}
- if (len > 0 && line[len-1] == '\n')
+
+ color = DIFF_PLAIN;
+ if (ecbdata->diff_words && ecbdata->nparents != 1)
+ /* fall back to normal diff */
+ free_diff_words_data(ecbdata);
+ if (ecbdata->diff_words) {
+ if (line[0] == '-') {
+ diff_words_append(line, len,
+ &ecbdata->diff_words->minus);
+ return;
+ } else if (line[0] == '+') {
+ diff_words_append(line, len,
+ &ecbdata->diff_words->plus);
+ return;
+ }
+ if (ecbdata->diff_words->minus.text.size ||
+ ecbdata->diff_words->plus.text.size)
+ diff_words_show(ecbdata->diff_words);
+ line++;
len--;
- fputs (set, stdout);
- fwrite (line, len, 1, stdout);
- puts (reset);
+ emit_line(set, reset, line, len);
+ return;
+ }
+ for (i = 0; i < ecbdata->nparents && len; i++) {
+ if (line[i] == '-')
+ color = DIFF_FILE_OLD;
+ else if (line[i] == '+')
+ color = DIFF_FILE_NEW;
+ }
+
+ if (color != DIFF_FILE_NEW) {
+ emit_line(diff_get_color(ecbdata->color_diff, color),
+ reset, line, len);
+ return;
+ }
+ emit_add_line(reset, ecbdata, line, len);
}
static char *pprint_rename(const char *a, const char *b)
diff --git a/diff.h b/diff.h
index b60a02e62..3435fe7b3 100644
--- a/diff.h
+++ b/diff.h
@@ -86,6 +86,7 @@ enum color_diff {
DIFF_FILE_OLD = 4,
DIFF_FILE_NEW = 5,
DIFF_COMMIT = 6,
+ DIFF_WHITESPACE = 7,
};
const char *diff_get_color(int diff_use_color, enum color_diff ix);
diff --git a/dir.c b/dir.c
index e2f472ba7..96389b32e 100644
--- a/dir.c
+++ b/dir.c
@@ -283,7 +283,7 @@ static int dir_exists(const char *dirname, int len)
* Also, we ignore the name ".git" (even if it is not a directory).
* That likely will not change.
*/
-static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen)
+static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only)
{
DIR *fdir = opendir(path);
int contents = 0;
@@ -314,7 +314,6 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
switch (DTYPE(de)) {
struct stat st;
- int subdir, rewind_base;
default:
continue;
case DT_UNKNOWN:
@@ -328,26 +327,30 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
case DT_DIR:
memcpy(fullname + baselen + len, "/", 2);
len++;
- rewind_base = dir->nr;
- subdir = read_directory_recursive(dir, fullname, fullname,
- baselen + len);
if (dir->show_other_directories &&
- (subdir || !dir->hide_empty_directories) &&
!dir_exists(fullname, baselen + len)) {
- /* Rewind the read subdirectory */
- while (dir->nr > rewind_base)
- free(dir->entries[--dir->nr]);
+ if (dir->hide_empty_directories &&
+ !read_directory_recursive(dir,
+ fullname, fullname,
+ baselen + len, 1))
+ continue;
break;
}
- contents += subdir;
+
+ contents += read_directory_recursive(dir,
+ fullname, fullname, baselen + len, 0);
continue;
case DT_REG:
case DT_LNK:
break;
}
- add_name(dir, fullname, baselen + len);
contents++;
+ if (check_only)
+ goto exit_early;
+ else
+ add_name(dir, fullname, baselen + len);
}
+exit_early:
closedir(fdir);
pop_exclude_per_directory(dir, exclude_stk);
@@ -393,7 +396,7 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
}
}
- read_directory_recursive(dir, path, base, baselen);
+ read_directory_recursive(dir, path, base, baselen, 0);
qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
return dir->nr;
}
diff --git a/git-checkout.sh b/git-checkout.sh
index 580a9e8a2..dd477245f 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -4,8 +4,8 @@ USAGE='[-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
SUBDIRECTORY_OK=Sometimes
. git-sh-setup
-old=$(git-rev-parse HEAD)
old_name=HEAD
+old=$(git-rev-parse --verify $old_name 2>/dev/null)
new=
new_name=
force=
@@ -139,6 +139,13 @@ fi
die "git checkout: to checkout the requested commit you need to specify
a name for a new branch which is created and switched to"
+if [ "X$old" = X ]
+then
+ echo "warning: You do not appear to currently be on a branch." >&2
+ echo "warning: Forcing checkout of $new_name." >&2
+ force=1
+fi
+
if [ "$force" ]
then
git-read-tree --reset -u $new
diff --git a/git-merge-recursive.py b/git-merge-recursive-old.py
index 4039435ce..4039435ce 100755
--- a/git-merge-recursive.py
+++ b/git-merge-recursive-old.py
diff --git a/git-merge.sh b/git-merge.sh
index d049e1643..5b34b4de9 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -9,21 +9,15 @@ USAGE='[-n] [--no-commit] [--squash] [-s <strategy>]... <merge-message> <head> <
LF='
'
-all_strategies='recursive recur octopus resolve stupid ours'
-case "${GIT_USE_RECUR_FOR_RECURSIVE}" in
-'')
- default_twohead_strategies=recursive ;;
-?*)
- default_twohead_strategies=recur ;;
-esac
+all_strategies='recur recursive recursive-old octopus resolve stupid ours'
+default_twohead_strategies='recursive'
default_octopus_strategies='octopus'
no_trivial_merge_strategies='ours'
use_strategies=
index_merge=t
if test "@@NO_PYTHON@@"; then
- all_strategies='recur resolve octopus stupid ours'
- default_twohead_strategies='resolve'
+ all_strategies='recur recursive resolve octopus stupid ours'
fi
dropsave() {
@@ -122,10 +116,6 @@ do
strategy="$2"
shift ;;
esac
- case "$strategy,${GIT_USE_RECUR_FOR_RECURSIVE}" in
- recursive,?*)
- strategy=recur ;;
- esac
case " $all_strategies " in
*" $strategy "*)
use_strategies="$use_strategies$strategy " ;;
diff --git a/git-rebase.sh b/git-rebase.sh
index 20f74d416..a7373c053 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -35,13 +35,7 @@ If you would prefer to skip this patch, instead run \"git rebase --skip\".
To restore the original branch and stop rebasing run \"git rebase --abort\".
"
unset newbase
-case "${GIT_USE_RECUR_FOR_RECURSIVE}" in
-'')
- strategy=recursive ;;
-?*)
- strategy=recur ;;
-esac
-
+strategy=recursive
do_merge=
dotest=$GIT_DIR/.dotest-merge
prec=4
@@ -206,11 +200,6 @@ do
shift
done
-case "$strategy,${GIT_USE_RECUR_FOR_RECURSIVE}" in
-recursive,?*)
- strategy=recur ;;
-esac
-
# Make sure we do not have .dotest
if test -z "$do_merge"
then
@@ -303,11 +292,11 @@ then
exit $?
fi
-if test "@@NO_PYTHON@@" && test "$strategy" = "recursive"
+if test "@@NO_PYTHON@@" && test "$strategy" = "recursive-old"
then
- die 'The recursive merge strategy currently relies on Python,
+ die 'The recursive-old merge strategy is written in Python,
which this installation of git was not configured with. Please consider
-a different merge strategy (e.g. octopus, resolve, stupid, ours)
+a different merge strategy (e.g. recursive, resolve, or stupid)
or install Python and git with Python support.'
fi
diff --git a/git-repack.sh b/git-repack.sh
index b525fc5df..f2c9071d1 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -4,6 +4,7 @@
#
USAGE='[-a] [-d] [-f] [-l] [-n] [-q]'
+SUBDIRECTORY_OK='Yes'
. git-sh-setup
no_update_info= all_into_one= remove_redundant=
@@ -32,12 +33,10 @@ trap 'rm -f "$PACKTMP"-*' 0 1 2 3 15
# There will be more repacking strategies to come...
case ",$all_into_one," in
,,)
- rev_list='--unpacked'
- pack_objects='--incremental'
+ args='--unpacked --incremental'
;;
,t,)
- rev_list=
- pack_objects=
+ args=
# Redundancy check in all-into-one case is trivial.
existing=`test -d "$PACKDIR" && cd "$PACKDIR" && \
@@ -45,11 +44,8 @@ case ",$all_into_one," in
;;
esac
-pack_objects="$pack_objects $local $quiet $no_reuse_delta$extra"
-name=$( { git-rev-list --objects --all $rev_list ||
- echo "git-rev-list died with exit code $?"
- } |
- git-pack-objects --non-empty $pack_objects "$PACKTMP") ||
+args="$args $local $quiet $no_reuse_delta$extra"
+name=$(git-pack-objects --non-empty --all $args </dev/null "$PACKTMP") ||
exit 1
if [ -z "$name" ]; then
echo Nothing new to pack.
diff --git a/git-svn.perl b/git-svn.perl
index 017f45ac9..f5c7d4634 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -1247,6 +1247,7 @@ sub assert_svn_wc_clean {
}
my @status = grep(!/^Performing status on external/,(`svn status`));
@status = grep(!/^\s*$/,@status);
+ @status = grep(!/^X/,@status) if $_no_ignore_ext;
if (scalar @status) {
print STDERR "Tree ($SVN_WC) is not clean:\n";
print STDERR $_ foreach @status;
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 66be61933..597d29f22 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -617,7 +617,7 @@ sub format_subject_html {
if (length($short) < length($long)) {
return $cgi->a({-href => $href, -class => "list subject",
- -title => $long},
+ -title => decode("utf8", $long, Encode::FB_DEFAULT)},
esc_html($short) . $extra);
} else {
return $cgi->a({-href => $href, -class => "list subject"},
diff --git a/grep.c b/grep.c
index cc8d6846a..c411ddd4d 100644
--- a/grep.c
+++ b/grep.c
@@ -138,16 +138,13 @@ void compile_grep_patterns(struct grep_opt *opt)
{
struct grep_pat *p;
- if (opt->fixed)
- return;
-
- /* First compile regexps */
for (p = opt->pattern_list; p; p = p->next) {
switch (p->token) {
case GREP_PATTERN: /* atom */
case GREP_PATTERN_HEAD:
case GREP_PATTERN_BODY:
- compile_regexp(p, opt);
+ if (!opt->fixed)
+ compile_regexp(p, opt);
break;
default:
opt->extended = 1;
@@ -167,6 +164,46 @@ void compile_grep_patterns(struct grep_opt *opt)
die("incomplete pattern expression: %s", p->pattern);
}
+static void free_pattern_expr(struct grep_expr *x)
+{
+ switch (x->node) {
+ case GREP_NODE_ATOM:
+ break;
+ case GREP_NODE_NOT:
+ free_pattern_expr(x->u.unary);
+ break;
+ case GREP_NODE_AND:
+ case GREP_NODE_OR:
+ free_pattern_expr(x->u.binary.left);
+ free_pattern_expr(x->u.binary.right);
+ break;
+ }
+ free(x);
+}
+
+void free_grep_patterns(struct grep_opt *opt)
+{
+ struct grep_pat *p, *n;
+
+ for (p = opt->pattern_list; p; p = n) {
+ n = p->next;
+ switch (p->token) {
+ case GREP_PATTERN: /* atom */
+ case GREP_PATTERN_HEAD:
+ case GREP_PATTERN_BODY:
+ regfree(&p->regexp);
+ break;
+ default:
+ break;
+ }
+ free(p);
+ }
+
+ if (!opt->extended)
+ return;
+ free_pattern_expr(opt->pattern_expression);
+}
+
static char *end_of_line(char *cp, unsigned long *left)
{
unsigned long l = *left;
@@ -439,6 +476,8 @@ int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long
lno++;
}
+ free(prev);
+
if (opt->status_only)
return 0;
if (opt->unmatch_name_only) {
diff --git a/grep.h b/grep.h
index 0b503ea66..af9098cfe 100644
--- a/grep.h
+++ b/grep.h
@@ -73,6 +73,7 @@ struct grep_opt {
extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
extern void compile_grep_patterns(struct grep_opt *opt);
+extern void free_grep_patterns(struct grep_opt *opt);
extern int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size);
#endif
diff --git a/read-cache.c b/read-cache.c
index 20c9d494a..97c38670b 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -347,11 +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.
+ * from it, otherwise force to 644.
*/
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);
}
if (index_path(ce->sha1, path, &st, 1))
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index 6cd05c3d9..c20e4c29f 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -19,4 +19,26 @@ test_expect_success \
'Test that "git-add -- -q" works' \
'touch -- -q && git-add -- -q'
+test_expect_success \
+ 'git-add: Test that executable bit is not used if core.filemode=0' \
+ 'git repo-config core.filemode 0 &&
+ echo foo >xfoo1 &&
+ chmod 755 xfoo1 &&
+ git-add xfoo1 &&
+ case "`git-ls-files --stage xfoo1`" in
+ 100644" "*xfoo1) echo ok;;
+ *) echo fail; git-ls-files --stage xfoo1; exit 1;;
+ esac'
+
+test_expect_success \
+ 'git-update-index --add: Test that executable bit is not used...' \
+ 'git repo-config core.filemode 0 &&
+ echo foo >xfoo2 &&
+ chmod 755 xfoo2 &&
+ 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;;
+ esac'
+
test_done
diff --git a/t/t6001-rev-list-graft.sh b/t/t6001-rev-list-graft.sh
new file mode 100755
index 000000000..b2131cdac
--- /dev/null
+++ b/t/t6001-rev-list-graft.sh
@@ -0,0 +1,113 @@
+#!/bin/sh
+
+test_description='Revision traversal vs grafts and path limiter'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ mkdir subdir &&
+ echo >fileA fileA &&
+ echo >subdir/fileB fileB &&
+ git add fileA subdir/fileB &&
+ git commit -a -m "Initial in one history." &&
+ A0=`git rev-parse --verify HEAD` &&
+
+ echo >fileA fileA modified &&
+ git commit -a -m "Second in one history." &&
+ A1=`git rev-parse --verify HEAD` &&
+
+ echo >subdir/fileB fileB modified &&
+ git commit -a -m "Third in one history." &&
+ A2=`git rev-parse --verify HEAD` &&
+
+ rm -f .git/refs/heads/master .git/index &&
+
+ echo >fileA fileA again &&
+ echo >subdir/fileB fileB again &&
+ git add fileA subdir/fileB &&
+ git commit -a -m "Initial in alternate history." &&
+ B0=`git rev-parse --verify HEAD` &&
+
+ echo >fileA fileA modified in alternate history &&
+ git commit -a -m "Second in alternate history." &&
+ B1=`git rev-parse --verify HEAD` &&
+
+ echo >subdir/fileB fileB modified in alternate history &&
+ git commit -a -m "Third in alternate history." &&
+ B2=`git rev-parse --verify HEAD` &&
+ : done
+'
+
+check () {
+ type=$1
+ shift
+
+ arg=
+ which=arg
+ rm -f test.expect
+ for a
+ do
+ if test "z$a" = z--
+ then
+ which=expect
+ child=
+ continue
+ fi
+ if test "$which" = arg
+ then
+ arg="$arg$a "
+ continue
+ fi
+ if test "$type" = basic
+ then
+ echo "$a"
+ else
+ if test "z$child" != z
+ then
+ echo "$child $a"
+ fi
+ child="$a"
+ fi
+ done >test.expect
+ if test "$type" != basic && test "z$child" != z
+ then
+ echo >>test.expect $child
+ fi
+ if test $type = basic
+ then
+ git rev-list $arg >test.actual
+ elif test $type = parents
+ then
+ git rev-list --parents $arg >test.actual
+ elif test $type = parents-raw
+ then
+ git rev-list --parents --pretty=raw $arg |
+ sed -n -e 's/^commit //p' >test.actual
+ fi
+ diff test.expect test.actual
+}
+
+for type in basic parents parents-raw
+do
+ test_expect_success 'without grafts' "
+ rm -f .git/info/grafts
+ check $type $B2 -- $B2 $B1 $B0
+ "
+
+ test_expect_success 'with grafts' "
+ echo '$B0 $A2' >.git/info/grafts
+ check $type $B2 -- $B2 $B1 $B0 $A2 $A1 $A0
+ "
+
+ test_expect_success 'without grafts, with pathlimit' "
+ rm -f .git/info/grafts
+ check $type $B2 subdir -- $B2 $B0
+ "
+
+ test_expect_success 'with grafts, with pathlimit' "
+ echo '$B0 $A2' >.git/info/grafts
+ check $type $B2 subdir -- $B2 $B0 $A2 $A0
+ "
+
+done
+test_done
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index b64e8b7d7..085d4a096 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -31,6 +31,15 @@ test_expect_success setup '
git checkout master
'
+test_expect_success "checkout from non-existing branch" '
+
+ git checkout -b delete-me master &&
+ rm .git/refs/heads/delete-me &&
+ test refs/heads/delete-me = "$(git symbolic-ref HEAD)" &&
+ git checkout master &&
+ test refs/heads/master = "$(git symbolic-ref HEAD)"
+'
+
test_expect_success "checkout with dirty tree without -m" '
fill 0 1 2 3 4 5 >one &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index e75ad5faa..0fe271884 100755
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -211,7 +211,7 @@ export PATH GIT_EXEC_PATH
PYTHON=`sed -e '1{
s/^#!//
q
-}' ../git-merge-recursive` || {
+}' ../git-merge-recursive-old` || {
error "You haven't built things yet, have you?"
}
"$PYTHON" -c 'import subprocess' 2>/dev/null || {