diff options
69 files changed, 879 insertions, 370 deletions
diff --git a/Documentation/RelNotes/2.6.4.txt b/Documentation/RelNotes/2.6.4.txt new file mode 100644 index 0000000000..b0256a2dc9 --- /dev/null +++ b/Documentation/RelNotes/2.6.4.txt @@ -0,0 +1,63 @@ +Git v2.6.4 Release Notes +======================== + +Fixes since v2.6.3 +------------------ + + * The "configure" script did not test for -lpthread correctly, which + upset some linkers. + + * Add support for talking http/https over socks proxy. + + * Portability fix for Windows, which may rewrite $SHELL variable using + non-POSIX paths. + + * We now consistently allow all hooks to ignore their standard input, + rather than having git complain of SIGPIPE. + + * Fix shell quoting in contrib script. + + * Test portability fix for a topic in v2.6.1. + + * Allow tilde-expansion in some http config variables. + + * Give a useful special case "diff/show --word-diff-regex=." as an + example in the documentation. + + * Fix for a corner case in filter-branch. + + * Make git-p4 work on a detached head. + + * Documentation clarification for "check-ignore" without "--verbose". + + * Just like the working tree is cleaned up when the user cancelled + submission in P4Submit.applyCommit(), clean up the mess if "p4 + submit" fails. + + * Having a leftover .idx file without corresponding .pack file in + the repository hurts performance; "git gc" learned to prune them. + + * The code to prepare the working tree side of temporary directory + for the "dir-diff" feature forgot that symbolic links need not be + copied (or symlinked) to the temporary area, as the code already + special cases and overwrites them. Besides, it was wrong to try + computing the object name of the target of symbolic link, which may + not even exist or may be a directory. + + * There was no way to defeat a configured rebase.autostash variable + from the command line, as "git rebase --no-autostash" was missing. + + * Allow "git interpret-trailers" to run outside of a Git repository. + + * Produce correct "dirty" marker for shell prompts, even when we + are on an orphan or an unborn branch. + + * Some corner cases have been fixed in string-matching done in "git + status". + + * Apple's common crypto implementation of SHA1_Update() does not take + more than 4GB at a time, and we now have a compile-time workaround + for it. + +Also contains typofixes, documentation updates and trivial code +clean-ups. diff --git a/Documentation/RelNotes/2.6.5.txt b/Documentation/RelNotes/2.6.5.txt new file mode 100644 index 0000000000..3e6331d9dc --- /dev/null +++ b/Documentation/RelNotes/2.6.5.txt @@ -0,0 +1,39 @@ +Git v2.6.5 Release Notes +======================== + +Fixes since v2.6.4 +------------------ + + * Because "test_when_finished" in our test framework queues the + clean-up tasks to be done in a shell variable, it should not be + used inside a subshell. Add a mechanism to allow 'bash' to catch + such uses, and fix the ones that were found. + + * Update "git subtree" (in contrib/) so that it can take whitespaces + in the pathnames, not only in the in-tree pathname but the name of + the directory that the repository is in. + + * Cosmetic improvement to lock-file error messages. + + * mark_tree_uninteresting() has code to handle the case where it gets + passed a NULL pointer in its 'tree' parameter, but the function had + 'object = &tree->object' assignment before checking if tree is + NULL. This gives a compiler an excuse to declare that tree will + never be NULL and apply a wrong optimization. Avoid it. + + * The helper used to iterate over loose object directories to prune + stale objects did not closedir() immediately when it is done with a + directory--a callback such as the one used for "git prune" may want + to do rmdir(), but it would fail on open directory on platforms + such as WinXP. + + * "git p4" used to import Perforce CLs that touch only paths outside + the client spec as empty commits. It has been corrected to ignore + them instead, with a new configuration git-p4.keepEmptyCommits as a + backward compatibility knob. + + * The exit code of git-fsck did not reflect some types of errors + found in packed objects, which has been corrected. + +Also contains typofixes, documentation updates and trivial code +clean-ups. diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index d56ca90998..306b7e3604 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -267,6 +267,9 @@ expression to make sure that it matches all non-whitespace characters. A match that contains a newline is silently truncated(!) at the newline. + +For example, `--word-diff-regex=.` will treat each character as a word +and, correspondingly, show differences character by character. ++ The regex can also be set via a diff driver or configuration option, see linkgit:gitattributes[1] or linkgit:git-config[1]. Giving it explicitly overrides any diff driver or configuration setting. Diff drivers diff --git a/Documentation/git-check-ignore.txt b/Documentation/git-check-ignore.txt index 59531abba4..e94367a5ed 100644 --- a/Documentation/git-check-ignore.txt +++ b/Documentation/git-check-ignore.txt @@ -16,10 +16,9 @@ DESCRIPTION ----------- For each pathname given via the command-line or from a file via -`--stdin`, show the pattern from .gitignore (or other input files to -the exclude mechanism) that decides if the pathname is excluded or -included. Later patterns within a file take precedence over earlier -ones. +`--stdin`, check whether the file is excluded by .gitignore (or other +input files to the exclude mechanism) and output the path if it is +excluded. By default, tracked files are not shown at all since they are not subject to exclude rules; but see `--no-index'. @@ -32,7 +31,8 @@ OPTIONS -v, --verbose:: Also output details about the matching pattern (if any) - for each given pathname. + for each given pathname. For precedence rules within and + between exclude sources, see linkgit:gitignore[5]. --stdin:: Read pathnames from the standard input, one per line, diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index 9044dfaada..91a3622ee4 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -60,7 +60,7 @@ Git imposes the following rules on how references are named: These rules make it easy for shell script based tools to parse reference names, pathname expansion by the shell when a reference name is used -unquoted (by mistake), and also avoids ambiguities in certain +unquoted (by mistake), and also avoid ambiguities in certain reference name expressions (see linkgit:gitrevisions[7]): . A double-dot `..` is often used as in `ref1..ref2`, and in some diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt index 82aa5d6073..b3e768ee81 100644 --- a/Documentation/git-p4.txt +++ b/Documentation/git-p4.txt @@ -510,6 +510,10 @@ git-p4.useClientSpec:: option '--use-client-spec'. See the "CLIENT SPEC" section above. This variable is a boolean, not the name of a p4 client. +git-p4.keepEmptyCommits:: + A changelist that contains only excluded files will be imported + as an empty commit if this boolean option is set to true. + Submit variables ~~~~~~~~~~~~~~~~ git-p4.detectRenames:: diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index bccfdf7fde..6cca8bb51d 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -434,7 +434,8 @@ If the '--autosquash' option is enabled by default using the configuration variable `rebase.autoSquash`, this option can be used to override and disable this setting. ---[no-]autostash:: +--autostash:: +--no-autostash:: Automatically create a temporary stash before the operation begins, and apply it after the operation ends. This means that you can run rebase on a dirty worktree. However, use diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index f17687e09d..1572f058f5 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -237,6 +237,9 @@ sync:: + "git submodule sync" synchronizes all submodules while "git submodule sync \-- A" synchronizes submodule "A" only. ++ +If `--recursive` is specified, this command will recurse into the +registered submodules, and sync any nested submodules within. OPTIONS ------- @@ -364,7 +367,7 @@ the submodule itself. for linkgit:git-clone[1]'s `--reference` and `--shared` options carefully. --recursive:: - This option is only valid for foreach, update and status commands. + This option is only valid for foreach, update, status and sync commands. Traverse submodules recursively. The operation is performed not only in the submodules of the current repo, but also in any nested submodules inside those submodules (and so on). diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt index 3df9c26f44..f4e5a85351 100644 --- a/Documentation/git-update-index.txt +++ b/Documentation/git-update-index.txt @@ -17,6 +17,7 @@ SYNOPSIS [--[no-]assume-unchanged] [--[no-]skip-worktree] [--ignore-submodules] + [--[no-]split-index] [--[no-|force-]untracked-cache] [--really-refresh] [--unresolve] [--again | -g] [--info-only] [--index-info] diff --git a/Documentation/git.txt b/Documentation/git.txt index c2e2a94e75..cbf157be43 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,10 @@ unreleased) version of Git, that is available from the 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v2.6.3/git.html[documentation for release 2.6.3] +* link:v2.6.4/git.html[documentation for release 2.6.4] * release notes for + link:RelNotes/2.6.4.txt[2.6.4], link:RelNotes/2.6.3.txt[2.6.3], link:RelNotes/2.6.2.txt[2.6.2], link:RelNotes/2.6.1.txt[2.6.1], @@ -1056,7 +1057,7 @@ of clones and fetches. cloning of shallow repositories. See 'GIT_TRACE' for available trace output options. -GIT_LITERAL_PATHSPECS:: +'GIT_LITERAL_PATHSPECS':: Setting this variable to `1` will cause Git to treat all pathspecs literally, rather than as glob patterns. For example, running `GIT_LITERAL_PATHSPECS=1 git log -- '*.c'` will search @@ -1065,15 +1066,15 @@ GIT_LITERAL_PATHSPECS:: literal paths to Git (e.g., paths previously given to you by `git ls-tree`, `--raw` diff output, etc). -GIT_GLOB_PATHSPECS:: +'GIT_GLOB_PATHSPECS':: Setting this variable to `1` will cause Git to treat all pathspecs as glob patterns (aka "glob" magic). -GIT_NOGLOB_PATHSPECS:: +'GIT_NOGLOB_PATHSPECS':: Setting this variable to `1` will cause Git to treat all pathspecs as literal (aka "literal" magic). -GIT_ICASE_PATHSPECS:: +'GIT_ICASE_PATHSPECS':: Setting this variable to `1` will cause Git to treat all pathspecs as case-insensitive. @@ -1087,7 +1088,7 @@ GIT_ICASE_PATHSPECS:: variable when it is invoked as the top level command by the end user, to be recorded in the body of the reflog. -`GIT_REF_PARANOIA`:: +'GIT_REF_PARANOIA':: If set to `1`, include broken or badly named refs when iterating over lists of refs. In a normal, non-corrupted repository, this does nothing. However, enabling it may help git to detect and @@ -1098,7 +1099,7 @@ GIT_ICASE_PATHSPECS:: an operation has touched every ref (e.g., because you are cloning a repository to make a backup). -`GIT_ALLOW_PROTOCOL`:: +'GIT_ALLOW_PROTOCOL':: If set, provide a colon-separated list of protocols which are allowed to be used with fetch/push/clone. This is useful to restrict recursive submodule initialization from an untrusted diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index abfdd9cb1d..f2a001f6c0 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.6.3 +DEF_VER=v2.6.4 LF=' ' @@ -144,6 +144,10 @@ all:: # Define PPC_SHA1 environment variable when running make to make use of # a bundled SHA1 routine optimized for PowerPC. # +# Define SHA1_MAX_BLOCK_SIZE to limit the amount of data that will be hashed +# in one call to the platform's SHA1_Update(). e.g. APPLE_COMMON_CRYPTO +# wants 'SHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L' defined. +# # Define NEEDS_CRYPTO_WITH_SSL if you need -lcrypto when using -lssl (Darwin). # # Define NEEDS_SSL_WITH_CRYPTO if you need -lssl when using -lcrypto (Darwin). @@ -1340,6 +1344,11 @@ ifdef NO_POSIX_GOODIES BASIC_CFLAGS += -DNO_POSIX_GOODIES endif +ifdef APPLE_COMMON_CRYPTO + # Apple CommonCrypto requires chunking + SHA1_MAX_BLOCK_SIZE = 1024L*1024L*1024L +endif + ifdef BLK_SHA1 SHA1_HEADER = "block-sha1/sha1.h" LIB_OBJS += block-sha1/sha1.o @@ -1358,6 +1367,10 @@ endif endif endif +ifdef SHA1_MAX_BLOCK_SIZE + LIB_OBJS += compat/sha1-chunked.o + BASIC_CFLAGS += -DSHA1_MAX_BLOCK_SIZE="$(SHA1_MAX_BLOCK_SIZE)" +endif ifdef NO_PERL_MAKEMAKER export NO_PERL_MAKEMAKER endif @@ -1 +1 @@ -Documentation/RelNotes/2.6.3.txt
\ No newline at end of file +Documentation/RelNotes/2.6.5.txt
\ No newline at end of file diff --git a/block-sha1/sha1.h b/block-sha1/sha1.h index b864df623e..4df6747752 100644 --- a/block-sha1/sha1.h +++ b/block-sha1/sha1.h @@ -16,7 +16,7 @@ void blk_SHA1_Init(blk_SHA_CTX *ctx); void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, unsigned long len); void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx); -#define git_SHA_CTX blk_SHA_CTX -#define git_SHA1_Init blk_SHA1_Init -#define git_SHA1_Update blk_SHA1_Update -#define git_SHA1_Final blk_SHA1_Final +#define platform_SHA_CTX blk_SHA_CTX +#define platform_SHA1_Init blk_SHA1_Init +#define platform_SHA1_Update blk_SHA1_Update +#define platform_SHA1_Final blk_SHA1_Final diff --git a/builtin/commit.c b/builtin/commit.c index dca09e2c3b..f2a8b78c7a 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -32,6 +32,7 @@ #include "sequencer.h" #include "notes-utils.h" #include "mailmap.h" +#include "sigchain.h" static const char * const builtin_commit_usage[] = { N_("git commit [<options>] [--] <pathspec>..."), @@ -1537,8 +1538,10 @@ static int run_rewrite_hook(const unsigned char *oldsha1, return code; n = snprintf(buf, sizeof(buf), "%s %s\n", sha1_to_hex(oldsha1), sha1_to_hex(newsha1)); + sigchain_push(SIGPIPE, SIG_IGN); write_in_full(proc.in, buf, n); close(proc.in); + sigchain_pop(SIGPIPE); return finish_command(&proc); } diff --git a/builtin/count-objects.c b/builtin/count-objects.c index ad0c79954a..ba9291944f 100644 --- a/builtin/count-objects.c +++ b/builtin/count-objects.c @@ -15,9 +15,31 @@ static int verbose; static unsigned long loose, packed, packed_loose; static off_t loose_size; -static void real_report_garbage(const char *desc, const char *path) +static const char *bits_to_msg(unsigned seen_bits) +{ + switch (seen_bits) { + case 0: + return "no corresponding .idx or .pack"; + case PACKDIR_FILE_GARBAGE: + return "garbage found"; + case PACKDIR_FILE_PACK: + return "no corresponding .idx"; + case PACKDIR_FILE_IDX: + return "no corresponding .pack"; + case PACKDIR_FILE_PACK|PACKDIR_FILE_IDX: + default: + return NULL; + } +} + +static void real_report_garbage(unsigned seen_bits, const char *path) { struct stat st; + const char *desc = bits_to_msg(seen_bits); + + if (!desc) + return; + if (!stat(path, &st)) size_garbage += st.st_size; warning("%s: %s", desc, path); @@ -27,7 +49,7 @@ static void real_report_garbage(const char *desc, const char *path) static void loose_garbage(const char *path) { if (verbose) - report_garbage("garbage found", path); + report_garbage(PACKDIR_FILE_GARBAGE, path); } static int count_loose(const unsigned char *sha1, const char *path, void *data) diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 4ba7f282a5..846004b833 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -537,7 +537,7 @@ static void fmt_merge_msg_sigs(struct strbuf *out) static void find_merge_parents(struct merge_parents *result, struct strbuf *in, unsigned char *head) { - struct commit_list *parents, *next; + struct commit_list *parents; struct commit *head_commit; int pos = 0, i, j; @@ -576,13 +576,10 @@ static void find_merge_parents(struct merge_parents *result, parents = reduce_heads(parents); while (parents) { + struct commit *cmit = pop_commit(&parents); for (i = 0; i < result->nr; i++) - if (!hashcmp(result->item[i].commit, - parents->item->object.sha1)) + if (!hashcmp(result->item[i].commit, cmit->object.sha1)) result->item[i].used = 1; - next = parents->next; - free(parents); - parents = next; } for (i = j = 0; i < result->nr; i++) { diff --git a/builtin/gc.c b/builtin/gc.c index cb13ab72c3..42258fe348 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -46,6 +46,22 @@ static struct argv_array rerere = ARGV_ARRAY_INIT; static struct tempfile pidfile; static struct lock_file log_lock; +static struct string_list pack_garbage = STRING_LIST_INIT_DUP; + +static void clean_pack_garbage(void) +{ + int i; + for (i = 0; i < pack_garbage.nr; i++) + unlink_or_warn(pack_garbage.items[i].string); + string_list_clear(&pack_garbage, 0); +} + +static void report_pack_garbage(unsigned seen_bits, const char *path) +{ + if (seen_bits == PACKDIR_FILE_IDX) + string_list_append(&pack_garbage, path); +} + static void git_config_date_string(const char *key, const char **output) { if (git_config_get_string_const(key, output)) @@ -416,6 +432,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix) if (run_command_v_opt(rerere.argv, RUN_GIT_CMD)) return error(FAILED_RUN, rerere.argv[0]); + report_garbage = report_pack_garbage; + reprepare_packed_git(); + if (pack_garbage.nr > 0) + clean_pack_garbage(); + if (auto_gc && too_many_loose_objects()) warning(_("There are too many unreachable loose objects; " "run 'git prune' to remove them.")); diff --git a/builtin/merge.c b/builtin/merge.c index e6741f3380..3ec97a8345 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -1019,7 +1019,7 @@ static struct commit_list *reduce_parents(struct commit *head_commit, int *head_subsumed, struct commit_list *remoteheads) { - struct commit_list *parents, *next, **remotes = &remoteheads; + struct commit_list *parents, **remotes; /* * Is the current HEAD reachable from another commit being @@ -1033,16 +1033,14 @@ static struct commit_list *reduce_parents(struct commit *head_commit, /* Find what parents to record by checking independent ones. */ parents = reduce_heads(remoteheads); - for (remoteheads = NULL, remotes = &remoteheads; - parents; - parents = next) { - struct commit *commit = parents->item; - next = parents->next; + remoteheads = NULL; + remotes = &remoteheads; + while (parents) { + struct commit *commit = pop_commit(&parents); if (commit == head_commit) *head_subsumed = 0; else remotes = &commit_list_insert(commit, remotes)->next; - free(parents); } return remoteheads; } diff --git a/builtin/reflog.c b/builtin/reflog.c index f96ca2a27d..cf1145e635 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -218,7 +218,6 @@ static int keep_entry(struct commit **it, unsigned char *sha1) */ static void mark_reachable(struct expire_reflog_policy_cb *cb) { - struct commit *commit; struct commit_list *pending; unsigned long expire_limit = cb->mark_limit; struct commit_list *leftover = NULL; @@ -228,11 +227,8 @@ static void mark_reachable(struct expire_reflog_policy_cb *cb) pending = cb->mark_list; while (pending) { - struct commit_list *entry = pending; struct commit_list *parent; - pending = entry->next; - commit = entry->item; - free(entry); + struct commit *commit = pop_commit(&pending); if (commit->object.flags & REACHABLE) continue; if (parse_commit(commit)) diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 02d747dcb1..e92a782f77 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -281,11 +281,8 @@ static int try_difference(const char *arg) b = lookup_commit_reference(end); exclude = get_merge_bases(a, b); while (exclude) { - struct commit_list *n = exclude->next; - show_rev(REVERSED, - exclude->item->object.sha1,NULL); - free(exclude); - exclude = n; + struct commit *commit = pop_commit(&exclude); + show_rev(REVERSED, commit->object.sha1, NULL); } } *dotdot = '.'; diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 408ce70307..717a8e7665 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -3,6 +3,7 @@ #include "refs.h" #include "builtin.h" #include "color.h" +#include "argv-array.h" #include "parse-options.h" static const char* show_branch_usage[] = { @@ -16,9 +17,7 @@ static const char* show_branch_usage[] = { static int showbranch_use_color = -1; -static int default_num; -static int default_alloc; -static const char **default_arg; +static struct argv_array default_args = ARGV_ARRAY_INIT; #define UNINTERESTING 01 @@ -53,17 +52,6 @@ static struct commit *interesting(struct commit_list *list) return NULL; } -static struct commit *pop_one_commit(struct commit_list **list_p) -{ - struct commit *commit; - struct commit_list *list; - list = *list_p; - commit = list->item; - *list_p = list->next; - free(list); - return commit; -} - struct commit_name { const char *head_name; /* which head's ancestor? */ int generation; /* how many parents away from head_name */ @@ -213,7 +201,7 @@ static void join_revs(struct commit_list **list_p, while (*list_p) { struct commit_list *parents; int still_interesting = !!interesting(*list_p); - struct commit *commit = pop_one_commit(list_p); + struct commit *commit = pop_commit(list_p); int flags = commit->object.flags & all_mask; if (!still_interesting && extra <= 0) @@ -504,7 +492,7 @@ static int show_merge_base(struct commit_list *seen, int num_rev) int exit_status = 1; while (seen) { - struct commit *commit = pop_one_commit(&seen); + struct commit *commit = pop_commit(&seen); int flags = commit->object.flags & all_mask; if (!(flags & UNINTERESTING) && ((flags & all_revs) == all_revs)) { @@ -567,16 +555,9 @@ static int git_show_branch_config(const char *var, const char *value, void *cb) * default_arg is now passed to parse_options(), so we need to * mimic the real argv a bit better. */ - if (!default_num) { - default_alloc = 20; - default_arg = xcalloc(default_alloc, sizeof(*default_arg)); - default_arg[default_num++] = "show-branch"; - } else if (default_alloc <= default_num + 1) { - default_alloc = default_alloc * 3 / 2 + 20; - REALLOC_ARRAY(default_arg, default_alloc); - } - default_arg[default_num++] = xstrdup(value); - default_arg[default_num] = NULL; + if (!default_args.argc) + argv_array_push(&default_args, "show-branch"); + argv_array_push(&default_args, value); return 0; } @@ -696,9 +677,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) git_config(git_show_branch_config, NULL); /* If nothing is specified, try the default first */ - if (ac == 1 && default_num) { - ac = default_num; - av = default_arg; + if (ac == 1 && default_args.argc) { + ac = default_args.argc; + av = default_args.argv; } ac = parse_options(ac, av, prefix, builtin_show_branch_options, @@ -927,7 +908,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) all_revs = all_mask & ~((1u << REV_SHIFT) - 1); while (seen) { - struct commit *commit = pop_one_commit(&seen); + struct commit *commit = pop_commit(&seen); int this_flag = commit->object.flags; int is_merge_point = ((this_flag & all_revs) == all_revs); @@ -11,11 +11,29 @@ #include "string-list.h" #include SHA1_HEADER -#ifndef git_SHA_CTX -#define git_SHA_CTX SHA_CTX -#define git_SHA1_Init SHA1_Init -#define git_SHA1_Update SHA1_Update -#define git_SHA1_Final SHA1_Final +#ifndef platform_SHA_CTX +/* + * platform's underlying implementation of SHA-1; could be OpenSSL, + * blk_SHA, Apple CommonCrypto, etc... Note that including + * SHA1_HEADER may have already defined platform_SHA_CTX for our + * own implementations like block-sha1 and ppc-sha1, so we list + * the default for OpenSSL compatible SHA-1 implementations here. + */ +#define platform_SHA_CTX SHA_CTX +#define platform_SHA1_Init SHA1_Init +#define platform_SHA1_Update SHA1_Update +#define platform_SHA1_Final SHA1_Final +#endif + +#define git_SHA_CTX platform_SHA_CTX +#define git_SHA1_Init platform_SHA1_Init +#define git_SHA1_Update platform_SHA1_Update +#define git_SHA1_Final platform_SHA1_Final + +#ifdef SHA1_MAX_BLOCK_SIZE +#include "compat/sha1-chunked.h" +#undef git_SHA1_Update +#define git_SHA1_Update git_SHA1_Update_Chunked #endif #include <zlib.h> @@ -1258,8 +1276,11 @@ struct pack_entry { extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path); -/* A hook for count-objects to report invalid files in pack directory */ -extern void (*report_garbage)(const char *desc, const char *path); +/* A hook to report invalid files in pack directory */ +#define PACKDIR_FILE_PACK 1 +#define PACKDIR_FILE_IDX 2 +#define PACKDIR_FILE_GARBAGE 4 +extern void (*report_garbage)(unsigned seen_bits, const char *path); extern void prepare_packed_git(void); extern void reprepare_packed_git(void); @@ -455,11 +455,8 @@ struct commit_list *copy_commit_list(struct commit_list *list) void free_commit_list(struct commit_list *list) { - while (list) { - struct commit_list *temp = list; - list = temp->next; - free(temp); - } + while (list) + pop_commit(&list); } struct commit_list * commit_list_insert_by_date(struct commit *item, struct commit_list **list) @@ -505,12 +502,8 @@ void commit_list_sort_by_date(struct commit_list **list) struct commit *pop_most_recent_commit(struct commit_list **list, unsigned int mark) { - struct commit *ret = (*list)->item; + struct commit *ret = pop_commit(list); struct commit_list *parents = ret->parents; - struct commit_list *old = *list; - - *list = (*list)->next; - free(old); while (parents) { struct commit *commit = parents->item; @@ -861,11 +854,9 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co list = paint_down_to_common(one, n, twos); while (list) { - struct commit_list *next = list->next; - if (!(list->item->object.flags & STALE)) - commit_list_insert_by_date(list->item, &result); - free(list); - list = next; + struct commit *commit = pop_commit(&list); + if (!(commit->object.flags & STALE)) + commit_list_insert_by_date(commit, &result); } return result; } @@ -1546,13 +1537,9 @@ int commit_tree_extended(const char *msg, size_t msg_len, * if everything else stays the same. */ while (parents) { - struct commit_list *next = parents->next; - struct commit *parent = parents->item; - + struct commit *parent = pop_commit(&parents); strbuf_addf(&buffer, "parent %s\n", sha1_to_hex(parent->object.sha1)); - free(parents); - parents = next; } /* Person/date information */ diff --git a/compat/apple-common-crypto.h b/compat/apple-common-crypto.h index c8b9b0e1a6..d3fb264181 100644 --- a/compat/apple-common-crypto.h +++ b/compat/apple-common-crypto.h @@ -16,6 +16,10 @@ #undef TYPE_BOOL #endif +#ifndef SHA1_MAX_BLOCK_SIZE +#error Using Apple Common Crypto library requires setting SHA1_MAX_BLOCK_SIZE +#endif + #ifdef APPLE_LION_OR_NEWER #define git_CC_error_check(pattern, err) \ do { \ diff --git a/compat/sha1-chunked.c b/compat/sha1-chunked.c new file mode 100644 index 0000000000..6adfcfd540 --- /dev/null +++ b/compat/sha1-chunked.c @@ -0,0 +1,19 @@ +#include "cache.h" + +int git_SHA1_Update_Chunked(platform_SHA_CTX *c, const void *data, size_t len) +{ + size_t nr; + size_t total = 0; + const char *cdata = (const char*)data; + + while (len) { + nr = len; + if (nr > SHA1_MAX_BLOCK_SIZE) + nr = SHA1_MAX_BLOCK_SIZE; + platform_SHA1_Update(c, cdata, nr); + total += nr; + cdata += nr; + len -= nr; + } + return total; +} diff --git a/compat/sha1-chunked.h b/compat/sha1-chunked.h new file mode 100644 index 0000000000..7b2df28eec --- /dev/null +++ b/compat/sha1-chunked.h @@ -0,0 +1,2 @@ + +int git_SHA1_Update_Chunked(platform_SHA_CTX *c, const void *data, size_t len); @@ -2144,7 +2144,8 @@ int git_config_set_multivar_in_file(const char *config_filename, } if (commit_lock_file(lock) < 0) { - error("could not commit config file %s", config_filename); + error("could not write config file %s: %s", config_filename, + strerror(errno)); ret = CONFIG_NO_WRITE; lock = NULL; goto out_free; @@ -2330,7 +2331,8 @@ int git_config_rename_section_in_file(const char *config_filename, fclose(config_file); unlock_and_out: if (commit_lock_file(lock) < 0) - ret = error("could not commit config file %s", config_filename); + ret = error("could not write config file %s: %s", + config_filename, strerror(errno)); out: free(filename_buf); return ret; diff --git a/configure.ac b/configure.ac index fd22d41b2f..1f55009bba 100644 --- a/configure.ac +++ b/configure.ac @@ -1149,7 +1149,12 @@ elif test -z "$PTHREAD_CFLAGS"; then # would then trigger compiler warnings on every single file we compile. for opt in "" -mt -pthread -lpthread; do old_CFLAGS="$CFLAGS" - CFLAGS="$opt $CFLAGS" + old_LIBS="$LIBS" + case "$opt" in + -l*) LIBS="$opt $LIBS" ;; + *) CFLAGS="$opt $CFLAGS" ;; + esac + AC_MSG_CHECKING([for POSIX Threads with '$opt']) AC_LINK_IFELSE([PTHREADTEST_SRC], [AC_MSG_RESULT([yes]) @@ -1161,6 +1166,7 @@ elif test -z "$PTHREAD_CFLAGS"; then ], [AC_MSG_RESULT([no])]) CFLAGS="$old_CFLAGS" + LIBS="$old_LIBS" done if test $threads_found != yes; then AC_CHECK_LIB([pthread], [pthread_create], diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 482ca84b45..b383ed05c3 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -663,6 +663,7 @@ __git_list_porcelain_commands () check-mailmap) : plumbing;; check-ref-format) : plumbing;; checkout-index) : plumbing;; + column) : internal helper;; commit-tree) : plumbing;; count-objects) : infrequent;; credential) : credentials;; diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh index 07b52bedf1..64219e631a 100644 --- a/contrib/completion/git-prompt.sh +++ b/contrib/completion/git-prompt.sh @@ -476,10 +476,9 @@ __git_ps1 () if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ] && [ "$(git config --bool bash.showDirtyState)" != "false" ] then - git diff --no-ext-diff --quiet --exit-code || w="*" - if [ -n "$short_sha" ]; then - git diff-index --cached --quiet HEAD -- || i="+" - else + git diff --no-ext-diff --quiet || w="*" + git diff --no-ext-diff --cached --quiet || i="+" + if [ -z "$short_sha" ] && [ -z "$i" ]; then i="#" fi fi diff --git a/contrib/rerere-train.sh b/contrib/rerere-train.sh index 36b6feebe0..52ad9e41fb 100755 --- a/contrib/rerere-train.sh +++ b/contrib/rerere-train.sh @@ -7,7 +7,7 @@ USAGE="$me rev-list-args" SUBDIRECTORY_OK=Yes OPTIONS_SPEC= -. $(git --exec-path)/git-sh-setup +. "$(git --exec-path)/git-sh-setup" require_work_tree cd_to_toplevel diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh index 9f06571851..308b777b0a 100755 --- a/contrib/subtree/git-subtree.sh +++ b/contrib/subtree/git-subtree.sh @@ -648,7 +648,7 @@ cmd_split() debug "Merging split branch into HEAD..." latest_old=$(cache_get latest_old) git merge -s ours \ - -m "$(rejoin_msg $dir $latest_old $latest_new)" \ + -m "$(rejoin_msg "$dir" $latest_old $latest_new)" \ $latest_new >&2 || exit $? fi if [ -n "$branch" ]; then @@ -735,7 +735,7 @@ cmd_push() refspec=$2 echo "git push using: " $repository $refspec localrev=$(git subtree split --prefix="$prefix") || die - git push $repository $localrev:refs/heads/$refspec + git push "$repository" $localrev:refs/heads/$refspec else die "'$dir' must already exist. Try 'git subtree add'." fi diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh index 90519823be..dfbe443dea 100755 --- a/contrib/subtree/t/t7900-subtree.sh +++ b/contrib/subtree/t/t7900-subtree.sh @@ -1,6 +1,7 @@ #!/bin/sh # # Copyright (c) 2012 Avery Pennaraum +# Copyright (c) 2015 Alexey Shumkin # test_description='Basic porcelain support for subtrees @@ -32,25 +33,6 @@ check_equal() fi } -fixnl() -{ - t="" - while read x; do - t="$t$x " - done - echo $t -} - -multiline() -{ - while read x; do - set -- $x - for d in "$@"; do - echo "$d" - done - done -} - undo() { git reset --hard HEAD~ @@ -62,11 +44,11 @@ last_commit_message() } test_expect_success 'init subproj' ' - test_create_repo subproj + test_create_repo "sub proj" ' # To the subproject! -cd subproj +cd ./"sub proj" test_expect_success 'add sub1' ' create sub1 && @@ -106,39 +88,39 @@ test_expect_success 'add main4' ' ' test_expect_success 'fetch subproj history' ' - git fetch ./subproj sub1 && + git fetch ./"sub proj" sub1 && git branch sub1 FETCH_HEAD ' test_expect_success 'no subtree exists in main tree' ' - test_must_fail git subtree merge --prefix=subdir sub1 + test_must_fail git subtree merge --prefix="sub dir" sub1 ' test_expect_success 'no pull from non-existant subtree' ' - test_must_fail git subtree pull --prefix=subdir ./subproj sub1 + test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" sub1 ' test_expect_success 'check if --message works for add' ' - git subtree add --prefix=subdir --message="Added subproject" sub1 && + git subtree add --prefix="sub dir" --message="Added subproject" sub1 && check_equal ''"$(last_commit_message)"'' "Added subproject" && undo ' test_expect_success 'check if --message works as -m and --prefix as -P' ' - git subtree add -P subdir -m "Added subproject using git subtree" sub1 && + git subtree add -P "sub dir" -m "Added subproject using git subtree" sub1 && check_equal ''"$(last_commit_message)"'' "Added subproject using git subtree" && undo ' test_expect_success 'check if --message works with squash too' ' - git subtree add -P subdir -m "Added subproject with squash" --squash sub1 && + git subtree add -P "sub dir" -m "Added subproject with squash" --squash sub1 && check_equal ''"$(last_commit_message)"'' "Added subproject with squash" && undo ' test_expect_success 'add subproj to mainline' ' - git subtree add --prefix=subdir/ FETCH_HEAD && - check_equal ''"$(last_commit_message)"'' "Add '"'subdir/'"' from commit '"'"'''"$(git rev-parse sub1)"'''"'"'" + git subtree add --prefix="sub dir"/ FETCH_HEAD && + check_equal ''"$(last_commit_message)"'' "Add '"'sub dir/'"' from commit '"'"'''"$(git rev-parse sub1)"'''"'"'" ' # this shouldn't actually do anything, since FETCH_HEAD is already a parent @@ -147,7 +129,7 @@ test_expect_success 'merge fetched subproj' ' ' test_expect_success 'add main-sub5' ' - create subdir/main-sub5 && + create "sub dir/main-sub5" && git commit -m "main-sub5" ' @@ -157,29 +139,29 @@ test_expect_success 'add main6' ' ' test_expect_success 'add main-sub7' ' - create subdir/main-sub7 && + create "sub dir/main-sub7" && git commit -m "main-sub7" ' test_expect_success 'fetch new subproj history' ' - git fetch ./subproj sub2 && + git fetch ./"sub proj" sub2 && git branch sub2 FETCH_HEAD ' test_expect_success 'check if --message works for merge' ' - git subtree merge --prefix=subdir -m "Merged changes from subproject" sub2 && + git subtree merge --prefix="sub dir" -m "Merged changes from subproject" sub2 && check_equal ''"$(last_commit_message)"'' "Merged changes from subproject" && undo ' test_expect_success 'check if --message for merge works with squash too' ' - git subtree merge --prefix subdir -m "Merged changes from subproject using squash" --squash sub2 && + git subtree merge --prefix "sub dir" -m "Merged changes from subproject using squash" --squash sub2 && check_equal ''"$(last_commit_message)"'' "Merged changes from subproject using squash" && undo ' test_expect_success 'merge new subproj history into subdir' ' - git subtree merge --prefix=subdir FETCH_HEAD && + git subtree merge --prefix="sub dir" FETCH_HEAD && git branch pre-split && check_equal ''"$(last_commit_message)"'' "Merge commit '"'"'"$(git rev-parse sub2)"'"'"' into mainline" && undo @@ -208,53 +190,53 @@ test_expect_success 'Check that the <prefix> exists for a split' ' ' test_expect_success 'check if --message works for split+rejoin' ' - spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' && + spl1=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' && git branch spl1 "$spl1" && check_equal ''"$(last_commit_message)"'' "Split & rejoin" && undo ' test_expect_success 'check split with --branch' ' - spl1=$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin) && + spl1=$(git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --message "Split & rejoin" --rejoin) && undo && - git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --branch splitbr1 && + git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --branch splitbr1 && check_equal ''"$(git rev-parse splitbr1)"'' "$spl1" ' test_expect_success 'check hash of split' ' - spl1=$(git subtree split --prefix subdir) && - git subtree split --prefix subdir --branch splitbr1test && + spl1=$(git subtree split --prefix "sub dir") && + git subtree split --prefix "sub dir" --branch splitbr1test && check_equal ''"$(git rev-parse splitbr1test)"'' "$spl1" && new_hash=$(git rev-parse splitbr1test~2) && check_equal ''"$new_hash"'' "$subdir_hash" ' test_expect_success 'check split with --branch for an existing branch' ' - spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' && + spl1=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' && undo && git branch splitbr2 sub1 && - git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --branch splitbr2 && + git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --branch splitbr2 && check_equal ''"$(git rev-parse splitbr2)"'' "$spl1" ' test_expect_success 'check split with --branch for an incompatible branch' ' - test_must_fail git subtree split --prefix subdir --onto FETCH_HEAD --branch subdir + test_must_fail git subtree split --prefix "sub dir" --onto FETCH_HEAD --branch subdir ' test_expect_success 'check split+rejoin' ' - spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' && + spl1=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' && undo && - git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --rejoin && - check_equal ''"$(last_commit_message)"'' "Split '"'"'subdir/'"'"' into commit '"'"'"$spl1"'"'"'" + git subtree split --annotate='"'*'"' --prefix "sub dir" --onto FETCH_HEAD --rejoin && + check_equal ''"$(last_commit_message)"'' "Split '"'"'sub dir/'"'"' into commit '"'"'"$spl1"'"'"'" ' test_expect_success 'add main-sub8' ' - create subdir/main-sub8 && + create "sub dir/main-sub8" && git commit -m "main-sub8" ' # To the subproject! -cd ./subproj +cd ./"sub proj" test_expect_success 'merge split into subproj' ' git fetch .. spl1 && @@ -271,22 +253,22 @@ test_expect_success 'add sub9' ' cd .. test_expect_success 'split for sub8' ' - split2=''"$(git subtree split --annotate='"'*'"' --prefix subdir/ --rejoin)"'' && + split2=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir/" --rejoin)"'' && git branch split2 "$split2" ' test_expect_success 'add main-sub10' ' - create subdir/main-sub10 && + create "sub dir/main-sub10" && git commit -m "main-sub10" ' test_expect_success 'split for sub10' ' - spl3=''"$(git subtree split --annotate='"'*'"' --prefix subdir --rejoin)"'' && + spl3=''"$(git subtree split --annotate='"'*'"' --prefix "sub dir" --rejoin)"'' && git branch spl3 "$spl3" ' # To the subproject! -cd ./subproj +cd ./"sub proj" test_expect_success 'merge split into subproj' ' git fetch .. spl3 && @@ -295,42 +277,64 @@ test_expect_success 'merge split into subproj' ' git branch subproj-merge-spl3 ' -chkm="main4 main6" -chkms="main-sub10 main-sub5 main-sub7 main-sub8" -chkms_sub=$(echo $chkms | multiline | sed 's,^,subdir/,' | fixnl) -chks="sub1 sub2 sub3 sub9" -chks_sub=$(echo $chks | multiline | sed 's,^,subdir/,' | fixnl) +chkm="main4 +main6" +chkms="main-sub10 +main-sub5 +main-sub7 +main-sub8" +chkms_sub=$(cat <<TXT | sed 's,^,sub dir/,' +$chkms +TXT +) +chks="sub1 +sub2 +sub3 +sub9" +chks_sub=$(cat <<TXT | sed 's,^,sub dir/,' +$chks +TXT +) test_expect_success 'make sure exactly the right set of files ends up in the subproj' ' - subfiles=''"$(git ls-files | fixnl)"'' && - check_equal "$subfiles" "$chkms $chks" + subfiles="$(git ls-files)" && + check_equal "$subfiles" "$chkms +$chks" ' - test_expect_success 'make sure the subproj history *only* contains commits that affect the subdir' ' - allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' && - check_equal "$allchanges" "$chkms $chks" + allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | sed "/^$/d")"'' && + check_equal "$allchanges" "$chkms +$chks" ' # Back to mainline cd .. test_expect_success 'pull from subproj' ' - git fetch ./subproj subproj-merge-spl3 && + git fetch ./"sub proj" subproj-merge-spl3 && git branch subproj-merge-spl3 FETCH_HEAD && - git subtree pull --prefix=subdir ./subproj subproj-merge-spl3 + git subtree pull --prefix="sub dir" ./"sub proj" subproj-merge-spl3 ' test_expect_success 'make sure exactly the right set of files ends up in the mainline' ' - mainfiles=''"$(git ls-files | fixnl)"'' && - check_equal "$mainfiles" "$chkm $chkms_sub $chks_sub" + mainfiles=$(git ls-files) && + check_equal "$mainfiles" "$chkm +$chkms_sub +$chks_sub" ' test_expect_success 'make sure each filename changed exactly once in the entire history' ' # main-sub?? and /subdir/main-sub?? both change, because those are the # changes that were split into their own history. And subdir/sub?? never # change, since they were *only* changed in the subtree branch. - allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' && - check_equal "$allchanges" ''"$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"'' + allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | sed "/^$/d")"'' && + check_equal "$allchanges" ''"$(cat <<TXT | sort +$chkms +$chkm +$chks +$chkms_sub +TXT +)"'' ' test_expect_success 'make sure the --rejoin commits never make it into subproj' ' @@ -377,7 +381,7 @@ cd ../main test_expect_success 'add sub as subdir in main' ' git fetch ../sub master && git branch sub2 FETCH_HEAD && - git subtree add --prefix subdir sub2 + git subtree add --prefix "sub dir" sub2 ' cd ../sub @@ -392,16 +396,16 @@ cd ../main test_expect_success 'merge from sub' ' git fetch ../sub master && git branch sub3 FETCH_HEAD && - git subtree merge --prefix subdir sub3 + git subtree merge --prefix "sub dir" sub3 ' test_expect_success 'add main-sub4' ' - create subdir/main-sub4 && + create "sub dir/main-sub4" && git commit -m "main-sub4" ' test_expect_success 'split for main-sub4 without --onto' ' - git subtree split --prefix subdir --branch mainsub4 + git subtree split --prefix "sub dir" --branch mainsub4 ' # at this point, the new commit parent should be sub3 if it is not, @@ -468,4 +472,50 @@ test_expect_success 'verify one file change per commit' ' )) ' +# test push + +cd ../.. + +mkdir test-push + +cd test-push + +test_expect_success 'init main' ' + test_create_repo main +' + +test_expect_success 'init sub' ' + test_create_repo "sub project" +' + +cd ./"sub project" + +test_expect_success 'add subproject' ' + create "sub project" && + git commit -m "Sub project: 1" && + git branch sub-branch-1 +' + +cd ../main + +test_expect_success 'make first commit and add subproject' ' + create "main-1" && + git commit -m "main: 1" && + git subtree add "../sub project" --prefix "sub dir" --message "Added subproject" sub-branch-1 && + check_equal "$(last_commit_message)" "Added subproject" +' + +test_expect_success 'make second commit to a subproject file and push it into a sub project' ' + create "sub dir/sub1" && + git commit -m "Sub project: 2" && + git subtree push "../sub project" --prefix "sub dir" sub-branch-1 +' + +cd ../"sub project" + +test_expect_success 'Test second commit is pushed' ' + git checkout sub-branch-1 && + check_equal "$(last_commit_message)" "Sub project: 2" +' + test_done diff --git a/credential-store.c b/credential-store.c index 00aea3aa30..54c4e04737 100644 --- a/credential-store.c +++ b/credential-store.c @@ -64,7 +64,7 @@ static void rewrite_credential_file(const char *fn, struct credential *c, print_line(extra); parse_credential_file(fn, c, NULL, print_line); if (commit_lock_file(&credential_lock) < 0) - die_errno("unable to commit credential store"); + die_errno("unable to write credential store"); } static void store_credential_file(const char *fn, struct credential *c) diff --git a/fast-import.c b/fast-import.c index 6c7c3c9b66..b141535e11 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1821,7 +1821,7 @@ static void dump_marks(void) dump_marks_helper(f, 0, marks); if (commit_lock_file(&mark_lock)) { - failure |= error("Unable to commit marks file %s: %s", + failure |= error("Unable to write file %s: %s", export_marks_file, strerror(errno)); return; } diff --git a/git-difftool.perl b/git-difftool.perl index 7df7c8a9a7..488d14b153 100755 --- a/git-difftool.perl +++ b/git-difftool.perl @@ -70,9 +70,7 @@ sub use_wt_file my ($repo, $workdir, $file, $sha1) = @_; my $null_sha1 = '0' x 40; - if (! -e "$workdir/$file") { - # If the file doesn't exist in the working tree, we cannot - # use it. + if (-l "$workdir/$file" || ! -e _) { return (0, $null_sha1); } diff --git a/git-filter-branch.sh b/git-filter-branch.sh index fff8093d4f..ad24c8d854 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -319,7 +319,7 @@ while read commit parents; do die "tree filter failed: $filter_tree" ( - git diff-index -r --name-only --ignore-submodules $commit && + git diff-index -r --name-only --ignore-submodules $commit -- && git ls-files --others ) > "$tempdir"/tree-state || exit git update-index --add --replace --remove --stdin \ @@ -190,14 +190,16 @@ def p4_has_move_command(): # assume it failed because @... was invalid changelist return True -def system(cmd): +def system(cmd, ignore_error=False): expand = isinstance(cmd,basestring) if verbose: sys.stderr.write("executing %s\n" % str(cmd)) retcode = subprocess.call(cmd, shell=expand) - if retcode: + if retcode and not ignore_error: raise CalledProcessError(retcode, cmd) + return retcode + def p4_system(cmd): """Specifically invoke p4 as the system command. """ real_cmd = p4_build_cmd(cmd) @@ -540,7 +542,12 @@ def p4Where(depotPath): return clientPath def currentGitBranch(): - return read_pipe("git name-rev HEAD").split(" ")[1].strip() + retcode = system(["git", "symbolic-ref", "-q", "HEAD"], ignore_error=True) + if retcode != 0: + # on a detached head + return None + else: + return read_pipe(["git", "name-rev", "HEAD"]).split(" ")[1].strip() def isValidGitDir(path): if (os.path.exists(path + "/HEAD") @@ -1536,44 +1543,47 @@ class P4Submit(Command, P4UserMap): # # Let the user edit the change description, then submit it. # - if self.edit_template(fileName): - # read the edited message and submit - ret = True - tmpFile = open(fileName, "rb") - message = tmpFile.read() - tmpFile.close() - if self.isWindows: - message = message.replace("\r\n", "\n") - submitTemplate = message[:message.index(separatorLine)] - p4_write_pipe(['submit', '-i'], submitTemplate) - - if self.preserveUser: - if p4User: - # Get last changelist number. Cannot easily get it from - # the submit command output as the output is - # unmarshalled. - changelist = self.lastP4Changelist() - self.modifyChangelistUser(changelist, p4User) - - # The rename/copy happened by applying a patch that created a - # new file. This leaves it writable, which confuses p4. - for f in pureRenameCopy: - p4_sync(f, "-f") + submitted = False - else: + try: + if self.edit_template(fileName): + # read the edited message and submit + tmpFile = open(fileName, "rb") + message = tmpFile.read() + tmpFile.close() + if self.isWindows: + message = message.replace("\r\n", "\n") + submitTemplate = message[:message.index(separatorLine)] + p4_write_pipe(['submit', '-i'], submitTemplate) + + if self.preserveUser: + if p4User: + # Get last changelist number. Cannot easily get it from + # the submit command output as the output is + # unmarshalled. + changelist = self.lastP4Changelist() + self.modifyChangelistUser(changelist, p4User) + + # The rename/copy happened by applying a patch that created a + # new file. This leaves it writable, which confuses p4. + for f in pureRenameCopy: + p4_sync(f, "-f") + submitted = True + + finally: # skip this patch - ret = False - print "Submission cancelled, undoing p4 changes." - for f in editedFiles: - p4_revert(f) - for f in filesToAdd: - p4_revert(f) - os.remove(f) - for f in filesToDelete: - p4_revert(f) + if not submitted: + print "Submission cancelled, undoing p4 changes." + for f in editedFiles: + p4_revert(f) + for f in filesToAdd: + p4_revert(f) + os.remove(f) + for f in filesToDelete: + p4_revert(f) os.remove(fileName) - return ret + return submitted # Export git tags as p4 labels. Create a p4 label and then tag # with that. @@ -1649,8 +1659,6 @@ class P4Submit(Command, P4UserMap): def run(self, args): if len(args) == 0: self.master = currentGitBranch() - if len(self.master) == 0 or not gitBranchExists("refs/heads/%s" % self.master): - die("Detecting current git branch failed!") elif len(args) == 1: self.master = args[0] if not branchExists(self.master): @@ -1658,9 +1666,10 @@ class P4Submit(Command, P4UserMap): else: return False - allowSubmit = gitConfig("git-p4.allowSubmit") - if len(allowSubmit) > 0 and not self.master in allowSubmit.split(","): - die("%s is not in git-p4.allowSubmit" % self.master) + if self.master: + allowSubmit = gitConfig("git-p4.allowSubmit") + if len(allowSubmit) > 0 and not self.master in allowSubmit.split(","): + die("%s is not in git-p4.allowSubmit" % self.master) [upstream, settings] = findUpstreamBranchPoint() self.depotPath = settings['depot-paths'][0] @@ -1728,7 +1737,12 @@ class P4Submit(Command, P4UserMap): self.check() commits = [] - for line in read_pipe_lines(["git", "rev-list", "--no-merges", "%s..%s" % (self.origin, self.master)]): + if self.master: + commitish = self.master + else: + commitish = 'HEAD' + + for line in read_pipe_lines(["git", "rev-list", "--no-merges", "%s..%s" % (self.origin, commitish)]): commits.append(line.strip()) commits.reverse() @@ -2293,12 +2307,6 @@ class P4Sync(Command, P4UserMap): filesToDelete = [] for f in files: - # if using a client spec, only add the files that have - # a path in the client - if self.clientSpecDirs: - if self.clientSpecDirs.map_in_client(f['path']) == "": - continue - filesForCommit.append(f) if f['action'] in self.delete_actions: filesToDelete.append(f) @@ -2369,25 +2377,41 @@ class P4Sync(Command, P4UserMap): gitStream.write(description) gitStream.write("\n") + def inClientSpec(self, path): + if not self.clientSpecDirs: + return True + inClientSpec = self.clientSpecDirs.map_in_client(path) + if not inClientSpec and self.verbose: + print('Ignoring file outside of client spec: {0}'.format(path)) + return inClientSpec + + def hasBranchPrefix(self, path): + if not self.branchPrefixes: + return True + hasPrefix = [p for p in self.branchPrefixes + if p4PathStartsWith(path, p)] + if hasPrefix and self.verbose: + print('Ignoring file outside of prefix: {0}'.format(path)) + return hasPrefix + def commit(self, details, files, branch, parent = ""): epoch = details["time"] author = details["user"] if self.verbose: - print "commit into %s" % branch - - # start with reading files; if that fails, we should not - # create a commit. - new_files = [] - for f in files: - if [p for p in self.branchPrefixes if p4PathStartsWith(f['path'], p)]: - new_files.append (f) - else: - sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path']) + print('commit into {0}'.format(branch)) if self.clientSpecDirs: self.clientSpecDirs.update_client_spec_path_cache(files) + files = [f for f in files + if self.inClientSpec(f['path']) and self.hasBranchPrefix(f['path'])] + + if not files and not gitConfigBool('git-p4.keepEmptyCommits'): + print('Ignoring revision {0} as it would produce an empty commit.' + .format(details['change'])) + return + self.gitStream.write("commit %s\n" % branch) self.gitStream.write("mark :%s\n" % details["change"]) self.committedChanges.add(int(details["change"])) @@ -2411,7 +2435,7 @@ class P4Sync(Command, P4UserMap): print "parent %s" % parent self.gitStream.write("from %s\n" % parent) - self.streamP4Files(new_files) + self.streamP4Files(files) self.gitStream.write("\n") change = int(details["change"]) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 30edb17925..b938a6d4aa 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -610,7 +610,7 @@ do_next () { read -r command rest < "$todo" mark_action_done printf 'Executing: %s\n' "$rest" - ${SHELL:-@SHELL_PATH@} -c "$rest" # Actual execution + "${SHELL:-@SHELL_PATH@}" -c "$rest" # Actual execution status=$? # Run in subshell because require_clean_work_tree can die. dirty=f diff --git a/git-rebase.sh b/git-rebase.sh index 1757404bc2..af7ba5fd90 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -14,7 +14,7 @@ git-rebase --continue | --abort | --skip | --edit-todo Available options are v,verbose! display a diffstat of what changed upstream q,quiet! be quiet. implies --no-stat -autostash! automatically stash/stash pop before and after +autostash automatically stash/stash pop before and after fork-point use 'merge-base --fork-point' to refine upstream onto=! rebase onto given branch instead of upstream p,preserve-merges! try to recreate merges instead of ignoring them @@ -292,6 +292,9 @@ do --autostash) autostash=true ;; + --no-autostash) + autostash=false + ;; --verbose) verbose=t diffstat=t @@ -417,7 +417,7 @@ static struct cmd_struct commands[] = { { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY }, { "init", cmd_init_db, NO_SETUP }, { "init-db", cmd_init_db, NO_SETUP }, - { "interpret-trailers", cmd_interpret_trailers, RUN_SETUP }, + { "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY }, { "log", cmd_log, RUN_SETUP }, { "ls-files", cmd_ls_files, RUN_SETUP }, { "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY }, @@ -215,10 +215,10 @@ static int http_options(const char *var, const char *value, void *cb) #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_pathname(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_pathname(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { ssl_cert_password_required = git_config_bool(var, value); return 0; @@ -465,6 +465,17 @@ static CURL *get_curl_handle(void) if (curl_http_proxy) { curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy); +#if LIBCURL_VERSION_NUM >= 0x071800 + if (starts_with(curl_http_proxy, "socks5")) + curl_easy_setopt(result, + CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); + else if (starts_with(curl_http_proxy, "socks4a")) + curl_easy_setopt(result, + CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4A); + else if (starts_with(curl_http_proxy, "socks")) + curl_easy_setopt(result, + CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); +#endif } #if LIBCURL_VERSION_NUM >= 0x070a07 curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); @@ -70,10 +70,35 @@ static int add_mailname_host(struct strbuf *buf) return 0; } +static int canonical_name(const char *host, struct strbuf *out) +{ + int status = -1; + +#ifndef NO_IPV6 + struct addrinfo hints, *ai; + memset (&hints, '\0', sizeof (hints)); + hints.ai_flags = AI_CANONNAME; + if (!getaddrinfo(host, NULL, &hints, &ai)) { + if (ai && strchr(ai->ai_canonname, '.')) { + strbuf_addstr(out, ai->ai_canonname); + status = 0; + } + freeaddrinfo(ai); + } +#else + struct hostent *he = gethostbyname(host); + if (he && strchr(he->h_name, '.')) { + strbuf_addstr(out, he->h_name); + status = 0; + } +#endif /* NO_IPV6 */ + + return status; +} + static void add_domainname(struct strbuf *out) { char buf[1024]; - struct hostent *he; if (gethostname(buf, sizeof(buf))) { warning("cannot get host name: %s", strerror(errno)); @@ -82,9 +107,7 @@ static void add_domainname(struct strbuf *out) } if (strchr(buf, '.')) strbuf_addstr(out, buf); - else if ((he = gethostbyname(buf)) && strchr(he->h_name, '.')) - strbuf_addstr(out, he->h_name); - else + else if (canonical_name(buf, out) < 0) strbuf_addf(out, "%s.(none)", buf); } diff --git a/pack-check.c b/pack-check.c index 63a595c45c..433bd86ccd 100644 --- a/pack-check.c +++ b/pack-check.c @@ -126,7 +126,7 @@ static int verify_packfile(struct packed_git *p, sha1_to_hex(entries[i].sha1), p->pack_name); else if (fn) { int eaten = 0; - fn(entries[i].sha1, type, size, data, &eaten); + err |= fn(entries[i].sha1, type, size, data, &eaten); if (eaten) data = NULL; } @@ -147,7 +147,7 @@ void report_linked_checkout_garbage(void) strbuf_setlen(&sb, len); strbuf_addstr(&sb, path); if (file_exists(sb.buf)) - report_garbage("unused in linked checkout", sb.buf); + report_garbage(PACKDIR_FILE_GARBAGE, sb.buf); } strbuf_release(&sb); } diff --git a/ppc/sha1.h b/ppc/sha1.h index c405f734c2..9b24b32615 100644 --- a/ppc/sha1.h +++ b/ppc/sha1.h @@ -19,7 +19,7 @@ int ppc_SHA1_Init(ppc_SHA_CTX *c); int ppc_SHA1_Update(ppc_SHA_CTX *c, const void *p, unsigned long n); int ppc_SHA1_Final(unsigned char *hash, ppc_SHA_CTX *c); -#define git_SHA_CTX ppc_SHA_CTX -#define git_SHA1_Init ppc_SHA1_Init -#define git_SHA1_Update ppc_SHA1_Update -#define git_SHA1_Final ppc_SHA1_Final +#define platform_SHA_CTX ppc_SHA_CTX +#define platform_SHA1_Init ppc_SHA1_Init +#define platform_SHA1_Update ppc_SHA1_Update +#define platform_SHA1_Final ppc_SHA1_Final @@ -4643,7 +4643,7 @@ int reflog_expire(const char *refname, const unsigned char *sha1, get_lock_file_path(lock->lk)); rollback_lock_file(&reflog_lock); } else if (commit_lock_file(&reflog_lock)) { - status |= error("unable to commit reflog '%s' (%s)", + status |= error("unable to write reflog %s: %s", log_file, strerror(errno)); } else if (update && commit_ref(lock)) { status |= error("couldn't set %s", lock->ref_name); @@ -1975,10 +1975,8 @@ int resolve_remote_symref(struct ref *ref, struct ref *list) static void unmark_and_free(struct commit_list *list, unsigned int mark) { while (list) { - struct commit_list *temp = list; - temp->item->object.flags &= ~mark; - list = temp->next; - free(temp); + struct commit *commit = pop_commit(&list); + commit->object.flags &= ~mark; } } diff --git a/revision.c b/revision.c index af2a18ed74..f6caef0672 100644 --- a/revision.c +++ b/revision.c @@ -135,10 +135,12 @@ static void mark_tree_contents_uninteresting(struct tree *tree) void mark_tree_uninteresting(struct tree *tree) { - struct object *obj = &tree->object; + struct object *obj; if (!tree) return; + + obj = &tree->object; if (obj->flags & UNINTERESTING) return; obj->flags |= UNINTERESTING; @@ -153,10 +155,7 @@ void mark_parents_uninteresting(struct commit *commit) commit_list_insert(l->item, &parents); while (parents) { - struct commit *commit = parents->item; - l = parents; - parents = parents->next; - free(l); + struct commit *commit = pop_commit(&parents); while (commit) { /* @@ -1102,14 +1101,10 @@ static int limit_list(struct rev_info *revs) } while (list) { - struct commit_list *entry = list; - struct commit *commit = list->item; + struct commit *commit = pop_commit(&list); struct object *obj = &commit->object; show_early_output_fn_t show; - list = list->next; - free(entry); - if (commit == interesting_cache) interesting_cache = NULL; @@ -2733,10 +2728,7 @@ static void simplify_merges(struct rev_info *revs) yet_to_do = NULL; tail = &yet_to_do; while (list) { - commit = list->item; - next = list->next; - free(list); - list = next; + commit = pop_commit(&list); tail = simplify_one(revs, commit, tail); } } @@ -2748,10 +2740,7 @@ static void simplify_merges(struct rev_info *revs) while (list) { struct merge_simplify_state *st; - commit = list->item; - next = list->next; - free(list); - list = next; + commit = pop_commit(&list); st = locate_simplify_state(revs, commit); if (st->simplified == commit) tail = &commit_list_insert(commit, tail)->next; @@ -3125,11 +3114,7 @@ static struct commit *get_revision_1(struct rev_info *revs) return NULL; do { - struct commit_list *entry = revs->commits; - struct commit *commit = entry->item; - - revs->commits = entry->next; - free(entry); + struct commit *commit = pop_commit(&revs->commits); if (revs->reflog_info) { save_parents(revs, commit); diff --git a/sha1_file.c b/sha1_file.c index 40a0169ceb..72289696d9 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1228,27 +1228,16 @@ void install_packed_git(struct packed_git *pack) packed_git = pack; } -void (*report_garbage)(const char *desc, const char *path); +void (*report_garbage)(unsigned seen_bits, const char *path); static void report_helper(const struct string_list *list, int seen_bits, int first, int last) { - const char *msg; - switch (seen_bits) { - case 0: - msg = "no corresponding .idx or .pack"; - break; - case 1: - msg = "no corresponding .idx"; - break; - case 2: - msg = "no corresponding .pack"; - break; - default: + if (seen_bits == (PACKDIR_FILE_PACK|PACKDIR_FILE_IDX)) return; - } + for (; first < last; first++) - report_garbage(msg, list->items[first].string); + report_garbage(seen_bits, list->items[first].string); } static void report_pack_garbage(struct string_list *list) @@ -1271,7 +1260,7 @@ static void report_pack_garbage(struct string_list *list) if (baselen == -1) { const char *dot = strrchr(path, '.'); if (!dot) { - report_garbage("garbage found", path); + report_garbage(PACKDIR_FILE_GARBAGE, path); continue; } baselen = dot - path + 1; @@ -1343,7 +1332,7 @@ static void prepare_packed_git_one(char *objdir, int local) ends_with(de->d_name, ".keep")) string_list_append(&garbage, path.buf); else - report_garbage("garbage found", path.buf); + report_garbage(PACKDIR_FILE_GARBAGE, path.buf); } closedir(dir); report_pack_garbage(&garbage); @@ -3518,12 +3507,12 @@ static int for_each_file_in_obj_subdir(int subdir_nr, break; } } - strbuf_setlen(path, baselen); + closedir(dir); + strbuf_setlen(path, baselen); if (!r && subdir_cb) r = subdir_cb(subdir_nr, path->buf, data); - closedir(dir); return r; } @@ -401,13 +401,9 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1, commit_list_insert(c, &head); while (head) { struct commit_list *p; - struct commit *c = head->item; + struct commit *c = pop_commit(&head); uint32_t **refs = ref_bitmap_at(&info->ref_bitmap, c); - p = head; - head = head->next; - free(p); - /* XXX check "UNINTERESTING" from pack bitmaps if available */ if (c->object.flags & (SEEN | UNINTERESTING)) continue; diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 98eb49ac23..9067e0206f 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -1234,7 +1234,7 @@ test_expect_success 'tabs and spaces are accepted in the todolist' ' # Turn single spaces into space/tab mix sed "1s/ / /g; 2s/ / /g; 3s/ / /g" "$1" printf "\n\t# comment\n #more\n\t # comment\n" - ) >$1.new + ) >"$1.new" mv "$1.new" "$1" EOF test_set_editor "$(pwd)/add-indent.sh" && diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh index d783f03d3f..944154b2e0 100755 --- a/t/t3420-rebase-autostash.sh +++ b/t/t3420-rebase-autostash.sh @@ -37,6 +37,16 @@ testrebase() { type=$1 dotest=$2 + test_expect_success "rebase$type: dirty worktree, --no-autostash" ' + test_config rebase.autostash true && + git reset --hard && + git checkout -b rebased-feature-branch feature-branch && + test_when_finished git branch -D rebased-feature-branch && + test_when_finished git checkout feature-branch && + echo dirty >>file3 && + test_must_fail git rebase$type --no-autostash unrelated-onto-branch + ' + test_expect_success "rebase$type: dirty worktree, non-conflicting rebase" ' test_config rebase.autostash true && git reset --hard && diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index 023d7c6f7b..def203c724 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -219,6 +219,7 @@ test_expect_success 'gc: prune old objects after local clone' ' test_expect_success 'garbage report in count-objects -v' ' test_when_finished "rm -f .git/objects/pack/fake*" && + test_when_finished "rm -f .git/objects/pack/foo*" && : >.git/objects/pack/foo && : >.git/objects/pack/foo.bar && : >.git/objects/pack/foo.keep && @@ -244,6 +245,26 @@ EOF test_cmp expected actual ' +test_expect_success 'clean pack garbage with gc' ' + test_when_finished "rm -f .git/objects/pack/fake*" && + test_when_finished "rm -f .git/objects/pack/foo*" && + : >.git/objects/pack/foo.keep && + : >.git/objects/pack/foo.pack && + : >.git/objects/pack/fake.idx && + : >.git/objects/pack/fake2.keep && + : >.git/objects/pack/fake2.idx && + : >.git/objects/pack/fake3.keep && + git gc && + git count-objects -v 2>stderr && + grep "^warning:" stderr | sort >actual && + cat >expected <<\EOF && +warning: no corresponding .idx or .pack: .git/objects/pack/fake3.keep +warning: no corresponding .idx: .git/objects/pack/foo.keep +warning: no corresponding .idx: .git/objects/pack/foo.pack +EOF + test_cmp expected actual +' + test_expect_success 'prune .git/shallow' ' SHA1=`echo hi|git commit-tree HEAD^{tree}` && echo $SHA1 >.git/shallow && diff --git a/t/t5571-pre-push-hook.sh b/t/t5571-pre-push-hook.sh index 6f9916a390..ba975bb355 100755 --- a/t/t5571-pre-push-hook.sh +++ b/t/t5571-pre-push-hook.sh @@ -109,23 +109,20 @@ test_expect_success 'push to URL' ' diff expected actual ' -# Test that filling pipe buffers doesn't cause failure -# Too slow to leave enabled for general use -if false -then - printf 'parent1\nrepo1\n' >expected - nr=1000 - while test $nr -lt 2000 - do - nr=$(( $nr + 1 )) - git branch b/$nr $COMMIT3 - echo "refs/heads/b/$nr $COMMIT3 refs/heads/b/$nr $_z40" >>expected - done - - test_expect_success 'push many refs' ' - git push parent1 "refs/heads/b/*:refs/heads/b/*" && - diff expected actual - ' -fi +test_expect_success 'set up many-ref tests' ' + { + nr=1000 + while test $nr -lt 2000 + do + nr=$(( $nr + 1 )) + echo "create refs/heads/b/$nr $COMMIT3" + done + } | git update-ref --stdin +' + +test_expect_success 'sigpipe does not cause pre-push hook failure' ' + echo "exit 0" | write_script "$HOOK" && + git push parent1 "refs/heads/b/*:refs/heads/b/*" +' test_done diff --git a/t/t5801-remote-helpers.sh b/t/t5801-remote-helpers.sh index c9d3ed14c3..362b1581e0 100755 --- a/t/t5801-remote-helpers.sh +++ b/t/t5801-remote-helpers.sh @@ -242,13 +242,6 @@ clean_mark () { sort >$(basename "$1") } -cmp_marks () { - test_when_finished "rm -rf git.marks testgit.marks" && - clean_mark ".git/testgit/$1/git.marks" && - clean_mark ".git/testgit/$1/testgit.marks" && - test_cmp git.marks testgit.marks -} - test_expect_success 'proper failure checks for fetching' ' (cd local && test_must_fail env GIT_REMOTE_TESTGIT_FAILURE=1 git fetch 2>error && @@ -258,12 +251,15 @@ test_expect_success 'proper failure checks for fetching' ' ' test_expect_success 'proper failure checks for pushing' ' + test_when_finished "rm -rf local/git.marks local/testgit.marks" && (cd local && git checkout -b crash master && echo crash >>file && git commit -a -m crash && test_must_fail env GIT_REMOTE_TESTGIT_FAILURE=1 git push --all && - cmp_marks origin + clean_mark ".git/testgit/origin/git.marks" && + clean_mark ".git/testgit/origin/testgit.marks" && + test_cmp git.marks testgit.marks ) ' diff --git a/t/t5813-proto-disable-ssh.sh b/t/t5813-proto-disable-ssh.sh index ad877d774a..a954ead8af 100755 --- a/t/t5813-proto-disable-ssh.sh +++ b/t/t5813-proto-disable-ssh.sh @@ -14,7 +14,7 @@ test_expect_success 'setup repository to clone' ' ' test_proto "host:path" ssh "remote:repo.git" -test_proto "ssh://" ssh "ssh://remote/$PWD/remote/repo.git" -test_proto "git+ssh://" ssh "git+ssh://remote/$PWD/remote/repo.git" +test_proto "ssh://" ssh "ssh://remote$PWD/remote/repo.git" +test_proto "git+ssh://" ssh "git+ssh://remote$PWD/remote/repo.git" test_done diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 377c648e04..869e0bf073 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -418,4 +418,11 @@ test_expect_success 'filter commit message without trailing newline' ' test_cmp expect actual ' +test_expect_success 'tree-filter deals with object name vs pathname ambiguity' ' + test_when_finished "git reset --hard original" && + ambiguous=$(git rev-list -1 HEAD) && + git filter-branch --tree-filter "mv file.t $ambiguous" HEAD^.. && + git show HEAD:$ambiguous +' + test_done diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index 7eeb207b32..6f12b235b3 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -174,9 +174,9 @@ test_expect_success 'mergetool skips autoresolved' ' ' test_expect_success 'mergetool merges all from subdir' ' + test_config rerere.enabled false && ( cd subdir && - test_config rerere.enabled false && test_must_fail git merge master && ( yes "r" | git mergetool ../submod ) && ( yes "d" "d" | git mergetool --no-prompt ) && diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index ea35a0241c..ec8bc8c765 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -492,12 +492,31 @@ test_expect_success PERL 'difftool --no-symlinks detects conflict ' ' test_expect_success PERL 'difftool properly honors gitlink and core.worktree' ' git submodule add ./. submod/ule && + test_config -C submod/ule diff.tool checktrees && + test_config -C submod/ule difftool.checktrees.cmd '\'' + test -d "$LOCAL" && test -d "$REMOTE" && echo good + '\'' && ( cd submod/ule && - test_config diff.tool checktrees && - test_config difftool.checktrees.cmd '\'' - test -d "$LOCAL" && test -d "$REMOTE" && echo good - '\'' && + echo good >expect && + git difftool --tool=checktrees --dir-diff HEAD~ >actual && + test_cmp expect actual + ) +' + +test_expect_success PERL,SYMLINKS 'difftool --dir-diff symlinked directories' ' + git init dirlinks && + ( + cd dirlinks && + git config diff.tool checktrees && + git config difftool.checktrees.cmd "echo good" && + mkdir foo && + : >foo/bar && + git add foo/bar && + test_commit symlink-one && + ln -s foo link && + git add link && + test_commit symlink-two && echo good >expect && git difftool --tool=checktrees --dir-diff HEAD~ >actual && test_cmp expect actual diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh index 90d41ed954..0730f18d0f 100755 --- a/t/t9800-git-p4-basic.sh +++ b/t/t9800-git-p4-basic.sh @@ -241,6 +241,22 @@ test_expect_success 'unresolvable host in P4PORT should display error' ' ) ' +test_expect_success 'submit from detached head' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git checkout p4/master && + >detached_head_test && + git add detached_head_test && + git commit -m "add detached_head" && + git config git-p4.skipSubmitEdit true && + git p4 submit && + git p4 rebase && + git log p4/master | grep detached_head + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9807-git-p4-submit.sh b/t/t9807-git-p4-submit.sh index 1f74a88385..593152817d 100755 --- a/t/t9807-git-p4-submit.sh +++ b/t/t9807-git-p4-submit.sh @@ -389,7 +389,7 @@ test_expect_success 'description with Jobs section and bogus following text' ' ( cd "$cli" && p4 revert desc6 && - rm desc6 + rm -f desc6 ) ' diff --git a/t/t9826-git-p4-keep-empty-commits.sh b/t/t9826-git-p4-keep-empty-commits.sh new file mode 100755 index 0000000000..be12960d39 --- /dev/null +++ b/t/t9826-git-p4-keep-empty-commits.sh @@ -0,0 +1,134 @@ +#!/bin/sh + +test_description='Clone repositories and keep empty commits' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'Create a repo' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + + mkdir -p subdir && + + >subdir/file1.txt && + p4 add subdir/file1.txt && + p4 submit -d "Add file 1" && + + >file2.txt && + p4 add file2.txt && + p4 submit -d "Add file 2" && + + >subdir/file3.txt && + p4 add subdir/file3.txt && + p4 submit -d "Add file 3" && + + >file4.txt && + p4 add file4.txt && + p4 submit -d "Add file 4" && + + p4 delete subdir/file3.txt && + p4 submit -d "Remove file 3" && + + p4 delete file4.txt && + p4 submit -d "Remove file 4" + ) +' + +test_expect_success 'Clone repo root path with all history' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git p4 clone --use-client-spec --destination="$git" //depot@all && + cat >expect <<-\EOF && +Remove file 4 +[git-p4: depot-paths = "//depot/": change = 6] + +Remove file 3 +[git-p4: depot-paths = "//depot/": change = 5] + +Add file 4 +[git-p4: depot-paths = "//depot/": change = 4] + +Add file 3 +[git-p4: depot-paths = "//depot/": change = 3] + +Add file 2 +[git-p4: depot-paths = "//depot/": change = 2] + +Add file 1 +[git-p4: depot-paths = "//depot/": change = 1] + + EOF + git log --format=%B >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone repo subdir with all history but keep empty commits' ' + client_view "//depot/subdir/... //client/subdir/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.keepEmptyCommits true && + git p4 clone --use-client-spec --destination="$git" //depot@all && + cat >expect <<-\EOF && +Remove file 4 +[git-p4: depot-paths = "//depot/": change = 6] + +Remove file 3 +[git-p4: depot-paths = "//depot/": change = 5] + +Add file 4 +[git-p4: depot-paths = "//depot/": change = 4] + +Add file 3 +[git-p4: depot-paths = "//depot/": change = 3] + +Add file 2 +[git-p4: depot-paths = "//depot/": change = 2] + +Add file 1 +[git-p4: depot-paths = "//depot/": change = 1] + + EOF + git log --format=%B >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone repo subdir with all history' ' + client_view "//depot/subdir/... //client/subdir/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git p4 clone --use-client-spec --destination="$git" --verbose //depot@all && + cat >expect <<-\EOF && +Remove file 3 +[git-p4: depot-paths = "//depot/": change = 5] + +Add file 3 +[git-p4: depot-paths = "//depot/": change = 3] + +Add file 1 +[git-p4: depot-paths = "//depot/": change = 1] + + EOF + git log --format=%B >actual && + test_cmp expect actual + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh index 6b68777b98..af82049f82 100755 --- a/t/t9903-bash-prompt.sh +++ b/t/t9903-bash-prompt.sh @@ -273,11 +273,36 @@ test_expect_success 'prompt - dirty status indicator - dirty index and worktree' test_cmp expected "$actual" ' -test_expect_success 'prompt - dirty status indicator - before root commit' ' - printf " (master #)" >expected && +test_expect_success 'prompt - dirty status indicator - orphan branch - clean' ' + printf " (orphan #)" >expected && + test_when_finished "git checkout master" && + git checkout --orphan orphan && + git reset --hard && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - orphan branch - dirty index' ' + printf " (orphan +)" >expected && + test_when_finished "git checkout master" && + git checkout --orphan orphan && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - orphan branch - dirty index and worktree' ' + printf " (orphan *+)" >expected && + test_when_finished "git checkout master" && + git checkout --orphan orphan && + >file && ( GIT_PS1_SHOWDIRTYSTATE=y && - cd otherrepo && __git_ps1 >"$actual" ) && test_cmp expected "$actual" diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index e8d3c0fdbc..6dffb8bcde 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -201,7 +201,14 @@ test_chmod () { # Unset a configuration variable, but don't fail if it doesn't exist. test_unconfig () { - git config --unset-all "$@" + config_dir= + if test "$1" = -C + then + shift + config_dir=$1 + shift + fi + git ${config_dir:+-C "$config_dir"} config --unset-all "$@" config_status=$? case "$config_status" in 5) # ok, nothing to unset @@ -213,8 +220,15 @@ test_unconfig () { # Set git config, automatically unsetting it after the test is over. test_config () { - test_when_finished "test_unconfig '$1'" && - git config "$@" + config_dir= + if test "$1" = -C + then + shift + config_dir=$1 + shift + fi + test_when_finished "test_unconfig ${config_dir:+-C '$config_dir'} '$1'" && + git ${config_dir:+-C "$config_dir"} config "$@" } test_config_global () { @@ -722,6 +736,11 @@ test_seq () { # what went wrong. test_when_finished () { + # We cannot detect when we are in a subshell in general, but by + # doing so on Bash is better than nothing (the test will + # silently pass on other shells). + test "${BASH_SUBSHELL-0}" = 0 || + error "bug in test script: test_when_finished does nothing in a subshell" test_cleanup="{ $* } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" } diff --git a/transport.c b/transport.c index 863eb524f9..37e4f5e42c 100644 --- a/transport.c +++ b/transport.c @@ -15,6 +15,7 @@ #include "submodule.h" #include "string-list.h" #include "sha1-array.h" +#include "sigchain.h" /* rsync support */ @@ -1126,6 +1127,8 @@ static int run_pre_push_hook(struct transport *transport, return -1; } + sigchain_push(SIGPIPE, SIG_IGN); + strbuf_init(&buf, 256); for (r = remote_refs; r; r = r->next) { @@ -1139,8 +1142,10 @@ static int run_pre_push_hook(struct transport *transport, r->peer_ref->name, sha1_to_hex(r->new_sha1), r->name, sha1_to_hex(r->old_sha1)); - if (write_in_full(proc.in, buf.buf, buf.len) != buf.len) { - ret = -1; + if (write_in_full(proc.in, buf.buf, buf.len) < 0) { + /* We do not mind if a hook does not read all refs. */ + if (errno != EPIPE) + ret = -1; break; } } @@ -1151,6 +1156,8 @@ static int run_pre_push_hook(struct transport *transport, if (!ret) ret = x; + sigchain_pop(SIGPIPE); + x = finish_command(&proc); if (!ret) ret = x; diff --git a/upload-pack.c b/upload-pack.c index 89e832b64a..d0bc3ca07a 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -316,10 +316,8 @@ static int reachable(struct commit *want) commit_list_insert_by_date(want, &work); while (work) { - struct commit_list *list = work->next; - struct commit *commit = work->item; - free(work); - work = list; + struct commit_list *list; + struct commit *commit = pop_commit(&work); if (commit->object.flags & THEY_HAVE) { want->object.flags |= COMMON_KNOWN; diff --git a/wt-status.c b/wt-status.c index 435fc2806e..ced53dd1d4 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1317,15 +1317,14 @@ static int grab_1st_switch(unsigned char *osha1, unsigned char *nsha1, target += strlen(" to "); strbuf_reset(&cb->buf); hashcpy(cb->nsha1, nsha1); - for (end = target; *end && *end != '\n'; end++) - ; - if (!memcmp(target, "HEAD", end - target)) { + end = strchrnul(target, '\n'); + strbuf_add(&cb->buf, target, end - target); + if (!strcmp(cb->buf.buf, "HEAD")) { /* HEAD is relative. Resolve it to the right reflog entry. */ + strbuf_reset(&cb->buf); strbuf_addstr(&cb->buf, find_unique_abbrev(nsha1, DEFAULT_ABBREV)); - return 1; } - strbuf_add(&cb->buf, target, end - target); return 1; } |