diff options
79 files changed, 1341 insertions, 235 deletions
diff --git a/Documentation/RelNotes/1.7.5.1.txt b/Documentation/RelNotes/1.7.5.1.txt new file mode 100644 index 0000000000..c6ebd76d19 --- /dev/null +++ b/Documentation/RelNotes/1.7.5.1.txt @@ -0,0 +1,47 @@ +Git v1.7.5.1 Release Notes +========================== + +Fixes since v1.7.5 +------------------ + + * When an object "$tree:$path" does not exist, if $path does exist in the + subtree of $tree that corresponds to the subdirectory the user is in, + git now suggests using "$tree:./$path" in addition to the advice to use + the full path from the root of the working tree. + + * The "--date=relative" output format used to say "X years, 12 months" + when it should have said "X+1 years". + + * The smart-HTTP transfer was broken in 1.7.5 when the client needs + to issue a small POST (which uses content-length) and then a large + POST (which uses chunked) back to back. + + * "git clean" used to fail on an empty directory that is not readable, + even though rmdir(2) could remove such a directory. Now we attempt it + as the last resort. + + * The "--dirstat" option of "diff" family of commands used to totally + ignore a change that only rearranged lines within a file. Such a + change now counts as at least a minimum but non zero change. + + * The "--dirstat" option of "diff" family of commands used to use the + pathname in the original, instead of the pathname in the result, + when renames are involved. + + * "git pack-object" did not take core.bigfilethreashold into account + (unlike fast-import); now it does. + + * "git reflog" ignored options like "--format=.." on the command line. + + * "git stash apply" used to refuse to work if there was any change in + the working tree, even when the change did not overlap with the change + the stash recorded. + + * "git stash apply @{99999}" was not diagnosed as an error, even when you + did not have that many stash entries. + + * An error message from "git send-email" to diagnose a broken SMTP + connection configuration lacked a space between "hello=<smtp-domain>" + and "port=<smtp-server-port>". + +And other minor fixes and documentation updates. diff --git a/Documentation/RelNotes/1.7.5.2.txt b/Documentation/RelNotes/1.7.5.2.txt new file mode 100644 index 0000000000..b985b07da5 --- /dev/null +++ b/Documentation/RelNotes/1.7.5.2.txt @@ -0,0 +1,42 @@ +Git v1.7.5.2 Release Notes +========================== + +The release notes to 1.7.5.1 forgot to mention: + + * "git stash -p --no-keep-index" and "git stash --no-keep-index -p" now + mean the same thing. + + * "git upload-pack" (hence "git push" over git native protocol) had a + subtle race condition that could lead to a deadlock. + +Fixes since v1.7.5.1 +-------------------- + + * "git cvsimport" did not know that CVSNT stores its password file in a + location different from the traditional CVS. + + * "git diff-files" did not show the mode information from the working + tree side of an unmerged path correctly. + + * "git diff -M --cached" used to use unmerged path as a possible rename + source candidate, which made no sense. + + * "git format-patch" did not quote RFC822 special characters in the + email address (e.g From: Junio C. Hamano <jch@example.com>, not + From: "Junio C. Hamano" <jch@example.com>). + + * "git format-patch" when run with "--quiet" option used to produce a + nonsense result that consists of alternating empty output. + + * "git merge-one-file" did not honor GIT_WORK_TREE settings when + handling a "both sides added, differently" conflict. + + * "git mergetool" did not handle conflicted submoudules gracefully. + + * "git-p4" (in contrib) used a wrong base image while merge a file that + was added on both branches differently. + + * "git rebase -i -p" failed to preserve the history when there is a + redundant merge created with the --no-ff option. + +And other minor fixes and documentation updates. diff --git a/Documentation/config.txt b/Documentation/config.txt index 750c86d4f5..0906499e7d 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -442,8 +442,6 @@ for most projects as source code and other text files can still be delta compressed, but larger binary media files won't be. + Common unit suffixes of 'k', 'm', or 'g' are supported. -+ -Currently only linkgit:git-fast-import[1] honors this setting. core.excludesfile:: In addition to '.gitignore' (per-directory) and diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index c93124be79..c32105f1ed 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -72,6 +72,10 @@ endif::git-format-patch[] a cut-off percent (3% by default) are not shown. The cut-off percent can be set with `--dirstat=<limit>`. Changes in a child directory are not counted for the parent directory, unless `--cumulative` is used. ++ +Note that the `--dirstat` option computes the changes while ignoring +the amount of pure code movements within a file. In other words, +rearranging lines in a file is not counted as much as other changes. --dirstat-by-file[=<limit>]:: Same as `--dirstat`, but counts changed files instead of lines. @@ -239,7 +243,7 @@ ifdef::git-log[] For following files across renames while traversing history, see `--follow`. endif::git-log[] - If `n` is specified, it is a is a threshold on the similarity + If `n` is specified, it is a threshold on the similarity index (i.e. amount of addition/deletions compared to the file's size). For example, `-M90%` means git should consider a delete/add pair to be a rename if more than 90% of the file diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index 7eebbefe7b..35cb5d3f64 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -134,6 +134,8 @@ subdirectories. If some files could not be added because of errors indexing them, do not abort the operation, but continue adding the others. The command shall still exit with non-zero status. + The configuration variable `add.ignoreErrors` can be set to + true to make this the default behaviour. --ignore-missing:: This option can only be used together with --dry-run. By using diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt index 2c2ea12c5c..249249aac7 100644 --- a/Documentation/git-fast-import.txt +++ b/Documentation/git-fast-import.txt @@ -83,7 +83,7 @@ OPTIONS skips the file if it does not exist. --relative-marks:: - After specifying --relative-marks= the paths specified + After specifying --relative-marks the paths specified with --import-marks= and --export-marks= are relative to an internal directory in the current repository. In git-fast-import this means that the paths are relative @@ -93,7 +93,7 @@ OPTIONS --no-relative-marks:: Negates a previous --relative-marks. Allows for combining relative and non-relative marks by interweaving - --(no-)-relative-marks= with the --(import|export)-marks= + --(no-)-relative-marks with the --(import|export)-marks= options. --cat-blob-fd=<fd>:: diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index a5525e9aa8..f4e959d662 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -20,7 +20,7 @@ SYNOPSIS [--ignore-if-in-upstream] [--subject-prefix=Subject-Prefix] [--to=<email>] [--cc=<email>] - [--cover-letter] + [--cover-letter] [--quiet] [<common diff options>] [ <since> | <revision range> ] @@ -196,6 +196,9 @@ will want to ensure that threading is disabled for `git send-email`. Note that the leading character does not have to be a dot; for example, you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`. +--quiet:: + Do not print the names of the generated files to standard output. + --no-binary:: Do not output contents of changes in binary files, instead display a notice that those files changed. Patches generated diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt index c9ede794b0..a2a508dc28 100644 --- a/Documentation/git-fsck.txt +++ b/Documentation/git-fsck.txt @@ -26,7 +26,7 @@ index file, all SHA1 references in .git/refs/*, and all reflogs (unless --no-reflogs is given) as heads. --unreachable:: - Print out objects that exist but that aren't readable from any + Print out objects that exist but that aren't reachable from any of the reference nodes. --root:: @@ -76,7 +76,7 @@ It tests SHA1 and general object sanity, and it does full tracking of the resulting reachability and everything else. It prints out any corruption it finds (missing or bad objects), and if you use the '--unreachable' flag it will also print out objects that exist but -that aren't readable from any of the specified head nodes. +that aren't reachable from any of the specified head nodes. So for example diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 30a67486d2..509dc03376 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -145,17 +145,6 @@ Skip "branches" and "tags" of first level directories;; ------------------------------------------------------------------------ -- ---use-log-author;; - When retrieving svn commits into git (as part of fetch, rebase, or - dcommit operations), look for the first From: or Signed-off-by: line - in the log message and use that as the author string. ---add-author-from;; - When committing to svn from git (as part of commit or dcommit - operations), if the existing log message doesn't already have a - From: or Signed-off-by: line, append a From: line based on the - git commit's author string. If you use this, then --use-log-author - will retrieve a valid author string for all commits. - 'clone':: Runs 'init' and 'fetch'. It will automatically create a directory based on the basename of the URL passed to it; @@ -572,6 +561,17 @@ repository that will be fetched from. For 'branch' and 'tag', display the urls that will be used for copying when creating the branch or tag. +--use-log-author:: + When retrieving svn commits into git (as part of 'fetch', 'rebase', or + 'dcommit' operations), look for the first `From:` or `Signed-off-by:` line + in the log message and use that as the author string. +--add-author-from:: + When committing to svn from git (as part of 'commit-diff', 'set-tree' or 'dcommit' + operations), if the existing log message doesn't already have a + `From:` or `Signed-off-by:` line, append a `From:` line based on the + git commit's author string. If you use this, then `--use-log-author` + will retrieve a valid author string for all commits. + ADVANCED OPTIONS ---------------- diff --git a/Documentation/git.txt b/Documentation/git.txt index 9d5949229a..78420b133a 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -44,9 +44,10 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.7.5/git.html[documentation for release 1.7.5] +* link:v1.7.5.1/git.html[documentation for release 1.7.5.1] * release notes for + link:RelNotes/1.7.5.1.txt[1.7.5.1], link:RelNotes/1.7.5.txt[1.7.5]. * link:v1.7.4.5/git.html[documentation for release 1.7.4.5] diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 68691b3c12..38ecb5314d 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.7.5 +DEF_VER=v1.7.5.1 LF=' ' @@ -1 +1 @@ -Documentation/RelNotes/1.7.5.txt
\ No newline at end of file +Documentation/RelNotes/1.7.5.2.txt
\ No newline at end of file diff --git a/builtin/add.c b/builtin/add.c index d39a6ab930..944e5a8cc9 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -330,8 +330,8 @@ static struct option builtin_add_options[] = { static int add_config(const char *var, const char *value, void *cb) { - if (!strcasecmp(var, "add.ignoreerrors") || - !strcasecmp(var, "add.ignore-errors")) { + if (!strcmp(var, "add.ignoreerrors") || + !strcmp(var, "add.ignore-errors")) { ignore_add_errors = git_config_bool(var, value); return 0; } diff --git a/builtin/apply.c b/builtin/apply.c index 36e150768b..530d4bb7e7 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -43,6 +43,7 @@ static int apply = 1; static int apply_in_reverse; static int apply_with_reject; static int apply_verbosely; +static int allow_overlap; static int no_add; static const char *fake_ancestor; static int line_termination = '\n'; @@ -2430,9 +2431,9 @@ static void update_image(struct image *img, memcpy(img->line + applied_pos, postimage->line, postimage->nr * sizeof(*img->line)); - for (i = 0; i < postimage->nr; i++) - img->line[applied_pos + i].flag |= LINE_PATCHED; - + if (!allow_overlap) + for (i = 0; i < postimage->nr; i++) + img->line[applied_pos + i].flag |= LINE_PATCHED; img->nr = nr; } @@ -3889,6 +3890,8 @@ int cmd_apply(int argc, const char **argv, const char *prefix_) "don't expect at least one line of context"), OPT_BOOLEAN(0, "reject", &apply_with_reject, "leave the rejected hunks in corresponding *.rej files"), + OPT_BOOLEAN(0, "allow-overlap", &allow_overlap, + "allow overlapping hunks"), OPT__VERBOSE(&apply_verbosely, "be verbose"), OPT_BIT(0, "inaccurate-eof", &options, "tolerate incorrectly detected missing new-line at the end of file", diff --git a/builtin/blame.c b/builtin/blame.c index f6b03f750a..41525f1ea1 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1377,7 +1377,7 @@ static void get_ac_line(const char *inbuf, const char *what, timepos = tmp; *tmp = 0; - while (person < tmp && *tmp != ' ') + while (person < tmp && !(*tmp == ' ' && tmp[1] == '<')) tmp--; if (tmp <= person) return; diff --git a/builtin/log.c b/builtin/log.c index 9db43edb06..c6dce9b895 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -49,13 +49,8 @@ static int parse_decoration_style(const char *var, const char *value) return -1; } -static void cmd_log_init(int argc, const char **argv, const char *prefix, - struct rev_info *rev, struct setup_revision_opt *opt) +static void cmd_log_init_defaults(struct rev_info *rev) { - int i; - int decoration_given = 0; - struct userformat_want w; - rev->abbrev = DEFAULT_ABBREV; rev->commit_format = CMIT_FMT_DEFAULT; if (fmt_pretty) @@ -68,7 +63,14 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, if (default_date_mode) rev->date_mode = parse_date_format(default_date_mode); +} +static void cmd_log_init_finish(int argc, const char **argv, const char *prefix, + struct rev_info *rev, struct setup_revision_opt *opt) +{ + int i; + int decoration_given = 0; + struct userformat_want w; /* * Check for -h before setup_revisions(), or "git log -h" will * fail when run without a git directory. @@ -128,6 +130,13 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, setup_pager(); } +static void cmd_log_init(int argc, const char **argv, const char *prefix, + struct rev_info *rev, struct setup_revision_opt *opt) +{ + cmd_log_init_defaults(rev); + cmd_log_init_finish(argc, argv, prefix, rev, opt); +} + /* * This gives a rough estimate for how many commits we * will print out in the list. @@ -486,16 +495,11 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix) rev.verbose_header = 1; memset(&opt, 0, sizeof(opt)); opt.def = "HEAD"; - cmd_log_init(argc, argv, prefix, &rev, &opt); - - /* - * This means that we override whatever commit format the user gave - * on the cmd line. Sad, but cmd_log_init() currently doesn't - * allow us to set a different default. - */ + cmd_log_init_defaults(&rev); rev.commit_format = CMIT_FMT_ONELINE; rev.use_terminator = 1; rev.always_show_header = 1; + cmd_log_init_finish(argc, argv, prefix, &rev, &opt); return cmd_log_walk(&rev); } @@ -623,7 +627,7 @@ static FILE *realstdout = NULL; static const char *output_directory = NULL; static int outdir_offset; -static int reopen_stdout(struct commit *commit, struct rev_info *rev) +static int reopen_stdout(struct commit *commit, struct rev_info *rev, int quiet) { struct strbuf filename = STRBUF_INIT; int suffix_len = strlen(fmt_patch_suffix) + 1; @@ -639,7 +643,7 @@ static int reopen_stdout(struct commit *commit, struct rev_info *rev) get_patch_filename(commit, rev->nr, fmt_patch_suffix, &filename); - if (!DIFF_OPT_TST(&rev->diffopt, QUICK)) + if (!quiet) fprintf(realstdout, "%s\n", filename.buf + outdir_offset); if (freopen(filename.buf, "w", stdout) == NULL) @@ -718,7 +722,8 @@ static void print_signature(void) static void make_cover_letter(struct rev_info *rev, int use_stdout, int numbered, int numbered_files, struct commit *origin, - int nr, struct commit **list, struct commit *head) + int nr, struct commit **list, struct commit *head, + int quiet) { const char *committer; const char *subject_start = NULL; @@ -754,7 +759,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, sha1_to_hex(head->object.sha1), committer, committer); } - if (!use_stdout && reopen_stdout(commit, rev)) + if (!use_stdout && reopen_stdout(commit, rev, quiet)) return; if (commit) { @@ -995,6 +1000,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) char *add_signoff = NULL; struct strbuf buf = STRBUF_INIT; int use_patch_format = 0; + int quiet = 0; const struct option builtin_format_patch_options[] = { { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL, "use [PATCH n/m] even with a single patch", @@ -1050,6 +1056,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) PARSE_OPT_OPTARG, thread_callback }, OPT_STRING(0, "signature", &signature, "signature", "add a signature"), + OPT_BOOLEAN(0, "quiet", &quiet, + "don't print the patch filenames"), OPT_END() }; @@ -1259,7 +1267,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (thread) gen_message_id(&rev, "cover"); make_cover_letter(&rev, use_stdout, numbered, numbered_files, - origin, nr, list, head); + origin, nr, list, head, quiet); total++; start_number--; } @@ -1305,7 +1313,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } if (!use_stdout && reopen_stdout(numbered_files ? NULL : commit, - &rev)) + &rev, quiet)) die(_("Failed to create output files")); shown = log_tree_commit(&rev, commit); free(commit->buffer); diff --git a/builtin/merge.c b/builtin/merge.c index d54e7ddbb1..0f03dff116 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -56,6 +56,7 @@ static size_t use_strategies_nr, use_strategies_alloc; static const char **xopts; static size_t xopts_nr, xopts_alloc; static const char *branch; +static char *branch_mergeoptions; static int option_renormalize; static int verbosity; static int allow_rerere_auto; @@ -503,26 +504,34 @@ cleanup: strbuf_release(&bname); } +static void parse_branch_merge_options(char *bmo) +{ + const char **argv; + int argc; + + if (!bmo) + return; + argc = split_cmdline(bmo, &argv); + if (argc < 0) + die(_("Bad branch.%s.mergeoptions string: %s"), branch, + split_cmdline_strerror(argc)); + argv = xrealloc(argv, sizeof(*argv) * (argc + 2)); + memmove(argv + 1, argv, sizeof(*argv) * (argc + 1)); + argc++; + argv[0] = "branch.*.mergeoptions"; + parse_options(argc, argv, NULL, builtin_merge_options, + builtin_merge_usage, 0); + free(argv); +} + static int git_merge_config(const char *k, const char *v, void *cb) { if (branch && !prefixcmp(k, "branch.") && !prefixcmp(k + 7, branch) && !strcmp(k + 7 + strlen(branch), ".mergeoptions")) { - const char **argv; - int argc; - char *buf; - - buf = xstrdup(v); - argc = split_cmdline(buf, &argv); - if (argc < 0) - die(_("Bad branch.%s.mergeoptions string: %s"), branch, - split_cmdline_strerror(argc)); - argv = xrealloc(argv, sizeof(*argv) * (argc + 2)); - memmove(argv + 1, argv, sizeof(*argv) * (argc + 1)); - argc++; - parse_options(argc, argv, NULL, builtin_merge_options, - builtin_merge_usage, 0); - free(buf); + free(branch_mergeoptions); + branch_mergeoptions = xstrdup(v); + return 0; } if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat")) @@ -1010,6 +1019,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; + if (branch_mergeoptions) + parse_branch_merge_options(branch_mergeoptions); argc = parse_options(argc, argv, prefix, builtin_merge_options, builtin_merge_usage, 0); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index b0503b202a..f402a843bb 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1142,8 +1142,12 @@ static void get_object_details(void) sorted_by_offset[i] = objects + i; qsort(sorted_by_offset, nr_objects, sizeof(*sorted_by_offset), pack_offset_sort); - for (i = 0; i < nr_objects; i++) - check_object(sorted_by_offset[i]); + for (i = 0; i < nr_objects; i++) { + struct object_entry *entry = sorted_by_offset[i]; + check_object(entry); + if (big_file_threshold <= entry->size) + entry->no_try_delta = 1; + } free(sorted_by_offset); } @@ -573,6 +573,7 @@ extern int core_compression_seen; extern size_t packed_git_window_size; extern size_t packed_git_limit; extern size_t delta_base_cache_limit; +extern unsigned long big_file_threshold; extern int read_replace_refs; extern int fsync_object_files; extern int core_preload_index; @@ -567,6 +567,12 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.bigfilethreshold")) { + long n = git_config_int(var, value); + big_file_threshold = 0 < n ? n : 0; + return 0; + } + if (!strcmp(var, "core.packedgitlimit")) { packed_git_limit = git_config_int(var, value); return 0; @@ -129,8 +129,9 @@ const char *show_date_relative(unsigned long time, int tz, } /* Give years and months for 5 years or so */ if (diff < 1825) { - unsigned long years = diff / 365; - unsigned long months = (diff % 365 + 15) / 30; + unsigned long totalmonths = (diff * 12 * 2 + 365) / (365 * 2); + unsigned long years = totalmonths / 12; + unsigned long months = totalmonths % 12; int n; n = snprintf(timebuf, timebuf_size, "%lu year%s", years, (years > 1 ? "s" : "")); diff --git a/diff-lib.c b/diff-lib.c index 2870de400e..3b5f2242a5 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -112,6 +112,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option) if (ce_stage(ce)) { struct combine_diff_path *dpath; + struct diff_filepair *pair; + unsigned int wt_mode = 0; int num_compare_stages = 0; size_t path_len; @@ -130,7 +132,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) changed = check_removed(ce, &st); if (!changed) - dpath->mode = ce_mode_from_stat(ce, st.st_mode); + wt_mode = ce_mode_from_stat(ce, st.st_mode); else { if (changed < 0) { perror(ce->name); @@ -138,7 +140,9 @@ int run_diff_files(struct rev_info *revs, unsigned int option) } if (silent_on_removed) continue; + wt_mode = 0; } + dpath->mode = wt_mode; while (i < entries) { struct cache_entry *nce = active_cache[i]; @@ -184,7 +188,9 @@ int run_diff_files(struct rev_info *revs, unsigned int option) * Show the diff for the 'ce' if we found the one * from the desired stage. */ - diff_unmerge(&revs->diffopt, ce->name, 0, null_sha1); + pair = diff_unmerge(&revs->diffopt, ce->name); + if (wt_mode) + pair->two->mode = wt_mode; if (ce_stage(ce) != diff_unmerged_stage) continue; } @@ -373,8 +379,9 @@ static void do_oneway_diff(struct unpack_trees_options *o, match_missing = !revs->ignore_merges; if (cached && idx && ce_stage(idx)) { - diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, - idx->sha1); + struct diff_filepair *pair; + pair = diff_unmerge(&revs->diffopt, idx->name); + fill_filespec(pair->one, idx->sha1, idx->ce_mode); return; } @@ -1538,8 +1538,36 @@ static void show_dirstat(struct diff_options *options) struct diff_filepair *p = q->queue[i]; const char *name; unsigned long copied, added, damage; + int content_changed; - name = p->one->path ? p->one->path : p->two->path; + name = p->two->path ? p->two->path : p->one->path; + + if (p->one->sha1_valid && p->two->sha1_valid) + content_changed = hashcmp(p->one->sha1, p->two->sha1); + else + content_changed = 1; + + if (!content_changed) { + /* + * The SHA1 has not changed, so pre-/post-content is + * identical. We can therefore skip looking at the + * file contents altogether. + */ + damage = 0; + goto found_damage; + } + + if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE)) { + /* + * In --dirstat-by-file mode, we don't really need to + * look at the actual file contents at all. + * The fact that the SHA1 changed is enough for us to + * add this file to the list of results + * (with each file contributing equal damage). + */ + damage = 1; + goto found_damage; + } if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) { diff_populate_filespec(p->one, 0); @@ -1563,14 +1591,18 @@ static void show_dirstat(struct diff_options *options) /* * Original minus copied is the removed material, * added is the new material. They are both damages - * made to the preimage. In --dirstat-by-file mode, count - * damaged files, not damaged lines. This is done by - * counting only a single damaged line per file. + * made to the preimage. + * If the resulting damage is zero, we know that + * diffcore_count_changes() considers the two entries to + * be identical, but since content_changed is true, we + * know that there must have been _some_ kind of change, + * so we force all entries to have damage > 0. */ damage = (p->one->size - copied) + added; - if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE) && damage > 0) + if (!damage) damage = 1; +found_damage: ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc); dir.files[dir.nr].name = name; dir.files[dir.nr].changed = damage; @@ -4349,20 +4381,20 @@ void diff_change(struct diff_options *options, DIFF_OPT_SET(options, HAS_CHANGES); } -void diff_unmerge(struct diff_options *options, - const char *path, - unsigned mode, const unsigned char *sha1) +struct diff_filepair *diff_unmerge(struct diff_options *options, const char *path) { + struct diff_filepair *pair; struct diff_filespec *one, *two; if (options->prefix && strncmp(path, options->prefix, options->prefix_length)) - return; + return NULL; one = alloc_filespec(path); two = alloc_filespec(path); - fill_filespec(one, sha1, mode); - diff_queue(&diff_queued_diff, one, two)->is_unmerged = 1; + pair = diff_queue(&diff_queued_diff, one, two); + pair->is_unmerged = 1; + return pair; } static char *run_textconv(const char *pgm, struct diff_filespec *spec, @@ -208,10 +208,7 @@ extern void diff_change(struct diff_options *, const char *fullpath, unsigned dirty_submodule1, unsigned dirty_submodule2); -extern void diff_unmerge(struct diff_options *, - const char *path, - unsigned mode, - const unsigned char *sha1); +extern struct diff_filepair *diff_unmerge(struct diff_options *, const char *path); #define DIFF_SETUP_REVERSE 1 #define DIFF_SETUP_USE_CACHE 2 diff --git a/diffcore-rename.c b/diffcore-rename.c index d40e40a3ac..0b9e99a04e 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -466,7 +466,7 @@ void diffcore_rename(struct diff_options *options) else locate_rename_dst(p->two, 1); } - else if (!DIFF_FILE_VALID(p->two)) { + else if (!DIFF_PAIR_UNMERGED(p) && !DIFF_FILE_VALID(p->two)) { /* * If the source is a broken "delete", and * they did not really want to get broken, @@ -586,7 +586,10 @@ void diffcore_rename(struct diff_options *options) struct diff_filepair *p = q->queue[i]; struct diff_filepair *pair_to_free = NULL; - if (!DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) { + if (DIFF_PAIR_UNMERGED(p)) { + diff_q(&outq, p); + } + else if (!DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) { /* * Creation * @@ -1192,7 +1192,7 @@ int remove_dir_recursively(struct strbuf *path, int flag) dir = opendir(path->buf); if (!dir) - return -1; + return rmdir(path->buf); if (path->buf[original_len - 1] != '/') strbuf_addch(path, '/'); diff --git a/environment.c b/environment.c index f4549d3f7b..40185bc854 100644 --- a/environment.c +++ b/environment.c @@ -35,6 +35,7 @@ int fsync_object_files; size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE; size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT; size_t delta_base_cache_limit = 16 * 1024 * 1024; +unsigned long big_file_threshold = 512 * 1024 * 1024; const char *pager_program; int pager_use_color = 1; const char *editor_program; diff --git a/fast-import.c b/fast-import.c index 65d65bf8f9..3e4e655bb9 100644 --- a/fast-import.c +++ b/fast-import.c @@ -274,7 +274,6 @@ struct recent_command { /* Configured limits on output */ static unsigned long max_depth = 10; static off_t max_packsize; -static uintmax_t big_file_threshold = 512 * 1024 * 1024; static int force_update; static int pack_compression_level = Z_DEFAULT_COMPRESSION; static int pack_compression_seen; @@ -3206,10 +3205,6 @@ static int git_pack_config(const char *k, const char *v, void *cb) max_packsize = git_config_ulong(k, v); return 0; } - if (!strcmp(k, "core.bigfilethreshold")) { - long n = git_config_int(k, v); - big_file_threshold = 0 < n ? n : 0; - } return git_default_config(k, v, cb); } diff --git a/git-add--interactive.perl b/git-add--interactive.perl index a329c5a1f8..4f08fe704b 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -705,7 +705,7 @@ sub add_untracked_cmd { sub run_git_apply { my $cmd = shift; my $fh; - open $fh, '| git ' . $cmd; + open $fh, '| git ' . $cmd . " --recount --allow-overlap"; print $fh @_; return close $fh; } @@ -1050,7 +1050,7 @@ EOF sub diff_applies { my $fh; - return run_git_apply($patch_mode_flavour{APPLY_CHECK} . ' --recount --check', + return run_git_apply($patch_mode_flavour{APPLY_CHECK} . ' --check', map { @{$_->{TEXT}} } @_); } @@ -1139,7 +1139,7 @@ EOF sub apply_patch { my $cmd = shift; - my $ret = run_git_apply $cmd . ' --recount', @_; + my $ret = run_git_apply $cmd, @_; if (!$ret) { print STDERR @_; } @@ -1148,17 +1148,17 @@ sub apply_patch { sub apply_patch_for_checkout_commit { my $reverse = shift; - my $applies_index = run_git_apply 'apply '.$reverse.' --cached --recount --check', @_; - my $applies_worktree = run_git_apply 'apply '.$reverse.' --recount --check', @_; + my $applies_index = run_git_apply 'apply '.$reverse.' --cached --check', @_; + my $applies_worktree = run_git_apply 'apply '.$reverse.' --check', @_; if ($applies_worktree && $applies_index) { - run_git_apply 'apply '.$reverse.' --cached --recount', @_; - run_git_apply 'apply '.$reverse.' --recount', @_; + run_git_apply 'apply '.$reverse.' --cached', @_; + run_git_apply 'apply '.$reverse, @_; return 1; } elsif (!$applies_index) { print colored $error_color, "The selected hunks do not apply to the index!\n"; if (prompt_yesno "Apply them to the worktree anyway? ") { - return run_git_apply 'apply '.$reverse.' --recount', @_; + return run_git_apply 'apply '.$reverse, @_; } else { print colored $error_color, "Nothing was applied.\n"; return 0; @@ -1366,14 +1366,13 @@ sub patch_update_file { next; } elsif ($line =~ /^q/i) { - while ($ix < $num) { - if (!defined $hunk[$ix]{USE}) { - $hunk[$ix]{USE} = 0; + for ($i = 0; $i < $num; $i++) { + if (!defined $hunk[$i]{USE}) { + $hunk[$i]{USE} = 0; } - $ix++; } $quit = 1; - next; + last; } elsif ($line =~ m|^/(.*)|) { my $regex = $1; diff --git a/git-cvsimport.perl b/git-cvsimport.perl index bbf327f3e8..8d41610bcf 100755 --- a/git-cvsimport.perl +++ b/git-cvsimport.perl @@ -227,6 +227,31 @@ sub new { return $self; } +sub find_password_entry { + my ($cvspass, @cvsroot) = @_; + my ($file, $delim) = @$cvspass; + my $pass; + local ($_); + + if (open(my $fh, $file)) { + # :pserver:cvs@mea.tmt.tele.fi:/cvsroot/zmailer Ah<Z + CVSPASSFILE: + while (<$fh>) { + chomp; + s/^\/\d+\s+//; + my ($w, $p) = split($delim,$_,2); + for my $cvsroot (@cvsroot) { + if ($w eq $cvsroot) { + $pass = $p; + last CVSPASSFILE; + } + } + } + close($fh); + } + return $pass; +} + sub conn { my $self = shift; my $repo = $self->{'fullrep'}; @@ -259,19 +284,23 @@ sub conn { if ($pass) { $pass = $self->_scramble($pass); } else { - open(H,$ENV{'HOME'}."/.cvspass") and do { - # :pserver:cvs@mea.tmt.tele.fi:/cvsroot/zmailer Ah<Z - while (<H>) { - chomp; - s/^\/\d+\s+//; - my ($w,$p) = split(/\s/,$_,2); - if ($w eq $rr or $w eq $rr2) { - $pass = $p; - last; - } + my @cvspass = ([$ENV{'HOME'}."/.cvspass", qr/\s/], + [$ENV{'HOME'}."/.cvs/cvspass", qr/=/]); + my @loc = (); + foreach my $cvspass (@cvspass) { + my $p = find_password_entry($cvspass, $rr, $rr2); + if ($p) { + push @loc, $cvspass->[0]; + $pass = $p; } - }; - $pass = "A" unless $pass; + } + + if (1 < @loc) { + die("Multiple cvs password files have ". + "entries for CVSROOT $opt_d: @loc"); + } elsif (!$pass) { + $pass = "A"; + } } my ($s, $rep); diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index b86402afa5..7aeb96952f 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -22,6 +22,11 @@ LONG_USAGE="Usage: git merge-one-file $USAGE Blob ids and modes should be empty for missing files." +SUBDIRECTORY_OK=Yes +. git-sh-setup +cd_to_toplevel +require_work_tree + if ! test "$#" -eq 7 then echo "$LONG_USAGE" @@ -132,7 +137,7 @@ case "${1:-.}${2:-.}${3:-.}" in # Create the working tree file, using "our tree" version from the # index, and then store the result of the merge. - git checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4" + git checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4" || exit 1 rm -f -- "$orig" "$src1" "$src2" if [ "$6" != "$7" ]; then diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index fb3f52ba25..4db9212331 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -258,12 +258,9 @@ run_merge_tool () { ;; p4merge) if merge_mode; then - touch "$BACKUP" - if $base_present; then - "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED" - else - "$merge_tool_path" "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED" - fi + touch "$BACKUP" + $base_present || >"$BASE" + "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED" check_unchanged else "$merge_tool_path" "$LOCAL" "$REMOTE" diff --git a/git-mergetool.sh b/git-mergetool.sh index bacbda2bb7..3aab5aae84 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -21,6 +21,10 @@ is_symlink () { test "$1" = 120000 } +is_submodule () { + test "$1" = 160000 +} + local_present () { test -n "$local_mode" } @@ -35,7 +39,8 @@ base_present () { cleanup_temp_files () { if test "$1" = --save-backup ; then - mv -- "$BACKUP" "$MERGED.orig" + rm -rf -- "$MERGED.orig" + test -e "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig" rm -f -- "$LOCAL" "$REMOTE" "$BASE" else rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP" @@ -52,11 +57,13 @@ describe_file () { echo "deleted" elif is_symlink "$mode" ; then echo "a symbolic link -> '$(cat "$file")'" + elif is_submodule "$mode" ; then + echo "submodule commit $file" else if base_present; then - echo "modified" + echo "modified file" else - echo "created" + echo "created file" fi fi } @@ -112,6 +119,67 @@ resolve_deleted_merge () { done } +resolve_submodule_merge () { + while true; do + printf "Use (l)ocal or (r)emote, or (a)bort? " + read ans + case "$ans" in + [lL]*) + if ! local_present; then + if test -n "$(git ls-tree HEAD -- "$MERGED")"; then + # Local isn't present, but it's a subdirectory + git ls-tree --full-name -r HEAD -- "$MERGED" | git update-index --index-info || exit $? + else + test -e "$MERGED" && mv -- "$MERGED" "$BACKUP" + git update-index --force-remove "$MERGED" + cleanup_temp_files --save-backup + fi + elif is_submodule "$local_mode"; then + stage_submodule "$MERGED" "$local_sha1" + else + git checkout-index -f --stage=2 -- "$MERGED" + git add -- "$MERGED" + fi + return 0 + ;; + [rR]*) + if ! remote_present; then + if test -n "$(git ls-tree MERGE_HEAD -- "$MERGED")"; then + # Remote isn't present, but it's a subdirectory + git ls-tree --full-name -r MERGE_HEAD -- "$MERGED" | git update-index --index-info || exit $? + else + test -e "$MERGED" && mv -- "$MERGED" "$BACKUP" + git update-index --force-remove "$MERGED" + fi + elif is_submodule "$remote_mode"; then + ! is_submodule "$local_mode" && test -e "$MERGED" && mv -- "$MERGED" "$BACKUP" + stage_submodule "$MERGED" "$remote_sha1" + else + test -e "$MERGED" && mv -- "$MERGED" "$BACKUP" + git checkout-index -f --stage=3 -- "$MERGED" + git add -- "$MERGED" + fi + cleanup_temp_files --save-backup + return 0 + ;; + [aA]*) + return 1 + ;; + esac + done +} + +stage_submodule () { + path="$1" + submodule_sha1="$2" + mkdir -p "$path" || die "fatal: unable to create directory for module at $path" + # Find $path relative to work tree + work_tree_root=$(cd_to_toplevel && pwd) + work_rel_path=$(cd "$path" && GIT_WORK_TREE="${work_tree_root}" git rev-parse --show-prefix) + test -n "$work_rel_path" || die "fatal: unable to get path of module $path relative to work tree" + git update-index --add --replace --cacheinfo 160000 "$submodule_sha1" "${work_rel_path%/}" || die +} + checkout_staged_file () { tmpfile=$(expr "$(git checkout-index --temp --stage="$1" "$2")" : '\([^ ]*\) ') @@ -139,13 +207,23 @@ merge_file () { REMOTE="./$MERGED.REMOTE.$ext" BASE="./$MERGED.BASE.$ext" - mv -- "$MERGED" "$BACKUP" - cp -- "$BACKUP" "$MERGED" - base_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}') local_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}') remote_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}') + if is_submodule "$local_mode" || is_submodule "$remote_mode"; then + echo "Submodule merge conflict for '$MERGED':" + local_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $2;}') + remote_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $2;}') + describe_file "$local_mode" "local" "$local_sha1" + describe_file "$remote_mode" "remote" "$remote_sha1" + resolve_submodule_merge + return + fi + + mv -- "$MERGED" "$BACKUP" + cp -- "$BACKUP" "$MERGED" + base_present && checkout_staged_file 1 "$MERGED" "$BASE" local_present && checkout_staged_file 2 "$MERGED" "$LOCAL" remote_present && checkout_staged_file 3 "$MERGED" "$REMOTE" diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 5873ba4bc3..c308529a9f 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -339,7 +339,7 @@ pick_one_preserving_merges () { # No point in merging the first parent, that's HEAD new_parents=${new_parents# $first_parent} if ! do_with_author output \ - git merge $STRATEGY -m "$msg" $new_parents + git merge --no-ff $STRATEGY -m "$msg" $new_parents then printf "%s\n" "$msg" > "$GIT_DIR"/MERGE_MSG die_with_patch $sha1 "Error redoing merge $sha1" diff --git a/git-send-email.perl b/git-send-email.perl index 76565de2ee..98ab33aae7 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1091,7 +1091,7 @@ X-Mailer: git-send-email $gitversion "VALUES: server=$smtp_server ", "encryption=$smtp_encryption ", "hello=$smtp_domain", - defined $smtp_server_port ? "port=$smtp_server_port" : ""; + defined $smtp_server_port ? " port=$smtp_server_port" : ""; } if (defined $smtp_authuser) { diff --git a/git-stash.sh b/git-stash.sh index a305fb19f1..0a9403653d 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -136,11 +136,12 @@ save_stash () { keep_index=t ;; --no-keep-index) - keep_index= + keep_index=n ;; -p|--patch) patch_mode=t - keep_index=t + # only default to keep if we don't already have an override + test -z "$keep_index" && keep_index=t ;; -q|--quiet) GIT_QUIET=t @@ -185,7 +186,7 @@ save_stash () { then git reset --hard ${GIT_QUIET:+-q} - if test -n "$keep_index" && test -n $i_tree + if test "$keep_index" = "t" && test -n $i_tree then git read-tree --reset -u $i_tree fi @@ -193,7 +194,7 @@ save_stash () { git apply -R < "$TMP-patch" || die "Cannot remove worktree changes" - if test -z "$keep_index" + if test "$keep_index" != "t" then git reset fi @@ -264,7 +265,7 @@ parse_flags_and_rev() b_tree= i_tree= - REV=$(git rev-parse --no-flags --symbolic "$@" 2>/dev/null) + REV=$(git rev-parse --no-flags --symbolic "$@") || exit 1 FLAGS= for opt @@ -310,16 +311,6 @@ parse_flags_and_rev() IS_STASH_LIKE=t && test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" && IS_STASH_REF=t - - if test "${REV}" != "${REV%{*\}}" - then - # maintainers: it would be better if git rev-parse indicated - # this condition with a non-zero status code but as of 1.7.2.1 it - # it did not. So, we use non-empty stderr output as a proxy for the - # condition of interest. - test -z "$(git rev-parse "$REV" 2>&1 >/dev/null)" || die "$REV does not exist in the stash log" - fi - } is_stash_like() @@ -344,9 +335,7 @@ apply_stash () { assert_stash_like "$@" - git update-index -q --refresh && - git diff-files --quiet --ignore-submodules || - die 'Cannot apply to a dirty working tree, please stage your changes' + git update-index -q --refresh || die 'unable to refresh index' # current index state c_tree=$(git write-tree) || @@ -536,6 +536,7 @@ struct active_request_slot *get_active_slot(void) curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, NULL); + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL); curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0); curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); diff --git a/merge-recursive.c b/merge-recursive.c index af131508ec..dba27643bd 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1711,15 +1711,15 @@ int merge_recursive_generic(struct merge_options *o, static int merge_recursive_config(const char *var, const char *value, void *cb) { struct merge_options *o = cb; - if (!strcasecmp(var, "merge.verbosity")) { + if (!strcmp(var, "merge.verbosity")) { o->verbosity = git_config_int(var, value); return 0; } - if (!strcasecmp(var, "diff.renamelimit")) { + if (!strcmp(var, "diff.renamelimit")) { o->diff_rename_limit = git_config_int(var, value); return 0; } - if (!strcasecmp(var, "merge.renamelimit")) { + if (!strcmp(var, "merge.renamelimit")) { o->merge_rename_limit = git_config_int(var, value); return 0; } @@ -208,6 +208,58 @@ int has_non_ascii(const char *s) return 0; } +static int is_rfc822_special(char ch) +{ + switch (ch) { + case '(': + case ')': + case '<': + case '>': + case '[': + case ']': + case ':': + case ';': + case '@': + case ',': + case '.': + case '"': + case '\\': + return 1; + default: + return 0; + } +} + +static int has_rfc822_specials(const char *s, int len) +{ + int i; + for (i = 0; i < len; i++) + if (is_rfc822_special(s[i])) + return 1; + return 0; +} + +static void add_rfc822_quoted(struct strbuf *out, const char *s, int len) +{ + int i; + + /* just a guess, we may have to also backslash-quote */ + strbuf_grow(out, len + 2); + + strbuf_addch(out, '"'); + for (i = 0; i < len; i++) { + switch (s[i]) { + case '"': + case '\\': + strbuf_addch(out, '\\'); + /* fall through */ + default: + strbuf_addch(out, s[i]); + } + } + strbuf_addch(out, '"'); +} + static int is_rfc2047_special(char ch) { return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_')); @@ -293,7 +345,14 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb, name_tail--; display_name_length = name_tail - line; strbuf_addstr(sb, "From: "); - add_rfc2047(sb, line, display_name_length, encoding); + if (!has_rfc822_specials(line, display_name_length)) { + add_rfc2047(sb, line, display_name_length, encoding); + } else { + struct strbuf quoted = STRBUF_INIT; + add_rfc822_quoted("ed, line, display_name_length); + add_rfc2047(sb, quoted.buf, quoted.len, encoding); + strbuf_release("ed); + } strbuf_add(sb, name_tail, namelen - display_name_length); strbuf_addch(sb, '\n'); } else { diff --git a/sha1_file.c b/sha1_file.c index 889fe71830..1a7e41070e 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -31,8 +31,6 @@ static inline uintmax_t sz_fmt(size_t s) { return s; } const unsigned char null_sha1[20]; -static int git_open_noatime(const char *name, struct packed_git *p); - /* * This is meant to hold a *small* number of objects that you would * want read_sha1_file() to be able to return, but yet you do not want @@ -227,6 +225,7 @@ struct alternate_object_database *alt_odb_list; static struct alternate_object_database **alt_odb_tail; static void read_info_alternates(const char * alternates, int depth); +static int git_open_noatime(const char *name); /* * Prepare alternate object database registry. @@ -360,7 +359,7 @@ static void read_info_alternates(const char * relative_base, int depth) int fd; sprintf(path, "%s/%s", relative_base, alt_file_name); - fd = git_open_noatime(path, NULL); + fd = git_open_noatime(path); if (fd < 0) return; if (fstat(fd, &st) || (st.st_size == 0)) { @@ -475,7 +474,7 @@ static int check_packed_git_idx(const char *path, struct packed_git *p) struct pack_idx_header *hdr; size_t idx_size; uint32_t version, nr, i, *index; - int fd = git_open_noatime(path, p); + int fd = git_open_noatime(path); struct stat st; if (fd < 0) @@ -757,7 +756,7 @@ static int open_packed_git_1(struct packed_git *p) while (pack_max_fds <= pack_open_fds && unuse_one_window(NULL, -1)) ; /* nothing */ - p->pack_fd = git_open_noatime(p->pack_name, p); + p->pack_fd = git_open_noatime(p->pack_name); if (p->pack_fd < 0 || fstat(p->pack_fd, &st)) return -1; pack_open_fds++; @@ -1145,7 +1144,7 @@ int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long siz return hashcmp(sha1, real_sha1) ? -1 : 0; } -static int git_open_noatime(const char *name, struct packed_git *p) +static int git_open_noatime(const char *name) { static int sha1_file_open_flag = O_NOATIME; @@ -1170,7 +1169,7 @@ static int open_sha1_file(const unsigned char *sha1) char *name = sha1_file_name(sha1); struct alternate_object_database *alt; - fd = git_open_noatime(name, NULL); + fd = git_open_noatime(name); if (fd >= 0) return fd; @@ -1179,7 +1178,7 @@ static int open_sha1_file(const unsigned char *sha1) for (alt = alt_odb_list; alt; alt = alt->next) { name = alt->name; fill_sha1_path(name, sha1); - fd = git_open_noatime(alt->base, NULL); + fd = git_open_noatime(alt->base); if (fd >= 0) return fd; } @@ -1308,7 +1307,7 @@ static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size /* * The above condition must be (bytes <= size), not * (bytes < size). In other words, even though we - * expect no more output and set avail_out to zer0, + * expect no more output and set avail_out to zero, * the input zlib stream may have bytes that express * "this concludes the stream", and we *do* want to * eat that input. diff --git a/sha1_name.c b/sha1_name.c index faea58dc8c..69cd6c815d 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -1012,11 +1012,13 @@ static void diagnose_invalid_sha1_path(const char *prefix, if (!get_tree_entry(tree_sha1, fullname, sha1, &mode)) { die("Path '%s' exists, but not '%s'.\n" - "Did you mean '%s:%s'?", + "Did you mean '%s:%s' aka '%s:./%s'?", fullname, filename, object_name, - fullname); + fullname, + object_name, + filename); } die("Path '%s' does not exist in '%s'", filename, object_name); @@ -1065,9 +1067,10 @@ static void diagnose_invalid_index_path(int stage, if (ce_namelen(ce) == fullnamelen && !memcmp(ce->name, fullname, fullnamelen)) die("Path '%s' is in the index, but not '%s'.\n" - "Did you mean ':%d:%s'?", + "Did you mean ':%d:%s' aka ':%d:./%s'?", fullname, filename, - ce_stage(ce), fullname); + ce_stage(ce), fullname, + ce_stage(ce), filename); } if (!lstat(filename, &st)) @@ -137,6 +137,8 @@ int main(int argc, char **argv) int devnull_fd; int count; + git_extract_argv0_path(argv[0]); + /* * Always open file descriptors 0/1/2 to avoid clobbering files * in die(). It also avoids not messing up when the pipes are diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index d34208cc27..c56a77d237 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -1,5 +1,5 @@ # This file isn't used as a test script directly, instead it is -# sourced from t8001-annotate.sh and t8001-blame.sh. +# sourced from t8001-annotate.sh and t8002-blame.sh. check_count () { head= @@ -124,3 +124,14 @@ test_expect_success \ test_expect_success \ 'some edit' \ 'check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1' + +test_expect_success \ + 'an obfuscated email added' \ + 'echo "No robots allowed" > file.new && + cat file >> file.new && + mv file.new file && + GIT_AUTHOR_NAME="E" GIT_AUTHOR_EMAIL="E at test dot git" git commit -a -m "norobots"' + +test_expect_success \ + 'obfuscated email parsed' \ + 'check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1' diff --git a/t/t0006-date.sh b/t/t0006-date.sh index 1d4d0a5c7d..f87abb5a06 100755 --- a/t/t0006-date.sh +++ b/t/t0006-date.sh @@ -25,6 +25,7 @@ check_show 37500000 '1 year, 2 months ago' check_show 55188000 '1 year, 9 months ago' check_show 630000000 '20 years ago' check_show 31449600 '12 months ago' +check_show 62985600 '2 years ago' check_parse() { echo "$1 -> $2" >expect diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index ff747f8229..4fd83a667a 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -6,7 +6,7 @@ test_description='Test git update-ref and basic ref logging' . ./test-lib.sh -Z=0000000000000000000000000000000000000000 +Z=$_z40 test_expect_success setup ' diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh index ba25ff354d..caa687b5b4 100755 --- a/t/t1411-reflog-show.sh +++ b/t/t1411-reflog-show.sh @@ -28,6 +28,24 @@ test_expect_success 'oneline reflog format' ' test_cmp expect actual ' +test_expect_success 'reflog default format' ' + git reflog -1 >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +commit e46513e +Reflog: HEAD@{0} (C O Mitter <committer@example.com>) +Reflog message: commit (initial): one +Author: A U Thor <author@example.com> + + one +EOF +test_expect_success 'override reflog default format' ' + git reflog --format=short -1 >actual && + test_cmp expect actual +' + cat >expect <<'EOF' Reflog: HEAD@{Thu Apr 7 15:13:13 2005 -0700} (C O Mitter <committer@example.com>) Reflog message: commit (initial): one diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index da6252b117..63849836c8 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -7,7 +7,6 @@ test_expect_success 'setup' ' EMPTY_TREE=$(git write-tree) && EMPTY_BLOB=$(git hash-object -t blob --stdin </dev/null) && CHANGED_BLOB=$(echo changed | git hash-object -t blob --stdin) && - ZEROES=0000000000000000000000000000000000000000 && EMPTY_BLOB7=$(echo $EMPTY_BLOB | sed "s/\(.......\).*/\1/") && CHANGED_BLOB7=$(echo $CHANGED_BLOB | sed "s/\(.......\).*/\1/") && @@ -239,10 +238,10 @@ test_expect_success '_gently() groks relative GIT_DIR & GIT_WORK_TREE' ' test_expect_success 'diff-index respects work tree under .git dir' ' cat >diff-index-cached.expected <<-EOF && - :000000 100644 $ZEROES $EMPTY_BLOB A sub/dir/tracked + :000000 100644 $_z40 $EMPTY_BLOB A sub/dir/tracked EOF cat >diff-index.expected <<-EOF && - :000000 100644 $ZEROES $ZEROES A sub/dir/tracked + :000000 100644 $_z40 $_z40 A sub/dir/tracked EOF ( @@ -258,7 +257,7 @@ test_expect_success 'diff-index respects work tree under .git dir' ' test_expect_success 'diff-files respects work tree under .git dir' ' cat >diff-files.expected <<-EOF && - :100644 100644 $EMPTY_BLOB $ZEROES M sub/dir/tracked + :100644 100644 $EMPTY_BLOB $_z40 M sub/dir/tracked EOF ( diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh index 9f8adb1f82..4a6396f9e3 100755 --- a/t/t1506-rev-parse-diagnosis.sh +++ b/t/t1506-rev-parse-diagnosis.sh @@ -6,6 +6,13 @@ exec </dev/null . ./test-lib.sh +test_did_you_mean () +{ + printf "fatal: Path '$2$3' $4, but not ${5:-'$3'}.\n" >expected && + printf "Did you mean '$1:$2$3'${2:+ aka '$1:./$3'}?\n" >>expected && + test_cmp expected error +} + HASH_file= test_expect_success 'set up basic repo' ' @@ -106,7 +113,7 @@ test_expect_success 'incorrect file in sha1:path' ' grep "fatal: Path '"'"'index-only.txt'"'"' exists on disk, but not in '"'"'HEAD'"'"'." error && (cd subdir && test_must_fail git rev-parse HEAD:file2.txt 2> error && - grep "Did you mean '"'"'HEAD:subdir/file2.txt'"'"'?" error ) + test_did_you_mean HEAD subdir/ file2.txt exists ) ' test_expect_success 'incorrect file in :path and :N:path' ' @@ -115,14 +122,14 @@ test_expect_success 'incorrect file in :path and :N:path' ' test_must_fail git rev-parse :1:nothing.txt 2> error && grep "Path '"'"'nothing.txt'"'"' does not exist (neither on disk nor in the index)." error && test_must_fail git rev-parse :1:file.txt 2> error && - grep "Did you mean '"'"':0:file.txt'"'"'?" error && + test_did_you_mean ":0" "" file.txt "is in the index" "at stage 1" && (cd subdir && test_must_fail git rev-parse :1:file.txt 2> error && - grep "Did you mean '"'"':0:file.txt'"'"'?" error && + test_did_you_mean ":0" "" file.txt "is in the index" "at stage 1" && test_must_fail git rev-parse :file2.txt 2> error && - grep "Did you mean '"'"':0:subdir/file2.txt'"'"'?" error && + test_did_you_mean ":0" subdir/ file2.txt "is in the index" && test_must_fail git rev-parse :2:file2.txt 2> error && - grep "Did you mean '"'"':0:subdir/file2.txt'"'"'?" error) && + test_did_you_mean :0 subdir/ file2.txt "is in the index") && test_must_fail git rev-parse :disk-only.txt 2> error && grep "fatal: Path '"'"'disk-only.txt'"'"' exists on disk, but not in the index." error ' diff --git a/t/t2011-checkout-invalid-head.sh b/t/t2011-checkout-invalid-head.sh index 15ebdc26eb..300f8bf25c 100755 --- a/t/t2011-checkout-invalid-head.sh +++ b/t/t2011-checkout-invalid-head.sh @@ -15,7 +15,7 @@ test_expect_success 'checkout should not start branch from a tree' ' ' test_expect_success 'checkout master from invalid HEAD' ' - echo 0000000000000000000000000000000000000000 >.git/HEAD && + echo $_z40 >.git/HEAD && git checkout master -- ' diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh index 2e8f702452..954fc51e5b 100755 --- a/t/t2201-add-update-typechange.sh +++ b/t/t2201-add-update-typechange.sh @@ -4,8 +4,6 @@ test_description='more git add -u' . ./test-lib.sh -_z40=0000000000000000000000000000000000000000 - test_expect_success setup ' >xyzzy && _empty=$(git hash-object --stdin <xyzzy) && diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 286a2a6869..463ef1909f 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -46,7 +46,7 @@ test_expect_success \ 'git branch a/b/c && test -f .git/refs/heads/a/b/c' cat >expect <<EOF -0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master +$_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master EOF test_expect_success \ 'git branch -l d/e/f should create a branch and a log' \ @@ -230,7 +230,7 @@ test_expect_success \ # Keep this test last, as it changes the current branch cat >expect <<EOF -0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master +$_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master EOF test_expect_success \ 'git checkout -b g/h/i -l should create a branch and a log' \ diff --git a/t/t3409-rebase-preserve-merges.sh b/t/t3409-rebase-preserve-merges.sh index 19341e5ca1..08201e2331 100755 --- a/t/t3409-rebase-preserve-merges.sh +++ b/t/t3409-rebase-preserve-merges.sh @@ -27,7 +27,17 @@ export GIT_AUTHOR_EMAIL # \ # B2 <-- origin/topic # -# In both cases, 'topic' is rebased onto 'origin/topic'. +# Clone 3 (no-ff merge): +# +# A1--A2--B3 <-- origin/master +# \ +# B1------M <-- topic +# \ / +# \--A3 <-- topic2 +# \ +# B2 <-- origin/topic +# +# In all cases, 'topic' is rebased onto 'origin/topic'. test_expect_success 'setup for merge-preserving rebase' \ 'echo First > A && @@ -61,6 +71,16 @@ test_expect_success 'setup for merge-preserving rebase' \ git commit -m "Merge origin/master into topic" ) && + git clone ./. clone3 && + ( + cd clone3 && + git checkout -b topic2 origin/topic && + echo Sixth > A && + git commit -a -m "Modify A3" && + git checkout -b topic origin/topic && + git merge --no-ff topic2 + ) && + git checkout topic && echo Fourth >> B && git commit -a -m "Modify B2" @@ -93,4 +113,14 @@ test_expect_success '--continue works after a conflict' ' ) ' +test_expect_success 'rebase -p preserves no-ff merges' ' + ( + cd clone3 && + git fetch && + git rebase -p origin/topic && + test 3 = $(git rev-list --all --pretty=oneline | grep "Modify A" | wc -l) && + test 1 = $(git rev-list --all --pretty=oneline | grep "Merge branch" | wc -l) + ) +' + test_done diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index cd093bd347..9fd28bcf34 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -240,11 +240,10 @@ test_expect_success 'refresh index before checking if it is up-to-date' ' test_expect_success 'choking "git rm" should not let it die with cruft' ' git reset -q --hard && - H=0000000000000000000000000000000000000000 && i=0 && while test $i -lt 12000 do - echo "100644 $H 0 some-file-$i" + echo "100644 $_z40 0 some-file-$i" i=$(( $i + 1 )) done | git update-index --index-info && git rm -n "some-file-*" | :; diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index d6327e7c74..9e236f9cc0 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -82,10 +82,9 @@ EOF ' test_expect_success PERL 'setup fake editor' ' - cat >fake_editor.sh <<EOF - EOF + >fake_editor.sh && chmod a+x fake_editor.sh && - test_set_editor "$(pwd)/fake_editor.sh" && + test_set_editor "$(pwd)/fake_editor.sh" ' test_expect_success PERL 'dummy edit works' ' @@ -295,4 +294,40 @@ test_expect_success PERL 'deleting an empty file' ' test_cmp expected diff ' +test_expect_success PERL 'split hunk setup' ' + git reset --hard && + for i in 10 20 30 40 50 60 + do + echo $i + done >test && + git add test && + test_tick && + git commit -m test && + + for i in 10 15 20 21 22 23 24 30 40 50 60 + do + echo $i + done >test +' + +test_expect_success PERL 'split hunk "add -p (edit)"' ' + # Split, say Edit and do nothing. Then: + # + # 1. Broken version results in a patch that does not apply and + # only takes [y/n] (edit again) so the first q is discarded + # and then n attempts to discard the edit. Repeat q enough + # times to get out. + # + # 2. Correct version applies the (not)edited version, and asks + # about the next hunk, against wich we say q and program + # exits. + for a in s e q n q q + do + echo $a + done | + EDITOR=: git add -p && + git diff >actual && + ! grep "^+15" actual +' + test_done diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index f62aaf5816..5c72540642 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -37,14 +37,32 @@ test_expect_success 'parents of stash' ' test_cmp output expect ' -test_expect_success 'apply needs clean working directory' ' - echo 4 > other-file && +test_expect_success 'applying bogus stash does nothing' ' + test_must_fail git stash apply stash@{1} && + echo 1 >expect && + test_cmp expect file +' + +test_expect_success 'apply does not need clean working directory' ' + echo 4 >other-file && git add other-file && - echo 5 > other-file && - test_must_fail git stash apply + echo 5 >other-file && + git stash apply && + echo 3 >expect && + test_cmp expect file +' + +test_expect_success 'apply does not clobber working directory changes' ' + git reset --hard && + echo 4 >file && + test_must_fail git stash apply && + echo 4 >expect && + test_cmp expect file ' test_expect_success 'apply stashed changes' ' + git reset --hard && + echo 5 >other-file && git add other-file && test_tick && git commit -m other-file && @@ -218,6 +236,14 @@ test_expect_success 'stash -k' ' test bar,bar4 = $(cat file),$(cat file2) ' +test_expect_success 'stash --no-keep-index' ' + echo bar33 > file && + echo bar44 > file2 && + git add file2 && + git stash --no-keep-index && + test bar,bar2 = $(cat file),$(cat file2) +' + test_expect_success 'stash --invalid-option' ' echo bar5 > file && echo bar6 > file2 && @@ -537,11 +563,11 @@ test_expect_success 'invalid ref of the form stash@{n}, n >= N' ' echo bar6 > file2 && git add file2 && git stash && - test_must_fail git drop stash@{1} && - test_must_fail git pop stash@{1} && - test_must_fail git apply stash@{1} && - test_must_fail git show stash@{1} && - test_must_fail git branch tmp stash@{1} && + test_must_fail git stash drop stash@{1} && + test_must_fail git stash pop stash@{1} && + test_must_fail git stash apply stash@{1} && + test_must_fail git stash show stash@{1} && + test_must_fail git stash branch tmp stash@{1} && git stash drop ' diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh index 1e7193ac0b..781fd71681 100755 --- a/t/t3904-stash-patch.sh +++ b/t/t3904-stash-patch.sh @@ -48,6 +48,18 @@ test_expect_success PERL 'git stash -p --no-keep-index' ' verify_state bar dummy bar_index ' +test_expect_success PERL 'git stash --no-keep-index -p' ' + set_state dir/foo work index && + set_state bar bar_work bar_index && + (echo n; echo y) | git stash save --no-keep-index -p && + verify_state dir/foo head head && + verify_state bar bar_work dummy && + git reset --hard && + git stash apply --index && + verify_state dir/foo work index && + verify_state bar dummy bar_index +' + test_expect_success PERL 'none of this moved HEAD' ' verify_saved_head ' diff --git a/t/t4002-diff-basic.sh b/t/t4002-diff-basic.sh index 9fb8ca06a8..a5e8b83083 100755 --- a/t/t4002-diff-basic.sh +++ b/t/t4002-diff-basic.sh @@ -126,15 +126,12 @@ cat >.test-recursive-AB <<\EOF :100644 100644 3fdbe17fd013303a2e981e1ca1c6cd6e72789087 7e09d6a3a14bd630913e8c75693cea32157b606d M Z/NM EOF -x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' -x40="$x40$x40$x40$x40$x40$x40$x40$x40" -z40='0000000000000000000000000000000000000000' cmp_diff_files_output () { # diff-files never reports additions. Also it does not fill in the # object ID for the changed files because it wants you to look at the # filesystem. sed <"$2" >.test-tmp \ - -e '/^:000000 /d;s/'$x40'\( [MCRNDU][0-9]*\) /'$z40'\1 /' && + -e '/^:000000 /d;s/'$_x40'\( [MCRNDU][0-9]*\) /'$_z40'\1 /' && test_cmp "$1" .test-tmp } diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 5daa0f2a0c..93a6f20871 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -80,18 +80,31 @@ test_expect_success setup ' git config log.showroot false && git commit --amend && + + GIT_AUTHOR_DATE="2006-06-26 00:06:00 +0000" && + GIT_COMMITTER_DATE="2006-06-26 00:06:00 +0000" && + export GIT_AUTHOR_DATE GIT_COMMITTER_DATE && + git checkout -b rearrange initial && + for i in B A; do echo $i; done >dir/sub && + git add dir/sub && + git commit -m "Rearranged lines in dir/sub" && + git checkout master && + git show-branch ' : <<\EOF ! [initial] Initial * [master] Merge branch 'side' - ! [side] Side ---- - - [master] Merge branch 'side' - *+ [side] Side - * [master^] Second -+*+ [initial] Initial + ! [rearrange] Rearranged lines in dir/sub + ! [side] Side +---- + + [rearrange] Rearranged lines in dir/sub + - [master] Merge branch 'side' + * + [side] Side + * [master^] Third + * [master~2] Second ++*++ [initial] Initial EOF V=`git version | sed -e 's/^git version //' -e 's/\./\\./g'` @@ -287,6 +300,8 @@ diff --no-index --name-status -- dir2 dir diff --no-index dir dir3 diff master master^ side diff --dirstat master~1 master~2 +diff --dirstat initial rearrange +diff --dirstat-by-file initial rearrange EOF test_expect_success 'log -S requires an argument' ' diff --git a/t/t4013/diff.diff_--dirstat-by-file_initial_rearrange b/t/t4013/diff.diff_--dirstat-by-file_initial_rearrange new file mode 100644 index 0000000000..e48e33f678 --- /dev/null +++ b/t/t4013/diff.diff_--dirstat-by-file_initial_rearrange @@ -0,0 +1,3 @@ +$ git diff --dirstat-by-file initial rearrange + 100.0% dir/ +$ diff --git a/t/t4013/diff.diff_--dirstat_initial_rearrange b/t/t4013/diff.diff_--dirstat_initial_rearrange new file mode 100644 index 0000000000..5fb02c13bc --- /dev/null +++ b/t/t4013/diff.diff_--dirstat_initial_rearrange @@ -0,0 +1,3 @@ +$ git diff --dirstat initial rearrange + 100.0% dir/ +$ diff --git a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ index 1f0f9ad44b..3b4e113012 100644 --- a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ +++ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ @@ -1,7 +1,7 @@ $ git format-patch --stdout --cover-letter -n initial..master^ From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 From: C O Mitter <committer@example.com> -Date: Mon, 26 Jun 2006 00:05:00 +0000 +Date: Mon, 26 Jun 2006 00:06:00 +0000 Subject: [DIFFERENT_PREFIX 0/2] *** SUBJECT HERE *** *** BLURB HERE *** diff --git a/t/t4013/diff.log_--decorate=full_--all b/t/t4013/diff.log_--decorate=full_--all index d155e0bab2..44d45257da 100644 --- a/t/t4013/diff.log_--decorate=full_--all +++ b/t/t4013/diff.log_--decorate=full_--all @@ -1,4 +1,10 @@ $ git log --decorate=full --all +commit cd4e72fd96faed3f0ba949dc42967430374e2290 (refs/heads/rearrange) +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:06:00 2006 +0000 + + Rearranged lines in dir/sub + commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, refs/heads/master) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_--decorate_--all b/t/t4013/diff.log_--decorate_--all index fd7c3e6439..27d3eabc26 100644 --- a/t/t4013/diff.log_--decorate_--all +++ b/t/t4013/diff.log_--decorate_--all @@ -1,4 +1,10 @@ $ git log --decorate --all +commit cd4e72fd96faed3f0ba949dc42967430374e2290 (rearrange) +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:06:00 2006 +0000 + + Rearranged lines in dir/sub + commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, master) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index c3cdb52053..dd406c44b5 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -793,4 +793,46 @@ test_expect_success 'format-patch wraps extremely long headers (rfc2047)' ' test_cmp expect subject ' +check_author() { + echo content >>file && + git add file && + GIT_AUTHOR_NAME=$1 git commit -m author-check && + git format-patch --stdout -1 >patch && + grep ^From: patch >actual && + test_cmp expect actual +} + +cat >expect <<'EOF' +From: "Foo B. Bar" <author@example.com> +EOF +test_expect_success 'format-patch quotes dot in headers' ' + check_author "Foo B. Bar" +' + +cat >expect <<'EOF' +From: "Foo \"The Baz\" Bar" <author@example.com> +EOF +test_expect_success 'format-patch quotes double-quote in headers' ' + check_author "Foo \"The Baz\" Bar" +' + +cat >expect <<'EOF' +From: =?UTF-8?q?"F=C3=B6o=20B.=20Bar"?= <author@example.com> +EOF +test_expect_success 'rfc2047-encoded headers also double-quote 822 specials' ' + check_author "Föo B. Bar" +' + +cat >expect <<'EOF' +Subject: header with . in it +EOF +test_expect_success 'subject lines do not have 822 atom-quoting' ' + echo content >>file && + git add file && + git commit -m "header with . in it" && + git format-patch -k -1 --stdout >patch && + grep ^Subject: patch >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index a7602cf923..083f62d1d6 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -4,8 +4,6 @@ test_description='external diff interface test' . ./test-lib.sh -_z40=0000000000000000000000000000000000000000 - test_expect_success setup ' test_tick && diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh index 241a74d2a2..518bf9524e 100755 --- a/t/t4027-diff-submodule.sh +++ b/t/t4027-diff-submodule.sh @@ -5,7 +5,6 @@ test_description='difference in submodules' . ./test-lib.sh . "$TEST_DIRECTORY"/diff-lib.sh -_z40=0000000000000000000000000000000000000000 test_expect_success setup ' test_tick && test_create_repo sub && diff --git a/t/t4046-diff-unmerged.sh b/t/t4046-diff-unmerged.sh new file mode 100755 index 0000000000..25d50a654a --- /dev/null +++ b/t/t4046-diff-unmerged.sh @@ -0,0 +1,87 @@ +#!/bin/sh + +test_description='diff with unmerged index entries' +. ./test-lib.sh + +test_expect_success setup ' + for i in 0 1 2 3 + do + blob=$(echo $i | git hash-object --stdin) && + eval "blob$i=$blob" && + eval "m$i=\"100644 \$blob$i $i\"" || break + done && + paths= && + for b in o x + do + for o in o x + do + for t in o x + do + path="$b$o$t" && + case "$path" in ooo) continue ;; esac + paths="$paths$path " && + p=" $path" && + case "$b" in x) echo "$m1$p" ;; esac && + case "$o" in x) echo "$m2$p" ;; esac && + case "$t" in x) echo "$m3$p" ;; esac || + break + done || break + done || break + done >ls-files-s.expect && + git update-index --index-info <ls-files-s.expect && + git ls-files -s >ls-files-s.actual && + test_cmp ls-files-s.expect ls-files-s.actual +' + +test_expect_success 'diff-files -0' ' + for path in $paths + do + >"$path" && + echo ":000000 100644 $_z40 $_z40 U $path" + done >diff-files-0.expect && + git diff-files -0 >diff-files-0.actual && + test_cmp diff-files-0.expect diff-files-0.actual +' + +test_expect_success 'diff-files -1' ' + for path in $paths + do + >"$path" && + echo ":000000 100644 $_z40 $_z40 U $path" && + case "$path" in + x??) echo ":100644 100644 $blob1 $_z40 M $path" + esac + done >diff-files-1.expect && + git diff-files -1 >diff-files-1.actual && + test_cmp diff-files-1.expect diff-files-1.actual +' + +test_expect_success 'diff-files -2' ' + for path in $paths + do + >"$path" && + echo ":000000 100644 $_z40 $_z40 U $path" && + case "$path" in + ?x?) echo ":100644 100644 $blob2 $_z40 M $path" + esac + done >diff-files-2.expect && + git diff-files -2 >diff-files-2.actual && + test_cmp diff-files-2.expect diff-files-2.actual && + git diff-files >diff-files-default-2.actual && + test_cmp diff-files-2.expect diff-files-default-2.actual +' + +test_expect_success 'diff-files -3' ' + for path in $paths + do + >"$path" && + echo ":000000 100644 $_z40 $_z40 U $path" && + case "$path" in + ??x) echo ":100644 100644 $blob3 $_z40 M $path" + esac + done >diff-files-3.expect && + git diff-files -3 >diff-files-3.actual && + test_cmp diff-files-3.expect diff-files-3.actual +' + +test_done diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh index b0b2684a1f..0eace37a03 100755 --- a/t/t5400-send-pack.sh +++ b/t/t5400-send-pack.sh @@ -190,7 +190,7 @@ test_expect_success 'pushing explicit refspecs respects forcing' ' +refs/heads/master:refs/heads/master ) && parent_head=$(cd parent && git rev-parse --verify master) && - child_head=$(cd parent && git rev-parse --verify master) && + child_head=$(cd child && git rev-parse --verify master) && test "$parent_head" = "$child_head" ' @@ -210,7 +210,7 @@ test_expect_success 'pushing wildcard refspecs respects forcing' ' "+refs/heads/*:refs/heads/*" ) && parent_head=$(cd parent && git rev-parse --verify master) && - child_head=$(cd parent && git rev-parse --verify master) && + child_head=$(cd child && git rev-parse --verify master) && test "$parent_head" = "$child_head" ' diff --git a/t/t6060-merge-index.sh b/t/t6060-merge-index.sh new file mode 100755 index 0000000000..debadbd299 --- /dev/null +++ b/t/t6060-merge-index.sh @@ -0,0 +1,100 @@ +#!/bin/sh + +test_description='basic git merge-index / git-merge-one-file tests' +. ./test-lib.sh + +test_expect_success 'setup diverging branches' ' + for i in 1 2 3 4 5 6 7 8 9 10; do + echo $i + done >file && + git add file && + git commit -m base && + git tag base && + sed s/2/two/ <file >tmp && + mv tmp file && + git commit -a -m two && + git tag two && + git checkout -b other HEAD^ && + sed s/10/ten/ <file >tmp && + mv tmp file && + git commit -a -m ten && + git tag ten +' + +cat >expect-merged <<'EOF' +1 +two +3 +4 +5 +6 +7 +8 +9 +ten +EOF + +test_expect_success 'read-tree does not resolve content merge' ' + git read-tree -i -m base ten two && + echo file >expect && + git diff-files --name-only --diff-filter=U >unmerged && + test_cmp expect unmerged +' + +test_expect_success 'git merge-index git-merge-one-file resolves' ' + git merge-index git-merge-one-file -a && + git diff-files --name-only --diff-filter=U >unmerged && + >expect && + test_cmp expect unmerged && + test_cmp expect-merged file && + git cat-file blob :file >file-index && + test_cmp expect-merged file-index +' + +test_expect_success 'setup bare merge' ' + git clone --bare . bare.git && + (cd bare.git && + GIT_INDEX_FILE=$PWD/merge.index && + export GIT_INDEX_FILE && + git read-tree -i -m base ten two + ) +' + +test_expect_success 'merge-one-file fails without a work tree' ' + (cd bare.git && + GIT_INDEX_FILE=$PWD/merge.index && + export GIT_INDEX_FILE && + test_must_fail git merge-index git-merge-one-file -a + ) +' + +test_expect_success 'merge-one-file respects GIT_WORK_TREE' ' + (cd bare.git && + mkdir work && + GIT_WORK_TREE=$PWD/work && + export GIT_WORK_TREE && + GIT_INDEX_FILE=$PWD/merge.index && + export GIT_INDEX_FILE && + git merge-index git-merge-one-file -a && + git cat-file blob :file >work/file-index + ) && + test_cmp expect-merged bare.git/work/file && + test_cmp expect-merged bare.git/work/file-index +' + +test_expect_success 'merge-one-file respects core.worktree' ' + mkdir subdir && + git clone . subdir/child && + (cd subdir && + GIT_DIR=$PWD/child/.git && + export GIT_DIR && + git config core.worktree "$PWD/child" && + git read-tree -i -m base ten two && + git merge-index git-merge-one-file -a && + git cat-file blob :file >file-index + ) && + test_cmp expect-merged subdir/child/file && + test_cmp expect-merged subdir/file-index +' + +test_done diff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh index bb4066f767..8f3b54d826 100755 --- a/t/t7011-skip-worktree-reading.sh +++ b/t/t7011-skip-worktree-reading.sh @@ -24,7 +24,7 @@ H sub/2 EOF NULL_SHA1=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 -ZERO_SHA0=0000000000000000000000000000000000000000 + setup_absent() { test -f 1 && rm 1 git update-index --remove 1 && @@ -120,7 +120,7 @@ test_expect_success 'grep with skip-worktree file' ' test "$(git grep --no-ext-grep test)" = "1:test" ' -echo ":000000 100644 $ZERO_SHA0 $NULL_SHA1 A 1" > expected +echo ":000000 100644 $_z40 $NULL_SHA1 A 1" > expected test_expect_success 'diff-index does not examine skip-worktree absent entries' ' setup_absent && git diff-index HEAD -- 1 > result && diff --git a/t/t7012-skip-worktree-writing.sh b/t/t7012-skip-worktree-writing.sh index 14fcb1c7f5..c4104009e1 100755 --- a/t/t7012-skip-worktree-writing.sh +++ b/t/t7012-skip-worktree-writing.sh @@ -54,7 +54,7 @@ test_expect_success 'read-tree removes worktree, dirty case' ' ' NULL_SHA1=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 -ZERO_SHA0=0000000000000000000000000000000000000000 + setup_absent() { test -f 1 && rm 1 git update-index --remove 1 && diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index b4fcc86a10..3a5d927f83 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -56,4 +56,66 @@ test_expect_success C_LOCALE_OUTPUT 'M/D conflict does not segfault' ' ) ' +test_expect_success 'rename & unmerged setup' ' + git rm -f -r . && + cat "$TEST_DIRECTORY/README" >ONE && + git add ONE && + test_tick && + git commit -m "One commit with ONE" && + + echo Modified >TWO && + cat ONE >>TWO && + cat ONE >>THREE && + git add TWO THREE && + sha1=$(git rev-parse :ONE) && + git rm --cached ONE && + ( + echo "100644 $sha1 1 ONE" && + echo "100644 $sha1 2 ONE" && + echo "100644 $sha1 3 ONE" + ) | git update-index --index-info && + echo Further >>THREE +' + +test_expect_success 'rename & unmerged status' ' + git status -suno >actual && + cat >expect <<-EOF && + UU ONE + AM THREE + A TWO + EOF + test_cmp expect actual +' + +test_expect_success 'git diff-index --cached shows 2 added + 1 unmerged' ' + cat >expected <<-EOF && + U ONE + A THREE + A TWO + EOF + git diff-index --cached --name-status HEAD >actual && + test_cmp expected actual +' + +test_expect_success 'git diff-index --cached -M shows 2 added + 1 unmerged' ' + cat >expected <<-EOF && + U ONE + A THREE + A TWO + EOF + git diff-index --cached --name-status HEAD >actual && + test_cmp expected actual +' + +test_expect_success 'git diff-index --cached -C shows 2 copies + 1 unmerged' ' + cat >expected <<-EOF && + U ONE + C ONE THREE + C ONE TWO + EOF + git diff-index --cached -C --name-status HEAD | + sed "s/^C[0-9]*/C/g" >actual && + test_cmp expected actual +' + test_done diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 7e1be44402..800b5368a5 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -453,4 +453,11 @@ test_expect_success 'git clean -e' ' ) ' +test_expect_success SANITY 'git clean -d with an unreadable empty directory' ' + mkdir foo && + chmod a= foo && + git clean -dfx foo && + ! test -d foo +' + test_done diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index 87d5d788cb..5463f87e68 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -324,6 +324,38 @@ test_expect_success 'merge c1 with c2 (no-commit in config)' ' test_debug 'git log --graph --decorate --oneline --all' +test_expect_success 'merge c1 with c2 (log in config)' ' + git config branch.master.mergeoptions "" && + git reset --hard c1 && + git merge --log c2 && + git show -s --pretty=tformat:%s%n%b >expect && + + git config branch.master.mergeoptions --log && + git reset --hard c1 && + git merge c2 && + git show -s --pretty=tformat:%s%n%b >actual && + + test_cmp expect actual +' + +test_expect_success 'merge c1 with c2 (log in config gets overridden)' ' + ( + git config --remove-section branch.master + git config --remove-section merge + ) + git reset --hard c1 && + git merge c2 && + git show -s --pretty=tformat:%s%n%b >expect && + + git config branch.master.mergeoptions "--no-log" && + git config merge.log true && + git reset --hard c1 && + git merge c2 && + git show -s --pretty=tformat:%s%n%b >actual && + + test_cmp expect actual +' + test_expect_success 'merge c1 with c2 (squash in config)' ' git reset --hard c1 && git config branch.master.mergeoptions "--squash" && diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index dc838c93bc..cbc08e3276 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -22,26 +22,50 @@ test_expect_success 'setup' ' echo master file14 >file14 && mkdir subdir && echo master sub >subdir/file3 && - git add file1 file1[1-4] subdir/file3 && + test_create_repo submod && + ( + cd submod && + : >foo && + git add foo && + git commit -m "Add foo" + ) && + git submodule add git://example.com/submod submod && + git add file1 file1[1-4] subdir/file3 .gitmodules submod && git commit -m "add initial versions" && git checkout -b branch1 master && + git submodule update -N && echo branch1 change >file1 && echo branch1 newfile >file2 && echo branch1 change file11 >file11 && echo branch1 change file13 >file13 && echo branch1 sub >subdir/file3 && - git add file1 file11 file13 file2 subdir/file3 && + ( + cd submod && + echo branch1 submodule >bar && + git add bar && + git commit -m "Add bar on branch1" && + git checkout -b submod-branch1 + ) && + git add file1 file11 file13 file2 subdir/file3 submod && git rm file12 && git commit -m "branch1 changes" && git checkout master && + git submodule update -N && echo master updated >file1 && echo master new >file2 && echo master updated file12 >file12 && echo master updated file14 >file14 && echo master new sub >subdir/file3 && - git add file1 file12 file14 file2 subdir/file3 && + ( + cd submod && + echo master submodule >bar && + git add bar && + git commit -m "Add bar on master" && + git checkout -b submod-master + ) && + git add file1 file12 file14 file2 subdir/file3 submod && git rm file11 && git commit -m "master updates" && @@ -52,15 +76,18 @@ test_expect_success 'setup' ' test_expect_success 'custom mergetool' ' git checkout -b test1 branch1 && + git submodule update -N && test_must_fail git merge master >/dev/null 2>&1 && ( yes "" | git mergetool file1 >/dev/null 2>&1 ) && ( yes "" | git mergetool file2 >/dev/null 2>&1 ) && ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) && ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool submod >/dev/null 2>&1 ) && test "$(cat file1)" = "master updated" && test "$(cat file2)" = "master new" && test "$(cat subdir/file3)" = "master new sub" && + test "$(cat submod/bar)" = "branch1 submodule" && git commit -m "branch1 resolved with mergetool" ' @@ -73,9 +100,12 @@ test_expect_success 'mergetool crlf' ' ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) && ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && + ( yes "r" | git mergetool submod >/dev/null 2>&1 ) && test "$(printf x | cat file1 -)" = "$(printf "master updated\r\nx")" && test "$(printf x | cat file2 -)" = "$(printf "master new\r\nx")" && test "$(printf x | cat subdir/file3 -)" = "$(printf "master new sub\r\nx")" && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && git commit -m "branch1 resolved with mergetool - autocrlf" && git config core.autocrlf false && git reset --hard @@ -83,6 +113,7 @@ test_expect_success 'mergetool crlf' ' test_expect_success 'mergetool in subdir' ' git checkout -b test3 branch1 && + git submodule update -N && ( cd subdir && test_must_fail git merge master >/dev/null 2>&1 && @@ -98,18 +129,22 @@ test_expect_success 'mergetool on file in parent dir' ' ( yes "" | git mergetool ../file2 >/dev/null 2>&1 ) && ( yes "d" | git mergetool ../file11 >/dev/null 2>&1 ) && ( yes "d" | git mergetool ../file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool ../submod >/dev/null 2>&1 ) && test "$(cat ../file1)" = "master updated" && test "$(cat ../file2)" = "master new" && + test "$(cat ../submod/bar)" = "branch1 submodule" && git commit -m "branch1 resolved with mergetool - subdir" ) ' test_expect_success 'mergetool skips autoresolved' ' git checkout -b test4 branch1 && + git submodule update -N && test_must_fail git merge master && test -n "$(git ls-files -u)" && ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool submod >/dev/null 2>&1 ) && output="$(git mergetool --no-prompt)" && test "$output" = "No files need merging" && git reset --hard @@ -120,10 +155,13 @@ test_expect_success 'mergetool merges all from subdir' ' cd subdir && git config rerere.enabled false && test_must_fail git merge master && + ( yes "r" | git mergetool ../submod ) && ( yes "d" "d" | git mergetool --no-prompt ) && test "$(cat ../file1)" = "master updated" && test "$(cat ../file2)" = "master new" && test "$(cat file3)" = "master new sub" && + ( cd .. && git submodule update -N ) && + test "$(cat ../submod/bar)" = "master submodule" && git commit -m "branch2 resolved by mergetool from subdir" ) ' @@ -132,11 +170,257 @@ test_expect_success 'mergetool skips resolved paths when rerere is active' ' git config rerere.enabled true && rm -rf .git/rr-cache && git checkout -b test5 branch1 + git submodule update -N && test_must_fail git merge master >/dev/null 2>&1 && + ( yes "l" | git mergetool --no-prompt submod >/dev/null 2>&1 ) && ( yes "d" "d" | git mergetool --no-prompt >/dev/null 2>&1 ) && + git submodule update -N && output="$(yes "n" | git mergetool --no-prompt)" && test "$output" = "No files need merging" && git reset --hard ' +test_expect_success 'deleted vs modified submodule' ' + git checkout -b test6 branch1 && + git submodule update -N && + mv submod submod-movedaside && + git rm submod && + git commit -m "Submodule deleted from branch" && + git checkout -b test6.a test6 && + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "r" | git mergetool submod ) && + rmdir submod && mv submod-movedaside submod && + test "$(cat submod/bar)" = "branch1 submodule" && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by keeping module" && + + mv submod submod-movedaside && + git checkout -b test6.b test6 && + git submodule update -N && + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool submod ) && + test ! -e submod && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by deleting module" && + + mv submod-movedaside submod && + git checkout -b test6.c master && + git submodule update -N && + test_must_fail git merge test6 && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "r" | git mergetool submod ) && + test ! -e submod && + test -d submod.orig && + git submodule update -N && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by deleting module" && + mv submod.orig submod && + + git checkout -b test6.d master && + git submodule update -N && + test_must_fail git merge test6 && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool submod ) && + test "$(cat submod/bar)" = "master submodule" && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by keeping module" && + git reset --hard HEAD +' + +test_expect_success 'file vs modified submodule' ' + git checkout -b test7 branch1 && + git submodule update -N && + mv submod submod-movedaside && + git rm submod && + echo not a submodule >submod && + git add submod && + git commit -m "Submodule path becomes file" && + git checkout -b test7.a branch1 && + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "r" | git mergetool submod ) && + rmdir submod && mv submod-movedaside submod && + test "$(cat submod/bar)" = "branch1 submodule" && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by keeping module" && + + mv submod submod-movedaside && + git checkout -b test7.b test7 && + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool submod ) && + git submodule update -N && + test "$(cat submod)" = "not a submodule" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by keeping file" && + + git checkout -b test7.c master && + rmdir submod && mv submod-movedaside submod && + test ! -e submod.orig && + git submodule update -N && + test_must_fail git merge test7 && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "r" | git mergetool submod ) && + test -d submod.orig && + git submodule update -N && + test "$(cat submod)" = "not a submodule" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by keeping file" && + + git checkout -b test7.d master && + rmdir submod && mv submod.orig submod && + git submodule update -N && + test_must_fail git merge test7 && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool submod ) && + test "$(cat submod/bar)" = "master submodule" && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by keeping module" +' + +test_expect_success 'submodule in subdirectory' ' + git checkout -b test10 branch1 && + git submodule update -N && + ( + cd subdir && + test_create_repo subdir_module && + ( + cd subdir_module && + : >file15 && + git add file15 && + git commit -m "add initial versions" + ) + ) && + git submodule add git://example.com/subsubmodule subdir/subdir_module && + git add subdir/subdir_module && + git commit -m "add submodule in subdirectory" && + + git checkout -b test10.a test10 && + git submodule update -N && + ( + cd subdir/subdir_module && + git checkout -b super10.a && + echo test10.a >file15 && + git add file15 && + git commit -m "on branch 10.a" + ) && + git add subdir/subdir_module && + git commit -m "change submodule in subdirectory on test10.a" && + + git checkout -b test10.b test10 && + git submodule update -N && + ( + cd subdir/subdir_module && + git checkout -b super10.b && + echo test10.b >file15 && + git add file15 && + git commit -m "on branch 10.b" + ) && + git add subdir/subdir_module && + git commit -m "change submodule in subdirectory on test10.b" && + + test_must_fail git merge test10.a >/dev/null 2>&1 && + ( + cd subdir && + ( yes "l" | git mergetool subdir_module ) + ) && + test "$(cat subdir/subdir_module/file15)" = "test10.b" && + git submodule update -N && + test "$(cat subdir/subdir_module/file15)" = "test10.b" && + git reset --hard && + git submodule update -N && + + test_must_fail git merge test10.a >/dev/null 2>&1 && + ( yes "r" | git mergetool subdir/subdir_module ) && + test "$(cat subdir/subdir_module/file15)" = "test10.b" && + git submodule update -N && + test "$(cat subdir/subdir_module/file15)" = "test10.a" && + git commit -m "branch1 resolved with mergetool" && + rm -rf subdir/subdir_module +' + +test_expect_success 'directory vs modified submodule' ' + git checkout -b test11 branch1 && + mv submod submod-movedaside && + git rm submod && + mkdir submod && + echo not a submodule >submod/file16 && + git add submod/file16 && + git commit -m "Submodule path becomes directory" && + + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + ( yes "l" | git mergetool submod ) && + test "$(cat submod/file16)" = "not a submodule" && + rm -rf submod.orig && + + git reset --hard && + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + test ! -e submod.orig && + ( yes "r" | git mergetool submod ) && + test -d submod.orig && + test "$(cat submod.orig/file16)" = "not a submodule" && + rm -r submod.orig && + mv submod-movedaside/.git submod && + ( cd submod && git clean -f && git reset --hard ) && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + git reset --hard && rm -rf submod-movedaside && + + git checkout -b test11.c master && + git submodule update -N && + test_must_fail git merge test11 && + test -n "$(git ls-files -u)" && + ( yes "l" | git mergetool submod ) && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + + git reset --hard && + git submodule update -N && + test_must_fail git merge test11 && + test -n "$(git ls-files -u)" && + test ! -e submod.orig && + ( yes "r" | git mergetool submod ) && + test "$(cat submod/file16)" = "not a submodule" && + + git reset --hard master && + ( cd submod && git clean -f && git reset --hard ) && + git submodule update -N +' + test_done diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh index d3a51e1269..e2896cffc1 100755 --- a/t/t8002-blame.sh +++ b/t/t8002-blame.sh @@ -8,7 +8,7 @@ PROG='git blame -c' PROG='git blame -c -e' test_expect_success 'Blame --show-email works' ' - check_count "<A@test.git>" 1 "<B@test.git>" 1 "<B1@test.git>" 1 "<B2@test.git>" 1 "<author@example.com>" 1 "<C@test.git>" 1 "<D@test.git>" 1 + check_count "<A@test.git>" 1 "<B@test.git>" 1 "<B1@test.git>" 1 "<B2@test.git>" 1 "<author@example.com>" 1 "<C@test.git>" 1 "<D@test.git>" 1 "<E at test dot git>" 1 ' test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index abc47f3abc..8a274fbe79 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -89,6 +89,9 @@ esac _x05='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x05$_x05$_x05$_x05$_x05$_x05$_x05$_x05" +# Zero SHA-1 +_z40=0000000000000000000000000000000000000000 + # Each test should start with something like this, after copyright notices: # # test_description='Description of this test... diff --git a/upload-pack.c b/upload-pack.c index bba053f0aa..ce5cbbea6b 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -157,15 +157,8 @@ static void create_pack_file(void) const char *argv[10]; int arg = 0; - if (shallow_nr) { - memset(&rev_list, 0, sizeof(rev_list)); - rev_list.proc = do_rev_list; - rev_list.out = -1; - if (start_async(&rev_list)) - die("git upload-pack: unable to fork git-rev-list"); - argv[arg++] = "pack-objects"; - } else { - argv[arg++] = "pack-objects"; + argv[arg++] = "pack-objects"; + if (!shallow_nr) { argv[arg++] = "--revs"; if (create_full_pack) argv[arg++] = "--all"; @@ -183,7 +176,7 @@ static void create_pack_file(void) argv[arg++] = NULL; memset(&pack_objects, 0, sizeof(pack_objects)); - pack_objects.in = shallow_nr ? rev_list.out : -1; + pack_objects.in = -1; pack_objects.out = -1; pack_objects.err = -1; pack_objects.git_cmd = 1; @@ -192,8 +185,14 @@ static void create_pack_file(void) if (start_command(&pack_objects)) die("git upload-pack: unable to fork git-pack-objects"); - /* pass on revisions we (don't) want */ - if (!shallow_nr) { + if (shallow_nr) { + memset(&rev_list, 0, sizeof(rev_list)); + rev_list.proc = do_rev_list; + rev_list.out = pack_objects.in; + if (start_async(&rev_list)) + die("git upload-pack: unable to fork git-rev-list"); + } + else { FILE *pipe_fd = xfdopen(pack_objects.in, "w"); if (!create_full_pack) { int i; diff --git a/xdiff-interface.c b/xdiff-interface.c index 164581f87f..0e2c169227 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -347,7 +347,7 @@ int git_xmerge_style = -1; int git_xmerge_config(const char *var, const char *value, void *cb) { - if (!strcasecmp(var, "merge.conflictstyle")) { + if (!strcmp(var, "merge.conflictstyle")) { if (!value) die("'%s' is not a boolean", var); if (!strcmp(value, "diff3")) |