Merge branch 'maint' into bc/master-diff-hunk-header-fix

* maint: (41 commits)
  Clarify commit error message for unmerged files
  Use strchrnul() instead of strchr() plus manual workaround
  Use remove_path from dir.c instead of own implementation
  Add remove_path: a function to remove as much as possible of a path
  git-submodule: Fix "Unable to checkout" for the initial 'update'
  Clarify how the user can satisfy stash's 'dirty state' check.
  Remove empty directories in recursive merge
  Documentation: clarify the details of overriding LESS via core.pager
  Update release notes for 1.6.0.3
  checkout: Do not show local changes when in quiet mode
  for-each-ref: Fix --format=%(subject) for log message without newlines
  git-stash.sh: don't default to refs/stash if invalid ref supplied
  maint: check return of split_cmdline to avoid bad config strings
  builtin-prune.c: prune temporary packs in <object_dir>/pack directory
  Do not perform cross-directory renames when creating packs
  Use dashless git commands in setgitperms.perl
  git-remote: do not use user input in a printf format string
  make "git remote" report multiple URLs
  Start draft release notes for 1.6.0.3
  git-repack uses --no-repack-object, not --no-repack-delta.
  ...

Conflicts:
	RelNotes
This commit is contained in:
Shawn O. Pearce 2008-09-29 10:52:34 -07:00
commit 5a139ba483
52 changed files with 600 additions and 196 deletions

View file

@ -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

View file

@ -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

View file

@ -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
~~~~~~~~~~~

View file

@ -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::

View file

@ -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"]

View file

@ -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"
----------------------------------------------------

View file

@ -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);
}
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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",

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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")) {

View file

@ -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;
}

View file

@ -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++;

View file

@ -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);

View file

@ -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;
}

View file

@ -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:

View file

@ -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;

View file

@ -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;
}

View file

@ -750,7 +750,7 @@ _git_commit ()
--*)
__gitcomp "
--all --author= --signoff --verify --no-verify
--edit --amend --include --only
--edit --amend --include --only --interactive
"
return
esac

View file

@ -50,7 +50,7 @@
)) { 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 @@
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) {

12
diff.c
View file

@ -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);

View file

@ -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);

20
dir.c
View file

@ -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;
}

3
dir.h
View file

@ -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

View file

@ -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));

View file

@ -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

View file

@ -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

View file

@ -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:") ||

View file

@ -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'"

View file

@ -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);

2
git.c
View file

@ -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"

View file

@ -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

11
http.c
View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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);

View file

@ -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,

View file

@ -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 &
}

46
t/t0024-crlf-archive.sh Normal file
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 &&

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 >$@

View file

@ -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);
}

View file

@ -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;