Merge commit 'v1.6.3.2' into devel

Conflicts:
	Makefile
	decorate.c
	object.c

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin
2009-06-07 11:54:07 +02:00
71 changed files with 720 additions and 163 deletions

View File

@@ -0,0 +1,61 @@
GIT v1.6.3.2 Release Notes
==========================
Fixes since v1.6.3.1
--------------------
* A few codepaths picked up the first few bytes from an sha1[] by
casting the (char *) pointer to (int *); GCC 4.4 did not like this,
and aborted compilation.
* Some unlink(2) failures went undiagnosed.
* The "recursive" merge strategy misbehaved when faced rename/delete
conflicts while coming up with an intermediate merge base.
* The low-level merge algorithm did not handle a degenerate case of
merging a file with itself using itself as the common ancestor
gracefully. It should produce the file itself, but instead
produced an empty result.
* GIT_TRACE mechanism segfaulted when tracing a shell-quoted aliases.
* OpenBSD also uses st_ctimspec in "struct stat", instead of "st_ctim".
* With NO_CROSS_DIRECTORY_HARDLINKS, "make install" can be told not to
create hardlinks between $(gitexecdir)/git-$builtin_commands and
$(bindir)/git.
* command completion code in bash did not reliably detect that we are
in a bare repository.
* "git add ." in an empty directory complained that pathspec "." did not
match anything, which may be technically correct, but not useful. We
silently make it a no-op now.
* "git add -p" (and "patch" action in "git add -i") was broken when
the first hunk that adds a line at the top was split into two and
both halves are marked to be used.
* "git blame path" misbehaved at the commit where path became file
from a directory with some files in it.
* "git for-each-ref" had a segfaulting bug when dealing with a tag object
created by an ancient git.
* "git format-patch -k" still added patch numbers if format.numbered
configuration was set.
* "git grep --color ''" did not terminate. The command also had
subtle bugs with its -w option.
* http-push had a small use-after-free bug.
* "git push" was converting OFS_DELTA pack representation into less
efficient REF_DELTA representation unconditionally upon transfer,
making the transferred data unnecessarily larger.
* "git remote show origin" segfaulted when origin was still empty.
Many other general usability updates around help text, diagnostic messages
and documentation are included as well.

View File

@@ -9,8 +9,8 @@ git-cat-file - Provide content or type and size information for repository objec
SYNOPSIS
--------
[verse]
'git cat-file' [-t | -s | -e | -p | <type>] <object>
'git cat-file' [--batch | --batch-check] < <list-of-objects>
'git cat-file' (-t | -s | -e | -p | <type>) <object>
'git cat-file' (--batch | --batch-check) < <list-of-objects>
DESCRIPTION
-----------

View File

@@ -82,8 +82,10 @@ Output Format
-------------
<mode> SP <type> SP <object> TAB <file>
When the `-z` option is not used, TAB, LF, and backslash characters
Unless the `-z` option is used, TAB, LF, and backslash characters
in pathnames are represented as `\t`, `\n`, and `\\`, respectively.
This output format is compatible with what '--index-info --stdin' of
'git update-index' expects.
When the `-l` option is used, format changes to

View File

@@ -75,14 +75,22 @@ show [<stash>]::
it will accept any format known to 'git-diff' (e.g., `git stash show
-p stash@\{1}` to view the second most recent stash in patch form).
pop [<stash>]::
Remove a single stashed state from the stash list and apply it
on top of the current working tree state, i.e., do the inverse
operation of `git stash save`. The working directory must
match the index.
+
Applying the state can fail with conflicts; in this case, it is not
removed from the stash list. You need to resolve the conflicts by hand
and call `git stash drop` manually afterwards.
+
When no `<stash>` is given, `stash@\{0}` is assumed. See also `apply`.
apply [--index] [<stash>]::
Restore the changes recorded in the stash on top of the current
working tree state. When no `<stash>` is given, applies the latest
one. The working directory must match the index.
+
This operation can fail with conflicts; you need to resolve them
by hand in the working tree.
Like `pop`, but do not remove the state from the stash list.
+
If the `--index` option is used, then tries to reinstate not only the working
tree's changes, but also the index's ones. However, this can fail, when you
@@ -112,12 +120,6 @@ drop [<stash>]::
Remove a single stashed state from the stash list. When no `<stash>`
is given, it removes the latest one. i.e. `stash@\{0}`
pop [<stash>]::
Remove a single stashed state from the stash list and apply on top
of the current working tree state. When no `<stash>` is given,
`stash@\{0}` is assumed. See also `apply`.
create::
Create a stash (which is a regular commit object) and return its
@@ -163,7 +165,7 @@ $ git pull
file foobar not up to date, cannot merge.
$ git stash
$ git pull
$ git stash apply
$ git stash pop
----------------------------------------------------------------
Interrupted workflow::
@@ -192,7 +194,7 @@ You can use 'git-stash' to simplify the above, like this:
$ git stash
$ edit emergency fix
$ git commit -a -m "Fix in a hurry"
$ git stash apply
$ git stash pop
# ... continue hacking ...
----------------------------------------------------------------

View File

@@ -39,7 +39,8 @@
--squash::
Produce the working tree and index state as if a real
merge happened, but do not actually make a commit or
merge happened (except for the merge information),
but do not actually make a commit or
move the `HEAD`, nor record `$GIT_DIR/MERGE_HEAD` to
cause the next `git commit` command to create a merge
commit. This allows you to create a single commit on

View File

@@ -198,7 +198,7 @@ The function must be defined in this form:
The callback mechanism is as follows:
* Inside `funct`, the only interesting member of the structure
* Inside `func`, the only interesting member of the structure
given by `opt` is the void pointer `opt->value`.
`\*opt->value` will be the value that is saved into `var`, if you
use `OPT_CALLBACK()`.

View File

@@ -1520,10 +1520,10 @@ $ git commit -a -m "blorpl: typofix"
------------------------------------------------
After that, you can go back to what you were working on with
`git stash apply`:
`git stash pop`:
------------------------------------------------
$ git stash apply
$ git stash pop
------------------------------------------------

View File

@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
DEF_VER=v1.6.3.1
DEF_VER=v1.6.3.2
LF='
'

View File

@@ -176,6 +176,9 @@ all::
# when hardlinking a file to another name and unlinking the original file right
# away (some NTFS drivers seem to zero the contents in that scenario).
#
# Define NO_CROSS_DIRECTORY_HARDLINKS if you plan to distribute the installed
# programs as a tar, where bin/ and libexec/ might be on different file systems.
#
# Define USE_NED_ALLOCATOR if you want to replace the platforms default
# memory allocators with the nedmalloc allocator written by Niall Douglas.
@@ -753,6 +756,7 @@ endif
ifeq ($(uname_S),OpenBSD)
NO_STRCASESTR = YesPlease
NO_MEMMEM = YesPlease
USE_ST_TIMESPEC = YesPlease
NEEDS_LIBICONV = YesPlease
BASIC_CFLAGS += -I/usr/local/include
BASIC_LDFLAGS += -L/usr/local/lib
@@ -1569,6 +1573,7 @@ endif
bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
{ $(RM) "$$execdir/git-add$X" && \
test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
ln "$$bindir/git$X" "$$execdir/git-add$X" 2>/dev/null || \
cp "$$bindir/git$X" "$$execdir/git-add$X"; } && \
{ for p in $(filter-out git-add$X,$(BUILT_INS)); do \

View File

@@ -1 +1 @@
Documentation/RelNotes-1.6.3.1.txt
Documentation/RelNotes-1.6.3.2.txt

View File

@@ -38,10 +38,7 @@ int split_cmdline(char *cmdline, const char ***argv)
while (cmdline[++src]
&& isspace(cmdline[src]))
; /* skip */
if (count >= size) {
size += 16;
*argv = xrealloc(*argv, sizeof(char *) * size);
}
ALLOC_GROW(*argv, count+1, size);
(*argv)[count++] = cmdline + dst;
} else if (!quoted && (c == '\'' || c == '"')) {
quoted = c;
@@ -72,6 +69,9 @@ int split_cmdline(char *cmdline, const char ***argv)
return error("unclosed quote");
}
ALLOC_GROW(*argv, count+1, size);
(*argv)[count] = NULL;
return count;
}

View File

@@ -61,7 +61,7 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
fill_pathspec_matches(pathspec, seen, specs);
for (i = 0; i < specs; i++) {
if (!seen[i] && !file_exists(pathspec[i]))
if (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))
die("pathspec '%s' did not match any files",
pathspec[i]);
}

View File

@@ -2781,7 +2781,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
if (rmdir(patch->old_name))
warning("unable to remove submodule %s",
patch->old_name);
} else if (!unlink(patch->old_name) && rmdir_empty) {
} else if (!unlink_or_warn(patch->old_name) && rmdir_empty) {
remove_path(patch->old_name);
}
}
@@ -2891,7 +2891,7 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
if (!try_create_file(newpath, mode, buf, size)) {
if (!rename(newpath, path))
return;
unlink(newpath);
unlink_or_warn(newpath);
break;
}
if (errno != EEXIST)
@@ -3315,6 +3315,10 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
argc = parse_options(argc, argv, builtin_apply_options,
apply_usage, 0);
fake_ancestor = parse_options_fix_filename(prefix, fake_ancestor);
if (fake_ancestor)
fake_ancestor = xstrdup(fake_ancestor);
if (apply_with_reject)
apply = apply_verbosely = 1;
if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))

View File

@@ -362,18 +362,28 @@ static struct origin *find_origin(struct scoreboard *sb,
"", &diff_opts);
diffcore_std(&diff_opts);
/* It is either one entry that says "modified", or "created",
* or nothing.
*/
if (!diff_queued_diff.nr) {
/* The path is the same as parent */
porigin = get_origin(sb, parent, origin->path);
hashcpy(porigin->blob_sha1, origin->blob_sha1);
}
else if (diff_queued_diff.nr != 1)
die("internal error in blame::find_origin");
else {
struct diff_filepair *p = diff_queued_diff.queue[0];
} else {
/*
* Since origin->path is a pathspec, if the parent
* commit had it as a directory, we will see a whole
* bunch of deletion of files in the directory that we
* do not care about.
*/
int i;
struct diff_filepair *p = NULL;
for (i = 0; i < diff_queued_diff.nr; i++) {
const char *name;
p = diff_queued_diff.queue[i];
name = p->one->path ? p->one->path : p->two->path;
if (!strcmp(name, origin->path))
break;
}
if (!p)
die("internal error in blame::find_origin");
switch (p->status) {
default:
die("internal error in blame::find_origin (%c)",

View File

@@ -201,8 +201,8 @@ static int batch_objects(int print_contents)
}
static const char * const cat_file_usage[] = {
"git cat-file [-t|-s|-e|-p|<type>] <sha1>",
"git cat-file [--batch|--batch-check] < <list_of_sha1s>",
"git cat-file (-t|-s|-e|-p|<type>) <object>",
"git cat-file (--batch|--batch-check) < <list_of_objects>",
NULL
};

View File

@@ -216,7 +216,7 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_locked_index(lock_file, 1);
if (read_cache() < 0)
if (read_cache_preload(pathspec) < 0)
return error("corrupt index file");
if (source_tree)
@@ -366,7 +366,7 @@ static int merge_working_tree(struct checkout_opts *opts,
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
int newfd = hold_locked_index(lock_file, 1);
if (read_cache() < 0)
if (read_cache_preload(NULL) < 0)
return error("corrupt index file");
if (opts->force) {
@@ -541,14 +541,6 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
parse_commit(new->commit);
}
/*
* If we were on a detached HEAD, but we are now moving to
* a new commit, we want to mention the old commit once more
* to remind the user that it might be lost.
*/
if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
describe_detached_head("Previous HEAD position was", old.commit);
if (!old.commit && !opts->force) {
if (!opts->quiet) {
warning("You appear to be on a branch yet to be born.");
@@ -561,6 +553,14 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
if (ret)
return ret;
/*
* If we were on a detached HEAD, but have now moved to
* a new commit, we want to mention the old commit once more
* to remind the user that it might be lost.
*/
if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
describe_detached_head("Previous HEAD position was", old.commit);
update_refs_for_switch(opts, &old, new);
ret = post_checkout_hook(old.commit, new->commit, 1);

View File

@@ -228,7 +228,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
}
if (unlink(dest->buf) && errno != ENOENT)
die("failed to unlink %s", dest->buf);
die("failed to unlink %s: %s",
dest->buf, strerror(errno));
if (!option_no_hardlinks) {
if (!link(src->buf, dest->buf))
continue;

View File

@@ -699,7 +699,11 @@ static int parse_and_validate_options(int argc, const char *argv[],
argc = parse_options(argc, argv, builtin_commit_options, usage, 0);
logfile = parse_options_fix_filename(prefix, logfile);
if (logfile)
logfile = xstrdup(logfile);
template_file = parse_options_fix_filename(prefix, template_file);
if (template_file)
template_file = xstrdup(template_file);
if (force_author && !strchr(force_author, '>'))
force_author = find_author_by_nickname(force_author);

View File

@@ -825,7 +825,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
fd = hold_lock_file_for_update(&lock, shallow,
LOCK_DIE_ON_ERROR);
if (!write_shallow_commits(fd, 0)) {
unlink(shallow);
unlink_or_warn(shallow);
rollback_lock_file(&lock);
} else {
commit_lock_file(&lock);

View File

@@ -167,6 +167,9 @@ static struct ref *get_ref_map(struct transport *transport,
return ref_map;
}
#define STORE_REF_ERROR_OTHER 1
#define STORE_REF_ERROR_DF_CONFLICT 2
static int s_update_ref(const char *action,
struct ref *ref,
int check_old)
@@ -181,9 +184,11 @@ static int s_update_ref(const char *action,
lock = lock_any_ref_for_update(ref->name,
check_old ? ref->old_sha1 : NULL, 0);
if (!lock)
return 2;
return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
STORE_REF_ERROR_OTHER;
if (write_ref_sha1(lock, ref->new_sha1, msg) < 0)
return 2;
return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
STORE_REF_ERROR_OTHER;
return 0;
}
@@ -377,7 +382,7 @@ static int store_updated_refs(const char *url, const char *remote_name,
}
}
fclose(fp);
if (rc & 2)
if (rc & STORE_REF_ERROR_DF_CONFLICT)
error("some local refs could not be updated; try running\n"
" 'git remote prune %s' to remove any old, conflicting "
"branches", remote_name);

View File

@@ -363,6 +363,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, options, fmt_merge_msg_usage, 0);
if (argc > 0)
usage_with_options(fmt_merge_msg_usage, options);
inpath = parse_options_fix_filename(prefix, inpath);
if (inpath && strcmp(inpath, "-")) {
in = fopen(inpath, "r");

View File

@@ -339,8 +339,11 @@ static const char *copy_name(const char *buf)
static const char *copy_email(const char *buf)
{
const char *email = strchr(buf, '<');
const char *eoemail = strchr(email, '>');
if (!email || !eoemail)
const char *eoemail;
if (!email)
return "";
eoemail = strchr(email, '>');
if (!eoemail)
return "";
return xmemdupz(email, eoemail + 1 - email);
}

View File

@@ -755,6 +755,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int cover_letter = 0;
int boundary_count = 0;
int no_binary_diff = 0;
int numbered_cmdline_opt = 0;
struct commit *origin = NULL, *head = NULL;
const char *in_reply_to = NULL;
struct patch_ids ids;
@@ -786,8 +787,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (!strcmp(argv[i], "--stdout"))
use_stdout = 1;
else if (!strcmp(argv[i], "-n") ||
!strcmp(argv[i], "--numbered"))
!strcmp(argv[i], "--numbered")) {
numbered = 1;
numbered_cmdline_opt = 1;
}
else if (!strcmp(argv[i], "-N") ||
!strcmp(argv[i], "--no-numbered")) {
numbered = 0;
@@ -918,6 +921,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (start_number < 0)
start_number = 1;
/*
* If numbered is set solely due to format.numbered in config,
* and it would conflict with --keep-subject (-k) from the
* command line, reset "numbered".
*/
if (numbered && keep_subject && !numbered_cmdline_opt)
numbered = 0;
if (numbered && keep_subject)
die ("-n and -k are mutually exclusive.");
if (keep_subject && subject_prefix)

View File

@@ -28,8 +28,8 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
memcpy(pathname + len, de->d_name, 38);
if (opts & DRY_RUN)
printf("rm -f %s\n", pathname);
else if (unlink(pathname) < 0)
error("unable to unlink %s", pathname);
else
unlink_or_warn(pathname);
display_progress(progress, i + 1);
}
pathname[len] = 0;

View File

@@ -27,7 +27,7 @@ static int prune_tmp_object(const char *path, const char *filename)
}
printf("Removing stale temporary file %s\n", fullpath);
if (!show_only)
unlink(fullpath);
unlink_or_warn(fullpath);
return 0;
}
@@ -47,7 +47,7 @@ static int prune_object(char *path, const char *filename, const unsigned char *s
(type > 0) ? typename(type) : "unknown");
}
if (!show_only)
unlink(fullpath);
unlink_or_warn(fullpath);
return 0;
}

View File

@@ -27,10 +27,9 @@ static int receive_unpack_limit = -1;
static int transfer_unpack_limit = -1;
static int unpack_limit = 100;
static int report_status;
static int prefer_ofs_delta = 1;
static const char *head_name;
static char capabilities[] = " report-status delete-refs ";
static int capabilities_sent;
static char *capabilities_to_send;
static enum deny_action parse_deny_action(const char *var, const char *value)
{
@@ -84,24 +83,29 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return 0;
}
if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
prefer_ofs_delta = git_config_bool(var, value);
return 0;
}
return git_default_config(var, value, cb);
}
static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
{
if (capabilities_sent)
if (!capabilities_to_send)
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
else
packet_write(1, "%s %s%c%s\n",
sha1_to_hex(sha1), path, 0, capabilities);
capabilities_sent = 1;
sha1_to_hex(sha1), path, 0, capabilities_to_send);
capabilities_to_send = NULL;
return 0;
}
static void write_head_info(void)
{
for_each_ref(show_ref, NULL);
if (!capabilities_sent)
if (capabilities_to_send)
show_ref("capabilities^{}", null_sha1, 0, NULL);
}
@@ -687,6 +691,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
else if (0 <= receive_unpack_limit)
unpack_limit = receive_unpack_limit;
capabilities_to_send = (prefer_ofs_delta) ?
" report-status delete-refs ofs-delta " :
" report-status delete-refs ";
add_alternate_refs();
write_head_info();
clear_extra_refs();
@@ -702,7 +710,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
unpack_status = unpack();
execute_commands(unpack_status);
if (pack_lockfile)
unlink(pack_lockfile);
unlink_or_warn(pack_lockfile);
if (report_status)
report(unpack_status);
run_receive_hook(post_receive_hook);

View File

@@ -299,11 +299,11 @@ static int get_push_ref_states(const struct ref *remote_refs,
return 0;
local_refs = get_local_heads();
ref = push_map = copy_ref_list(remote_refs);
while (ref->next)
ref = ref->next;
push_tail = &ref->next;
push_map = copy_ref_list(remote_refs);
push_tail = &push_map;
while (*push_tail)
push_tail = &((*push_tail)->next);
match_refs(local_refs, push_map, &push_tail, remote->push_refspec_nr,
remote->push_refspec, MATCH_REFS_NONE);
@@ -525,8 +525,8 @@ static int migrate_file(struct remote *remote)
path = git_path("remotes/%s", remote->name);
else if (remote->origin == REMOTE_BRANCHES)
path = git_path("branches/%s", remote->name);
if (path && unlink(path))
warning("failed to remove '%s'", path);
if (path)
unlink_or_warn(path);
return 0;
}

View File

@@ -116,7 +116,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
if (!has_rerere_resolution(name))
unlink_rr_item(name);
}
unlink(git_path("rr-cache/MERGE_RR"));
unlink_or_warn(git_path("rr-cache/MERGE_RR"));
} else if (!strcmp(argv[1], "gc"))
garbage_collect(&merge_rr);
else if (!strcmp(argv[1], "status"))

View File

@@ -43,12 +43,16 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
"--stdout",
NULL,
NULL,
NULL,
};
struct child_process po;
int i;
i = 4;
if (args->use_thin_pack)
argv[4] = "--thin";
argv[i++] = "--thin";
if (args->use_ofs_delta)
argv[i++] = "--delta-base-offset";
memset(&po, 0, sizeof(po));
po.argv = argv;
po.in = -1;
@@ -315,6 +319,8 @@ int send_pack(struct send_pack_args *args,
ask_for_status_report = 1;
if (server_supports("delete-refs"))
allow_deleting_refs = 1;
if (server_supports("ofs-delta"))
args->use_ofs_delta = 1;
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"

View File

@@ -576,7 +576,7 @@ static void parse_reflog_param(const char *arg, int *cnt, const char **base)
if (*ep == ',')
*base = ep + 1;
else if (*ep)
die("unrecognized reflog param '%s'", arg + 9);
die("unrecognized reflog param '%s'", arg);
else
*base = NULL;
if (*cnt <= 0)

View File

@@ -338,7 +338,7 @@ static void create_tag(const unsigned char *object, const char *tag,
exit(128);
}
if (path) {
unlink(path);
unlink_or_warn(path);
free(path);
}
}

View File

@@ -55,7 +55,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
close(gpg.in);
ret = finish_command(&gpg);
unlink(path);
unlink_or_warn(path);
return ret;
}

View File

@@ -99,20 +99,32 @@ __git_ps1 ()
elif [ -d "$g/rebase-merge" ]; then
r="|REBASE-m"
b="$(cat "$g/rebase-merge/head-name")"
elif [ -f "$g/MERGE_HEAD" ]; then
r="|MERGING"
b="$(git symbolic-ref HEAD 2>/dev/null)"
else
if [ -f "$g/MERGE_HEAD" ]; then
r="|MERGING"
fi
if [ -f "$g/BISECT_LOG" ]; then
r="|BISECTING"
fi
if ! b="$(git symbolic-ref HEAD 2>/dev/null)"; then
if ! b="$(git describe --exact-match HEAD 2>/dev/null)"; then
if [ -r "$g/HEAD" ]; then
b="$(cut -c1-7 "$g/HEAD")..."
fi
fi
fi
b="$(git symbolic-ref HEAD 2>/dev/null)" || {
b="$(
case "${GIT_PS1_DESCRIBE_STYLE-}" in
(contains)
git describe --contains HEAD ;;
(branch)
git describe --contains --all HEAD ;;
(describe)
git describe HEAD ;;
(* | default)
git describe --exact-match HEAD ;;
esac 2>/dev/null)" ||
b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
b="unknown"
b="($b)"
}
fi
local w
@@ -120,7 +132,7 @@ __git_ps1 ()
local c
if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
if [ "true" = "$(git config --bool core.bare 2>/dev/null)" ]; then
if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
c="BARE:"
else
b="GIT_DIR!"
@@ -1792,7 +1804,7 @@ _git_show ()
return
;;
--*)
__gitcomp "--pretty= --format=
__gitcomp "--pretty= --format= --abbrev-commit --oneline
$__git_diff_common_options
"
return
@@ -1809,7 +1821,7 @@ _git_show_branch ()
__gitcomp "
--all --remotes --topo-order --current --more=
--list --independent --merge-base --no-name
--sha1-name --topics --reflog
--sha1-name --sparse --topics --reflog
"
return
;;

View File

@@ -8,8 +8,9 @@
static unsigned int hash_obj(const struct object *obj, unsigned int n)
{
const void *p = obj->sha1;
unsigned int hash = *(const unsigned int *)p;
unsigned int hash;
memcpy(&hash, obj->sha1, sizeof(unsigned int));
return hash % n;
}

View File

@@ -214,7 +214,7 @@ static int get_stat_data(struct cache_entry *ce,
const unsigned char *sha1 = ce->sha1;
unsigned int mode = ce->ce_mode;
if (!cached) {
if (!cached && !ce_uptodate(ce)) {
int changed;
struct stat st;
changed = check_removed(ce, &st);

2
diff.c
View File

@@ -189,7 +189,7 @@ static void remove_tempfile(void)
int i;
for (i = 0; i < ARRAY_SIZE(diff_temp); i++) {
if (diff_temp[i].name == diff_temp[i].tmp_path)
unlink(diff_temp[i].name);
unlink_or_warn(diff_temp[i].name);
diff_temp[i].name = NULL;
}
}

2
dir.c
View File

@@ -576,7 +576,7 @@ static int get_dtype(struct dirent *de, const char *path)
*/
static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
{
DIR *fdir = opendir(path);
DIR *fdir = opendir(*path ? path : ".");
int contents = 0;
if (fdir) {

View File

@@ -35,7 +35,7 @@ static void create_directories(const char *path, int path_len,
*/
if (mkdir(buf, 0777)) {
if (errno == EEXIST && state->force &&
!unlink(buf) && !mkdir(buf, 0777))
!unlink_or_warn(buf) && !mkdir(buf, 0777))
continue;
die("cannot create directory at %s", buf);
}

View File

@@ -931,7 +931,7 @@ static void unkeep_all_packs(void)
struct packed_git *p = all_packs[k];
snprintf(name, sizeof(name), "%s/pack/pack-%s.keep",
get_object_directory(), sha1_to_hex(p->sha1));
unlink(name);
unlink_or_warn(name);
}
}
@@ -981,7 +981,7 @@ static void end_packfile(void)
}
else {
close(old_p->pack_fd);
unlink(old_p->pack_name);
unlink_or_warn(old_p->pack_name);
}
free(old_p);

View File

@@ -767,6 +767,96 @@ sub split_hunk {
return @split;
}
sub find_last_o_ctx {
my ($it) = @_;
my $text = $it->{TEXT};
my ($o_ofs, $o_cnt) = parse_hunk_header($text->[0]);
my $i = @{$text};
my $last_o_ctx = $o_ofs + $o_cnt;
while (0 < --$i) {
my $line = $text->[$i];
if ($line =~ /^ /) {
$last_o_ctx--;
next;
}
last;
}
return $last_o_ctx;
}
sub merge_hunk {
my ($prev, $this) = @_;
my ($o0_ofs, $o0_cnt, $n0_ofs, $n0_cnt) =
parse_hunk_header($prev->{TEXT}[0]);
my ($o1_ofs, $o1_cnt, $n1_ofs, $n1_cnt) =
parse_hunk_header($this->{TEXT}[0]);
my (@line, $i, $ofs, $o_cnt, $n_cnt);
$ofs = $o0_ofs;
$o_cnt = $n_cnt = 0;
for ($i = 1; $i < @{$prev->{TEXT}}; $i++) {
my $line = $prev->{TEXT}[$i];
if ($line =~ /^\+/) {
$n_cnt++;
push @line, $line;
next;
}
last if ($o1_ofs <= $ofs);
$o_cnt++;
$ofs++;
if ($line =~ /^ /) {
$n_cnt++;
}
push @line, $line;
}
for ($i = 1; $i < @{$this->{TEXT}}; $i++) {
my $line = $this->{TEXT}[$i];
if ($line =~ /^\+/) {
$n_cnt++;
push @line, $line;
next;
}
$ofs++;
$o_cnt++;
if ($line =~ /^ /) {
$n_cnt++;
}
push @line, $line;
}
my $head = ("@@ -$o0_ofs" .
(($o_cnt != 1) ? ",$o_cnt" : '') .
" +$n0_ofs" .
(($n_cnt != 1) ? ",$n_cnt" : '') .
" @@\n");
@{$prev->{TEXT}} = ($head, @line);
}
sub coalesce_overlapping_hunks {
my (@in) = @_;
my @out = ();
my ($last_o_ctx, $last_was_dirty);
for (grep { $_->{USE} } @in) {
my $text = $_->{TEXT};
my ($o_ofs) = parse_hunk_header($text->[0]);
if (defined $last_o_ctx &&
$o_ofs <= $last_o_ctx &&
!$_->{DIRTY} &&
!$last_was_dirty) {
merge_hunk($out[-1], $_);
}
else {
push @out, $_;
}
$last_o_ctx = find_last_o_ctx($out[-1]);
$last_was_dirty = $_->{DIRTY};
}
return @out;
}
sub color_diff {
return map {
@@ -878,7 +968,8 @@ sub edit_hunk_loop {
my $newhunk = {
TEXT => $text,
TYPE => $hunk->[$ix]->{TYPE},
USE => 1
USE => 1,
DIRTY => 1,
};
if (diff_applies($head,
@{$hunk}[0..$ix-1],
@@ -1210,6 +1301,8 @@ sub patch_update_file {
}
}
@hunk = coalesce_overlapping_hunks(@hunk);
my $n_lofs = 0;
my @result = ();
for (@hunk) {

View File

@@ -415,4 +415,10 @@ void git_qsort(void *base, size_t nmemb, size_t size,
#define fstat_is_reliable() 1
#endif
/*
* Preserves errno, prints a message, but gives no warning for ENOENT.
* Always returns the return value of unlink(2).
*/
int unlink_or_warn(const char *path);
#endif

14
grep.c
View File

@@ -305,6 +305,7 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
{
int hit = 0;
int saved_ch = 0;
const char *start = bol;
if ((p->token != GREP_PATTERN) &&
((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD)))
@@ -330,7 +331,7 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
if (hit && p->word_regexp) {
if ((pmatch[0].rm_so < 0) ||
(eol - bol) <= pmatch[0].rm_so ||
(eol - bol) < pmatch[0].rm_so ||
(pmatch[0].rm_eo < 0) ||
(eol - bol) < pmatch[0].rm_eo)
die("regexp returned nonsense");
@@ -349,6 +350,10 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
else
hit = 0;
/* Words consist of at least one character. */
if (pmatch->rm_so == pmatch->rm_eo)
hit = 0;
if (!hit && pmatch[0].rm_so + bol + 1 < eol) {
/* There could be more than one match on the
* line, and the first match might not be
@@ -359,12 +364,17 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
bol = pmatch[0].rm_so + bol + 1;
while (word_char(bol[-1]) && bol < eol)
bol++;
eflags |= REG_NOTBOL;
if (bol < eol)
goto again;
}
}
if (p->token == GREP_PATTERN_HEAD && saved_ch)
*eol = saved_ch;
if (hit) {
pmatch[0].rm_so += bol - start;
pmatch[0].rm_eo += bol - start;
}
return hit;
}
@@ -494,6 +504,8 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
*eol = '\0';
while (next_match(opt, bol, eol, ctx, &match, eflags)) {
if (match.rm_so == match.rm_eo)
break;
printf("%.*s%s%.*s%s",
(int)match.rm_so, bol,
opt->color_match,

View File

@@ -315,9 +315,9 @@ static void start_fetch_loose(struct transfer_request *request)
"%s.temp", filename);
snprintf(prevfile, sizeof(prevfile), "%s.prev", request->filename);
unlink(prevfile);
unlink_or_warn(prevfile);
rename(request->tmpfile, prevfile);
unlink(request->tmpfile);
unlink_or_warn(request->tmpfile);
if (request->local_fileno != -1)
error("fd leakage in start: %d", request->local_fileno);
@@ -372,7 +372,7 @@ static void start_fetch_loose(struct transfer_request *request)
} while (prev_read > 0);
close(prevlocal);
}
unlink(prevfile);
unlink_or_warn(prevfile);
/* Reset inflate/SHA1 if there was an error reading the previous temp
file; also rewind to the beginning of the local file. */
@@ -784,7 +784,7 @@ static void finish_request(struct transfer_request *request)
request->http_code != 416) {
if (stat(request->tmpfile, &st) == 0) {
if (st.st_size == 0)
unlink(request->tmpfile);
unlink_or_warn(request->tmpfile);
}
} else {
if (request->http_code == 416)
@@ -793,9 +793,9 @@ static void finish_request(struct transfer_request *request)
git_inflate_end(&request->stream);
git_SHA1_Final(request->real_sha1, &request->c);
if (request->zret != Z_STREAM_END) {
unlink(request->tmpfile);
unlink_or_warn(request->tmpfile);
} else if (hashcmp(request->obj->sha1, request->real_sha1)) {
unlink(request->tmpfile);
unlink_or_warn(request->tmpfile);
} else {
request->rename =
move_temp_to_file(
@@ -1415,8 +1415,9 @@ static void remove_locks(void)
fprintf(stderr, "Removing remote locks...\n");
while (lock) {
struct remote_lock *next = lock->next;
unlock_remote(lock);
lock = lock->next;
lock = next;
}
}

View File

@@ -111,9 +111,9 @@ static void start_object_request(struct walker *walker,
struct walker_data *data = walker->data;
snprintf(prevfile, sizeof(prevfile), "%s.prev", obj_req->filename);
unlink(prevfile);
unlink_or_warn(prevfile);
rename(obj_req->tmpfile, prevfile);
unlink(obj_req->tmpfile);
unlink_or_warn(obj_req->tmpfile);
if (obj_req->local != -1)
error("fd leakage in start: %d", obj_req->local);
@@ -177,7 +177,7 @@ static void start_object_request(struct walker *walker,
} while (prev_read > 0);
close(prevlocal);
}
unlink(prevfile);
unlink_or_warn(prevfile);
/* Reset inflate/SHA1 if there was an error reading the previous temp
file; also rewind to the beginning of the local file. */
@@ -238,18 +238,18 @@ static void finish_object_request(struct object_request *obj_req)
} else if (obj_req->curl_result != CURLE_OK) {
if (stat(obj_req->tmpfile, &st) == 0)
if (st.st_size == 0)
unlink(obj_req->tmpfile);
unlink_or_warn(obj_req->tmpfile);
return;
}
git_inflate_end(&obj_req->stream);
git_SHA1_Final(obj_req->real_sha1, &obj_req->c);
if (obj_req->zret != Z_STREAM_END) {
unlink(obj_req->tmpfile);
unlink_or_warn(obj_req->tmpfile);
return;
}
if (hashcmp(obj_req->sha1, obj_req->real_sha1)) {
unlink(obj_req->tmpfile);
unlink_or_warn(obj_req->tmpfile);
return;
}
obj_req->rename =
@@ -809,7 +809,7 @@ static void abort_object_request(struct object_request *obj_req)
close(obj_req->local);
obj_req->local = -1;
}
unlink(obj_req->tmpfile);
unlink_or_warn(obj_req->tmpfile);
if (obj_req->slot) {
release_active_slot(obj_req->slot);
obj_req->slot = NULL;

View File

@@ -219,7 +219,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,
close(fd);
bad:
for (i = 0; i < 3; i++)
unlink(temp[i]);
unlink_or_warn(temp[i]);
strbuf_release(&cmd);
return status;
}

View File

@@ -16,7 +16,7 @@ static void remove_lock_file(void)
lock_file_list->filename[0]) {
if (lock_file_list->fd >= 0)
close(lock_file_list->fd);
unlink(lock_file_list->filename);
unlink_or_warn(lock_file_list->filename);
}
lock_file_list = lock_file_list->next;
}
@@ -259,7 +259,7 @@ void rollback_lock_file(struct lock_file *lk)
if (lk->filename[0]) {
if (lk->fd >= 0)
close(lk->fd);
unlink(lk->filename);
unlink_or_warn(lk->filename);
}
lk->filename[0] = 0;
}

View File

@@ -933,11 +933,12 @@ static int process_renames(struct merge_options *o,
ren1_src, ren1_dst, branch1,
branch2);
update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst);
update_stages(ren1_dst, NULL,
branch1 == o->branch1 ?
ren1->pair->two : NULL,
branch1 == o->branch1 ?
NULL : ren1->pair->two, 1);
if (!o->call_depth)
update_stages(ren1_dst, NULL,
branch1 == o->branch1 ?
ren1->pair->two : NULL,
branch1 == o->branch1 ?
NULL : ren1->pair->two, 1);
} else if (!sha_eq(dst_other.sha1, null_sha1)) {
const char *new_path;
clean_merge = 0;

View File

@@ -45,8 +45,8 @@ int type_from_string(const char *str)
static unsigned int hash_obj(struct object *obj, unsigned int n)
{
const void *p = obj->sha1;
unsigned int hash = *(const unsigned int *)p;
unsigned int hash;
memcpy(&hash, obj->sha1, sizeof(unsigned int));
return hash % n;
}

View File

@@ -66,7 +66,7 @@ static void prune_ref(struct ref_to_prune *r)
struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1);
if (lock) {
unlink(git_path("%s", r->name));
unlink_or_warn(git_path("%s", r->name));
unlock_ref(lock);
}
}

19
refs.c
View File

@@ -893,8 +893,10 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
* name is a proper prefix of our refname.
*/
if (missing &&
!is_refname_available(ref, NULL, get_packed_refs(), 0))
!is_refname_available(ref, NULL, get_packed_refs(), 0)) {
last_errno = ENOTDIR;
goto error_return;
}
lock->lk = xcalloc(1, sizeof(struct lock_file));
@@ -1002,12 +1004,10 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
} else {
path = git_path("%s", refname);
}
err = unlink(path);
if (err && errno != ENOENT) {
err = unlink_or_warn(path);
if (err && errno != ENOENT)
ret = 1;
error("unlink(%s) failed: %s",
path, strerror(errno));
}
if (!(delopt & REF_NODEREF))
lock->lk->filename[i] = '.';
}
@@ -1017,10 +1017,7 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
*/
ret |= repack_without_ref(refname);
err = unlink(git_path("logs/%s", lock->ref_name));
if (err && errno != ENOENT)
warning("unlink(%s) failed: %s",
git_path("logs/%s", lock->ref_name), strerror(errno));
unlink_or_warn(git_path("logs/%s", lock->ref_name));
invalidate_cached_refs();
unlock_ref(lock);
return ret;
@@ -1381,7 +1378,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
if (adjust_shared_perm(git_HEAD)) {
error("Unable to fix permissions on %s", lockpath);
error_unlink_return:
unlink(lockpath);
unlink_or_warn(lockpath);
error_free_return:
free(git_HEAD);
return -1;

View File

@@ -173,7 +173,7 @@ static int handle_file(const char *path,
git_SHA1_Final(sha1, &ctx);
if (hunk != RR_CONTEXT) {
if (output)
unlink(output);
unlink_or_warn(output);
return error("Could not parse conflict hunks in %s", path);
}
if (wrerror)

View File

@@ -6,6 +6,7 @@ struct send_pack_args {
send_mirror:1,
force_update:1,
use_thin_pack:1,
use_ofs_delta:1,
dry_run:1;
};

View File

@@ -246,7 +246,7 @@ int update_server_info(int force)
errs = errs | update_info_packs(force);
/* remove leftover rev-cache file if there is any */
unlink(git_path("info/rev-cache"));
unlink_or_warn(git_path("info/rev-cache"));
return errs;
}

View File

@@ -720,6 +720,8 @@ static int open_packed_git_1(struct packed_git *p)
return error("packfile %s index unavailable", p->pack_name);
p->pack_fd = open(p->pack_name, O_RDONLY);
while (p->pack_fd < 0 && errno == EMFILE && unuse_one_window(p, -1))
p->pack_fd = open(p->pack_name, O_RDONLY);
if (p->pack_fd < 0 || fstat(p->pack_fd, &st))
return -1;
@@ -937,6 +939,8 @@ static void prepare_packed_git_one(char *objdir, int local)
sprintf(path, "%s/pack", objdir);
len = strlen(path);
dir = opendir(path);
while (!dir && errno == EMFILE && unuse_one_window(packed_git, -1))
dir = opendir(path);
if (!dir) {
if (errno != ENOENT)
error("unable to open object pack directory: %s: %s",
@@ -2247,7 +2251,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
goto out;
ret = errno;
}
unlink(tmpfile);
unlink_or_warn(tmpfile);
if (ret) {
if (ret != EEXIST) {
return error("unable to write sha1 filename %s: %s\n", filename, strerror(ret));
@@ -2339,6 +2343,8 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
filename = sha1_file_name(sha1);
fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
while (fd < 0 && errno == EMFILE && unuse_one_window(packed_git, -1))
fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
if (fd < 0) {
if (errno == EACCES)
return error("insufficient permission for adding an object to repository database %s\n", get_object_directory());

95
t/t3031-merge-criscross.sh Executable file
View File

@@ -0,0 +1,95 @@
#!/bin/sh
test_description='merge-recursive backend test'
. ./test-lib.sh
# A <- create some files
# / \
# B C <- cause rename/delete conflicts between B and C
# / \
# |\ /|
# | D E |
# | \ / |
# | X |
# | / \ |
# | / \ |
# |/ \|
# F G <- merge E into B, D into C
# \ /
# \ /
# \ /
# H <- recursive merge crashes
#
# initialize
test_expect_success 'setup repo with criss-cross history' '
mkdir data &&
# create a bunch of files
n=1 &&
while test $n -le 10
do
echo $n > data/$n &&
n=$(($n+1)) ||
break
done &&
# check them in
git add data &&
git commit -m A &&
git branch A &&
# a file in one branch
git checkout -b B A &&
git rm data/9 &&
git add data &&
git commit -m B &&
# with a branch off of it
git branch D &&
# put some commits on D
git checkout D &&
echo testD > data/testD &&
git add data &&
git commit -m D &&
# back up to the top, create another branch and cause
# a rename conflict with the file we deleted earlier
git checkout -b C A &&
git mv data/9 data/new-9 &&
git add data &&
git commit -m C &&
# with a branch off of it
git branch E &&
# put a commit on E
git checkout E &&
echo testE > data/testE &&
git add data &&
git commit -m E &&
# now, merge E into B
git checkout B &&
test_must_fail git merge E &&
# force-resolve
git add data &&
git commit -m F &&
git branch F &&
# and merge D into C
git checkout C &&
test_must_fail git merge D &&
# force-resolve
git add data &&
git commit -m G &&
git branch G
'
test_expect_success 'recursive merge between F and G, causes segfault' '
git merge F
'
test_done

View File

@@ -165,4 +165,42 @@ test_expect_success FILEMODE 'stage mode but not hunk' '
# end of tests disabled when filemode is not usable
test_expect_success 'setup again' '
git reset --hard &&
test_chmod +x file &&
echo content >>file
'
# Write the patch file with a new line at the top and bottom
cat >patch <<EOF
index 180b47c..b6f2c08 100644
--- a/file
+++ b/file
@@ -1,2 +1,4 @@
+firstline
baseline
content
+lastline
EOF
# Expected output, similar to the patch but w/ diff at the top
cat >expected <<EOF
diff --git a/file b/file
index b6f2c08..61b9053 100755
--- a/file
+++ b/file
@@ -1,2 +1,4 @@
+firstline
baseline
content
+lastline
EOF
# Test splitting the first patch, then adding both
test_expect_success 'add first line works' '
git commit -am "clear local changes" &&
git apply patch &&
(echo s; echo y; echo y) | git add -p file &&
git diff --cached > diff &&
test_cmp expected diff
'
test_done

View File

@@ -505,4 +505,15 @@ test_expect_success 'format-patch from a subdirectory (3)' '
test -f "$basename"
'
test_expect_success 'format-patch --in-reply-to' '
git format-patch -1 --stdout --in-reply-to "baz@foo.bar" > patch8 &&
grep "^In-Reply-To: <baz@foo.bar>" patch8 &&
grep "^References: <baz@foo.bar>" patch8
'
test_expect_success 'format-patch --signoff' '
git format-patch -1 --signoff --stdout |
grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
'
test_done

View File

@@ -86,6 +86,13 @@ test_expect_success 'format.numbered && --no-numbered' '
'
test_expect_success 'format.numbered && --keep-subject' '
git format-patch --keep-subject --stdout HEAD^ >patch4a &&
grep "^Subject: Third" patch4a
'
test_expect_success 'format.numbered = auto' '
git config format.numbered auto
@@ -108,4 +115,10 @@ test_expect_success 'format.numbered = auto && --no-numbered' '
'
test_expect_success '--start-number && --numbered' '
git format-patch --start-number 3 --numbered --stdout HEAD~1 > patch8 &&
grep "^Subject: \[PATCH 3/3\]" patch8
'
test_done

42
t/t4131-apply-fake-ancestor.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/bin/sh
#
# Copyright (c) 2009 Stephen Boyd
#
test_description='git apply --build-fake-ancestor handling.'
. ./test-lib.sh
test_expect_success 'setup' '
test_commit 1 &&
test_commit 2 &&
mkdir sub &&
test_commit 3 sub/3 &&
test_commit 4
'
test_expect_success 'apply --build-fake-ancestor' '
git checkout 2 &&
echo "A" > 1.t &&
git diff > 1.patch &&
git reset --hard &&
git checkout 1 &&
git apply --build-fake-ancestor 1.ancestor 1.patch
'
test_expect_success 'apply --build-fake-ancestor in a subdirectory' '
git checkout 3 &&
echo "C" > sub/3.t &&
git diff > 3.patch &&
git reset --hard &&
git checkout 4 &&
(
cd sub &&
git apply --build-fake-ancestor 3.ancestor ../3.patch &&
test -f 3.ancestor
) &&
git apply --build-fake-ancestor 3.ancestor 3.patch &&
test_cmp sub/3.ancestor 3.ancestor
'
test_done

View File

@@ -494,5 +494,15 @@ test_expect_success 'remote prune to cause a dangling symref' '
grep "dangling symref" err
'
test_expect_success 'show empty remote' '
test_create_repo empty &&
git clone empty empty-clone &&
(
cd empty-clone &&
git remote show origin
)
'
test_done

View File

@@ -54,6 +54,12 @@ deduxit me super semitas jusitiae,
EOF
printf "propter nomen suum." >> new4.txt
test_expect_success 'merge with no changes' '
cp orig.txt test.txt &&
git merge-file test.txt orig.txt orig.txt &&
test_cmp test.txt orig.txt
'
cp new1.txt test.txt
test_expect_success "merge without conflict" \
"git merge-file test.txt orig.txt new2.txt"

View File

@@ -209,4 +209,36 @@ test_expect_success 'merge-msg test #5-2' '
test_cmp expected actual
'
test_expect_success 'merge-msg -F' '
git config --unset-all merge.log
git config --unset-all merge.summary
git config merge.summary yes &&
git checkout master &&
setdate &&
git fetch . left right &&
git fmt-merge-msg -F .git/FETCH_HEAD >actual &&
test_cmp expected actual
'
test_expect_success 'merge-msg -F in subdirectory' '
git config --unset-all merge.log
git config --unset-all merge.summary
git config merge.summary yes &&
git checkout master &&
setdate &&
git fetch . left right &&
mkdir sub &&
cp .git/FETCH_HEAD sub/FETCH_HEAD &&
(
cd sub &&
git fmt-merge-msg -F FETCH_HEAD >../actual
) &&
test_cmp expected actual
'
test_done

View File

@@ -16,12 +16,13 @@ test_expect_success setup '
echo foo mmap bar_mmap
echo foo_mmap bar mmap baz
} >file &&
echo ww w >w &&
echo x x xx x >x &&
echo y yy >y &&
echo zzz > z &&
mkdir t &&
echo test >t/t &&
git add file x y z t/t &&
git add file w x y z t/t &&
test_tick &&
git commit -m initial
'
@@ -48,6 +49,12 @@ do
diff expected actual
'
test_expect_success "grep -w $L (w)" '
: >expected &&
! git grep -n -w -e "^w" >actual &&
test_cmp expected actual
'
test_expect_success "grep -w $L (x)" '
{
echo ${HC}x:1:x x xx x

View File

@@ -534,4 +534,12 @@ test_expect_success 'failing checkout -b should not break working tree' '
'
test_expect_success 'switch out of non-branch' '
git reset --hard master &&
git checkout master^0 &&
echo modified >one &&
test_must_fail git checkout renamer 2>error.log &&
! grep "^Previous HEAD" error.log
'
test_done

View File

@@ -183,4 +183,14 @@ test_expect_success 'commit message from stdin' '
commit_msg_is "Log with foo word"
'
test_expect_success 'commit -F overrides -t' '
(
cd subdir &&
echo "-F log" > f.log &&
echo "-t template" > t.template &&
git commit --allow-empty -F f.log -t t.template
) &&
commit_msg_is "-F log"
'
test_done

View File

@@ -129,4 +129,19 @@ test_expect_success 'blame wholesale copy and more' '
'
test_expect_success 'blame path that used to be a directory' '
mkdir path &&
echo A A A A A >path/file &&
echo B B B B B >path/elif &&
git add path &&
test_tick &&
git commit -m "path was a directory" &&
rm -fr path &&
echo A A A A A >path &&
git add path &&
test_tick &&
git commit -m "path is a regular file" &&
git blame HEAD^.. -- path
'
test_done

View File

@@ -7,7 +7,7 @@
#
# To enable this hook, rename this file to "pre-commit".
if git-rev-parse --verify HEAD 2>/dev/null
if git-rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else

View File

@@ -1069,7 +1069,7 @@ int transport_fetch_refs(struct transport *transport, const struct ref *refs)
void transport_unlock_pack(struct transport *transport)
{
if (transport->pack_lockfile) {
unlink(transport->pack_lockfile);
unlink_or_warn(transport->pack_lockfile);
free(transport->pack_lockfile);
transport->pack_lockfile = NULL;
}

View File

@@ -61,7 +61,7 @@ static void unlink_entry(struct cache_entry *ce)
{
if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
return;
if (unlink(ce->name))
if (unlink_or_warn(ce->name))
return;
schedule_dir_for_removal(ce->name, ce_namelen(ce));
}

View File

@@ -289,3 +289,19 @@ int odb_pack_keep(char *name, size_t namesz, unsigned char *sha1)
safe_create_leading_directories(name);
return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
}
int unlink_or_warn(const char *file)
{
int rc = unlink(file);
if (rc < 0) {
int err = errno;
if (ENOENT != err) {
warning("unable to unlink %s: %s",
file, strerror(errno));
errno = err;
}
}
return rc;
}

View File

@@ -563,23 +563,22 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
return -1;
}
status = 0;
if (xscr1 || xscr2) {
if (!xscr1) {
result->ptr = xdl_malloc(mf2->size);
memcpy(result->ptr, mf2->ptr, mf2->size);
result->size = mf2->size;
} else if (!xscr2) {
result->ptr = xdl_malloc(mf1->size);
memcpy(result->ptr, mf1->ptr, mf1->size);
result->size = mf1->size;
} else {
status = xdl_do_merge(&xe1, xscr1, name1,
&xe2, xscr2, name2,
flags, xpp, result);
}
xdl_free_script(xscr1);
xdl_free_script(xscr2);
if (!xscr1) {
result->ptr = xdl_malloc(mf2->size);
memcpy(result->ptr, mf2->ptr, mf2->size);
result->size = mf2->size;
} else if (!xscr2) {
result->ptr = xdl_malloc(mf1->size);
memcpy(result->ptr, mf1->ptr, mf1->size);
result->size = mf1->size;
} else {
status = xdl_do_merge(&xe1, xscr1, name1,
&xe2, xscr2, name2,
flags, xpp, result);
}
xdl_free_script(xscr1);
xdl_free_script(xscr2);
xdl_free_env(&xe1);
xdl_free_env(&xe2);