aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes-1.6.0.3.txt45
-rw-r--r--Documentation/config.txt13
-rw-r--r--Documentation/git-read-tree.txt11
-rw-r--r--Documentation/git-repack.txt2
-rw-r--r--Documentation/gitattributes.txt18
-rw-r--r--Documentation/gitdiffcore.txt55
-rw-r--r--builtin-apply.c11
-rw-r--r--builtin-archive.c2
-rw-r--r--builtin-checkout.c4
-rw-r--r--builtin-clone.c2
-rw-r--r--builtin-commit.c2
-rw-r--r--builtin-diff-files.c7
-rw-r--r--builtin-diff.c8
-rw-r--r--builtin-for-each-ref.c4
-rw-r--r--builtin-log.c2
-rw-r--r--builtin-merge-recursive.c23
-rw-r--r--builtin-merge.c2
-rw-r--r--builtin-pack-objects.c2
-rw-r--r--builtin-prune.c22
-rw-r--r--builtin-read-tree.c1
-rw-r--r--builtin-remote.c41
-rw-r--r--builtin-rm.c22
-rwxr-xr-xcontrib/completion/git-completion.bash2
-rw-r--r--contrib/hooks/setgitperms.perl4
-rw-r--r--diff.c12
-rw-r--r--diffcore.h1
-rw-r--r--dir.c20
-rw-r--r--dir.h3
-rw-r--r--fast-import.c4
-rwxr-xr-xgit-rebase--interactive.sh14
-rwxr-xr-xgit-repack.sh2
-rwxr-xr-xgit-stash.sh19
-rwxr-xr-xgit-submodule.sh9
-rwxr-xr-xgit-svn.perl26
-rw-r--r--git.c2
-rwxr-xr-xgitweb/gitweb.perl2
-rw-r--r--http.c11
-rw-r--r--index-pack.c2
-rw-r--r--pack-write.c2
-rw-r--r--read-cache.c1
-rw-r--r--sha1_file.c4
-rw-r--r--t/lib-git-svn.sh17
-rw-r--r--t/t0024-crlf-archive.sh46
-rwxr-xr-xt/t1300-repo-config.sh10
-rwxr-xr-xt/t3030-merge-recursive.sh11
-rwxr-xr-xt/t9113-git-svn-dcommit-new-file.sh14
-rwxr-xr-xt/t9118-git-svn-funky-branch-names.sh16
-rwxr-xr-xt/t9126-git-svn-follow-deleted-readded-directory.sh22
-rw-r--r--t/t9126/follow-deleted-readded.dump201
-rw-r--r--templates/Makefile8
-rw-r--r--unpack-trees.c11
-rw-r--r--unpack-trees.h1
52 files changed, 600 insertions, 196 deletions
diff --git a/Documentation/RelNotes-1.6.0.3.txt b/Documentation/RelNotes-1.6.0.3.txt
new file mode 100644
index 000000000..46e13a450
--- /dev/null
+++ b/Documentation/RelNotes-1.6.0.3.txt
@@ -0,0 +1,45 @@
+GIT v1.6.0.3 Release Notes
+==========================
+
+Fixes since v1.6.0.2
+--------------------
+
+* "git archive --format=zip" did not honor core.autocrlf while
+ --format=tar did.
+
+* Continuing "git rebase -i" was very confused when the user left modified
+ files in the working tree while resolving conflicts.
+
+* Continuing "git rebase -i" was also very confused when the user left
+ some staged changes in the index after "edit".
+
+* Behaviour of "git diff --quiet" was inconsistent with "diff --exit-code"
+ with the output redirected to /dev/null.
+
+* "git stash apply sash@{1}" was fixed to error out. Prior versions
+ would have applied stash@{0} incorrectly.
+
+* "git for-each-ref --format=%(subject)" fixed for commits with no
+ no newline in the message body.
+
+* "git remote" fixed to protect printf from user input.
+
+* "git checkout -q" once again suppresses the locally modified file list.
+
+* Cross-directory renames are no longer used when creating packs. This
+ allows more graceful behavior on filesystems like sshfs.
+
+* Stale temporary files under $GIT_DIR/objects/pack are now cleaned up
+ automatically by "git prune".
+
+* "Git.pm" tests relied on unnecessarily more recent version of Perl.
+
+* "gitweb" triggered undef warning on commits without log messages.
+
+Many other documentation updates.
+
+--
+exec >/var/tmp/1
+O=v1.6.0.2-41-g7fe4a72
+echo O=$(git describe maint)
+git shortlog --no-merges $O..maint
diff --git a/Documentation/config.txt b/Documentation/config.txt
index ed3285f89..5dda70de9 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -363,8 +363,17 @@ core.pager::
variable. Note that git sets the `LESS` environment
variable to `FRSX` if it is unset when it runs the
pager. One can change these settings by setting the
- `LESS` variable to some other value or by giving the
- `core.pager` option a value such as "`less -+FRSX`".
+ `LESS` variable to some other value. Alternately,
+ these settings can be overridden on a project or
+ global basis by setting the `core.pager` option.
+ Setting `core.pager` has no affect on the `LESS`
+ environment variable behaviour above, so if you want
+ to override git's default settings this way, you need
+ to be explicit. For example, to disable the S option
+ in a backward compatible manner, set `core.pager`
+ to "`less -+$LESS -FRX`". This will be passed to the
+ shell by git, which will translate the final command to
+ "`LESS=FRSX less -+FRSX -FRX`".
core.whitespace::
A comma separated list of common whitespace problems to
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index 6f4b9b017..309deac23 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -160,7 +160,10 @@ Here are the "carry forward" rules:
0 nothing nothing nothing (does not happen)
1 nothing nothing exists use M
2 nothing exists nothing remove path from index
- 3 nothing exists exists use M
+ 3 nothing exists exists, use M if "initial checkout"
+ H == M keep index otherwise
+ exists fail
+ H != M
clean I==H I==M
------------------
@@ -207,6 +210,12 @@ you picked it up via e-mail in a patch form), `git diff-index
merge, but it would not show in `git diff-index --cached $M`
output after two-tree merge.
+Case #3 is slightly tricky and needs explanation. The result from this
+rule logically should be to remove the path if the user staged the removal
+of the path and then swiching to a new branch. That however will prevent
+the initial checkout from happening, so the rule is modified to use M (new
+tree) only when the contents of the index is empty. Otherwise the removal
+of the path is kept as long as $H and $M are the same.
3-Way Merge
~~~~~~~~~~~
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index 38ac60947..bbe1485a9 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -60,7 +60,7 @@ OPTIONS
linkgit:git-pack-objects[1].
-f::
- Pass the `--no-reuse-delta` option to 'git-pack-objects'. See
+ Pass the `--no-reuse-object` option to `git-pack-objects`, see
linkgit:git-pack-objects[1].
-q::
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 9a752570f..2ae771f2f 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -270,27 +270,27 @@ See linkgit:git[1] for details.
Defining a custom hunk-header
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Each group of changes (called "hunk") in the textual diff output
+Each group of changes (called a "hunk") in the textual diff output
is prefixed with a line of the form:
@@ -k,l +n,m @@ TEXT
-The text is called 'hunk header', and by default a line that
-begins with an alphabet, an underscore or a dollar sign is used,
-which matches what GNU 'diff -p' output uses. This default
-selection however is not suited for some contents, and you can
-use customized pattern to make a selection.
+This is called a 'hunk header'. The "TEXT" portion is by default a line
+that begins with an alphabet, an underscore or a dollar sign; this
+matches what GNU 'diff -p' output uses. This default selection however
+is not suited for some contents, and you can use a customized pattern
+to make a selection.
-First in .gitattributes, you would assign the `diff` attribute
+First, in .gitattributes, you would assign the `diff` attribute
for paths.
------------------------
*.tex diff=tex
------------------------
-Then, you would define "diff.tex.xfuncname" configuration to
+Then, you would define a "diff.tex.xfuncname" configuration to
specify a regular expression that matches a line that you would
-want to appear as the hunk header, like this:
+want to appear as the hunk header "TEXT", like this:
------------------------
[diff "tex"]
diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt
index 2bdbc3d4f..e8041bc08 100644
--- a/Documentation/gitdiffcore.txt
+++ b/Documentation/gitdiffcore.txt
@@ -36,11 +36,25 @@ files:
- 'git-diff-tree' compares contents of two "tree" objects;
-In all of these cases, the commands themselves compare
-corresponding paths in the two sets of files. The result of
-comparison is passed from these commands to what is internally
-called "diffcore", in a format similar to what is output when
-the -p option is not used. E.g.
+In all of these cases, the commands themselves first optionally limit
+the two sets of files by any pathspecs given on their command-lines,
+and compare corresponding paths in the two resulting sets of files.
+
+The pathspecs are used to limit the world diff operates in. They remove
+the filepairs outside the specified sets of pathnames. E.g. If the
+input set of filepairs included:
+
+------------------------------------------------
+:100644 100644 bcd1234... 0123456... M junkfile
+------------------------------------------------
+
+but the command invocation was `git diff-files myfile`, then the
+junkfile entry would be removed from the list because only "myfile"
+is under consideration.
+
+The result of comparison is passed from these commands to what is
+internally called "diffcore", in a format similar to what is output
+when the -p option is not used. E.g.
------------------------------------------------
in-place edit :100644 100644 bcd1234... 0123456... M file0
@@ -52,9 +66,8 @@ unmerged :000000 000000 0000000... 0000000... U file6
The diffcore mechanism is fed a list of such comparison results
(each of which is called "filepair", although at this point each
of them talks about a single file), and transforms such a list
-into another list. There are currently 6 such transformations:
+into another list. There are currently 5 such transformations:
-- diffcore-pathspec
- diffcore-break
- diffcore-rename
- diffcore-merge-broken
@@ -62,38 +75,14 @@ into another list. There are currently 6 such transformations:
- diffcore-order
These are applied in sequence. The set of filepairs 'git-diff-{asterisk}'
-commands find are used as the input to diffcore-pathspec, and
-the output from diffcore-pathspec is used as the input to the
+commands find are used as the input to diffcore-break, and
+the output from diffcore-break is used as the input to the
next transformation. The final result is then passed to the
output routine and generates either diff-raw format (see Output
format sections of the manual for 'git-diff-{asterisk}' commands) or
diff-patch format.
-diffcore-pathspec: For Ignoring Files Outside Our Consideration
----------------------------------------------------------------
-
-The first transformation in the chain is diffcore-pathspec, and
-is controlled by giving the pathname parameters to the
-'git-diff-{asterisk}' commands on the command line. The pathspec is used
-to limit the world diff operates in. It removes the filepairs
-outside the specified set of pathnames. E.g. If the input set
-of filepairs included:
-
-------------------------------------------------
-:100644 100644 bcd1234... 0123456... M junkfile
-------------------------------------------------
-
-but the command invocation was `git diff-files myfile`, then the
-junkfile entry would be removed from the list because only "myfile"
-is under consideration.
-
-Implementation note. For performance reasons, 'git-diff-tree'
-uses the pathname parameters on the command line to cull set of
-filepairs it feeds the diffcore mechanism itself, and does not
-use diffcore-pathspec, but the end result is the same.
-
-
diffcore-break: For Splitting Up "Complete Rewrites"
----------------------------------------------------
diff --git a/builtin-apply.c b/builtin-apply.c
index 20bef1f21..70c9f9355 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -13,6 +13,7 @@
#include "delta.h"
#include "builtin.h"
#include "string-list.h"
+#include "dir.h"
/*
* --check turns on checking that the working tree matches the
@@ -2735,15 +2736,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
warning("unable to remove submodule %s",
patch->old_name);
} else if (!unlink(patch->old_name) && rmdir_empty) {
- char *name = xstrdup(patch->old_name);
- char *end = strrchr(name, '/');
- while (end) {
- *end = 0;
- if (rmdir(name))
- break;
- end = strrchr(name, '/');
- }
- free(name);
+ remove_path(patch->old_name);
}
}
}
diff --git a/builtin-archive.c b/builtin-archive.c
index 5ceec433f..432ce2acc 100644
--- a/builtin-archive.c
+++ b/builtin-archive.c
@@ -111,6 +111,8 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
{
const char *remote = NULL;
+ git_config(git_default_config, NULL);
+
remote = extract_remote_arg(&argc, argv);
if (remote)
return run_remote_archiver(remote, argc, argv);
diff --git a/builtin-checkout.c b/builtin-checkout.c
index d986ac7ab..4ca76a6f4 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -269,6 +269,8 @@ static int merge_working_tree(struct checkout_opts *opts,
}
/* 2-way merge to the new branch */
+ topts.initial_checkout = (!active_nr &&
+ (old->commit == new->commit));
topts.update = 1;
topts.merge = 1;
topts.gently = opts->merge;
@@ -326,7 +328,7 @@ static int merge_working_tree(struct checkout_opts *opts,
commit_locked_index(lock_file))
die("unable to write new index file");
- if (!opts->force)
+ if (!opts->force && !opts->quiet)
show_local_changes(&new->commit->object);
return 0;
diff --git a/builtin-clone.c b/builtin-clone.c
index c8435295c..5b40e07ba 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -58,7 +58,7 @@ static struct option builtin_clone_options[] = {
OPT_STRING(0, "reference", &option_reference, "repo",
"reference repository"),
OPT_STRING('o', "origin", &option_origin, "branch",
- "use <branch> instead or 'origin' to track upstream"),
+ "use <branch> instead of 'origin' to track upstream"),
OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
"path to git-upload-pack on the remote"),
OPT_STRING(0, "depth", &option_depth, "depth",
diff --git a/builtin-commit.c b/builtin-commit.c
index 8165bb3d3..6b23143cd 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -639,7 +639,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
active_cache_tree = cache_tree();
if (cache_tree_update(active_cache_tree,
active_cache, active_nr, 0, 0) < 0) {
- error("Error building trees");
+ error("Error building trees; the index is unmerged?");
return 0;
}
diff --git a/builtin-diff-files.c b/builtin-diff-files.c
index 9bf10bb37..2b578c714 100644
--- a/builtin-diff-files.c
+++ b/builtin-diff-files.c
@@ -50,7 +50,12 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
3 < rev.max_count)
usage(diff_files_usage);
- if (rev.max_count == -1 &&
+ /*
+ * "diff-files --base -p" should not combine merges because it
+ * was not asked to. "diff-files -c -p" should not densify
+ * (the user should ask with "diff-files --cc" explicitly).
+ */
+ if (rev.max_count == -1 && !rev.combine_merges &&
(rev.diffopt.output_format & DIFF_FORMAT_PATCH))
rev.combine_merges = rev.dense_combined_merges = 1;
diff --git a/builtin-diff.c b/builtin-diff.c
index 037c3039a..d5fe775fc 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -223,7 +223,13 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
argv++; argc--;
}
- if (revs->max_count == -1 &&
+ /*
+ * "diff --base" should not combine merges because it was not
+ * asked to. "diff -c" should not densify (if the user wants
+ * dense one, --cc can be explicitly asked for, or just rely
+ * on the default).
+ */
+ if (revs->max_count == -1 && !revs->combine_merges &&
(revs->diffopt.output_format & DIFF_FORMAT_PATCH))
revs->combine_merges = revs->dense_combined_merges = 1;
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index 21e92bbcb..72c087840 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -320,9 +320,7 @@ static const char *find_wholine(const char *who, int wholen, const char *buf, un
static const char *copy_line(const char *buf)
{
- const char *eol = strchr(buf, '\n');
- if (!eol)
- return "";
+ const char *eol = strchrnul(buf, '\n');
return xmemdupz(buf, eol - buf);
}
diff --git a/builtin-log.c b/builtin-log.c
index 1d3c5cbf5..d4aaddc9d 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -844,7 +844,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
committer = git_committer_info(IDENT_ERROR_ON_NO_NAME);
endpos = strchr(committer, '>');
if (!endpos)
- die("bogos committer info %s\n", committer);
+ die("bogus committer info %s\n", committer);
add_signoff = xmemdupz(committer, endpos - committer + 1);
}
else if (!strcmp(argv[i], "--attach")) {
diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c
index dfb363ee2..36aa79845 100644
--- a/builtin-merge-recursive.c
+++ b/builtin-merge-recursive.c
@@ -18,6 +18,7 @@
#include "ll-merge.h"
#include "interpolate.h"
#include "attr.h"
+#include "dir.h"
#include "merge-recursive.h"
static int subtree_merge;
@@ -416,24 +417,6 @@ static int update_stages(const char *path, struct diff_filespec *o,
return 0;
}
-static int remove_path(const char *name)
-{
- int ret;
- char *slash, *dirs;
-
- ret = unlink(name);
- if (ret)
- return ret;
- dirs = xstrdup(name);
- while ((slash = strrchr(name, '/'))) {
- *slash = '\0';
- if (rmdir(name) != 0)
- break;
- }
- free(dirs);
- return ret;
-}
-
static int remove_file(int clean, const char *path, int no_wd)
{
int update_cache = index_only || clean;
@@ -444,10 +427,8 @@ static int remove_file(int clean, const char *path, int no_wd)
return -1;
}
if (update_working_directory) {
- unlink(path);
- if (errno != ENOENT || errno != EISDIR)
+ if (remove_path(path))
return -1;
- remove_path(path);
}
return 0;
}
diff --git a/builtin-merge.c b/builtin-merge.c
index 9ad979106..1094c5fd5 100644
--- a/builtin-merge.c
+++ b/builtin-merge.c
@@ -476,6 +476,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
buf = xstrdup(v);
argc = split_cmdline(buf, &argv);
+ if (argc < 0)
+ die("Bad branch.%s.mergeoptions string", branch);
argv = xrealloc(argv, sizeof(*argv) * (argc + 2));
memmove(argv + 1, argv, sizeof(*argv) * (argc + 1));
argc++;
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 217fd49da..4004e73e4 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -465,7 +465,7 @@ static void write_pack_file(void)
char tmpname[PATH_MAX];
int fd;
snprintf(tmpname, sizeof(tmpname),
- "%s/tmp_pack_XXXXXX", get_object_directory());
+ "%s/pack/tmp_pack_XXXXXX", get_object_directory());
fd = xmkstemp(tmpname);
pack_tmp_name = xstrdup(tmpname);
f = sha1fd(fd, pack_tmp_name);
diff --git a/builtin-prune.c b/builtin-prune.c
index c767a0ac8..1663f8bdb 100644
--- a/builtin-prune.c
+++ b/builtin-prune.c
@@ -13,7 +13,7 @@ static const char * const prune_usage[] = {
static int show_only;
static unsigned long expire;
-static int prune_tmp_object(char *path, const char *filename)
+static int prune_tmp_object(const char *path, const char *filename)
{
const char *fullpath = mkpath("%s/%s", path, filename);
if (expire) {
@@ -110,24 +110,22 @@ static void prune_object_dir(const char *path)
/*
* Write errors (particularly out of space) can result in
* failed temporary packs (and more rarely indexes and other
- * files begining with "tmp_") accumulating in the
- * object directory.
+ * files begining with "tmp_") accumulating in the object
+ * and the pack directories.
*/
-static void remove_temporary_files(void)
+static void remove_temporary_files(const char *path)
{
DIR *dir;
struct dirent *de;
- char* dirname=get_object_directory();
- dir = opendir(dirname);
+ dir = opendir(path);
if (!dir) {
- fprintf(stderr, "Unable to open object directory %s\n",
- dirname);
+ fprintf(stderr, "Unable to open directory %s\n", path);
return;
}
while ((de = readdir(dir)) != NULL)
if (!prefixcmp(de->d_name, "tmp_"))
- prune_tmp_object(dirname, de->d_name);
+ prune_tmp_object(path, de->d_name);
closedir(dir);
}
@@ -141,6 +139,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
"expire objects older than <time>"),
OPT_END()
};
+ char *s;
save_commit_buffer = 0;
init_revisions(&revs, prefix);
@@ -163,6 +162,9 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
prune_object_dir(get_object_directory());
prune_packed_objects(show_only);
- remove_temporary_files();
+ remove_temporary_files(get_object_directory());
+ s = xstrdup(mkpath("%s/pack", get_object_directory()));
+ remove_temporary_files(s);
+ free(s);
return 0;
}
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index ac219ac2d..0706c9581 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -206,6 +206,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
break;
case 2:
opts.fn = twoway_merge;
+ opts.initial_checkout = !active_nr;
break;
case 3:
default:
diff --git a/builtin-remote.c b/builtin-remote.c
index 01945a865..90a4e3582 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -407,14 +407,15 @@ static int rm(int argc, const char **argv)
return i;
}
-static void show_list(const char *title, struct string_list *list)
+static void show_list(const char *title, struct string_list *list,
+ const char *extra_arg)
{
int i;
if (!list->nr)
return;
- printf(title, list->nr > 1 ? "es" : "");
+ printf(title, list->nr > 1 ? "es" : "", extra_arg);
printf("\n ");
for (i = 0; i < list->nr; i++)
printf("%s%s", i ? " " : "", list->items[i].string);
@@ -477,7 +478,6 @@ static int show(int argc, const char **argv)
memset(&states, 0, sizeof(states));
for (; argc; argc--, argv++) {
- struct strbuf buf;
int i;
get_remote_ref_states(*argv, &states, !no_query);
@@ -503,18 +503,16 @@ static int show(int argc, const char **argv)
}
if (!no_query) {
- strbuf_init(&buf, 0);
- strbuf_addf(&buf, " New remote branch%%s (next fetch "
- "will store in remotes/%s)", states.remote->name);
- show_list(buf.buf, &states.new);
- strbuf_release(&buf);
+ show_list(" New remote branch%s (next fetch "
+ "will store in remotes/%s)",
+ &states.new, states.remote->name);
show_list(" Stale tracking branch%s (use 'git remote "
- "prune')", &states.stale);
+ "prune')", &states.stale, "");
}
if (no_query)
for_each_ref(append_ref_to_tracked_list, &states);
- show_list(" Tracked remote branch%s", &states.tracked);
+ show_list(" Tracked remote branch%s", &states.tracked, "");
if (states.remote->push_refspec_nr) {
printf(" Local branch%s pushed with 'git push'\n ",
@@ -652,10 +650,13 @@ static int get_one_entry(struct remote *remote, void *priv)
{
struct string_list *list = priv;
- string_list_append(remote->name, list)->util = remote->url_nr ?
- (void *)remote->url[0] : NULL;
- if (remote->url_nr > 1)
- warning("Remote %s has more than one URL", remote->name);
+ if (remote->url_nr > 0) {
+ int i;
+
+ for (i = 0; i < remote->url_nr; i++)
+ string_list_append(remote->name, list)->util = (void *)remote->url[i];
+ } else
+ string_list_append(remote->name, list)->util = NULL;
return 0;
}
@@ -671,10 +672,14 @@ static int show_all(void)
sort_string_list(&list);
for (i = 0; i < list.nr; i++) {
struct string_list_item *item = list.items + i;
- printf("%s%s%s\n", item->string,
- verbose ? "\t" : "",
- verbose && item->util ?
- (const char *)item->util : "");
+ if (verbose)
+ printf("%s\t%s\n", item->string,
+ item->util ? (const char *)item->util : "");
+ else {
+ if (i && !strcmp((item - 1)->string, item->string))
+ continue;
+ printf("%s\n", item->string);
+ }
}
}
return result;
diff --git a/builtin-rm.c b/builtin-rm.c
index fdac34f24..50ae6d540 100644
--- a/builtin-rm.c
+++ b/builtin-rm.c
@@ -29,26 +29,6 @@ static void add_list(const char *name)
list.name[list.nr++] = name;
}
-static int remove_file(const char *name)
-{
- int ret;
- char *slash;
-
- ret = unlink(name);
- if (ret && errno == ENOENT)
- /* The user has removed it from the filesystem by hand */
- ret = errno = 0;
-
- if (!ret && (slash = strrchr(name, '/'))) {
- char *n = xstrdup(name);
- do {
- n[slash - name] = 0;
- name = n;
- } while (!rmdir(name) && (slash = strrchr(name, '/')));
- }
- return ret;
-}
-
static int check_local_mod(unsigned char *head, int index_only)
{
/* items in list are already sorted in the cache order,
@@ -239,7 +219,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
int removed = 0;
for (i = 0; i < list.nr; i++) {
const char *path = list.name[i];
- if (!remove_file(path)) {
+ if (!remove_path(path)) {
removed = 1;
continue;
}
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index d3fb6ae50..2d8d1c3d7 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -750,7 +750,7 @@ _git_commit ()
--*)
__gitcomp "
--all --author= --signoff --verify --no-verify
- --edit --amend --include --only
+ --edit --amend --include --only --interactive
"
return
esac
diff --git a/contrib/hooks/setgitperms.perl b/contrib/hooks/setgitperms.perl
index dab7c8e3a..a577ad095 100644
--- a/contrib/hooks/setgitperms.perl
+++ b/contrib/hooks/setgitperms.perl
@@ -50,7 +50,7 @@ if ((@ARGV < 0) || !GetOptions(
)) { die $usage; }
die $usage unless ($read_mode xor $write_mode);
-my $topdir = `git-rev-parse --show-cdup` or die "\n"; chomp $topdir;
+my $topdir = `git rev-parse --show-cdup` or die "\n"; chomp $topdir;
my $gitdir = $topdir . '.git';
my $gitmeta = $topdir . '.gitmeta';
@@ -155,7 +155,7 @@ elsif ($read_mode) {
open (OUT, ">$gitmeta.tmp") or die "Could not open $gitmeta.tmp for writing: $!\n";
}
- my @files = `git-ls-files`;
+ my @files = `git ls-files`;
my %dirs;
foreach my $path (@files) {
diff --git a/diff.c b/diff.c
index 05dd8f0b5..a3793f65e 100644
--- a/diff.c
+++ b/diff.c
@@ -2417,13 +2417,6 @@ int diff_setup_done(struct diff_options *options)
DIFF_OPT_SET(options, EXIT_WITH_STATUS);
}
- /*
- * If we postprocess in diffcore, we cannot simply return
- * upon the first hit. We need to run diff as usual.
- */
- if (options->pickaxe || options->filter)
- DIFF_OPT_CLR(options, QUIET);
-
return 0;
}
@@ -3411,10 +3404,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
void diffcore_std(struct diff_options *options)
{
- if (DIFF_OPT_TST(options, QUIET))
- return;
-
- if (options->skip_stat_unmatch && !DIFF_OPT_TST(options, FIND_COPIES_HARDER))
+ if (options->skip_stat_unmatch)
diffcore_skip_stat_unmatch(options);
if (options->break_opt != -1)
diffcore_break(options->break_opt);
diff --git a/diffcore.h b/diffcore.h
index cc96c2073..8ae35785f 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -92,7 +92,6 @@ extern struct diff_filepair *diff_queue(struct diff_queue_struct *,
struct diff_filespec *);
extern void diff_q(struct diff_queue_struct *, struct diff_filepair *);
-extern void diffcore_pathspec(const char **pathspec);
extern void diffcore_break(int);
extern void diffcore_rename(struct diff_options *);
extern void diffcore_merge_broken(void);
diff --git a/dir.c b/dir.c
index acf1001c4..1c3c50152 100644
--- a/dir.c
+++ b/dir.c
@@ -831,3 +831,23 @@ void setup_standard_excludes(struct dir_struct *dir)
if (excludes_file && !access(excludes_file, R_OK))
add_excludes_from_file(dir, excludes_file);
}
+
+int remove_path(const char *name)
+{
+ char *slash;
+
+ if (unlink(name) && errno != ENOENT)
+ return -1;
+
+ slash = strrchr(name, '/');
+ if (slash) {
+ char *dirs = xstrdup(name);
+ slash = dirs + (slash - name);
+ do {
+ *slash = '\0';
+ } while (rmdir(dirs) && (slash = strrchr(dirs, '/')));
+ free(dirs);
+ }
+ return 0;
+}
+
diff --git a/dir.h b/dir.h
index 2df15defb..278ee4229 100644
--- a/dir.h
+++ b/dir.h
@@ -81,4 +81,7 @@ extern int is_inside_dir(const char *dir);
extern void setup_standard_excludes(struct dir_struct *dir);
extern int remove_dir_recursively(struct strbuf *path, int only_empty);
+/* tries to remove the path with empty directories along it, ignores ENOENT */
+extern int remove_path(const char *path);
+
#endif
diff --git a/fast-import.c b/fast-import.c
index ccdf2e57b..ab6689a64 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -816,7 +816,7 @@ static void start_packfile(void)
int pack_fd;
snprintf(tmpfile, sizeof(tmpfile),
- "%s/tmp_pack_XXXXXX", get_object_directory());
+ "%s/pack/tmp_pack_XXXXXX", get_object_directory());
pack_fd = xmkstemp(tmpfile);
p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2);
strcpy(p->pack_name, tmpfile);
@@ -878,7 +878,7 @@ static char *create_index(void)
}
snprintf(tmpfile, sizeof(tmpfile),
- "%s/tmp_idx_XXXXXX", get_object_directory());
+ "%s/pack/tmp_idx_XXXXXX", get_object_directory());
idx_fd = xmkstemp(tmpfile);
f = sha1fd(idx_fd, tmpfile);
sha1write(f, array, 256 * sizeof(int));
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 929d681c4..edb6ec6ed 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -284,7 +284,7 @@ do_next () {
pick_one $sha1 ||
die_with_patch $sha1 "Could not apply $sha1... $rest"
make_patch $sha1
- : > "$DOTEST"/amend
+ git rev-parse --verify HEAD > "$DOTEST"/amend
warn "Stopped at $sha1... $rest"
warn "You can amend the commit now, with"
warn
@@ -427,14 +427,22 @@ do
else
. "$DOTEST"/author-script ||
die "Cannot find the author identity"
+ amend=
if test -f "$DOTEST"/amend
then
+ amend=$(git rev-parse --verify HEAD)
+ test "$amend" = $(cat "$DOTEST"/amend) ||
+ die "\
+You have uncommitted changes in your working tree. Please, commit them
+first and then run 'git rebase --continue' again."
git reset --soft HEAD^ ||
die "Cannot rewind the HEAD"
fi
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE &&
- git commit --no-verify -F "$DOTEST"/message -e ||
- die "Could not commit staged changes."
+ git commit --no-verify -F "$DOTEST"/message -e || {
+ test -n "$amend" && git reset --soft $amend
+ die "Could not commit staged changes."
+ }
fi
require_clean_work_tree
diff --git a/git-repack.sh b/git-repack.sh
index 683960b04..d39eb6cea 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -10,7 +10,7 @@ git repack [options]
a pack everything in a single pack
A same as -a, and turn unreachable objects loose
d remove redundant packs, and run git-prune-packed
-f pass --no-reuse-delta to git-pack-objects
+f pass --no-reuse-object to git-pack-objects
n do not run git-update-server-info
q,quiet be quiet
l pass --local to git-pack-objects
diff --git a/git-stash.sh b/git-stash.sh
index d799c7637..42f626f9d 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -144,7 +144,14 @@ show_stash () {
then
flags=--stat
fi
- s=$(git rev-parse --revs-only --no-flags --default $ref_stash "$@")
+
+ if test $# = 0
+ then
+ set x "$ref_stash@{0}"
+ shift
+ fi
+
+ s=$(git rev-parse --revs-only --no-flags "$@")
w_commit=$(git rev-parse --verify "$s") &&
b_commit=$(git rev-parse --verify "$s^") &&
@@ -154,7 +161,7 @@ show_stash () {
apply_stash () {
git update-index -q --refresh &&
git diff-files --quiet --ignore-submodules ||
- die 'Cannot restore on top of a dirty state'
+ die 'Cannot apply to a dirty working tree, please stage your changes'
unstash_index=
case "$1" in
@@ -163,13 +170,19 @@ apply_stash () {
shift
esac
+ if test $# = 0
+ then
+ set x "$ref_stash@{0}"
+ shift
+ fi
+
# current index state
c_tree=$(git write-tree) ||
die 'Cannot apply a stash in the middle of a merge'
# stash records the work tree, and is a merge between the
# base commit (first parent) and the index tree (second parent).
- s=$(git rev-parse --revs-only --no-flags --default $ref_stash "$@") &&
+ s=$(git rev-parse --revs-only --no-flags "$@") &&
w_tree=$(git rev-parse --verify "$s:") &&
b_tree=$(git rev-parse --verify "$s^1:") &&
i_tree=$(git rev-parse --verify "$s^2:") ||
diff --git a/git-submodule.sh b/git-submodule.sh
index 1c39b593a..c3d0d24bc 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -194,7 +194,7 @@ cmd_add()
else
module_clone "$path" "$realrepo" || exit
- (unset GIT_DIR; cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) ||
+ (unset GIT_DIR; cd "$path" && git checkout -f -q ${branch:+-b "$branch" "origin/$branch"}) ||
die "Unable to checkout submodule '$path'"
fi
@@ -340,8 +340,13 @@ cmd_update()
if test "$subsha1" != "$sha1"
then
+ force=
+ if test -z "$subsha1"
+ then
+ force="-f"
+ fi
(unset GIT_DIR; cd "$path" && git-fetch &&
- git-checkout -q "$sha1") ||
+ git-checkout $force -q "$sha1") ||
die "Unable to checkout '$sha1' in submodule path '$path'"
say "Submodule path '$path': checked out '$sha1'"
diff --git a/git-svn.perl b/git-svn.perl
index 2fe7bd3c4..af8279aca 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -4010,21 +4010,21 @@ sub gs_do_switch {
my $old_url = $full_url;
$full_url .= '/' . escape_uri_only($path) if length $path;
my ($ra, $reparented);
- if ($old_url ne $full_url) {
- if ($old_url !~ m#^svn(\+ssh)?://#) {
- SVN::_Ra::svn_ra_reparent($self->{session}, $full_url,
- $pool);
- $self->{url} = $full_url;
- $reparented = 1;
- } else {
- $_[0] = undef;
- $self = undef;
- $RA = undef;
- $ra = Git::SVN::Ra->new($full_url);
- $ra_invalid = 1;
- }
+
+ if ($old_url =~ m#^svn(\+ssh)?://#) {
+ $_[0] = undef;
+ $self = undef;
+ $RA = undef;
+ $ra = Git::SVN::Ra->new($full_url);
+ $ra_invalid = 1;
+ } elsif ($old_url ne $full_url) {
+ SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, $pool);
+ $self->{url} = $full_url;
+ $reparented = 1;
}
+
$ra ||= $self;
+ $url_b = escape_url($url_b);
my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool);
my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : ();
$reporter->set_path('', $rev_a, 0, @lock, $pool);
diff --git a/git.c b/git.c
index fdb0f7101..5582c515a 100644
--- a/git.c
+++ b/git.c
@@ -162,6 +162,8 @@ static int handle_alias(int *argcp, const char ***argv)
alias_string + 1, alias_command);
}
count = split_cmdline(alias_string, &new_argv);
+ if (count < 0)
+ die("Bad alias.%s string", alias_command);
option_count = handle_options(&new_argv, &count, &envchanged);
if (envchanged)
die("alias '%s' changes environment variables\n"
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 29e21564c..da474d082 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -2123,7 +2123,7 @@ sub parse_commit_text {
last;
}
}
- if ($co{'title'} eq "") {
+ if (! defined $co{'title'} || $co{'title'} eq "") {
$co{'title'} = $co{'title_short'} = '(no commit message)';
}
# remove added spaces
diff --git a/http.c b/http.c
index 1108ab4a3..a97fdf511 100644
--- a/http.c
+++ b/http.c
@@ -165,7 +165,16 @@ static CURL* get_curl_handle(void)
{
CURL* result = curl_easy_init();
- curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, curl_ssl_verify);
+ if (!curl_ssl_verify) {
+ curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 0);
+ } else {
+ /* Verify authenticity of the peer's certificate */
+ curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 1);
+ /* The name in the cert must match whom we tried to connect */
+ curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 2);
+ }
+
#if LIBCURL_VERSION_NUM >= 0x070907
curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
#endif
diff --git a/index-pack.c b/index-pack.c
index a6e91fe3b..530d82037 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -172,7 +172,7 @@ static char *open_pack_file(char *pack_name)
if (!pack_name) {
static char tmpfile[PATH_MAX];
snprintf(tmpfile, sizeof(tmpfile),
- "%s/tmp_pack_XXXXXX", get_object_directory());
+ "%s/pack/tmp_pack_XXXXXX", get_object_directory());
output_fd = xmkstemp(tmpfile);
pack_name = xstrdup(tmpfile);
} else
diff --git a/pack-write.c b/pack-write.c
index 939ed5636..3621f1dd3 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -45,7 +45,7 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects,
if (!index_name) {
static char tmpfile[PATH_MAX];
snprintf(tmpfile, sizeof(tmpfile),
- "%s/tmp_idx_XXXXXX", get_object_directory());
+ "%s/pack/tmp_idx_XXXXXX", get_object_directory());
fd = xmkstemp(tmpfile);
index_name = xstrdup(tmpfile);
} else {
diff --git a/read-cache.c b/read-cache.c
index 5150c1e14..5b1b3ad03 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1253,6 +1253,7 @@ int discard_index(struct index_state *istate)
istate->cache_nr = 0;
istate->cache_changed = 0;
istate->timestamp = 0;
+ istate->name_hash_initialized = 0;
free_hash(&istate->name_hash);
cache_tree_free(&(istate->cache_tree));
free(istate->alloc);
diff --git a/sha1_file.c b/sha1_file.c
index 9ee1ed16a..aec81bbae 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -2136,7 +2136,9 @@ static void write_sha1_file_prepare(const void *buf, unsigned long len,
*/
int move_temp_to_file(const char *tmpfile, const char *filename)
{
- int ret = link(tmpfile, filename);
+ int ret = 0;
+ if (link(tmpfile, filename))
+ ret = errno;
/*
* Coda hack - coda doesn't like cross-directory links,
diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh
index a841df2a9..5b5f28880 100644
--- a/t/lib-git-svn.sh
+++ b/t/lib-git-svn.sh
@@ -135,3 +135,20 @@ close $wr or die $!;
close $rd or die $!;
EOF
}
+
+require_svnserve () {
+ if test -z "$SVNSERVE_PORT"
+ then
+ say 'skipping svnserve test. (set $SVNSERVE_PORT to enable)'
+ test_done
+ exit
+ fi
+}
+
+start_svnserve () {
+ svnserve --listen-port $SVNSERVE_PORT \
+ --root "$rawsvnrepo" \
+ --listen-once \
+ --listen-host 127.0.0.1 &
+}
+
diff --git a/t/t0024-crlf-archive.sh b/t/t0024-crlf-archive.sh
new file mode 100644
index 000000000..e5330395f
--- /dev/null
+++ b/t/t0024-crlf-archive.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+test_description='respect crlf in git archive'
+
+. ./test-lib.sh
+UNZIP=${UNZIP:-unzip}
+
+test_expect_success setup '
+
+ git config core.autocrlf true
+
+ printf "CRLF line ending\r\nAnd another\r\n" > sample &&
+ git add sample &&
+
+ test_tick &&
+ git commit -m Initial
+
+'
+
+test_expect_success 'tar archive' '
+
+ git archive --format=tar HEAD |
+ ( mkdir untarred && cd untarred && "$TAR" -xf - )
+
+ test_cmp sample untarred/sample
+
+'
+
+"$UNZIP" -v >/dev/null 2>&1
+if [ $? -eq 127 ]; then
+ echo "Skipping ZIP test, because unzip was not found"
+ test_done
+ exit
+fi
+
+test_expect_success 'zip archive' '
+
+ git archive --format=zip HEAD >test.zip &&
+
+ ( mkdir unzipped && cd unzipped && unzip ../test.zip ) &&
+
+ test_cmp sample unzipped/sample
+
+'
+
+test_done
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 64567fb94..11b82f43d 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -741,4 +741,14 @@ test_expect_success 'symlinked configuration' '
'
+test_expect_success 'check split_cmdline return' "
+ git config alias.split-cmdline-fix 'echo \"' &&
+ test_must_fail git split-cmdline-fix &&
+ echo foo > foo &&
+ git add foo &&
+ git commit -m 'initial commit' &&
+ git config branch.master.mergeoptions 'echo \"' &&
+ test_must_fail git merge master
+ "
+
test_done
diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh
index de0cdb1cf..0de613dc5 100755
--- a/t/t3030-merge-recursive.sh
+++ b/t/t3030-merge-recursive.sh
@@ -535,4 +535,15 @@ test_expect_success 'reset and bind merge' '
'
+test_expect_success 'merge removes empty directories' '
+
+ git reset --hard master &&
+ git checkout -b rm &&
+ git rm d/e &&
+ git commit -mremoved-d/e &&
+ git checkout master &&
+ git merge -s recursive rm &&
+ test_must_fail test -d d
+'
+
test_done
diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh
index ae78e334a..c2b24a439 100755
--- a/t/t9113-git-svn-dcommit-new-file.sh
+++ b/t/t9113-git-svn-dcommit-new-file.sh
@@ -12,19 +12,7 @@ test_description='git-svn dcommit new files over svn:// test'
. ./lib-git-svn.sh
-if test -z "$SVNSERVE_PORT"
-then
- say 'skipping svnserve test. (set $SVNSERVE_PORT to enable)'
- test_done
- exit
-fi
-
-start_svnserve () {
- svnserve --listen-port $SVNSERVE_PORT \
- --root "$rawsvnrepo" \
- --listen-once \
- --listen-host 127.0.0.1 &
-}
+require_svnserve
test_expect_success 'start tracking an empty repo' '
svn mkdir -m "empty dir" "$svnrepo"/empty-dir &&
diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh
index 3281cbd34..43ceb75d5 100755
--- a/t/t9118-git-svn-funky-branch-names.sh
+++ b/t/t9118-git-svn-funky-branch-names.sh
@@ -6,6 +6,10 @@
test_description='git-svn funky branch names'
. ./lib-git-svn.sh
+# Abo-Uebernahme (Bug #994)
+scary_uri='Abo-Uebernahme%20%28Bug%20%23994%29'
+scary_ref='Abo-Uebernahme%20(Bug%20#994)'
+
test_expect_success 'setup svnrepo' '
mkdir project project/trunk project/branches project/tags &&
echo foo > project/trunk/foo &&
@@ -15,6 +19,8 @@ test_expect_success 'setup svnrepo' '
"$svnrepo/pr ject/branches/fun plugin" &&
svn cp -m "more fun!" "$svnrepo/pr ject/branches/fun plugin" \
"$svnrepo/pr ject/branches/more fun plugin!" &&
+ svn cp -m "scary" "$svnrepo/pr ject/branches/fun plugin" \
+ "$svnrepo/pr ject/branches/$scary_uri" &&
start_httpd
'
@@ -23,6 +29,7 @@ test_expect_success 'test clone with funky branch names' '
cd project &&
git rev-parse "refs/remotes/fun%20plugin" &&
git rev-parse "refs/remotes/more%20fun%20plugin!" &&
+ git rev-parse "refs/remotes/$scary_ref" &&
cd ..
'
@@ -35,6 +42,15 @@ test_expect_success 'test dcommit to funky branch' "
cd ..
"
+test_expect_success 'test dcommit to scary branch' '
+ cd project &&
+ git reset --hard "refs/remotes/$scary_ref" &&
+ echo urls are scary >> foo &&
+ git commit -m "eep" -- foo &&
+ git svn dcommit &&
+ cd ..
+ '
+
stop_httpd
test_done
diff --git a/t/t9126-git-svn-follow-deleted-readded-directory.sh b/t/t9126-git-svn-follow-deleted-readded-directory.sh
new file mode 100755
index 000000000..edec640e9
--- /dev/null
+++ b/t/t9126-git-svn-follow-deleted-readded-directory.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Alec Berryman
+
+test_description='git svn fetch repository with deleted and readded directory'
+
+. ./lib-git-svn.sh
+
+# Don't run this by default; it opens up a port.
+require_svnserve
+
+test_expect_success 'load repository' '
+ svnadmin load -q "$rawsvnrepo" < "$TEST_DIRECTORY"/t9126/follow-deleted-readded.dump
+ '
+
+test_expect_success 'fetch repository' '
+ start_svnserve &&
+ git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
+ git svn fetch
+ '
+
+test_done
diff --git a/t/t9126/follow-deleted-readded.dump b/t/t9126/follow-deleted-readded.dump
new file mode 100644
index 000000000..19da5d1dd
--- /dev/null
+++ b/t/t9126/follow-deleted-readded.dump
@@ -0,0 +1,201 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 1807dc6f-c693-4cda-9710-00e1be8c1f21
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2008-09-14T19:53:13.006748Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 111
+Content-length: 111
+
+K 7
+svn:log
+V 12
+Create trunk
+K 10
+svn:author
+V 4
+alec
+K 8
+svn:date
+V 27
+2008-09-14T19:53:13.239689Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 119
+Content-length: 119
+
+K 7
+svn:log
+V 20
+Create trunk/project
+K 10
+svn:author
+V 4
+alec
+K 8
+svn:date
+V 27
+2008-09-14T19:53:13.548860Z
+PROPS-END
+
+Node-path: trunk/project
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 3
+Prop-content-length: 111
+Content-length: 111
+
+K 7
+svn:log
+V 12
+add new file
+K 10
+svn:author
+V 4
+alec
+K 8
+svn:date
+V 27
+2008-09-14T19:53:15.433630Z
+PROPS-END
+
+Node-path: trunk/project/foo
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 4
+Text-content-md5: d3b07384d113edec49eaa6238ad5ff00
+Content-length: 14
+
+PROPS-END
+foo
+
+
+Revision-number: 4
+Prop-content-length: 116
+Content-length: 116
+
+K 7
+svn:log
+V 17
+change foo to bar
+K 10
+svn:author
+V 4
+alec
+K 8
+svn:date
+V 27
+2008-09-14T19:53:17.339884Z
+PROPS-END
+
+Node-path: trunk/project/foo
+Node-kind: file
+Node-action: change
+Text-content-length: 4
+Text-content-md5: c157a79031e1c40f85931829bc5fc552
+Content-length: 4
+
+bar
+
+
+Revision-number: 5
+Prop-content-length: 114
+Content-length: 114
+
+K 7
+svn:log
+V 15
+don't like that
+K 10
+svn:author
+V 4
+alec
+K 8
+svn:date
+V 27
+2008-09-14T19:53:19.335001Z
+PROPS-END
+
+Node-path: trunk/project
+Node-action: delete
+
+
+Revision-number: 6
+Prop-content-length: 110
+Content-length: 110
+
+K 7
+svn:log
+V 11
+reset trunk
+K 10
+svn:author
+V 4
+alec
+K 8
+svn:date
+V 27
+2008-09-14T19:53:19.845897Z
+PROPS-END
+
+Node-path: trunk/project
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 4
+Node-copyfrom-path: trunk/project
+
+
+Revision-number: 7
+Prop-content-length: 113
+Content-length: 113
+
+K 7
+svn:log
+V 14
+change to quux
+K 10
+svn:author
+V 4
+alec
+K 8
+svn:date
+V 27
+2008-09-14T19:53:21.367947Z
+PROPS-END
+
+Node-path: trunk/project/foo
+Node-kind: file
+Node-action: change
+Text-content-length: 5
+Text-content-md5: d3b07a382ec010c01889250fce66fb13
+Content-length: 5
+
+quux
+
+
diff --git a/templates/Makefile b/templates/Makefile
index 0722a926f..a12c6e214 100644
--- a/templates/Makefile
+++ b/templates/Makefile
@@ -31,9 +31,11 @@ boilerplates.made : $(bpsrc)
dir=`expr "$$dst" : '\(.*\)/'` && \
mkdir -p blt/$$dir && \
case "$$boilerplate" in \
- *--) ;; \
- *) cp -p $$boilerplate blt/$$dst ;; \
- esac || exit; \
+ *--) continue;; \
+ esac && \
+ cp $$boilerplate blt/$$dst && \
+ if test -x "blt/$$dst"; then rx=rx; else rx=r; fi && \
+ chmod a+$$rx "blt/$$dst" || exit; \
done && \
date >$@
diff --git a/unpack-trees.c b/unpack-trees.c
index ef21c6219..e59d144d2 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -941,8 +941,17 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
return -1;
}
}
- else if (newtree)
+ else if (newtree) {
+ if (oldtree && !o->initial_checkout) {
+ /*
+ * deletion of the path was staged;
+ */
+ if (same(oldtree, newtree))
+ return 1;
+ return reject_merge(oldtree, o);
+ }
return merged_entry(newtree, current, o);
+ }
return deleted_entry(oldtree, current, o);
}
diff --git a/unpack-trees.h b/unpack-trees.h
index 94e567265..0d26f3d73 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -26,6 +26,7 @@ struct unpack_trees_options {
verbose_update:1,
aggressive:1,
skip_unmerged:1,
+ initial_checkout:1,
gently:1;
const char *prefix;
int pos;