Merge branch 'master' of github.com:git/git into git-po-master

* 'master' of github.com:git/git: (27 commits)
  Git 2.26-rc1
  remote-curl: show progress for fetches over dumb HTTP
  show_one_mergetag: print non-parent in hex form.
  config.mak.dev: re-enable -Wformat-zero-length
  rebase-interactive.c: silence format-zero-length warnings
  mingw: workaround for hangs when sending STDIN
  t6020: new test with interleaved lexicographic ordering of directories
  t6022, t6046: test expected behavior instead of testing a proxy for it
  t3035: prefer test_must_fail to bash negation for git commands
  t6020, t6022, t6035: update merge tests to use test helper functions
  t602[1236], t6034: modernize test formatting
  merge-recursive: apply collision handling unification to recursive case
  completion: add diff --color-moved[-ws]
  t1050: replace test -f with test_path_is_file
  am: support --show-current-patch=diff to retrieve .git/rebase-apply/patch
  am: support --show-current-patch=raw as a synonym for--show-current-patch
  am: convert "resume" variable to a struct
  parse-options: convert "command mode" to a flag
  parse-options: add testcases for OPT_CMDMODE()
  stash push: support the --pathspec-from-file option
  ...
This commit is contained in:
Jiang Xin 2020-03-11 14:59:05 +08:00
Родитель 9643441983 b4374e96c8
Коммит 52b2742df8
37 изменённых файлов: 1433 добавлений и 977 удалений

Просмотреть файл

@ -47,6 +47,18 @@ UI, Workflows & Features
* "git clone --recurse-submodules --single-branch" now uses the same * "git clone --recurse-submodules --single-branch" now uses the same
single-branch option when cloning the submodules. single-branch option when cloning the submodules.
* "git rm" and "git stash" learns the new "--pathspec-from-file"
option.
* "git am --short-current-patch" is a way to show the piece of e-mail
for the stopped step, which is not suitable to directly feed "git
apply" (it is designed to be a good "git am" input). It learned a
new option to show only the patch part.
* Handling of conflicting renames in merge-recursive have further
been made consistent with how existing codepaths try to mimic what
is done to add/add conflicts.
Performance, Internal Implementation, Development Support etc. Performance, Internal Implementation, Development Support etc.
@ -288,6 +300,18 @@ Fixes since v2.25
reverted. reverted.
(merge 0106b1d4be hi/gpg-use-check-signature later to maint). (merge 0106b1d4be hi/gpg-use-check-signature later to maint).
* MinGW's poll() emulation has been improved.
(merge 94f4d01932 am/mingw-poll-fix later to maint).
* "git show" and others gave an object name in raw format in its
error output, which has been corrected to give it in hex.
(merge 237a28173f hd/show-one-mergetag-fix later to maint).
* "git fetch" over HTTP walker protocol did not show any progress
output. We inherently do not know how much work remains, but still
we can show something not to bore users.
(merge 7655b4119d rs/show-progress-in-dumb-http-fetch later to maint).
* Other code cleanup, docfix, build fix, etc. * Other code cleanup, docfix, build fix, etc.
(merge 26f924d50e en/simplify-check-updates-in-unpack-trees later to maint). (merge 26f924d50e en/simplify-check-updates-in-unpack-trees later to maint).
(merge d0d0a357a1 am/update-pathspec-f-f-tests later to maint). (merge d0d0a357a1 am/update-pathspec-f-f-tests later to maint).
@ -315,3 +339,6 @@ Fixes since v2.25
(merge 240fc04f81 ag/rebase-remove-redundant-code later to maint). (merge 240fc04f81 ag/rebase-remove-redundant-code later to maint).
(merge 7f487ce062 js/ci-windows-update later to maint). (merge 7f487ce062 js/ci-windows-update later to maint).
(merge d68ce906c7 rs/commit-graph-code-simplification later to maint). (merge d68ce906c7 rs/commit-graph-code-simplification later to maint).
(merge a51d9e8f07 rj/t1050-use-test-path-is-file later to maint).
(merge fd0bc17557 kk/complete-diff-color-moved later to maint).
(merge 65bf820d0e en/test-cleanup later to maint).

Просмотреть файл

@ -16,7 +16,7 @@ SYNOPSIS
[--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet] [--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
[--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>] [--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>]
[(<mbox> | <Maildir>)...] [(<mbox> | <Maildir>)...]
'git am' (--continue | --skip | --abort | --quit | --show-current-patch) 'git am' (--continue | --skip | --abort | --quit | --show-current-patch[=(diff|raw)])
DESCRIPTION DESCRIPTION
----------- -----------
@ -176,9 +176,11 @@ default. You can use `--no-utf8` to override this.
Abort the patching operation but keep HEAD and the index Abort the patching operation but keep HEAD and the index
untouched. untouched.
--show-current-patch:: --show-current-patch[=(diff|raw)]::
Show the entire e-mail message "git am" has stopped at, because Show the message at which `git am` has stopped due to
of conflicts. conflicts. If `raw` is specified, show the raw contents of
the e-mail message; if `diff`, show the diff portion only.
Defaults to `raw`.
DISCUSSION DISCUSSION
---------- ----------

Просмотреть файл

@ -8,16 +8,18 @@ git-rm - Remove files from the working tree and from the index
SYNOPSIS SYNOPSIS
-------- --------
[verse] [verse]
'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <file>... 'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]
[--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]]
[--] [<pathspec>...]
DESCRIPTION DESCRIPTION
----------- -----------
Remove files from the index, or from the working tree and the index. Remove files matching pathspec from the index, or from the working tree
`git rm` will not remove a file from just your working directory. and the index. `git rm` will not remove a file from just your working
(There is no option to remove a file only from the working tree directory. (There is no option to remove a file only from the working
and yet keep it in the index; use `/bin/rm` if you want to do that.) tree and yet keep it in the index; use `/bin/rm` if you want to do
The files being removed have to be identical to the tip of the branch, that.) The files being removed have to be identical to the tip of the
and no updates to their contents can be staged in the index, branch, and no updates to their contents can be staged in the index,
though that default behavior can be overridden with the `-f` option. though that default behavior can be overridden with the `-f` option.
When `--cached` is given, the staged content has to When `--cached` is given, the staged content has to
match either the tip of the branch or the file on disk, match either the tip of the branch or the file on disk,
@ -26,15 +28,20 @@ allowing the file to be removed from just the index.
OPTIONS OPTIONS
------- -------
<file>...:: <pathspec>...::
Files to remove. Fileglobs (e.g. `*.c`) can be given to Files to remove. A leading directory name (e.g. `dir` to remove
remove all matching files. If you want Git to expand `dir/file1` and `dir/file2`) can be given to remove all files in
file glob characters, you may need to shell-escape them. the directory, and recursively all sub-directories, but this
A leading directory name requires the `-r` option to be explicitly given.
(e.g. `dir` to remove `dir/file1` and `dir/file2`) can be +
given to remove all files in the directory, and recursively The command removes only the paths that are known to Git.
all sub-directories, +
but this requires the `-r` option to be explicitly given. File globbing matches across directory boundaries. Thus, given two
directories `d` and `d2`, there is a difference between using
`git rm 'd*'` and `git rm 'd/*'`, as the former will also remove all
of directory `d2`.
+
For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
-f:: -f::
--force:: --force::
@ -68,19 +75,19 @@ OPTIONS
`git rm` normally outputs one line (in the form of an `rm` command) `git rm` normally outputs one line (in the form of an `rm` command)
for each file removed. This option suppresses that output. for each file removed. This option suppresses that output.
--pathspec-from-file=<file>::
Pathspec is passed in `<file>` instead of commandline args. If
`<file>` is exactly `-` then standard input is used. Pathspec
elements are separated by LF or CR/LF. Pathspec elements can be
quoted as explained for the configuration variable `core.quotePath`
(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
global `--literal-pathspecs`.
DISCUSSION --pathspec-file-nul::
---------- Only meaningful with `--pathspec-from-file`. Pathspec elements are
separated with NUL character and all other characters are taken
literally (including newlines and quotes).
The <file> list given to the command can be exact pathnames,
file glob patterns, or leading directory names. The command
removes only the paths that are known to Git. Giving the name of
a file that you have not told Git about does not remove that file.
File globbing matches across directory boundaries. Thus, given
two directories `d` and `d2`, there is a difference between
using `git rm 'd*'` and `git rm 'd/*'`, as the former will
also remove all of directory `d2`.
REMOVING FILES THAT HAVE DISAPPEARED FROM THE FILESYSTEM REMOVING FILES THAT HAVE DISAPPEARED FROM THE FILESYSTEM
-------------------------------------------------------- --------------------------------------------------------

Просмотреть файл

@ -15,6 +15,7 @@ SYNOPSIS
'git stash' branch <branchname> [<stash>] 'git stash' branch <branchname> [<stash>]
'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] 'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
[-u|--include-untracked] [-a|--all] [-m|--message <message>] [-u|--include-untracked] [-a|--all] [-m|--message <message>]
[--pathspec-from-file=<file> [--pathspec-file-nul]]
[--] [<pathspec>...]] [--] [<pathspec>...]]
'git stash' clear 'git stash' clear
'git stash' create [<message>] 'git stash' create [<message>]
@ -43,10 +44,10 @@ created stash, `stash@{1}` is the one before it, `stash@{2.hours.ago}`
is also possible). Stashes may also be referenced by specifying just the is also possible). Stashes may also be referenced by specifying just the
stash index (e.g. the integer `n` is equivalent to `stash@{n}`). stash index (e.g. the integer `n` is equivalent to `stash@{n}`).
OPTIONS COMMANDS
------- --------
push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]:: push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]::
Save your local modifications to a new 'stash entry' and roll them Save your local modifications to a new 'stash entry' and roll them
back to HEAD (in the working tree and in the index). back to HEAD (in the working tree and in the index).
@ -56,38 +57,13 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q
For quickly making a snapshot, you can omit "push". In this mode, For quickly making a snapshot, you can omit "push". In this mode,
non-option arguments are not allowed to prevent a misspelled non-option arguments are not allowed to prevent a misspelled
subcommand from making an unwanted stash entry. The two exceptions to this subcommand from making an unwanted stash entry. The two exceptions to this
are `stash -p` which acts as alias for `stash push -p` and pathspecs, are `stash -p` which acts as alias for `stash push -p` and pathspec elements,
which are allowed after a double hyphen `--` for disambiguation. which are allowed after a double hyphen `--` for disambiguation.
+
When pathspec is given to 'git stash push', the new stash entry records the
modified states only for the files that match the pathspec. The index
entries and working tree files are then rolled back to the state in
HEAD only for these files, too, leaving files that do not match the
pathspec intact.
+
If the `--keep-index` option is used, all changes already added to the
index are left intact.
+
If the `--include-untracked` option is used, all untracked files are also
stashed and then cleaned up with `git clean`, leaving the working directory
in a very clean state. If the `--all` option is used instead then the
ignored files are stashed and cleaned in addition to the untracked files.
+
With `--patch`, you can interactively select hunks from the diff
between HEAD and the working tree to be stashed. The stash entry is
constructed such that its index state is the same as the index state
of your repository, and its worktree contains only the changes you
selected interactively. The selected changes are then rolled back
from your worktree. See the ``Interactive Mode'' section of
linkgit:git-add[1] to learn how to operate the `--patch` mode.
+
The `--patch` option implies `--keep-index`. You can use
`--no-keep-index` to override this.
save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]:: save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::
This option is deprecated in favour of 'git stash push'. It This option is deprecated in favour of 'git stash push'. It
differs from "stash push" in that it cannot take pathspecs. differs from "stash push" in that it cannot take pathspec.
Instead, all non-option arguments are concatenated to form the stash Instead, all non-option arguments are concatenated to form the stash
message. message.
@ -111,7 +87,7 @@ show [<options>] [<stash>]::
Show the changes recorded in the stash entry as a diff between the Show the changes recorded in the stash entry as a diff between the
stashed contents and the commit back when the stash entry was first stashed contents and the commit back when the stash entry was first
created. When no `<stash>` is given, it shows the latest one. created.
By default, the command shows the diffstat, but it will accept any By default, the command shows the diffstat, but it will accept any
format known to 'git diff' (e.g., `git stash show -p stash@{1}` format known to 'git diff' (e.g., `git stash show -p stash@{1}`
to view the second most recent entry in patch form). to view the second most recent entry in patch form).
@ -128,14 +104,6 @@ pop [--index] [-q|--quiet] [<stash>]::
Applying the state can fail with conflicts; in this case, it is not Applying the state can fail with conflicts; in this case, it is not
removed from the stash list. You need to resolve the conflicts by hand removed from the stash list. You need to resolve the conflicts by hand
and call `git stash drop` manually afterwards. and call `git stash drop` manually afterwards.
+
If the `--index` option is used, then tries to reinstate not only the working
tree's changes, but also the index's ones. However, this can fail, when you
have conflicts (which are stored in the index, where you therefore can no
longer apply the changes as they were originally).
+
When no `<stash>` is given, `stash@{0}` is assumed, otherwise `<stash>` must
be a reference of the form `stash@{<revision>}`.
apply [--index] [-q|--quiet] [<stash>]:: apply [--index] [-q|--quiet] [<stash>]::
@ -149,8 +117,7 @@ branch <branchname> [<stash>]::
the commit at which the `<stash>` was originally created, applies the the commit at which the `<stash>` was originally created, applies the
changes recorded in `<stash>` to the new working tree and index. changes recorded in `<stash>` to the new working tree and index.
If that succeeds, and `<stash>` is a reference of the form If that succeeds, and `<stash>` is a reference of the form
`stash@{<revision>}`, it then drops the `<stash>`. When no `<stash>` `stash@{<revision>}`, it then drops the `<stash>`.
is given, applies the latest one.
+ +
This is useful if the branch on which you ran `git stash push` has This is useful if the branch on which you ran `git stash push` has
changed enough that `git stash apply` fails due to conflicts. Since changed enough that `git stash apply` fails due to conflicts. Since
@ -166,9 +133,6 @@ clear::
drop [-q|--quiet] [<stash>]:: drop [-q|--quiet] [<stash>]::
Remove a single stash entry from the list of stash entries. Remove a single stash entry from the list of stash entries.
When no `<stash>` is given, it removes the latest one.
i.e. `stash@{0}`, otherwise `<stash>` must be a valid stash
log reference of the form `stash@{<revision>}`.
create:: create::
@ -185,6 +149,98 @@ store::
reflog. This is intended to be useful for scripts. It is reflog. This is intended to be useful for scripts. It is
probably not the command you want to use; see "push" above. probably not the command you want to use; see "push" above.
OPTIONS
-------
-a::
--all::
This option is only valid for `push` and `save` commands.
+
All ignored and untracked files are also stashed and then cleaned
up with `git clean`.
-u::
--include-untracked::
This option is only valid for `push` and `save` commands.
+
All untracked files are also stashed and then cleaned up with
`git clean`.
--index::
This option is only valid for `pop` and `apply` commands.
+
Tries to reinstate not only the working tree's changes, but also
the index's ones. However, this can fail, when you have conflicts
(which are stored in the index, where you therefore can no longer
apply the changes as they were originally).
-k::
--keep-index::
--no-keep-index::
This option is only valid for `push` and `save` commands.
+
All changes already added to the index are left intact.
-p::
--patch::
This option is only valid for `push` and `save` commands.
+
Interactively select hunks from the diff between HEAD and the
working tree to be stashed. The stash entry is constructed such
that its index state is the same as the index state of your
repository, and its worktree contains only the changes you selected
interactively. The selected changes are then rolled back from your
worktree. See the ``Interactive Mode'' section of linkgit:git-add[1]
to learn how to operate the `--patch` mode.
+
The `--patch` option implies `--keep-index`. You can use
`--no-keep-index` to override this.
--pathspec-from-file=<file>::
This option is only valid for `push` command.
+
Pathspec is passed in `<file>` instead of commandline args. If
`<file>` is exactly `-` then standard input is used. Pathspec
elements are separated by LF or CR/LF. Pathspec elements can be
quoted as explained for the configuration variable `core.quotePath`
(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
global `--literal-pathspecs`.
--pathspec-file-nul::
This option is only valid for `push` command.
+
Only meaningful with `--pathspec-from-file`. Pathspec elements are
separated with NUL character and all other characters are taken
literally (including newlines and quotes).
-q::
--quiet::
This option is only valid for `apply`, `drop`, `pop`, `push`,
`save`, `store` commands.
+
Quiet, suppress feedback messages.
\--::
This option is only valid for `push` command.
+
Separates pathspec from options for disambiguation purposes.
<pathspec>...::
This option is only valid for `push` command.
+
The new stash entry records the modified states only for the files
that match the pathspec. The index entries and working tree files
are then rolled back to the state in HEAD only for these files,
too, leaving files that do not match the pathspec intact.
+
For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
<stash>::
This option is only valid for `apply`, `branch`, `drop`, `pop`,
`show` commands.
+
A reference of the form `stash@{<revision>}`. When no `<stash>` is
given, the latest stash is assumed (that is, `stash@{0}`).
DISCUSSION DISCUSSION
---------- ----------

Просмотреть файл

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
GVF=GIT-VERSION-FILE GVF=GIT-VERSION-FILE
DEF_VER=v2.26.0-rc0 DEF_VER=v2.26.0-rc1
LF=' LF='
' '

Просмотреть файл

@ -81,6 +81,11 @@ enum signoff_type {
SIGNOFF_EXPLICIT /* --signoff was set on the command-line */ SIGNOFF_EXPLICIT /* --signoff was set on the command-line */
}; };
enum show_patch_type {
SHOW_PATCH_RAW = 0,
SHOW_PATCH_DIFF = 1,
};
struct am_state { struct am_state {
/* state directory path */ /* state directory path */
char *dir; char *dir;
@ -1763,7 +1768,7 @@ static void am_run(struct am_state *state, int resume)
linelen(state->msg), state->msg); linelen(state->msg), state->msg);
if (advice_amworkdir) if (advice_amworkdir)
advise(_("Use 'git am --show-current-patch' to see the failed patch")); advise(_("Use 'git am --show-current-patch=diff' to see the failed patch"));
die_user_resolve(state); die_user_resolve(state);
} }
@ -2061,7 +2066,7 @@ static void am_abort(struct am_state *state)
am_destroy(state); am_destroy(state);
} }
static int show_patch(struct am_state *state) static int show_patch(struct am_state *state, enum show_patch_type sub_mode)
{ {
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
const char *patch_path; const char *patch_path;
@ -2078,7 +2083,17 @@ static int show_patch(struct am_state *state)
return ret; return ret;
} }
patch_path = am_path(state, msgnum(state)); switch (sub_mode) {
case SHOW_PATCH_RAW:
patch_path = am_path(state, msgnum(state));
break;
case SHOW_PATCH_DIFF:
patch_path = am_path(state, "patch");
break;
default:
BUG("invalid mode for --show-current-patch");
}
len = strbuf_read_file(&sb, patch_path, 0); len = strbuf_read_file(&sb, patch_path, 0);
if (len < 0) if (len < 0)
die_errno(_("failed to read '%s'"), patch_path); die_errno(_("failed to read '%s'"), patch_path);
@ -2118,7 +2133,7 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
return 0; return 0;
} }
enum resume_mode { enum resume_type {
RESUME_FALSE = 0, RESUME_FALSE = 0,
RESUME_APPLY, RESUME_APPLY,
RESUME_RESOLVED, RESUME_RESOLVED,
@ -2128,6 +2143,45 @@ enum resume_mode {
RESUME_SHOW_PATCH RESUME_SHOW_PATCH
}; };
struct resume_mode {
enum resume_type mode;
enum show_patch_type sub_mode;
};
static int parse_opt_show_current_patch(const struct option *opt, const char *arg, int unset)
{
int *opt_value = opt->value;
struct resume_mode *resume = container_of(opt_value, struct resume_mode, mode);
/*
* Please update $__git_showcurrentpatch in git-completion.bash
* when you add new options
*/
const char *valid_modes[] = {
[SHOW_PATCH_DIFF] = "diff",
[SHOW_PATCH_RAW] = "raw"
};
int new_value = SHOW_PATCH_RAW;
if (arg) {
for (new_value = 0; new_value < ARRAY_SIZE(valid_modes); new_value++) {
if (!strcmp(arg, valid_modes[new_value]))
break;
}
if (new_value >= ARRAY_SIZE(valid_modes))
return error(_("Invalid value for --show-current-patch: %s"), arg);
}
if (resume->mode == RESUME_SHOW_PATCH && new_value != resume->sub_mode)
return error(_("--show-current-patch=%s is incompatible with "
"--show-current-patch=%s"),
arg, valid_modes[resume->sub_mode]);
resume->mode = RESUME_SHOW_PATCH;
resume->sub_mode = new_value;
return 0;
}
static int git_am_config(const char *k, const char *v, void *cb) static int git_am_config(const char *k, const char *v, void *cb)
{ {
int status; int status;
@ -2145,7 +2199,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
int binary = -1; int binary = -1;
int keep_cr = -1; int keep_cr = -1;
int patch_format = PATCH_FORMAT_UNKNOWN; int patch_format = PATCH_FORMAT_UNKNOWN;
enum resume_mode resume = RESUME_FALSE; struct resume_mode resume = { .mode = RESUME_FALSE };
int in_progress; int in_progress;
int ret = 0; int ret = 0;
@ -2214,24 +2268,26 @@ int cmd_am(int argc, const char **argv, const char *prefix)
PARSE_OPT_NOARG), PARSE_OPT_NOARG),
OPT_STRING(0, "resolvemsg", &state.resolvemsg, NULL, OPT_STRING(0, "resolvemsg", &state.resolvemsg, NULL,
N_("override error message when patch failure occurs")), N_("override error message when patch failure occurs")),
OPT_CMDMODE(0, "continue", &resume, OPT_CMDMODE(0, "continue", &resume.mode,
N_("continue applying patches after resolving a conflict"), N_("continue applying patches after resolving a conflict"),
RESUME_RESOLVED), RESUME_RESOLVED),
OPT_CMDMODE('r', "resolved", &resume, OPT_CMDMODE('r', "resolved", &resume.mode,
N_("synonyms for --continue"), N_("synonyms for --continue"),
RESUME_RESOLVED), RESUME_RESOLVED),
OPT_CMDMODE(0, "skip", &resume, OPT_CMDMODE(0, "skip", &resume.mode,
N_("skip the current patch"), N_("skip the current patch"),
RESUME_SKIP), RESUME_SKIP),
OPT_CMDMODE(0, "abort", &resume, OPT_CMDMODE(0, "abort", &resume.mode,
N_("restore the original branch and abort the patching operation."), N_("restore the original branch and abort the patching operation."),
RESUME_ABORT), RESUME_ABORT),
OPT_CMDMODE(0, "quit", &resume, OPT_CMDMODE(0, "quit", &resume.mode,
N_("abort the patching operation but keep HEAD where it is."), N_("abort the patching operation but keep HEAD where it is."),
RESUME_QUIT), RESUME_QUIT),
OPT_CMDMODE(0, "show-current-patch", &resume, { OPTION_CALLBACK, 0, "show-current-patch", &resume.mode,
N_("show the patch being applied."), "(diff|raw)",
RESUME_SHOW_PATCH), N_("show the patch being applied"),
PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
parse_opt_show_current_patch, RESUME_SHOW_PATCH },
OPT_BOOL(0, "committer-date-is-author-date", OPT_BOOL(0, "committer-date-is-author-date",
&state.committer_date_is_author_date, &state.committer_date_is_author_date,
N_("lie about committer date")), N_("lie about committer date")),
@ -2281,12 +2337,12 @@ int cmd_am(int argc, const char **argv, const char *prefix)
* intend to feed us a patch but wanted to continue * intend to feed us a patch but wanted to continue
* unattended. * unattended.
*/ */
if (argc || (resume == RESUME_FALSE && !isatty(0))) if (argc || (resume.mode == RESUME_FALSE && !isatty(0)))
die(_("previous rebase directory %s still exists but mbox given."), die(_("previous rebase directory %s still exists but mbox given."),
state.dir); state.dir);
if (resume == RESUME_FALSE) if (resume.mode == RESUME_FALSE)
resume = RESUME_APPLY; resume.mode = RESUME_APPLY;
if (state.signoff == SIGNOFF_EXPLICIT) if (state.signoff == SIGNOFF_EXPLICIT)
am_append_signoff(&state); am_append_signoff(&state);
@ -2300,7 +2356,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
* stray directories. * stray directories.
*/ */
if (file_exists(state.dir) && !state.rebasing) { if (file_exists(state.dir) && !state.rebasing) {
if (resume == RESUME_ABORT || resume == RESUME_QUIT) { if (resume.mode == RESUME_ABORT || resume.mode == RESUME_QUIT) {
am_destroy(&state); am_destroy(&state);
am_state_release(&state); am_state_release(&state);
return 0; return 0;
@ -2311,7 +2367,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
state.dir); state.dir);
} }
if (resume) if (resume.mode)
die(_("Resolve operation not in progress, we are not resuming.")); die(_("Resolve operation not in progress, we are not resuming."));
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
@ -2329,7 +2385,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
argv_array_clear(&paths); argv_array_clear(&paths);
} }
switch (resume) { switch (resume.mode) {
case RESUME_FALSE: case RESUME_FALSE:
am_run(&state, 0); am_run(&state, 0);
break; break;
@ -2350,7 +2406,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
am_destroy(&state); am_destroy(&state);
break; break;
case RESUME_SHOW_PATCH: case RESUME_SHOW_PATCH:
ret = show_patch(&state); ret = show_patch(&state, resume.sub_mode);
break; break;
default: default:
BUG("invalid resume value"); BUG("invalid resume value");

Просмотреть файл

@ -235,7 +235,8 @@ static int check_local_mod(struct object_id *head, int index_only)
} }
static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0; static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
static int ignore_unmatch = 0; static int ignore_unmatch = 0, pathspec_file_nul;
static char *pathspec_from_file;
static struct option builtin_rm_options[] = { static struct option builtin_rm_options[] = {
OPT__DRY_RUN(&show_only, N_("dry run")), OPT__DRY_RUN(&show_only, N_("dry run")),
@ -245,6 +246,8 @@ static struct option builtin_rm_options[] = {
OPT_BOOL('r', NULL, &recursive, N_("allow recursive removal")), OPT_BOOL('r', NULL, &recursive, N_("allow recursive removal")),
OPT_BOOL( 0 , "ignore-unmatch", &ignore_unmatch, OPT_BOOL( 0 , "ignore-unmatch", &ignore_unmatch,
N_("exit with a zero status even if nothing matched")), N_("exit with a zero status even if nothing matched")),
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END(), OPT_END(),
}; };
@ -259,8 +262,24 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, builtin_rm_options, argc = parse_options(argc, argv, prefix, builtin_rm_options,
builtin_rm_usage, 0); builtin_rm_usage, 0);
if (!argc)
usage_with_options(builtin_rm_usage, builtin_rm_options); parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_CWD,
prefix, argv);
if (pathspec_from_file) {
if (pathspec.nr)
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
parse_pathspec_file(&pathspec, 0,
PATHSPEC_PREFER_CWD,
prefix, pathspec_from_file, pathspec_file_nul);
} else if (pathspec_file_nul) {
die(_("--pathspec-file-nul requires --pathspec-from-file"));
}
if (!pathspec.nr)
die(_("No pathspec was given. Which files should I remove?"));
if (!index_only) if (!index_only)
setup_work_tree(); setup_work_tree();
@ -270,9 +289,6 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (read_cache() < 0) if (read_cache() < 0)
die(_("index file corrupt")); die(_("index file corrupt"));
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_CWD,
prefix, argv);
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL); refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);
seen = xcalloc(pathspec.nr, 1); seen = xcalloc(pathspec.nr, 1);

Просмотреть файл

@ -27,6 +27,7 @@ static const char * const git_stash_usage[] = {
N_("git stash clear"), N_("git stash clear"),
N_("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n" N_("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
" [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n" " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
" [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
" [--] [<pathspec>...]]"), " [--] [<pathspec>...]]"),
N_("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n" N_("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
" [-u|--include-untracked] [-a|--all] [<message>]"), " [-u|--include-untracked] [-a|--all] [<message>]"),
@ -1451,13 +1452,17 @@ done:
return ret; return ret;
} }
static int push_stash(int argc, const char **argv, const char *prefix) static int push_stash(int argc, const char **argv, const char *prefix,
int push_assumed)
{ {
int force_assume = 0;
int keep_index = -1; int keep_index = -1;
int patch_mode = 0; int patch_mode = 0;
int include_untracked = 0; int include_untracked = 0;
int quiet = 0; int quiet = 0;
int pathspec_file_nul = 0;
const char *stash_msg = NULL; const char *stash_msg = NULL;
const char *pathspec_from_file = NULL;
struct pathspec ps; struct pathspec ps;
struct option options[] = { struct option options[] = {
OPT_BOOL('k', "keep-index", &keep_index, OPT_BOOL('k', "keep-index", &keep_index,
@ -1471,16 +1476,45 @@ static int push_stash(int argc, const char **argv, const char *prefix)
N_("include ignore files"), 2), N_("include ignore files"), 2),
OPT_STRING('m', "message", &stash_msg, N_("message"), OPT_STRING('m', "message", &stash_msg, N_("message"),
N_("stash message")), N_("stash message")),
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END() OPT_END()
}; };
if (argc) if (argc) {
force_assume = !strcmp(argv[0], "-p");
argc = parse_options(argc, argv, prefix, options, argc = parse_options(argc, argv, prefix, options,
git_stash_push_usage, git_stash_push_usage,
0); PARSE_OPT_KEEP_DASHDASH);
}
if (argc) {
if (!strcmp(argv[0], "--")) {
argc--;
argv++;
} else if (push_assumed && !force_assume) {
die("subcommand wasn't specified; 'push' can't be assumed due to unexpected token '%s'",
argv[0]);
}
}
parse_pathspec(&ps, 0, PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN, parse_pathspec(&ps, 0, PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN,
prefix, argv); prefix, argv);
if (pathspec_from_file) {
if (patch_mode)
die(_("--pathspec-from-file is incompatible with --patch"));
if (ps.nr)
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
parse_pathspec_file(&ps, 0,
PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN,
prefix, pathspec_from_file, pathspec_file_nul);
} else if (pathspec_file_nul) {
die(_("--pathspec-file-nul requires --pathspec-from-file"));
}
return do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode, return do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
include_untracked); include_untracked);
} }
@ -1550,7 +1584,6 @@ static int use_builtin_stash(void)
int cmd_stash(int argc, const char **argv, const char *prefix) int cmd_stash(int argc, const char **argv, const char *prefix)
{ {
int i = -1;
pid_t pid = getpid(); pid_t pid = getpid();
const char *index_file; const char *index_file;
struct argv_array args = ARGV_ARRAY_INIT; struct argv_array args = ARGV_ARRAY_INIT;
@ -1583,7 +1616,7 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
(uintmax_t)pid); (uintmax_t)pid);
if (!argc) if (!argc)
return !!push_stash(0, NULL, prefix); return !!push_stash(0, NULL, prefix, 0);
else if (!strcmp(argv[0], "apply")) else if (!strcmp(argv[0], "apply"))
return !!apply_stash(argc, argv, prefix); return !!apply_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "clear")) else if (!strcmp(argv[0], "clear"))
@ -1603,45 +1636,15 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
else if (!strcmp(argv[0], "create")) else if (!strcmp(argv[0], "create"))
return !!create_stash(argc, argv, prefix); return !!create_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "push")) else if (!strcmp(argv[0], "push"))
return !!push_stash(argc, argv, prefix); return !!push_stash(argc, argv, prefix, 0);
else if (!strcmp(argv[0], "save")) else if (!strcmp(argv[0], "save"))
return !!save_stash(argc, argv, prefix); return !!save_stash(argc, argv, prefix);
else if (*argv[0] != '-') else if (*argv[0] != '-')
usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]), usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
git_stash_usage, options); git_stash_usage, options);
if (strcmp(argv[0], "-p")) { /* Assume 'stash push' */
while (++i < argc && strcmp(argv[i], "--")) {
/*
* `akpqu` is a string which contains all short options,
* except `-m` which is verified separately.
*/
if ((strlen(argv[i]) == 2) && *argv[i] == '-' &&
strchr("akpqu", argv[i][1]))
continue;
if (!strcmp(argv[i], "--all") ||
!strcmp(argv[i], "--keep-index") ||
!strcmp(argv[i], "--no-keep-index") ||
!strcmp(argv[i], "--patch") ||
!strcmp(argv[i], "--quiet") ||
!strcmp(argv[i], "--include-untracked"))
continue;
/*
* `-m` and `--message=` are verified separately because
* they need to be immediately followed by a string
* (i.e.`-m"foobar"` or `--message="foobar"`).
*/
if (starts_with(argv[i], "-m") ||
starts_with(argv[i], "--message="))
continue;
usage_with_options(git_stash_usage, options);
}
}
argv_array_push(&args, "push"); argv_array_push(&args, "push");
argv_array_pushv(&args, argv); argv_array_pushv(&args, argv);
return !!push_stash(args.argc, args.argv, prefix); return !!push_stash(args.argc, args.argv, prefix, 1);
} }

Просмотреть файл

@ -139,22 +139,10 @@ win32_compute_revents (HANDLE h, int *p_sought)
INPUT_RECORD *irbuffer; INPUT_RECORD *irbuffer;
DWORD avail, nbuffer; DWORD avail, nbuffer;
BOOL bRet; BOOL bRet;
IO_STATUS_BLOCK iosb;
FILE_PIPE_LOCAL_INFORMATION fpli;
static PNtQueryInformationFile NtQueryInformationFile;
static BOOL once_only;
switch (GetFileType (h)) switch (GetFileType (h))
{ {
case FILE_TYPE_PIPE: case FILE_TYPE_PIPE:
if (!once_only)
{
NtQueryInformationFile = (PNtQueryInformationFile)(void (*)(void))
GetProcAddress (GetModuleHandleW (L"ntdll.dll"),
"NtQueryInformationFile");
once_only = TRUE;
}
happened = 0; happened = 0;
if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0) if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
{ {
@ -166,22 +154,9 @@ win32_compute_revents (HANDLE h, int *p_sought)
else else
{ {
/* It was the write-end of the pipe. Check if it is writable. /* It was the write-end of the pipe. Unfortunately there is no
If NtQueryInformationFile fails, optimistically assume the pipe is reliable way of knowing if it can be written without blocking.
writable. This could happen on Win9x, where NtQueryInformationFile Just say that it's all good. */
is not available, or if we inherit a pipe that doesn't permit
FILE_READ_ATTRIBUTES access on the write end (I think this should
not happen since WinXP SP2; WINE seems fine too). Otherwise,
ensure that enough space is available for atomic writes. */
memset (&iosb, 0, sizeof (iosb));
memset (&fpli, 0, sizeof (fpli));
if (!NtQueryInformationFile
|| NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
FilePipeLocalInformation)
|| fpli.WriteQuotaAvailable >= PIPE_BUF
|| (fpli.OutboundQuota < PIPE_BUF &&
fpli.WriteQuotaAvailable == fpli.OutboundQuota))
happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND); happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
} }
return happened; return happened;

Просмотреть файл

@ -9,7 +9,6 @@ endif
DEVELOPER_CFLAGS += -Wall DEVELOPER_CFLAGS += -Wall
DEVELOPER_CFLAGS += -Wdeclaration-after-statement DEVELOPER_CFLAGS += -Wdeclaration-after-statement
DEVELOPER_CFLAGS += -Wformat-security DEVELOPER_CFLAGS += -Wformat-security
DEVELOPER_CFLAGS += -Wno-format-zero-length
DEVELOPER_CFLAGS += -Wold-style-definition DEVELOPER_CFLAGS += -Wold-style-definition
DEVELOPER_CFLAGS += -Woverflow DEVELOPER_CFLAGS += -Woverflow
DEVELOPER_CFLAGS += -Wpointer-arith DEVELOPER_CFLAGS += -Wpointer-arith

Просмотреть файл

@ -1197,6 +1197,7 @@ __git_count_arguments ()
__git_whitespacelist="nowarn warn error error-all fix" __git_whitespacelist="nowarn warn error error-all fix"
__git_patchformat="mbox stgit stgit-series hg mboxrd" __git_patchformat="mbox stgit stgit-series hg mboxrd"
__git_showcurrentpatch="diff raw"
__git_am_inprogress_options="--skip --continue --resolved --abort --quit --show-current-patch" __git_am_inprogress_options="--skip --continue --resolved --abort --quit --show-current-patch"
_git_am () _git_am ()
@ -1215,6 +1216,10 @@ _git_am ()
__gitcomp "$__git_patchformat" "" "${cur##--patch-format=}" __gitcomp "$__git_patchformat" "" "${cur##--patch-format=}"
return return
;; ;;
--show-current-patch=*)
__gitcomp "$__git_showcurrentpatch" "" "${cur##--show-current-patch=}"
return
;;
--*) --*)
__gitcomp_builtin am "" \ __gitcomp_builtin am "" \
"$__git_am_inprogress_options" "$__git_am_inprogress_options"
@ -1487,9 +1492,16 @@ __git_diff_algorithms="myers minimal patience histogram"
__git_diff_submodule_formats="diff log short" __git_diff_submodule_formats="diff log short"
__git_color_moved_opts="no default plain blocks zebra dimmed-zebra"
__git_color_moved_ws_opts="no ignore-space-at-eol ignore-space-change
ignore-all-space allow-indentation-change"
__git_diff_common_options="--stat --numstat --shortstat --summary __git_diff_common_options="--stat --numstat --shortstat --summary
--patch-with-stat --name-only --name-status --color --patch-with-stat --name-only --name-status --color
--no-color --color-words --no-renames --check --no-color --color-words --no-renames --check
--color-moved --color-moved= --no-color-moved
--color-moved-ws= --no-color-moved-ws
--full-index --binary --abbrev --diff-filter= --full-index --binary --abbrev --diff-filter=
--find-copies-harder --ignore-cr-at-eol --find-copies-harder --ignore-cr-at-eol
--text --ignore-space-at-eol --ignore-space-change --text --ignore-space-at-eol --ignore-space-change
@ -1520,6 +1532,14 @@ _git_diff ()
__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}" __gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}"
return return
;; ;;
--color-moved=*)
__gitcomp "$__git_color_moved_opts" "" "${cur##--color-moved=}"
return
;;
--color-moved-ws=*)
__gitcomp "$__git_color_moved_ws_opts" "" "${cur##--color-moved-ws=}"
return
;;
--*) --*)
__gitcomp "--cached --staged --pickaxe-all --pickaxe-regex __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
--base --ours --theirs --no-index --base --ours --theirs --no-index

Просмотреть файл

@ -516,7 +516,7 @@ static int show_one_mergetag(struct commit *commit,
"merged tag '%s'\n", tag->tag); "merged tag '%s'\n", tag->tag);
else if ((nth = which_parent(&tag->tagged->oid, commit)) < 0) else if ((nth = which_parent(&tag->tagged->oid, commit)) < 0)
strbuf_addf(&verify_message, "tag %s names a non-parent %s\n", strbuf_addf(&verify_message, "tag %s names a non-parent %s\n",
tag->tag, tag->tagged->oid.hash); tag->tag, oid_to_hex(&tag->tagged->oid));
else else
strbuf_addf(&verify_message, strbuf_addf(&verify_message,
"parent #%d, tagged '%s'\n", nth + 1, tag->tag); "parent #%d, tagged '%s'\n", nth + 1, tag->tag);

Просмотреть файл

@ -1560,35 +1560,6 @@ static int handle_file_collision(struct merge_options *opt,
b, a); b, a);
} }
/*
* In the recursive case, we just opt to undo renames
*/
if (opt->priv->call_depth && (prev_path1 || prev_path2)) {
/* Put first file (a->oid, a->mode) in its original spot */
if (prev_path1) {
if (update_file(opt, 1, a, prev_path1))
return -1;
} else {
if (update_file(opt, 1, a, collide_path))
return -1;
}
/* Put second file (b->oid, b->mode) in its original spot */
if (prev_path2) {
if (update_file(opt, 1, b, prev_path2))
return -1;
} else {
if (update_file(opt, 1, b, collide_path))
return -1;
}
/* Don't leave something at collision path if unrenaming both */
if (prev_path1 && prev_path2)
remove_file(opt, 1, collide_path, 0);
return 0;
}
/* Remove rename sources if rename/add or rename/rename(2to1) */ /* Remove rename sources if rename/add or rename/rename(2to1) */
if (prev_path1) if (prev_path1)
remove_file(opt, 1, prev_path1, remove_file(opt, 1, prev_path1,
@ -1749,85 +1720,56 @@ static int handle_rename_rename_1to2(struct merge_options *opt,
return -1; return -1;
free(path_desc); free(path_desc);
if (opt->priv->call_depth) { if (opt->priv->call_depth)
/* remove_file_from_index(opt->repo->index, o->path);
* FIXME: For rename/add-source conflicts (if we could detect
* such), this is wrong. We should instead find a unique /*
* pathname and then either rename the add-source file to that * For each destination path, we need to see if there is a
* unique path, or use that unique path instead of src here. * rename/add collision. If not, we can write the file out
*/ * to the specified location.
if (update_file(opt, 0, &mfi.blob, o->path)) */
add = &ci->ren1->dst_entry->stages[flip_stage(2)];
if (is_valid(add)) {
add->path = mfi.blob.path = a->path;
if (handle_file_collision(opt, a->path,
NULL, NULL,
ci->ren1->branch,
ci->ren2->branch,
&mfi.blob, add) < 0)
return -1; return -1;
/*
* Above, we put the merged content at the merge-base's
* path. Now we usually need to delete both a->path and
* b->path. However, the rename on each side of the merge
* could also be involved in a rename/add conflict. In
* such cases, we should keep the added file around,
* resolving the conflict at that path in its favor.
*/
add = &ci->ren1->dst_entry->stages[flip_stage(2)];
if (is_valid(add)) {
if (update_file(opt, 0, add, a->path))
return -1;
}
else
remove_file_from_index(opt->repo->index, a->path);
add = &ci->ren2->dst_entry->stages[flip_stage(3)];
if (is_valid(add)) {
if (update_file(opt, 0, add, b->path))
return -1;
}
else
remove_file_from_index(opt->repo->index, b->path);
} else { } else {
/* char *new_path = find_path_for_conflict(opt, a->path,
* For each destination path, we need to see if there is a ci->ren1->branch,
* rename/add collision. If not, we can write the file out ci->ren2->branch);
* to the specified location. if (update_file(opt, 0, &mfi.blob,
*/ new_path ? new_path : a->path))
add = &ci->ren1->dst_entry->stages[flip_stage(2)]; return -1;
if (is_valid(add)) { free(new_path);
add->path = mfi.blob.path = a->path; if (!opt->priv->call_depth &&
if (handle_file_collision(opt, a->path, update_stages(opt, a->path, NULL, a, NULL))
NULL, NULL, return -1;
ci->ren1->branch, }
ci->ren2->branch,
&mfi.blob, add) < 0)
return -1;
} else {
char *new_path = find_path_for_conflict(opt, a->path,
ci->ren1->branch,
ci->ren2->branch);
if (update_file(opt, 0, &mfi.blob,
new_path ? new_path : a->path))
return -1;
free(new_path);
if (update_stages(opt, a->path, NULL, a, NULL))
return -1;
}
add = &ci->ren2->dst_entry->stages[flip_stage(3)]; add = &ci->ren2->dst_entry->stages[flip_stage(3)];
if (is_valid(add)) { if (is_valid(add)) {
add->path = mfi.blob.path = b->path; add->path = mfi.blob.path = b->path;
if (handle_file_collision(opt, b->path, if (handle_file_collision(opt, b->path,
NULL, NULL, NULL, NULL,
ci->ren1->branch, ci->ren1->branch,
ci->ren2->branch, ci->ren2->branch,
add, &mfi.blob) < 0) add, &mfi.blob) < 0)
return -1; return -1;
} else { } else {
char *new_path = find_path_for_conflict(opt, b->path, char *new_path = find_path_for_conflict(opt, b->path,
ci->ren2->branch, ci->ren2->branch,
ci->ren1->branch); ci->ren1->branch);
if (update_file(opt, 0, &mfi.blob, if (update_file(opt, 0, &mfi.blob,
new_path ? new_path : b->path)) new_path ? new_path : b->path))
return -1; return -1;
free(new_path); free(new_path);
if (update_stages(opt, b->path, NULL, NULL, b)) if (!opt->priv->call_depth &&
return -1; update_stages(opt, b->path, NULL, NULL, b))
} return -1;
} }
return 0; return 0;

Просмотреть файл

@ -61,7 +61,7 @@ static enum parse_opt_result opt_command_mode_error(
*/ */
for (that = all_opts; that->type != OPTION_END; that++) { for (that = all_opts; that->type != OPTION_END; that++) {
if (that == opt || if (that == opt ||
that->type != OPTION_CMDMODE || !(that->flags & PARSE_OPT_CMDMODE) ||
that->value != opt->value || that->value != opt->value ||
that->defval != *(int *)opt->value) that->defval != *(int *)opt->value)
continue; continue;
@ -95,6 +95,14 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
if (!(flags & OPT_SHORT) && p->opt && (opt->flags & PARSE_OPT_NOARG)) if (!(flags & OPT_SHORT) && p->opt && (opt->flags & PARSE_OPT_NOARG))
return error(_("%s takes no value"), optname(opt, flags)); return error(_("%s takes no value"), optname(opt, flags));
/*
* Giving the same mode option twice, although unnecessary,
* is not a grave error, so let it pass.
*/
if ((opt->flags & PARSE_OPT_CMDMODE) &&
*(int *)opt->value && *(int *)opt->value != opt->defval)
return opt_command_mode_error(opt, all_opts, flags);
switch (opt->type) { switch (opt->type) {
case OPTION_LOWLEVEL_CALLBACK: case OPTION_LOWLEVEL_CALLBACK:
return opt->ll_callback(p, opt, NULL, unset); return opt->ll_callback(p, opt, NULL, unset);
@ -130,16 +138,6 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
*(int *)opt->value = unset ? 0 : opt->defval; *(int *)opt->value = unset ? 0 : opt->defval;
return 0; return 0;
case OPTION_CMDMODE:
/*
* Giving the same mode option twice, although is unnecessary,
* is not a grave error, so let it pass.
*/
if (*(int *)opt->value && *(int *)opt->value != opt->defval)
return opt_command_mode_error(opt, all_opts, flags);
*(int *)opt->value = opt->defval;
return 0;
case OPTION_STRING: case OPTION_STRING:
if (unset) if (unset)
*(const char **)opt->value = NULL; *(const char **)opt->value = NULL;

Просмотреть файл

@ -18,7 +18,6 @@ enum parse_opt_type {
OPTION_BITOP, OPTION_BITOP,
OPTION_COUNTUP, OPTION_COUNTUP,
OPTION_SET_INT, OPTION_SET_INT,
OPTION_CMDMODE,
/* options with arguments (usually) */ /* options with arguments (usually) */
OPTION_STRING, OPTION_STRING,
OPTION_INTEGER, OPTION_INTEGER,
@ -47,7 +46,8 @@ enum parse_opt_option_flags {
PARSE_OPT_LITERAL_ARGHELP = 64, PARSE_OPT_LITERAL_ARGHELP = 64,
PARSE_OPT_SHELL_EVAL = 256, PARSE_OPT_SHELL_EVAL = 256,
PARSE_OPT_NOCOMPLETE = 512, PARSE_OPT_NOCOMPLETE = 512,
PARSE_OPT_COMP_ARG = 1024 PARSE_OPT_COMP_ARG = 1024,
PARSE_OPT_CMDMODE = 2048
}; };
enum parse_opt_result { enum parse_opt_result {
@ -168,8 +168,8 @@ struct option {
#define OPT_BOOL(s, l, v, h) OPT_BOOL_F(s, l, v, h, 0) #define OPT_BOOL(s, l, v, h) OPT_BOOL_F(s, l, v, h, 0)
#define OPT_HIDDEN_BOOL(s, l, v, h) { OPTION_SET_INT, (s), (l), (v), NULL, \ #define OPT_HIDDEN_BOOL(s, l, v, h) { OPTION_SET_INT, (s), (l), (v), NULL, \
(h), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1} (h), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1}
#define OPT_CMDMODE(s, l, v, h, i) { OPTION_CMDMODE, (s), (l), (v), NULL, \ #define OPT_CMDMODE(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, \
(h), PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, (i) } (h), PARSE_OPT_CMDMODE|PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, (i) }
#define OPT_INTEGER(s, l, v, h) OPT_INTEGER_F(s, l, v, h, 0) #define OPT_INTEGER(s, l, v, h) OPT_INTEGER_F(s, l, v, h, 0)
#define OPT_MAGNITUDE(s, l, v, h) { OPTION_MAGNITUDE, (s), (l), (v), \ #define OPT_MAGNITUDE(s, l, v, h) { OPTION_MAGNITUDE, (s), (l), (v), \
N_("n"), (h), PARSE_OPT_NONEG } N_("n"), (h), PARSE_OPT_NONEG }

Просмотреть файл

@ -129,14 +129,14 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,
if (incorrect) { if (incorrect) {
if (todo_list_check_against_backup(r, new_todo)) { if (todo_list_check_against_backup(r, new_todo)) {
write_file(rebase_path_dropped(), ""); write_file(rebase_path_dropped(), "%s", "");
return -4; return -4;
} }
if (incorrect > 0) if (incorrect > 0)
unlink(rebase_path_dropped()); unlink(rebase_path_dropped());
} else if (todo_list_check(todo_list, new_todo)) { } else if (todo_list_check(todo_list, new_todo)) {
write_file(rebase_path_dropped(), ""); write_file(rebase_path_dropped(), "%s", "");
return -4; return -4;
} }

Просмотреть файл

@ -1026,6 +1026,7 @@ static int fetch_dumb(int nr_heads, struct ref **to_fetch)
walker = get_http_walker(url.buf); walker = get_http_walker(url.buf);
walker->get_verbosely = options.verbosity >= 3; walker->get_verbosely = options.verbosity >= 3;
walker->get_progress = options.progress;
walker->get_recover = 0; walker->get_recover = 0;
ret = walker_fetch(walker, nr_heads, targets, NULL, NULL); ret = walker_fetch(walker, nr_heads, targets, NULL, NULL);
walker_free(walker); walker_free(walker);

Просмотреть файл

@ -121,6 +121,8 @@ int cmd__parse_options(int argc, const char **argv)
OPT_INTEGER('j', NULL, &integer, "get a integer, too"), OPT_INTEGER('j', NULL, &integer, "get a integer, too"),
OPT_MAGNITUDE('m', "magnitude", &magnitude, "get a magnitude"), OPT_MAGNITUDE('m', "magnitude", &magnitude, "get a magnitude"),
OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23), OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23),
OPT_CMDMODE(0, "mode1", &integer, "set integer to 1 (cmdmode option)", 1),
OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2),
OPT_CALLBACK('L', "length", &integer, "str", OPT_CALLBACK('L', "length", &integer, "str",
"get length of <str>", length_callback), "get length of <str>", length_callback),
OPT_FILENAME('F', "file", &file, "set file to <file>"), OPT_FILENAME('F', "file", &file, "set file to <file>"),

Просмотреть файл

@ -23,6 +23,8 @@ usage: test-tool parse-options <options>
-j <n> get a integer, too -j <n> get a integer, too
-m, --magnitude <n> get a magnitude -m, --magnitude <n> get a magnitude
--set23 set integer to 23 --set23 set integer to 23
--mode1 set integer to 1 (cmdmode option)
--mode2 set integer to 2 (cmdmode option)
-L, --length <str> get length of <str> -L, --length <str> get length of <str>
-F, --file <file> set file to <file> -F, --file <file> set file to <file>
@ -324,6 +326,22 @@ test_expect_success 'OPT_NEGBIT() works' '
test-tool parse-options --expect="boolean: 6" -bb --no-neg-or4 test-tool parse-options --expect="boolean: 6" -bb --no-neg-or4
' '
test_expect_success 'OPT_CMDMODE() works' '
test-tool parse-options --expect="integer: 1" --mode1
'
test_expect_success 'OPT_CMDMODE() detects incompatibility' '
test_must_fail test-tool parse-options --mode1 --mode2 >output 2>output.err &&
test_must_be_empty output &&
test_i18ngrep "incompatible with --mode" output.err
'
test_expect_success 'OPT_CMDMODE() detects incompatibility with something else' '
test_must_fail test-tool parse-options --set23 --mode2 >output 2>output.err &&
test_must_be_empty output &&
test_i18ngrep "incompatible with something else" output.err
'
test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' ' test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' '
test-tool parse-options --expect="boolean: 6" + + + + + + test-tool parse-options --expect="boolean: 6" + + + + + +
' '

Просмотреть файл

@ -53,7 +53,8 @@ test_expect_success 'add a large file or two' '
for p in .git/objects/pack/pack-*.pack for p in .git/objects/pack/pack-*.pack
do do
count=$(( $count + 1 )) count=$(( $count + 1 ))
if test -f "$p" && idx=${p%.pack}.idx && test -f "$idx" if test_path_is_file "$p" &&
idx=${p%.pack}.idx && test_path_is_file "$idx"
then then
continue continue
fi fi
@ -65,7 +66,7 @@ test_expect_success 'add a large file or two' '
test $cnt = 2 && test $cnt = 2 &&
for l in .git/objects/??/?????????????????????????????????????? for l in .git/objects/??/??????????????????????????????????????
do do
test -f "$l" || continue test_path_is_file "$l" || continue
bad=t bad=t
done && done &&
test -z "$bad" && test -z "$bad" &&
@ -76,7 +77,8 @@ test_expect_success 'add a large file or two' '
for p in .git/objects/pack/pack-*.pack for p in .git/objects/pack/pack-*.pack
do do
count=$(( $count + 1 )) count=$(( $count + 1 ))
if test -f "$p" && idx=${p%.pack}.idx && test -f "$idx" if test_path_is_file "$p" &&
idx=${p%.pack}.idx && test_path_is_file "$idx"
then then
continue continue
fi fi
@ -111,7 +113,7 @@ test_expect_success 'packsize limit' '
count=0 && count=0 &&
for pi in .git/objects/pack/pack-*.idx for pi in .git/objects/pack/pack-*.idx
do do
test -f "$pi" && count=$(( $count + 1 )) test_path_is_file "$pi" && count=$(( $count + 1 ))
done && done &&
test $count = 2 && test $count = 2 &&

Просмотреть файл

@ -28,7 +28,7 @@ test_expect_success 'setup' '
git config core.sparseCheckout true && git config core.sparseCheckout true &&
echo "/checked-out" >.git/info/sparse-checkout && echo "/checked-out" >.git/info/sparse-checkout &&
git reset --hard && git reset --hard &&
! git merge theirs test_must_fail git merge theirs
' '
test_expect_success 'reset --hard works after the conflict' ' test_expect_success 'reset --hard works after the conflict' '
@ -42,7 +42,7 @@ test_expect_success 'is reset properly' '
' '
test_expect_success 'setup: conflict back' ' test_expect_success 'setup: conflict back' '
! git merge theirs test_must_fail git merge theirs
' '
test_expect_success 'Merge abort works after the conflict' ' test_expect_success 'Merge abort works after the conflict' '

79
t/t3601-rm-pathspec-file.sh Executable file
Просмотреть файл

@ -0,0 +1,79 @@
#!/bin/sh
test_description='rm --pathspec-from-file'
. ./test-lib.sh
test_tick
test_expect_success setup '
echo A >fileA.t &&
echo B >fileB.t &&
echo C >fileC.t &&
echo D >fileD.t &&
git add fileA.t fileB.t fileC.t fileD.t &&
git commit -m "files" &&
git tag checkpoint
'
restore_checkpoint () {
git reset --hard checkpoint
}
verify_expect () {
git status --porcelain --untracked-files=no -- fileA.t fileB.t fileC.t fileD.t >actual &&
test_cmp expect actual
}
test_expect_success 'simplest' '
restore_checkpoint &&
cat >expect <<-\EOF &&
D fileA.t
EOF
echo fileA.t | git rm --pathspec-from-file=- &&
verify_expect
'
test_expect_success '--pathspec-file-nul' '
restore_checkpoint &&
cat >expect <<-\EOF &&
D fileA.t
D fileB.t
EOF
printf "fileA.t\0fileB.t\0" | git rm --pathspec-from-file=- --pathspec-file-nul &&
verify_expect
'
test_expect_success 'only touches what was listed' '
restore_checkpoint &&
cat >expect <<-\EOF &&
D fileB.t
D fileC.t
EOF
printf "fileB.t\nfileC.t\n" | git rm --pathspec-from-file=- &&
verify_expect
'
test_expect_success 'error conditions' '
restore_checkpoint &&
echo fileA.t >list &&
test_must_fail git rm --pathspec-from-file=list -- fileA.t 2>err &&
test_i18ngrep -e "--pathspec-from-file is incompatible with pathspec arguments" err &&
test_must_fail git rm --pathspec-file-nul 2>err &&
test_i18ngrep -e "--pathspec-file-nul requires --pathspec-from-file" err &&
>empty_list &&
test_must_fail git rm --pathspec-from-file=empty_list 2>err &&
test_i18ngrep -e "No pathspec was given. Which files should I remove?" err
'
test_done

Просмотреть файл

@ -285,6 +285,11 @@ test_expect_success 'stash --no-keep-index' '
test bar,bar2 = $(cat file),$(cat file2) test bar,bar2 = $(cat file),$(cat file2)
' '
test_expect_success 'dont assume push with non-option args' '
test_must_fail git stash -q drop 2>err &&
test_i18ngrep -e "subcommand wasn'\''t specified; '\''push'\'' can'\''t be assumed due to unexpected token '\''drop'\''" err
'
test_expect_success 'stash --invalid-option' ' test_expect_success 'stash --invalid-option' '
echo bar5 >file && echo bar5 >file &&
echo bar6 >file2 && echo bar6 >file2 &&

100
t/t3909-stash-pathspec-file.sh Executable file
Просмотреть файл

@ -0,0 +1,100 @@
#!/bin/sh
test_description='stash --pathspec-from-file'
. ./test-lib.sh
test_tick
test_expect_success setup '
>fileA.t &&
>fileB.t &&
>fileC.t &&
>fileD.t &&
git add fileA.t fileB.t fileC.t fileD.t &&
git commit -m "Files" &&
git tag checkpoint
'
restore_checkpoint () {
git reset --hard checkpoint
}
verify_expect () {
git stash show --name-status >actual &&
test_cmp expect actual
}
test_expect_success 'simplest' '
restore_checkpoint &&
# More files are written to make sure that git didnt ignore
# --pathspec-from-file, stashing everything
echo A >fileA.t &&
echo B >fileB.t &&
echo C >fileC.t &&
echo D >fileD.t &&
cat >expect <<-\EOF &&
M fileA.t
EOF
echo fileA.t | git stash push --pathspec-from-file=- &&
verify_expect
'
test_expect_success '--pathspec-file-nul' '
restore_checkpoint &&
# More files are written to make sure that git didnt ignore
# --pathspec-from-file, stashing everything
echo A >fileA.t &&
echo B >fileB.t &&
echo C >fileC.t &&
echo D >fileD.t &&
cat >expect <<-\EOF &&
M fileA.t
M fileB.t
EOF
printf "fileA.t\0fileB.t\0" | git stash push --pathspec-from-file=- --pathspec-file-nul &&
verify_expect
'
test_expect_success 'only touches what was listed' '
restore_checkpoint &&
# More files are written to make sure that git didnt ignore
# --pathspec-from-file, stashing everything
echo A >fileA.t &&
echo B >fileB.t &&
echo C >fileC.t &&
echo D >fileD.t &&
cat >expect <<-\EOF &&
M fileB.t
M fileC.t
EOF
printf "fileB.t\nfileC.t\n" | git stash push --pathspec-from-file=- &&
verify_expect
'
test_expect_success 'error conditions' '
restore_checkpoint &&
echo A >fileA.t &&
echo fileA.t >list &&
test_must_fail git stash push --pathspec-from-file=list --patch 2>err &&
test_i18ngrep -e "--pathspec-from-file is incompatible with --patch" err &&
test_must_fail git stash push --pathspec-from-file=list -- fileA.t 2>err &&
test_i18ngrep -e "--pathspec-from-file is incompatible with pathspec arguments" err &&
test_must_fail git stash push --pathspec-file-nul 2>err &&
test_i18ngrep -e "--pathspec-file-nul requires --pathspec-from-file" err
'
test_done

Просмотреть файл

@ -666,6 +666,26 @@ test_expect_success 'am --show-current-patch' '
test_cmp .git/rebase-apply/0001 actual.patch test_cmp .git/rebase-apply/0001 actual.patch
' '
test_expect_success 'am --show-current-patch=raw' '
git am --show-current-patch=raw >actual.patch &&
test_cmp .git/rebase-apply/0001 actual.patch
'
test_expect_success 'am --show-current-patch=diff' '
git am --show-current-patch=diff >actual.patch &&
test_cmp .git/rebase-apply/patch actual.patch
'
test_expect_success 'am accepts repeated --show-current-patch' '
git am --show-current-patch --show-current-patch=raw >actual.patch &&
test_cmp .git/rebase-apply/0001 actual.patch
'
test_expect_success 'am detects incompatible --show-current-patch' '
test_must_fail git am --show-current-patch=raw --show-current-patch=diff &&
test_must_fail git am --show-current-patch --show-current-patch=diff
'
test_expect_success 'am --skip works' ' test_expect_success 'am --skip works' '
echo goodbye >expected && echo goodbye >expected &&
git am --skip && git am --skip &&

Просмотреть файл

@ -1607,6 +1607,26 @@ test_expect_success GPG 'log --graph --show-signature for merged tag' '
grep "^| | gpg: Good signature" actual grep "^| | gpg: Good signature" actual
' '
test_expect_success GPG 'log --graph --show-signature for merged tag in shallow clone' '
test_when_finished "git reset --hard && git checkout master" &&
git checkout -b plain-shallow master &&
echo aaa >bar &&
git add bar &&
git commit -m bar_commit &&
git checkout --detach master &&
echo bbb >baz &&
git add baz &&
git commit -m baz_commit &&
git tag -s -m signed_tag_msg signed_tag_shallow &&
hash=$(git rev-parse HEAD) &&
git checkout plain-shallow &&
git merge --no-ff -m msg signed_tag_shallow &&
git clone --depth 1 --no-local . shallow &&
test_when_finished "rm -rf shallow" &&
git -C shallow log --graph --show-signature -n1 plain-shallow >actual &&
grep "tag signed_tag_shallow names a non-parent $hash" actual
'
test_expect_success GPGSM 'log --graph --show-signature for merged tag x509' ' test_expect_success GPGSM 'log --graph --show-signature for merged tag x509' '
test_when_finished "git reset --hard && git checkout master" && test_when_finished "git reset --hard && git checkout master" &&
test_config gpg.format x509 && test_config gpg.format x509 &&

Просмотреть файл

@ -83,9 +83,9 @@ test_expect_success 'modify/delete + directory/file conflict' '
test 4 -eq $(git ls-files -u | wc -l) && test 4 -eq $(git ls-files -u | wc -l) &&
test 1 -eq $(git ls-files -o | wc -l) && test 1 -eq $(git ls-files -o | wc -l) &&
test -f letters/file && test_path_is_file letters/file &&
test -f letters.txt && test_path_is_file letters.txt &&
test -f letters~modify test_path_is_file letters~modify
' '
test_expect_success 'modify/delete + directory/file conflict; other way' ' test_expect_success 'modify/delete + directory/file conflict; other way' '
@ -99,9 +99,52 @@ test_expect_success 'modify/delete + directory/file conflict; other way' '
test 4 -eq $(git ls-files -u | wc -l) && test 4 -eq $(git ls-files -u | wc -l) &&
test 1 -eq $(git ls-files -o | wc -l) && test 1 -eq $(git ls-files -o | wc -l) &&
test -f letters/file && test_path_is_file letters/file &&
test -f letters.txt && test_path_is_file letters.txt &&
test -f letters~HEAD test_path_is_file letters~HEAD
'
test_expect_success 'Simple merge in repo with interesting pathnames' '
# Simple lexicographic ordering of files and directories would be:
# foo
# foo/bar
# foo/bar-2
# foo/bar/baz
# foo/bar-2/baz
# The fact that foo/bar-2 appears between foo/bar and foo/bar/baz
# can trip up some codepaths, and is the point of this test.
test_create_repo name-ordering &&
(
cd name-ordering &&
mkdir -p foo/bar &&
mkdir -p foo/bar-2 &&
>foo/bar/baz &&
>foo/bar-2/baz &&
git add . &&
git commit -m initial &&
git branch main &&
git branch other &&
git checkout other &&
echo other >foo/bar-2/baz &&
git add -u &&
git commit -m other &&
git checkout main &&
echo main >foo/bar/baz &&
git add -u &&
git commit -m main &&
git merge other &&
git ls-files -s >out &&
test_line_count = 2 out &&
git rev-parse :0:foo/bar/baz :0:foo/bar-2/baz >actual &&
git rev-parse HEAD~1:foo/bar/baz other:foo/bar-2/baz >expect &&
test_cmp expect actual
)
' '
test_done test_done

Просмотреть файл

@ -10,87 +10,58 @@
test_description='Test criss-cross merge' test_description='Test criss-cross merge'
. ./test-lib.sh . ./test-lib.sh
test_expect_success 'prepare repository' \ test_expect_success 'prepare repository' '
'echo "1 test_write_lines 1 2 3 4 5 6 7 8 9 >file &&
2 git add file &&
3 git commit -m "Initial commit" file &&
4
5
6
7
8
9" > file &&
git add file &&
git commit -m "Initial commit" file &&
git branch A &&
git branch B &&
git checkout A &&
echo "1
2
3
4
5
6
7
8 changed in B8, branch A
9" > file &&
git commit -m "B8" file &&
git checkout B &&
echo "1
2
3 changed in C3, branch B
4
5
6
7
8
9
" > file &&
git commit -m "C3" file &&
git branch C3 &&
git merge -m "pre E3 merge" A &&
echo "1
2
3 changed in E3, branch B. New file size
4
5
6
7
8 changed in B8, branch A
9
" > file &&
git commit -m "E3" file &&
git checkout A &&
git merge -m "pre D8 merge" C3 &&
echo "1
2
3 changed in C3, branch B
4
5
6
7
8 changed in D8, branch A. New file size 2
9" > file &&
git commit -m D8 file'
test_expect_success 'Criss-cross merge' 'git merge -m "final merge" B' git branch A &&
git branch B &&
git checkout A &&
cat > file-expect <<EOF test_write_lines 1 2 3 4 5 6 7 "8 changed in B8, branch A" 9 >file &&
1 git commit -m "B8" file &&
2 git checkout B &&
3 changed in E3, branch B. New file size
4
5
6
7
8 changed in D8, branch A. New file size 2
9
EOF
test_expect_success 'Criss-cross merge result' 'cmp file file-expect' test_write_lines 1 2 "3 changed in C3, branch B" 4 5 6 7 8 9 >file &&
git commit -m "C3" file &&
git branch C3 &&
test_expect_success 'Criss-cross merge fails (-s resolve)' \ git merge -m "pre E3 merge" A &&
'git reset --hard A^ &&
test_must_fail git merge -s resolve -m "final merge" B' test_write_lines 1 2 "3 changed in E3, branch B. New file size" 4 5 6 7 "8 changed in B8, branch A" 9 >file &&
git commit -m "E3" file &&
git checkout A &&
git merge -m "pre D8 merge" C3 &&
test_write_lines 1 2 "3 changed in C3, branch B" 4 5 6 7 "8 changed in D8, branch A. New file size 2" 9 >file &&
git commit -m D8 file
'
test_expect_success 'Criss-cross merge' '
git merge -m "final merge" B
'
test_expect_success 'Criss-cross merge result' '
cat <<-\EOF >file-expect &&
1
2
3 changed in E3, branch B. New file size
4
5
6
7
8 changed in D8, branch A. New file size 2
9
EOF
test_cmp file-expect file
'
test_expect_success 'Criss-cross merge fails (-s resolve)' '
git reset --hard A^ &&
test_must_fail git merge -s resolve -m "final merge" B
'
test_done test_done

Просмотреть файл

@ -8,94 +8,94 @@ modify () {
mv "$2.x" "$2" mv "$2.x" "$2"
} }
test_expect_success setup \ test_expect_success 'setup' '
cat >A <<-\EOF &&
a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
c cccccccccccccccccccccccccccccccccccccccccccccccc
d dddddddddddddddddddddddddddddddddddddddddddddddd
e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
f ffffffffffffffffffffffffffffffffffffffffffffffff
g gggggggggggggggggggggggggggggggggggggggggggggggg
h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
l llllllllllllllllllllllllllllllllllllllllllllllll
m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
o oooooooooooooooooooooooooooooooooooooooooooooooo
EOF
cat >M <<-\EOF &&
A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
EOF
git add A M &&
git commit -m "initial has A and M" &&
git branch white &&
git branch red &&
git branch blue &&
git branch yellow &&
git branch change &&
git branch change+rename &&
sed -e "/^g /s/.*/g : master changes a line/" <A >A+ &&
mv A+ A &&
git commit -a -m "master updates A" &&
git checkout yellow &&
rm -f M &&
git commit -a -m "yellow removes M" &&
git checkout white &&
sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
rm -f A M &&
git update-index --add --remove A B M N &&
git commit -m "white renames A->B, M->N" &&
git checkout red &&
sed -e "/^g /s/.*/g : red changes a line/" <A >B &&
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
rm -f A M &&
git update-index --add --remove A B M N &&
git commit -m "red renames A->B, M->N" &&
git checkout blue &&
sed -e "/^g /s/.*/g : blue changes a line/" <A >C &&
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
rm -f A M &&
git update-index --add --remove A C M N &&
git commit -m "blue renames A->C, M->N" &&
git checkout change &&
sed -e "/^g /s/.*/g : changed line/" <A >A+ &&
mv A+ A &&
git commit -q -a -m "changed" &&
git checkout change+rename &&
sed -e "/^g /s/.*/g : changed line/" <A >B &&
rm A &&
git update-index --add B &&
git commit -q -a -m "changed and renamed" &&
git checkout master
' '
cat >A <<\EOF &&
a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
c cccccccccccccccccccccccccccccccccccccccccccccccc
d dddddddddddddddddddddddddddddddddddddddddddddddd
e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
f ffffffffffffffffffffffffffffffffffffffffffffffff
g gggggggggggggggggggggggggggggggggggggggggggggggg
h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
l llllllllllllllllllllllllllllllllllllllllllllllll
m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
o oooooooooooooooooooooooooooooooooooooooooooooooo
EOF
cat >M <<\EOF &&
A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
EOF
git add A M &&
git commit -m "initial has A and M" &&
git branch white &&
git branch red &&
git branch blue &&
git branch yellow &&
git branch change &&
git branch change+rename &&
sed -e "/^g /s/.*/g : master changes a line/" <A >A+ &&
mv A+ A &&
git commit -a -m "master updates A" &&
git checkout yellow &&
rm -f M &&
git commit -a -m "yellow removes M" &&
git checkout white &&
sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
rm -f A M &&
git update-index --add --remove A B M N &&
git commit -m "white renames A->B, M->N" &&
git checkout red &&
sed -e "/^g /s/.*/g : red changes a line/" <A >B &&
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
rm -f A M &&
git update-index --add --remove A B M N &&
git commit -m "red renames A->B, M->N" &&
git checkout blue &&
sed -e "/^g /s/.*/g : blue changes a line/" <A >C &&
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
rm -f A M &&
git update-index --add --remove A C M N &&
git commit -m "blue renames A->C, M->N" &&
git checkout change &&
sed -e "/^g /s/.*/g : changed line/" <A >A+ &&
mv A+ A &&
git commit -q -a -m "changed" &&
git checkout change+rename &&
sed -e "/^g /s/.*/g : changed line/" <A >B &&
rm A &&
git update-index --add B &&
git commit -q -a -m "changed and renamed" &&
git checkout master'
test_expect_success 'pull renaming branch into unrenaming one' \ test_expect_success 'pull renaming branch into unrenaming one' \
' '
@ -242,12 +242,23 @@ test_expect_success 'merge of identical changes in a renamed file' '
rm -f A M N && rm -f A M N &&
git reset --hard && git reset --hard &&
git checkout change+rename && git checkout change+rename &&
test-tool chmtime =31337 B &&
test-tool chmtime --get B >old-mtime &&
GIT_MERGE_VERBOSITY=3 git merge change >out && GIT_MERGE_VERBOSITY=3 git merge change >out &&
test_i18ngrep "^Skipped B" out &&
test-tool chmtime --get B >new-mtime &&
test_cmp old-mtime new-mtime &&
git reset --hard HEAD^ && git reset --hard HEAD^ &&
git checkout change && git checkout change &&
test-tool chmtime =-1 M &&
test-tool chmtime --get M >old-mtime &&
GIT_MERGE_VERBOSITY=3 git merge change+rename >out && GIT_MERGE_VERBOSITY=3 git merge change+rename >out &&
test_i18ngrep ! "^Skipped B" out
test-tool chmtime --get B >new-mtime &&
test $(cat old-mtime) -lt $(cat new-mtime)
' '
test_expect_success 'setup for rename + d/f conflicts' ' test_expect_success 'setup for rename + d/f conflicts' '
@ -288,14 +299,15 @@ test_expect_success 'setup for rename + d/f conflicts' '
git commit -m "Conflicting change" git commit -m "Conflicting change"
' '
printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n11\n" >expected
test_expect_success 'Rename+D/F conflict; renamed file merges + dir not in way' ' test_expect_success 'Rename+D/F conflict; renamed file merges + dir not in way' '
git reset --hard && git reset --hard &&
git checkout -q renamed-file-has-no-conflicts^0 && git checkout -q renamed-file-has-no-conflicts^0 &&
git merge --strategy=recursive dir-not-in-way && git merge --strategy=recursive dir-not-in-way &&
git diff --quiet && git diff --quiet &&
test -f dir && test_path_is_file dir &&
test_write_lines 1 2 3 4 5555 6 7 8 9 10 11 >expected &&
test_cmp expected dir test_cmp expected dir
' '
@ -315,8 +327,8 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
test_must_fail git diff --quiet && test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet && test_must_fail git diff --cached --quiet &&
test -f dir/file-in-the-way && test_path_is_file dir/file-in-the-way &&
test -f dir~HEAD && test_path_is_file dir~HEAD &&
test_cmp expected dir~HEAD test_cmp expected dir~HEAD
' '
@ -337,29 +349,11 @@ test_expect_success 'Same as previous, but merged other way' '
test_must_fail git diff --quiet && test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet && test_must_fail git diff --cached --quiet &&
test -f dir/file-in-the-way && test_path_is_file dir/file-in-the-way &&
test -f dir~renamed-file-has-no-conflicts && test_path_is_file dir~renamed-file-has-no-conflicts &&
test_cmp expected dir~renamed-file-has-no-conflicts test_cmp expected dir~renamed-file-has-no-conflicts
' '
cat >expected <<\EOF &&
1
2
3
4
5
6
7
8
9
10
<<<<<<< HEAD:dir
12
=======
11
>>>>>>> dir-not-in-way:sub/file
EOF
test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in way' ' test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
git reset --hard && git reset --hard &&
rm -rf dir~* && rm -rf dir~* &&
@ -372,7 +366,24 @@ test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in
test_must_fail git diff --quiet && test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet && test_must_fail git diff --cached --quiet &&
test -f dir && test_path_is_file dir &&
cat >expected <<-\EOF &&
1
2
3
4
5
6
7
8
9
10
<<<<<<< HEAD:dir
12
=======
11
>>>>>>> dir-not-in-way:sub/file
EOF
test_cmp expected dir test_cmp expected dir
' '
@ -391,29 +402,11 @@ test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in t
test_must_fail git diff --quiet && test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet && test_must_fail git diff --cached --quiet &&
test -f dir/file-in-the-way && test_path_is_file dir/file-in-the-way &&
test -f dir~HEAD && test_path_is_file dir~HEAD &&
test_cmp expected dir~HEAD test_cmp expected dir~HEAD
' '
cat >expected <<\EOF &&
1
2
3
4
5
6
7
8
9
10
<<<<<<< HEAD:sub/file
11
=======
12
>>>>>>> renamed-file-has-conflicts:dir
EOF
test_expect_success 'Same as previous, but merged other way' ' test_expect_success 'Same as previous, but merged other way' '
git reset --hard && git reset --hard &&
rm -rf dir~* && rm -rf dir~* &&
@ -427,8 +420,25 @@ test_expect_success 'Same as previous, but merged other way' '
test_must_fail git diff --quiet && test_must_fail git diff --quiet &&
test_must_fail git diff --cached --quiet && test_must_fail git diff --cached --quiet &&
test -f dir/file-in-the-way && test_path_is_file dir/file-in-the-way &&
test -f dir~renamed-file-has-conflicts && test_path_is_file dir~renamed-file-has-conflicts &&
cat >expected <<-\EOF &&
1
2
3
4
5
6
7
8
9
10
<<<<<<< HEAD:sub/file
11
=======
12
>>>>>>> renamed-file-has-conflicts:dir
EOF
test_cmp expected dir~renamed-file-has-conflicts test_cmp expected dir~renamed-file-has-conflicts
' '
@ -464,9 +474,9 @@ test_expect_success 'both rename source and destination involved in D/F conflict
test_must_fail git diff --quiet && test_must_fail git diff --quiet &&
test -f destdir/foo && test_path_is_file destdir/foo &&
test -f one && test_path_is_file one &&
test -f destdir~HEAD && test_path_is_file destdir~HEAD &&
test "stuff" = "$(cat destdir~HEAD)" test "stuff" = "$(cat destdir~HEAD)"
' '
@ -507,9 +517,9 @@ test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked
test 4 -eq $(find . | grep -v .git | wc -l) && test 4 -eq $(find . | grep -v .git | wc -l) &&
test -d one && test_path_is_dir one &&
test -f one~rename-two && test_path_is_file one~rename-two &&
test -f two && test_path_is_file two &&
test "other" = $(cat one~rename-two) && test "other" = $(cat one~rename-two) &&
test "stuff" = $(cat two) test "stuff" = $(cat two)
' '
@ -527,8 +537,8 @@ test_expect_success 'pair rename to parent of other (D/F conflicts) w/ clean sta
test 3 -eq $(find . | grep -v .git | wc -l) && test 3 -eq $(find . | grep -v .git | wc -l) &&
test -f one && test_path_is_file one &&
test -f two && test_path_is_file two &&
test "other" = $(cat one) && test "other" = $(cat one) &&
test "stuff" = $(cat two) test "stuff" = $(cat two)
' '
@ -568,11 +578,11 @@ test_expect_success 'check handling of differently renamed file with D/F conflic
test 1 -eq "$(git ls-files -u original | wc -l)" && test 1 -eq "$(git ls-files -u original | wc -l)" &&
test 2 -eq "$(git ls-files -o | wc -l)" && test 2 -eq "$(git ls-files -o | wc -l)" &&
test -f one/file && test_path_is_file one/file &&
test -f two/file && test_path_is_file two/file &&
test -f one~HEAD && test_path_is_file one~HEAD &&
test -f two~second-rename && test_path_is_file two~second-rename &&
! test -f original test_path_is_missing original
' '
test_expect_success 'setup rename one file to two; directories moving out of the way' ' test_expect_success 'setup rename one file to two; directories moving out of the way' '
@ -607,9 +617,9 @@ test_expect_success 'check handling of differently renamed file with D/F conflic
test 1 -eq "$(git ls-files -u original | wc -l)" && test 1 -eq "$(git ls-files -u original | wc -l)" &&
test 0 -eq "$(git ls-files -o | wc -l)" && test 0 -eq "$(git ls-files -o | wc -l)" &&
test -f one && test_path_is_file one &&
test -f two && test_path_is_file two &&
! test -f original test_path_is_missing original
' '
test_expect_success 'setup avoid unnecessary update, normal rename' ' test_expect_success 'setup avoid unnecessary update, normal rename' '
@ -810,48 +820,48 @@ test_expect_success 'setup for use of extended merge markers' '
git commit -mC git commit -mC
' '
cat >expected <<\EOF &&
1
2
3
4
5
6
7
8
<<<<<<< HEAD:renamed_file
9
=======
8.5
>>>>>>> master^0:original_file
EOF
test_expect_success 'merge master into rename has correct extended markers' ' test_expect_success 'merge master into rename has correct extended markers' '
git checkout rename^0 && git checkout rename^0 &&
test_must_fail git merge -s recursive master^0 && test_must_fail git merge -s recursive master^0 &&
cat >expected <<-\EOF &&
1
2
3
4
5
6
7
8
<<<<<<< HEAD:renamed_file
9
=======
8.5
>>>>>>> master^0:original_file
EOF
test_cmp expected renamed_file test_cmp expected renamed_file
' '
cat >expected <<\EOF &&
1
2
3
4
5
6
7
8
<<<<<<< HEAD:original_file
8.5
=======
9
>>>>>>> rename^0:renamed_file
EOF
test_expect_success 'merge rename into master has correct extended markers' ' test_expect_success 'merge rename into master has correct extended markers' '
git reset --hard && git reset --hard &&
git checkout master^0 && git checkout master^0 &&
test_must_fail git merge -s recursive rename^0 && test_must_fail git merge -s recursive rename^0 &&
cat >expected <<-\EOF &&
1
2
3
4
5
6
7
8
<<<<<<< HEAD:original_file
8.5
=======
9
>>>>>>> rename^0:renamed_file
EOF
test_cmp expected renamed_file test_cmp expected renamed_file
' '

Просмотреть файл

@ -3,56 +3,59 @@
test_description='RCS merge replacement: merge-file' test_description='RCS merge replacement: merge-file'
. ./test-lib.sh . ./test-lib.sh
cat > orig.txt << EOF test_expect_success 'setup' '
Dominus regit me, cat >orig.txt <<-\EOF &&
et nihil mihi deerit. Dominus regit me,
In loco pascuae ibi me collocavit, et nihil mihi deerit.
super aquam refectionis educavit me; In loco pascuae ibi me collocavit,
animam meam convertit, super aquam refectionis educavit me;
deduxit me super semitas jusitiae, animam meam convertit,
propter nomen suum. deduxit me super semitas jusitiae,
EOF propter nomen suum.
EOF
cat > new1.txt << EOF cat >new1.txt <<-\EOF &&
Dominus regit me, Dominus regit me,
et nihil mihi deerit. et nihil mihi deerit.
In loco pascuae ibi me collocavit, In loco pascuae ibi me collocavit,
super aquam refectionis educavit me; super aquam refectionis educavit me;
animam meam convertit, animam meam convertit,
deduxit me super semitas jusitiae, deduxit me super semitas jusitiae,
propter nomen suum. propter nomen suum.
Nam et si ambulavero in medio umbrae mortis, Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam tu mecum es: non timebo mala, quoniam tu mecum es:
virga tua et baculus tuus ipsa me consolata sunt. virga tua et baculus tuus ipsa me consolata sunt.
EOF EOF
cat > new2.txt << EOF cat >new2.txt <<-\EOF &&
Dominus regit me, et nihil mihi deerit. Dominus regit me, et nihil mihi deerit.
In loco pascuae ibi me collocavit, In loco pascuae ibi me collocavit,
super aquam refectionis educavit me; super aquam refectionis educavit me;
animam meam convertit, animam meam convertit,
deduxit me super semitas jusitiae, deduxit me super semitas jusitiae,
propter nomen suum. propter nomen suum.
EOF EOF
cat > new3.txt << EOF cat >new3.txt <<-\EOF &&
DOMINUS regit me, DOMINUS regit me,
et nihil mihi deerit. et nihil mihi deerit.
In loco pascuae ibi me collocavit, In loco pascuae ibi me collocavit,
super aquam refectionis educavit me; super aquam refectionis educavit me;
animam meam convertit, animam meam convertit,
deduxit me super semitas jusitiae, deduxit me super semitas jusitiae,
propter nomen suum. propter nomen suum.
EOF EOF
cat > new4.txt << EOF cat >new4.txt <<-\EOF &&
Dominus regit me, et nihil mihi deerit. Dominus regit me, et nihil mihi deerit.
In loco pascuae ibi me collocavit, In loco pascuae ibi me collocavit,
super aquam refectionis educavit me; super aquam refectionis educavit me;
animam meam convertit, animam meam convertit,
deduxit me super semitas jusitiae, deduxit me super semitas jusitiae,
EOF EOF
printf "propter nomen suum." >> new4.txt
printf "propter nomen suum." >>new4.txt
'
test_expect_success 'merge with no changes' ' test_expect_success 'merge with no changes' '
cp orig.txt test.txt && cp orig.txt test.txt &&
@ -60,9 +63,10 @@ test_expect_success 'merge with no changes' '
test_cmp test.txt orig.txt test_cmp test.txt orig.txt
' '
cp new1.txt test.txt test_expect_success "merge without conflict" '
test_expect_success "merge without conflict" \ cp new1.txt test.txt &&
"git merge-file test.txt orig.txt new2.txt" git merge-file test.txt orig.txt new2.txt
'
test_expect_success 'works in subdirectory' ' test_expect_success 'works in subdirectory' '
mkdir dir && mkdir dir &&
@ -73,151 +77,176 @@ test_expect_success 'works in subdirectory' '
test_path_is_missing a.txt test_path_is_missing a.txt
' '
cp new1.txt test.txt test_expect_success "merge without conflict (--quiet)" '
test_expect_success "merge without conflict (--quiet)" \ cp new1.txt test.txt &&
"git merge-file --quiet test.txt orig.txt new2.txt" git merge-file --quiet test.txt orig.txt new2.txt
'
cp new1.txt test2.txt test_expect_failure "merge without conflict (missing LF at EOF)" '
test_expect_failure "merge without conflict (missing LF at EOF)" \ cp new1.txt test2.txt &&
"git merge-file test2.txt orig.txt new4.txt" git merge-file test2.txt orig.txt new4.txt
'
test_expect_failure "merge result added missing LF" \ test_expect_failure "merge result added missing LF" '
"test_cmp test.txt test2.txt" test_cmp test.txt test2.txt
'
cp new4.txt test3.txt test_expect_success "merge without conflict (missing LF at EOF, away from change in the other file)" '
test_expect_success "merge without conflict (missing LF at EOF, away from change in the other file)" \ cp new4.txt test3.txt &&
"git merge-file --quiet test3.txt new2.txt new3.txt" git merge-file --quiet test3.txt new2.txt new3.txt
'
cat > expect.txt << EOF test_expect_success "merge does not add LF away of change" '
DOMINUS regit me, cat >expect.txt <<-\EOF &&
et nihil mihi deerit. DOMINUS regit me,
In loco pascuae ibi me collocavit, et nihil mihi deerit.
super aquam refectionis educavit me; In loco pascuae ibi me collocavit,
animam meam convertit, super aquam refectionis educavit me;
deduxit me super semitas jusitiae, animam meam convertit,
EOF deduxit me super semitas jusitiae,
printf "propter nomen suum." >> expect.txt EOF
printf "propter nomen suum." >>expect.txt &&
test_expect_success "merge does not add LF away of change" \ test_cmp expect.txt test3.txt
"test_cmp expect.txt test3.txt" '
cp test.txt backup.txt test_expect_success "merge with conflicts" '
test_expect_success "merge with conflicts" \ cp test.txt backup.txt &&
"test_must_fail git merge-file test.txt orig.txt new3.txt" test_must_fail git merge-file test.txt orig.txt new3.txt
'
cat > expect.txt << EOF test_expect_success "expected conflict markers" '
<<<<<<< test.txt cat >expect.txt <<-\EOF &&
Dominus regit me, et nihil mihi deerit. <<<<<<< test.txt
======= Dominus regit me, et nihil mihi deerit.
DOMINUS regit me, =======
et nihil mihi deerit. DOMINUS regit me,
>>>>>>> new3.txt et nihil mihi deerit.
In loco pascuae ibi me collocavit, >>>>>>> new3.txt
super aquam refectionis educavit me; In loco pascuae ibi me collocavit,
animam meam convertit, super aquam refectionis educavit me;
deduxit me super semitas jusitiae, animam meam convertit,
propter nomen suum. deduxit me super semitas jusitiae,
Nam et si ambulavero in medio umbrae mortis, propter nomen suum.
non timebo mala, quoniam tu mecum es: Nam et si ambulavero in medio umbrae mortis,
virga tua et baculus tuus ipsa me consolata sunt. non timebo mala, quoniam tu mecum es:
EOF virga tua et baculus tuus ipsa me consolata sunt.
EOF
test_expect_success "expected conflict markers" "test_cmp expect.txt test.txt" test_cmp expect.txt test.txt
'
cp backup.txt test.txt test_expect_success "merge conflicting with --ours" '
cp backup.txt test.txt &&
cat > expect.txt << EOF cat >expect.txt <<-\EOF &&
Dominus regit me, et nihil mihi deerit. Dominus regit me, et nihil mihi deerit.
In loco pascuae ibi me collocavit, In loco pascuae ibi me collocavit,
super aquam refectionis educavit me; super aquam refectionis educavit me;
animam meam convertit, animam meam convertit,
deduxit me super semitas jusitiae, deduxit me super semitas jusitiae,
propter nomen suum. propter nomen suum.
Nam et si ambulavero in medio umbrae mortis, Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam tu mecum es: non timebo mala, quoniam tu mecum es:
virga tua et baculus tuus ipsa me consolata sunt. virga tua et baculus tuus ipsa me consolata sunt.
EOF EOF
test_expect_success "merge conflicting with --ours" \
"git merge-file --ours test.txt orig.txt new3.txt && test_cmp expect.txt test.txt"
cp backup.txt test.txt
cat > expect.txt << EOF git merge-file --ours test.txt orig.txt new3.txt &&
DOMINUS regit me, test_cmp expect.txt test.txt
et nihil mihi deerit. '
In loco pascuae ibi me collocavit,
super aquam refectionis educavit me;
animam meam convertit,
deduxit me super semitas jusitiae,
propter nomen suum.
Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam tu mecum es:
virga tua et baculus tuus ipsa me consolata sunt.
EOF
test_expect_success "merge conflicting with --theirs" \
"git merge-file --theirs test.txt orig.txt new3.txt && test_cmp expect.txt test.txt"
cp backup.txt test.txt
cat > expect.txt << EOF test_expect_success "merge conflicting with --theirs" '
Dominus regit me, et nihil mihi deerit. cp backup.txt test.txt &&
DOMINUS regit me,
et nihil mihi deerit.
In loco pascuae ibi me collocavit,
super aquam refectionis educavit me;
animam meam convertit,
deduxit me super semitas jusitiae,
propter nomen suum.
Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam tu mecum es:
virga tua et baculus tuus ipsa me consolata sunt.
EOF
test_expect_success "merge conflicting with --union" \
"git merge-file --union test.txt orig.txt new3.txt && test_cmp expect.txt test.txt"
cp backup.txt test.txt
test_expect_success "merge with conflicts, using -L" \ cat >expect.txt <<-\EOF &&
"test_must_fail git merge-file -L 1 -L 2 test.txt orig.txt new3.txt" DOMINUS regit me,
et nihil mihi deerit.
In loco pascuae ibi me collocavit,
super aquam refectionis educavit me;
animam meam convertit,
deduxit me super semitas jusitiae,
propter nomen suum.
Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam tu mecum es:
virga tua et baculus tuus ipsa me consolata sunt.
EOF
cat > expect.txt << EOF git merge-file --theirs test.txt orig.txt new3.txt &&
<<<<<<< 1 test_cmp expect.txt test.txt
Dominus regit me, et nihil mihi deerit. '
=======
DOMINUS regit me,
et nihil mihi deerit.
>>>>>>> new3.txt
In loco pascuae ibi me collocavit,
super aquam refectionis educavit me;
animam meam convertit,
deduxit me super semitas jusitiae,
propter nomen suum.
Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam tu mecum es:
virga tua et baculus tuus ipsa me consolata sunt.
EOF
test_expect_success "expected conflict markers, with -L" \ test_expect_success "merge conflicting with --union" '
"test_cmp expect.txt test.txt" cp backup.txt test.txt &&
sed "s/ tu / TU /" < new1.txt > new5.txt cat >expect.txt <<-\EOF &&
test_expect_success "conflict in removed tail" \ Dominus regit me, et nihil mihi deerit.
"test_must_fail git merge-file -p orig.txt new1.txt new5.txt > out" DOMINUS regit me,
et nihil mihi deerit.
In loco pascuae ibi me collocavit,
super aquam refectionis educavit me;
animam meam convertit,
deduxit me super semitas jusitiae,
propter nomen suum.
Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam tu mecum es:
virga tua et baculus tuus ipsa me consolata sunt.
EOF
cat > expect << EOF git merge-file --union test.txt orig.txt new3.txt &&
Dominus regit me, test_cmp expect.txt test.txt
et nihil mihi deerit. '
In loco pascuae ibi me collocavit,
super aquam refectionis educavit me;
animam meam convertit,
deduxit me super semitas jusitiae,
propter nomen suum.
<<<<<<< orig.txt
=======
Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam TU mecum es:
virga tua et baculus tuus ipsa me consolata sunt.
>>>>>>> new5.txt
EOF
test_expect_success "expected conflict markers" "test_cmp expect out" test_expect_success "merge with conflicts, using -L" '
cp backup.txt test.txt &&
test_must_fail git merge-file -L 1 -L 2 test.txt orig.txt new3.txt
'
test_expect_success "expected conflict markers, with -L" '
cat >expect.txt <<-\EOF &&
<<<<<<< 1
Dominus regit me, et nihil mihi deerit.
=======
DOMINUS regit me,
et nihil mihi deerit.
>>>>>>> new3.txt
In loco pascuae ibi me collocavit,
super aquam refectionis educavit me;
animam meam convertit,
deduxit me super semitas jusitiae,
propter nomen suum.
Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam tu mecum es:
virga tua et baculus tuus ipsa me consolata sunt.
EOF
test_cmp expect.txt test.txt
'
test_expect_success "conflict in removed tail" '
sed "s/ tu / TU /" <new1.txt >new5.txt &&
test_must_fail git merge-file -p orig.txt new1.txt new5.txt >out
'
test_expect_success "expected conflict markers" '
cat >expect <<-\EOF &&
Dominus regit me,
et nihil mihi deerit.
In loco pascuae ibi me collocavit,
super aquam refectionis educavit me;
animam meam convertit,
deduxit me super semitas jusitiae,
propter nomen suum.
<<<<<<< orig.txt
=======
Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam TU mecum es:
virga tua et baculus tuus ipsa me consolata sunt.
>>>>>>> new5.txt
EOF
test_cmp expect out
'
test_expect_success 'binary files cannot be merged' ' test_expect_success 'binary files cannot be merged' '
test_must_fail git merge-file -p \ test_must_fail git merge-file -p \
@ -225,59 +254,55 @@ test_expect_success 'binary files cannot be merged' '
grep "Cannot merge binary files" merge.err grep "Cannot merge binary files" merge.err
' '
sed -e "s/deerit.\$/deerit;/" -e "s/me;\$/me./" < new5.txt > new6.txt
sed -e "s/deerit.\$/deerit,/" -e "s/me;\$/me,/" < new5.txt > new7.txt
test_expect_success 'MERGE_ZEALOUS simplifies non-conflicts' ' test_expect_success 'MERGE_ZEALOUS simplifies non-conflicts' '
sed -e "s/deerit.\$/deerit;/" -e "s/me;\$/me./" <new5.txt >new6.txt &&
sed -e "s/deerit.\$/deerit,/" -e "s/me;\$/me,/" <new5.txt >new7.txt &&
test_must_fail git merge-file -p new6.txt new5.txt new7.txt > output && test_must_fail git merge-file -p new6.txt new5.txt new7.txt > output &&
test 1 = $(grep ======= < output | wc -l) test 1 = $(grep ======= <output | wc -l)
' '
sed -e 's/deerit./&%%%%/' -e "s/locavit,/locavit;/"< new6.txt | tr '%' '\012' > new8.txt
sed -e 's/deerit./&%%%%/' -e "s/locavit,/locavit --/" < new7.txt | tr '%' '\012' > new9.txt
test_expect_success 'ZEALOUS_ALNUM' ' test_expect_success 'ZEALOUS_ALNUM' '
sed -e "s/deerit./&%%%%/" -e "s/locavit,/locavit;/" <new6.txt | tr % "\012" >new8.txt &&
sed -e "s/deerit./&%%%%/" -e "s/locavit,/locavit --/" <new7.txt | tr % "\012" >new9.txt &&
test_must_fail git merge-file -p \ test_must_fail git merge-file -p \
new8.txt new5.txt new9.txt > merge.out && new8.txt new5.txt new9.txt >merge.out &&
test 1 = $(grep ======= < merge.out | wc -l) test 1 = $(grep ======= <merge.out | wc -l)
' '
cat >expect <<\EOF
Dominus regit me,
<<<<<<< new8.txt
et nihil mihi deerit;
In loco pascuae ibi me collocavit;
super aquam refectionis educavit me.
||||||| new5.txt
et nihil mihi deerit.
In loco pascuae ibi me collocavit,
super aquam refectionis educavit me;
=======
et nihil mihi deerit,
In loco pascuae ibi me collocavit --
super aquam refectionis educavit me,
>>>>>>> new9.txt
animam meam convertit,
deduxit me super semitas jusitiae,
propter nomen suum.
Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam TU mecum es:
virga tua et baculus tuus ipsa me consolata sunt.
EOF
test_expect_success '"diff3 -m" style output (1)' ' test_expect_success '"diff3 -m" style output (1)' '
cat >expect <<-\EOF &&
Dominus regit me,
<<<<<<< new8.txt
et nihil mihi deerit;
In loco pascuae ibi me collocavit;
super aquam refectionis educavit me.
||||||| new5.txt
et nihil mihi deerit.
In loco pascuae ibi me collocavit,
super aquam refectionis educavit me;
=======
et nihil mihi deerit,
In loco pascuae ibi me collocavit --
super aquam refectionis educavit me,
>>>>>>> new9.txt
animam meam convertit,
deduxit me super semitas jusitiae,
propter nomen suum.
Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam TU mecum es:
virga tua et baculus tuus ipsa me consolata sunt.
EOF
test_must_fail git merge-file -p --diff3 \ test_must_fail git merge-file -p --diff3 \
new8.txt new5.txt new9.txt >actual && new8.txt new5.txt new9.txt >actual &&
test_cmp expect actual test_cmp expect actual
@ -290,61 +315,64 @@ test_expect_success '"diff3 -m" style output (2)' '
test_cmp expect actual test_cmp expect actual
' '
cat >expect <<\EOF
Dominus regit me,
<<<<<<<<<< new8.txt
et nihil mihi deerit;
In loco pascuae ibi me collocavit;
super aquam refectionis educavit me.
|||||||||| new5.txt
et nihil mihi deerit.
In loco pascuae ibi me collocavit,
super aquam refectionis educavit me;
==========
et nihil mihi deerit,
In loco pascuae ibi me collocavit --
super aquam refectionis educavit me,
>>>>>>>>>> new9.txt
animam meam convertit,
deduxit me super semitas jusitiae,
propter nomen suum.
Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam TU mecum es:
virga tua et baculus tuus ipsa me consolata sunt.
EOF
test_expect_success 'marker size' ' test_expect_success 'marker size' '
cat >expect <<-\EOF &&
Dominus regit me,
<<<<<<<<<< new8.txt
et nihil mihi deerit;
In loco pascuae ibi me collocavit;
super aquam refectionis educavit me.
|||||||||| new5.txt
et nihil mihi deerit.
In loco pascuae ibi me collocavit,
super aquam refectionis educavit me;
==========
et nihil mihi deerit,
In loco pascuae ibi me collocavit --
super aquam refectionis educavit me,
>>>>>>>>>> new9.txt
animam meam convertit,
deduxit me super semitas jusitiae,
propter nomen suum.
Nam et si ambulavero in medio umbrae mortis,
non timebo mala, quoniam TU mecum es:
virga tua et baculus tuus ipsa me consolata sunt.
EOF
test_must_fail git merge-file -p --marker-size=10 \ test_must_fail git merge-file -p --marker-size=10 \
new8.txt new5.txt new9.txt >actual && new8.txt new5.txt new9.txt >actual &&
test_cmp expect actual test_cmp expect actual
' '
printf "line1\nline2\nline3" >nolf-orig.txt test_expect_success 'conflict at EOF without LF resolved by --ours' '
printf "line1\nline2\nline3x" >nolf-diff1.txt printf "line1\nline2\nline3" >nolf-orig.txt &&
printf "line1\nline2\nline3y" >nolf-diff2.txt printf "line1\nline2\nline3x" >nolf-diff1.txt &&
printf "line1\nline2\nline3y" >nolf-diff2.txt &&
test_expect_success 'conflict at EOF without LF resolved by --ours' \ git merge-file -p --ours nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >output.txt &&
'git merge-file -p --ours nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >output.txt && printf "line1\nline2\nline3x" >expect.txt &&
printf "line1\nline2\nline3x" >expect.txt && test_cmp expect.txt output.txt
test_cmp expect.txt output.txt' '
test_expect_success 'conflict at EOF without LF resolved by --theirs' \ test_expect_success 'conflict at EOF without LF resolved by --theirs' '
'git merge-file -p --theirs nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >output.txt && git merge-file -p --theirs nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >output.txt &&
printf "line1\nline2\nline3y" >expect.txt && printf "line1\nline2\nline3y" >expect.txt &&
test_cmp expect.txt output.txt' test_cmp expect.txt output.txt
'
test_expect_success 'conflict at EOF without LF resolved by --union' \ test_expect_success 'conflict at EOF without LF resolved by --union' '
'git merge-file -p --union nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >output.txt && git merge-file -p --union nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >output.txt &&
printf "line1\nline2\nline3x\nline3y" >expect.txt && printf "line1\nline2\nline3x\nline3y" >expect.txt &&
test_cmp expect.txt output.txt' test_cmp expect.txt output.txt
'
test_expect_success 'conflict sections match existing line endings' ' test_expect_success 'conflict sections match existing line endings' '
printf "1\\r\\n2\\r\\n3" >crlf-orig.txt && printf "1\\r\\n2\\r\\n3" >crlf-orig.txt &&

Просмотреть файл

@ -32,7 +32,29 @@ test_expect_success setup '
test_tick && test_tick &&
git commit -m Side && git commit -m Side &&
git tag anchor git tag anchor &&
cat >./custom-merge <<-\EOF &&
#!/bin/sh
orig="$1" ours="$2" theirs="$3" exit="$4" path=$5
(
echo "orig is $orig"
echo "ours is $ours"
echo "theirs is $theirs"
echo "path is $path"
echo "=== orig ==="
cat "$orig"
echo "=== ours ==="
cat "$ours"
echo "=== theirs ==="
cat "$theirs"
) >"$ours+"
cat "$ours+" >"$ours"
rm -f "$ours+"
exit "$exit"
EOF
chmod +x ./custom-merge
' '
test_expect_success merge ' test_expect_success merge '
@ -82,28 +104,6 @@ test_expect_success 'retry the merge with longer context' '
grep "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" actual grep "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" actual
' '
cat >./custom-merge <<\EOF
#!/bin/sh
orig="$1" ours="$2" theirs="$3" exit="$4" path=$5
(
echo "orig is $orig"
echo "ours is $ours"
echo "theirs is $theirs"
echo "path is $path"
echo "=== orig ==="
cat "$orig"
echo "=== ours ==="
cat "$ours"
echo "=== theirs ==="
cat "$theirs"
) >"$ours+"
cat "$ours+" >"$ours"
rm -f "$ours+"
exit "$exit"
EOF
chmod +x ./custom-merge
test_expect_success 'custom merge backend' ' test_expect_success 'custom merge backend' '
echo "* merge=union" >.gitattributes && echo "* merge=union" >.gitattributes &&

Просмотреть файл

@ -3,74 +3,73 @@
test_description='Merge-recursive merging renames' test_description='Merge-recursive merging renames'
. ./test-lib.sh . ./test-lib.sh
test_expect_success setup \ test_expect_success 'setup' '
cat >A <<-\EOF &&
a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
c cccccccccccccccccccccccccccccccccccccccccccccccc
d dddddddddddddddddddddddddddddddddddddddddddddddd
e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
f ffffffffffffffffffffffffffffffffffffffffffffffff
g gggggggggggggggggggggggggggggggggggggggggggggggg
h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
l llllllllllllllllllllllllllllllllllllllllllllllll
m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
o oooooooooooooooooooooooooooooooooooooooooooooooo
EOF
cat >M <<-\EOF &&
A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
EOF
git add A M &&
git commit -m "initial has A and M" &&
git branch white &&
git branch red &&
git branch blue &&
git checkout white &&
sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
rm -f A M &&
git update-index --add --remove A B M N &&
git commit -m "white renames A->B, M->N" &&
git checkout red &&
echo created by red >R &&
git update-index --add R &&
git commit -m "red creates R" &&
git checkout blue &&
sed -e "/^o /s/.*/g : blue changes a line/" <A >B &&
rm -f A &&
mv B A &&
git update-index A &&
git commit -m "blue modify A" &&
git checkout master
' '
cat >A <<\EOF &&
a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
c cccccccccccccccccccccccccccccccccccccccccccccccc
d dddddddddddddddddddddddddddddddddddddddddddddddd
e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
f ffffffffffffffffffffffffffffffffffffffffffffffff
g gggggggggggggggggggggggggggggggggggggggggggggggg
h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
l llllllllllllllllllllllllllllllllllllllllllllllll
m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
o oooooooooooooooooooooooooooooooooooooooooooooooo
EOF
cat >M <<\EOF &&
A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
EOF
git add A M &&
git commit -m "initial has A and M" &&
git branch white &&
git branch red &&
git branch blue &&
git checkout white &&
sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
rm -f A M &&
git update-index --add --remove A B M N &&
git commit -m "white renames A->B, M->N" &&
git checkout red &&
echo created by red >R &&
git update-index --add R &&
git commit -m "red creates R" &&
git checkout blue &&
sed -e "/^o /s/.*/g : blue changes a line/" <A >B &&
rm -f A &&
mv B A &&
git update-index A &&
git commit -m "blue modify A" &&
git checkout master'
# This test broke in 65ac6e9c3f47807cb603af07a6a9e1a43bc119ae # This test broke in 65ac6e9c3f47807cb603af07a6a9e1a43bc119ae
test_expect_success 'merge white into red (A->B,M->N)' \ test_expect_success 'merge white into red (A->B,M->N)' '
'
git checkout -b red-white red && git checkout -b red-white red &&
git merge white && git merge white &&
git write-tree && git write-tree &&
@ -82,8 +81,7 @@ test_expect_success 'merge white into red (A->B,M->N)' \
' '
# This test broke in 8371234ecaaf6e14fe3f2082a855eff1bbd79ae9 # This test broke in 8371234ecaaf6e14fe3f2082a855eff1bbd79ae9
test_expect_success 'merge blue into white (A->B, mod A, A untracked)' \ test_expect_success 'merge blue into white (A->B, mod A, A untracked)' '
'
git checkout -b white-blue white && git checkout -b white-blue white &&
echo dirty >A && echo dirty >A &&
git merge blue && git merge blue &&

Просмотреть файл

@ -31,19 +31,19 @@ test_expect_success 'a/b-2/c/d is kept when clobbering symlink b' '
git rm --cached a/b && git rm --cached a/b &&
git commit -m "untracked symlink remains" && git commit -m "untracked symlink remains" &&
git checkout -f start^0 && git checkout -f start^0 &&
test -f a/b-2/c/d test_path_is_file a/b-2/c/d
' '
test_expect_success 'checkout should not have deleted a/b-2/c/d' ' test_expect_success 'checkout should not have deleted a/b-2/c/d' '
git checkout HEAD^0 && git checkout HEAD^0 &&
git reset --hard master && git reset --hard master &&
git checkout start^0 && git checkout start^0 &&
test -f a/b-2/c/d test_path_is_file a/b-2/c/d
' '
test_expect_success 'setup for merge test' ' test_expect_success 'setup for merge test' '
git reset --hard && git reset --hard &&
test -f a/b-2/c/d && test_path_is_file a/b-2/c/d &&
echo x > a/x && echo x > a/x &&
git add a/x && git add a/x &&
git commit -m x && git commit -m x &&
@ -54,7 +54,7 @@ test_expect_success 'Handle D/F conflict, do not lose a/b-2/c/d in merge (resolv
git reset --hard && git reset --hard &&
git checkout baseline^0 && git checkout baseline^0 &&
git merge -s resolve master && git merge -s resolve master &&
test -f a/b-2/c/d test_path_is_file a/b-2/c/d
' '
test_expect_success SYMLINKS 'a/b was resolved as symlink' ' test_expect_success SYMLINKS 'a/b was resolved as symlink' '
@ -65,7 +65,7 @@ test_expect_success 'Handle D/F conflict, do not lose a/b-2/c/d in merge (recurs
git reset --hard && git reset --hard &&
git checkout baseline^0 && git checkout baseline^0 &&
git merge -s recursive master && git merge -s recursive master &&
test -f a/b-2/c/d test_path_is_file a/b-2/c/d
' '
test_expect_success SYMLINKS 'a/b was resolved as symlink' ' test_expect_success SYMLINKS 'a/b was resolved as symlink' '
@ -76,7 +76,7 @@ test_expect_success 'Handle F/D conflict, do not lose a/b-2/c/d in merge (resolv
git reset --hard && git reset --hard &&
git checkout master^0 && git checkout master^0 &&
git merge -s resolve baseline^0 && git merge -s resolve baseline^0 &&
test -f a/b-2/c/d test_path_is_file a/b-2/c/d
' '
test_expect_success SYMLINKS 'a/b was resolved as symlink' ' test_expect_success SYMLINKS 'a/b was resolved as symlink' '
@ -87,7 +87,7 @@ test_expect_success 'Handle F/D conflict, do not lose a/b-2/c/d in merge (recurs
git reset --hard && git reset --hard &&
git checkout master^0 && git checkout master^0 &&
git merge -s recursive baseline^0 && git merge -s recursive baseline^0 &&
test -f a/b-2/c/d test_path_is_file a/b-2/c/d
' '
test_expect_success SYMLINKS 'a/b was resolved as symlink' ' test_expect_success SYMLINKS 'a/b was resolved as symlink' '
@ -99,8 +99,8 @@ test_expect_failure 'do not lose untracked in merge (resolve)' '
git checkout baseline^0 && git checkout baseline^0 &&
>a/b/c/e && >a/b/c/e &&
test_must_fail git merge -s resolve master && test_must_fail git merge -s resolve master &&
test -f a/b/c/e && test_path_is_file a/b/c/e &&
test -f a/b-2/c/d test_path_is_file a/b-2/c/d
' '
test_expect_success 'do not lose untracked in merge (recursive)' ' test_expect_success 'do not lose untracked in merge (recursive)' '
@ -108,8 +108,8 @@ test_expect_success 'do not lose untracked in merge (recursive)' '
git checkout baseline^0 && git checkout baseline^0 &&
>a/b/c/e && >a/b/c/e &&
test_must_fail git merge -s recursive master && test_must_fail git merge -s recursive master &&
test -f a/b/c/e && test_path_is_file a/b/c/e &&
test -f a/b-2/c/d test_path_is_file a/b-2/c/d
' '
test_expect_success 'do not lose modifications in merge (resolve)' ' test_expect_success 'do not lose modifications in merge (resolve)' '
@ -140,7 +140,7 @@ test_expect_success 'merge should not have D/F conflicts (resolve)' '
git reset --hard && git reset --hard &&
git checkout baseline^0 && git checkout baseline^0 &&
git merge -s resolve test2 && git merge -s resolve test2 &&
test -f a/b/c/d test_path_is_file a/b/c/d
' '
test_expect_success SYMLINKS 'a/b-2 was resolved as symlink' ' test_expect_success SYMLINKS 'a/b-2 was resolved as symlink' '
@ -151,7 +151,7 @@ test_expect_success 'merge should not have D/F conflicts (recursive)' '
git reset --hard && git reset --hard &&
git checkout baseline^0 && git checkout baseline^0 &&
git merge -s recursive test2 && git merge -s recursive test2 &&
test -f a/b/c/d test_path_is_file a/b/c/d
' '
test_expect_success SYMLINKS 'a/b-2 was resolved as symlink' ' test_expect_success SYMLINKS 'a/b-2 was resolved as symlink' '
@ -162,7 +162,7 @@ test_expect_success 'merge should not have F/D conflicts (recursive)' '
git reset --hard && git reset --hard &&
git checkout -b foo test2 && git checkout -b foo test2 &&
git merge -s recursive baseline^0 && git merge -s recursive baseline^0 &&
test -f a/b/c/d test_path_is_file a/b/c/d
' '
test_expect_success SYMLINKS 'a/b-2 was resolved as symlink' ' test_expect_success SYMLINKS 'a/b-2 was resolved as symlink' '

Просмотреть файл

@ -60,9 +60,9 @@ test_expect_success 'merge simple rename+criss-cross with no modifications' '
test_must_fail git merge -s recursive R2^0 && test_must_fail git merge -s recursive R2^0 &&
git ls-files -s >out && git ls-files -s >out &&
test_line_count = 2 out && test_line_count = 5 out &&
git ls-files -u >out && git ls-files -u >out &&
test_line_count = 2 out && test_line_count = 3 out &&
git ls-files -o >out && git ls-files -o >out &&
test_line_count = 1 out && test_line_count = 1 out &&
@ -133,9 +133,9 @@ test_expect_success 'merge criss-cross + rename merges with basic modification'
test_must_fail git merge -s recursive R2^0 && test_must_fail git merge -s recursive R2^0 &&
git ls-files -s >out && git ls-files -s >out &&
test_line_count = 2 out && test_line_count = 5 out &&
git ls-files -u >out && git ls-files -u >out &&
test_line_count = 2 out && test_line_count = 3 out &&
git ls-files -o >out && git ls-files -o >out &&
test_line_count = 1 out && test_line_count = 1 out &&
@ -218,8 +218,18 @@ test_expect_success 'git detects differently handled merges conflict' '
git ls-files -o >out && git ls-files -o >out &&
test_line_count = 1 out && test_line_count = 1 out &&
git rev-parse >expect \ git cat-file -p C:new_a >ours &&
C:new_a D:new_a E:new_a && git cat-file -p C:a >theirs &&
>empty &&
test_must_fail git merge-file \
-L "Temporary merge branch 1" \
-L "" \
-L "Temporary merge branch 2" \
ours empty theirs &&
sed -e "s/^\([<=>]\)/\1\1\1/" ours >ours-tweaked &&
git hash-object ours-tweaked >expect &&
git rev-parse >>expect \
D:new_a E:new_a &&
git rev-parse >actual \ git rev-parse >actual \
:1:new_a :2:new_a :3:new_a && :1:new_a :2:new_a :3:new_a &&
test_cmp expect actual && test_cmp expect actual &&
@ -257,7 +267,8 @@ test_expect_success 'git detects differently handled merges conflict, swapped' '
ctime=$(git log --no-walk --date=raw --format=%cd C | awk "{print \$1}") && ctime=$(git log --no-walk --date=raw --format=%cd C | awk "{print \$1}") &&
newctime=$(($btime+1)) && newctime=$(($btime+1)) &&
git fast-export --no-data --all | sed -e s/$ctime/$newctime/ | git fast-import --force --quiet && git fast-export --no-data --all | sed -e s/$ctime/$newctime/ | git fast-import --force --quiet &&
# End of differences; rest is copy-paste of last test # End of most differences; rest is copy-paste of last test,
# other than swapping C:a and C:new_a due to order switch
git checkout D^0 && git checkout D^0 &&
test_must_fail git merge -s recursive E^0 && test_must_fail git merge -s recursive E^0 &&
@ -269,8 +280,18 @@ test_expect_success 'git detects differently handled merges conflict, swapped' '
git ls-files -o >out && git ls-files -o >out &&
test_line_count = 1 out && test_line_count = 1 out &&
git rev-parse >expect \ git cat-file -p C:a >ours &&
C:new_a D:new_a E:new_a && git cat-file -p C:new_a >theirs &&
>empty &&
test_must_fail git merge-file \
-L "Temporary merge branch 1" \
-L "" \
-L "Temporary merge branch 2" \
ours empty theirs &&
sed -e "s/^\([<=>]\)/\1\1\1/" ours >ours-tweaked &&
git hash-object ours-tweaked >expect &&
git rev-parse >>expect \
D:new_a E:new_a &&
git rev-parse >actual \ git rev-parse >actual \
:1:new_a :2:new_a :3:new_a && :1:new_a :2:new_a :3:new_a &&
test_cmp expect actual && test_cmp expect actual &&

Просмотреть файл

@ -71,16 +71,16 @@ test_expect_success '1a-L: Modify(A)/Modify(B), change on B subset of A' '
git checkout A^0 && git checkout A^0 &&
test-tool chmtime =31337 b && test-tool chmtime =-1 b &&
test-tool chmtime -v +0 b >expected-mtime && test-tool chmtime --get b >old-mtime &&
GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err && GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
test_i18ngrep "Skipped b" out &&
test_must_be_empty err && test_must_be_empty err &&
test-tool chmtime -v +0 b >actual-mtime && # Make sure b was NOT updated
test_cmp expected-mtime actual-mtime && test-tool chmtime --get b >new-mtime &&
test_cmp old-mtime new-mtime &&
git ls-files -s >index_files && git ls-files -s >index_files &&
test_line_count = 1 index_files && test_line_count = 1 index_files &&
@ -102,9 +102,14 @@ test_expect_success '1a-R: Modify(A)/Modify(B), change on B subset of A' '
git checkout B^0 && git checkout B^0 &&
test-tool chmtime =-1 b &&
test-tool chmtime --get b >old-mtime &&
GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err && GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
test_i18ngrep "Auto-merging b" out && # Make sure b WAS updated
test-tool chmtime --get b >new-mtime &&
test $(cat old-mtime) -lt $(cat new-mtime) &&
test_must_be_empty err && test_must_be_empty err &&
git ls-files -s >index_files && git ls-files -s >index_files &&
@ -165,10 +170,10 @@ test_expect_success '2a-L: Modify/rename, merge into modify side' '
git checkout A^0 && git checkout A^0 &&
test_path_is_missing c &&
GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err && GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
test_i18ngrep ! "Skipped c" out && test_path_is_file c &&
test_must_be_empty err &&
git ls-files -s >index_files && git ls-files -s >index_files &&
test_line_count = 1 index_files && test_line_count = 1 index_files &&
@ -193,9 +198,14 @@ test_expect_success '2a-R: Modify/rename, merge into rename side' '
git checkout B^0 && git checkout B^0 &&
test-tool chmtime =-1 c &&
test-tool chmtime --get c >old-mtime &&
GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err && GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
test_i18ngrep ! "Skipped c" out && # Make sure c WAS updated
test-tool chmtime --get c >new-mtime &&
test $(cat old-mtime) -lt $(cat new-mtime) &&
test_must_be_empty err && test_must_be_empty err &&
git ls-files -s >index_files && git ls-files -s >index_files &&
@ -256,16 +266,15 @@ test_expect_success '2b-L: Rename+Mod(A)/Mod(B), B mods subset of A' '
git checkout A^0 && git checkout A^0 &&
test-tool chmtime =31337 c && test-tool chmtime =-1 c &&
test-tool chmtime -v +0 c >expected-mtime && test-tool chmtime --get c >old-mtime &&
GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err && GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
test_i18ngrep "Skipped c" out &&
test_must_be_empty err && test_must_be_empty err &&
test-tool chmtime -v +0 c >actual-mtime && # Make sure c WAS updated
test_cmp expected-mtime actual-mtime && test-tool chmtime --get c >new-mtime &&
test_cmp old-mtime new-mtime &&
git ls-files -s >index_files && git ls-files -s >index_files &&
test_line_count = 1 index_files && test_line_count = 1 index_files &&
@ -290,9 +299,12 @@ test_expect_success '2b-R: Rename+Mod(A)/Mod(B), B mods subset of A' '
git checkout B^0 && git checkout B^0 &&
test_path_is_missing c &&
GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err && GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
test_i18ngrep "Auto-merging c" out && # Make sure c now present (and thus was updated)
test_path_is_file c &&
test_must_be_empty err && test_must_be_empty err &&
git ls-files -s >index_files && git ls-files -s >index_files &&
@ -361,13 +373,18 @@ test_expect_success '2c: Modify b & add c VS rename b->c' '
git checkout A^0 && git checkout A^0 &&
test-tool chmtime =-1 c &&
test-tool chmtime --get c >old-mtime &&
GIT_MERGE_VERBOSITY=3 && GIT_MERGE_VERBOSITY=3 &&
export GIT_MERGE_VERBOSITY && export GIT_MERGE_VERBOSITY &&
test_must_fail git merge -s recursive B^0 >out 2>err && test_must_fail git merge -s recursive B^0 >out 2>err &&
test_i18ngrep "CONFLICT (rename/add): Rename b->c" out && test_i18ngrep "CONFLICT (rename/add): Rename b->c" out &&
test_i18ngrep ! "Skipped c" out && test_must_be_empty err &&
test_must_be_empty err
# Make sure c WAS updated
test-tool chmtime --get c >new-mtime &&
test $(cat old-mtime) -lt $(cat new-mtime)
# FIXME: rename/add conflicts are horribly broken right now; # FIXME: rename/add conflicts are horribly broken right now;
# when I get back to my patch series fixing it and # when I get back to my patch series fixing it and
@ -460,11 +477,13 @@ test_expect_success '3a-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
git checkout A^0 && git checkout A^0 &&
test_path_is_missing bar/bq &&
GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err && GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
test_i18ngrep ! "Skipped bar/bq" out &&
test_must_be_empty err && test_must_be_empty err &&
test_path_is_file bar/bq &&
git ls-files -s >index_files && git ls-files -s >index_files &&
test_line_count = 2 index_files && test_line_count = 2 index_files &&
@ -488,11 +507,13 @@ test_expect_success '3a-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
git checkout B^0 && git checkout B^0 &&
test_path_is_missing bar/bq &&
GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err && GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
test_i18ngrep ! "Skipped bar/bq" out &&
test_must_be_empty err && test_must_be_empty err &&
test_path_is_file bar/bq &&
git ls-files -s >index_files && git ls-files -s >index_files &&
test_line_count = 2 index_files && test_line_count = 2 index_files &&
@ -552,11 +573,13 @@ test_expect_success '3b-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
git checkout A^0 && git checkout A^0 &&
test_path_is_missing bar/bq &&
GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err && GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
test_i18ngrep ! "Skipped bar/bq" out &&
test_must_be_empty err && test_must_be_empty err &&
test_path_is_file bar/bq &&
git ls-files -s >index_files && git ls-files -s >index_files &&
test_line_count = 2 index_files && test_line_count = 2 index_files &&
@ -580,11 +603,13 @@ test_expect_success '3b-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
git checkout B^0 && git checkout B^0 &&
test_path_is_missing bar/bq &&
GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err && GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
test_i18ngrep ! "Skipped bar/bq" out &&
test_must_be_empty err && test_must_be_empty err &&
test_path_is_file bar/bq &&
git ls-files -s >index_files && git ls-files -s >index_files &&
test_line_count = 2 index_files && test_line_count = 2 index_files &&
@ -654,16 +679,16 @@ test_expect_failure '4a: Change on A, change on B subset of A, dirty mods presen
git checkout A^0 && git checkout A^0 &&
echo "File rewritten" >b && echo "File rewritten" >b &&
test-tool chmtime =31337 b && test-tool chmtime =-1 b &&
test-tool chmtime -v +0 b >expected-mtime && test-tool chmtime --get b >old-mtime &&
GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err && GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
test_i18ngrep "Skipped b" out &&
test_must_be_empty err && test_must_be_empty err &&
test-tool chmtime -v +0 b >actual-mtime && # Make sure b was NOT updated
test_cmp expected-mtime actual-mtime && test-tool chmtime --get b >new-mtime &&
test_cmp old-mtime new-mtime &&
git ls-files -s >index_files && git ls-files -s >index_files &&
test_line_count = 1 index_files && test_line_count = 1 index_files &&
@ -722,16 +747,16 @@ test_expect_success '4b: Rename+Mod(A)/Mod(B), change on B subset of A, dirty mo
git checkout A^0 && git checkout A^0 &&
echo "File rewritten" >c && echo "File rewritten" >c &&
test-tool chmtime =31337 c && test-tool chmtime =-1 c &&
test-tool chmtime -v +0 c >expected-mtime && test-tool chmtime --get c >old-mtime &&
GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err && GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
test_i18ngrep "Skipped c" out &&
test_must_be_empty err && test_must_be_empty err &&
test-tool chmtime -v +0 c >actual-mtime && # Make sure c was NOT updated
test_cmp expected-mtime actual-mtime && test-tool chmtime --get c >new-mtime &&
test_cmp old-mtime new-mtime &&
git ls-files -s >index_files && git ls-files -s >index_files &&
test_line_count = 1 index_files && test_line_count = 1 index_files &&

Просмотреть файл

@ -8,6 +8,7 @@
#include "tag.h" #include "tag.h"
#include "blob.h" #include "blob.h"
#include "refs.h" #include "refs.h"
#include "progress.h"
static struct object_id current_commit_oid; static struct object_id current_commit_oid;
@ -162,6 +163,11 @@ static int process(struct walker *walker, struct object *obj)
static int loop(struct walker *walker) static int loop(struct walker *walker)
{ {
struct object_list *elem; struct object_list *elem;
struct progress *progress = NULL;
uint64_t nr = 0;
if (walker->get_progress)
progress = start_delayed_progress(_("Fetching objects"), 0);
while (process_queue) { while (process_queue) {
struct object *obj = process_queue->item; struct object *obj = process_queue->item;
@ -176,15 +182,20 @@ static int loop(struct walker *walker)
*/ */
if (! (obj->flags & TO_SCAN)) { if (! (obj->flags & TO_SCAN)) {
if (walker->fetch(walker, obj->oid.hash)) { if (walker->fetch(walker, obj->oid.hash)) {
stop_progress(&progress);
report_missing(obj); report_missing(obj);
return -1; return -1;
} }
} }
if (!obj->type) if (!obj->type)
parse_object(the_repository, &obj->oid); parse_object(the_repository, &obj->oid);
if (process_object(walker, obj)) if (process_object(walker, obj)) {
stop_progress(&progress);
return -1; return -1;
}
display_progress(progress, ++nr);
} }
stop_progress(&progress);
return 0; return 0;
} }

Просмотреть файл

@ -10,6 +10,7 @@ struct walker {
int (*fetch)(struct walker *, unsigned char *sha1); int (*fetch)(struct walker *, unsigned char *sha1);
void (*cleanup)(struct walker *); void (*cleanup)(struct walker *);
int get_verbosely; int get_verbosely;
int get_progress;
int get_recover; int get_recover;
int corrupt_object_found; int corrupt_object_found;