summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/SubmittingPatches2
-rw-r--r--Documentation/config/http.txt4
-rw-r--r--Documentation/config/trace2.txt2
-rw-r--r--Documentation/git-maintenance.txt2
-rw-r--r--Documentation/git-p4.txt2
-rw-r--r--Documentation/githooks.txt2
-rw-r--r--Documentation/gitmodules.txt30
-rw-r--r--Documentation/technical/reftable.txt2
-rw-r--r--builtin/rebase.c4
-rw-r--r--builtin/stash.c165
-rw-r--r--submodule.c7
-rw-r--r--t/lib-submodule-update.sh16
-rwxr-xr-xt/perf/p7519-fsmonitor.sh7
-rwxr-xr-xt/t5526-fetch-submodules.sh117
-rwxr-xr-xt/t7012-skip-worktree-writing.sh88
-rw-r--r--t/test-lib-functions.sh9
16 files changed, 374 insertions, 85 deletions
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index d12094bac5..0452db2e67 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -307,7 +307,7 @@ wrote the patch or have the right to pass it on under the same license
as ours, by "signing off" your patch. Without sign-off, we cannot
accept your patches.
-If you can certify the below D-C-O:
+If (and only if) you certify the below D-C-O:
[[dco]]
.Developer's Certificate of Origin 1.1
diff --git a/Documentation/config/http.txt b/Documentation/config/http.txt
index 3968fbb697..7003661c0d 100644
--- a/Documentation/config/http.txt
+++ b/Documentation/config/http.txt
@@ -42,12 +42,12 @@ http.proxySSLKey::
http.proxySSLCertPasswordProtected::
Enable Git's password prompt for the proxy SSL certificate. Otherwise OpenSSL
will prompt the user, possibly many times, if the certificate or private key
- is encrypted. Can be overriden by the `GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED`
+ is encrypted. Can be overridden by the `GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED`
environment variable.
http.proxySSLCAInfo::
Pathname to the file containing the certificate bundle that should be used to
- verify the proxy with when using an HTTPS proxy. Can be overriden by the
+ verify the proxy with when using an HTTPS proxy. Can be overridden by the
`GIT_PROXY_SSL_CAINFO` environment variable.
http.emptyAuth::
diff --git a/Documentation/config/trace2.txt b/Documentation/config/trace2.txt
index 01d3afd8a8..fe1642f0d4 100644
--- a/Documentation/config/trace2.txt
+++ b/Documentation/config/trace2.txt
@@ -54,7 +54,7 @@ trace2.envVars::
`GIT_HTTP_USER_AGENT,GIT_CONFIG` would cause the trace2 output to
contain events listing the overrides for HTTP user agent and the
location of the Git configuration file (assuming any are set). May be
- overriden by the `GIT_TRACE2_ENV_VARS` environment variable. Unset by
+ overridden by the `GIT_TRACE2_ENV_VARS` environment variable. Unset by
default.
trace2.destinationDebug::
diff --git a/Documentation/git-maintenance.txt b/Documentation/git-maintenance.txt
index d1f9b5172d..6fe1e5e105 100644
--- a/Documentation/git-maintenance.txt
+++ b/Documentation/git-maintenance.txt
@@ -38,7 +38,7 @@ register::
for running in the background without disrupting foreground
processes.
+
-The `register` subcomand will also set the `maintenance.strategy` config
+The `register` subcommand will also set the `maintenance.strategy` config
value to `incremental`, if this value is not previously set. The
`incremental` strategy uses the following schedule for each maintenance
task:
diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index ec233ac0c1..f89e68b424 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -397,7 +397,7 @@ changelist text. Exiting with a non-zero status from the script
will abort the process.
The purpose of the hook is to edit the message file in place,
-and it is not supressed by the `--no-verify` option. This hook
+and it is not suppressed by the `--no-verify` option. This hook
is called even if `--prepare-p4-only` is set.
p4-changelist
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index ffccfc7760..1f3b57d04d 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -644,7 +644,7 @@ changelist text. Exiting with a non-zero status from the script
will abort the process.
The purpose of the hook is to edit the message file in place,
-and it is not supressed by the `--no-verify` option. This hook
+and it is not suppressed by the `--no-verify` option. This hook
is called even if `--prepare-p4-only` is set.
Run `git-p4 submit --help` for details.
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index 539b4e1997..8e333dde1b 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -7,7 +7,7 @@ gitmodules - Defining submodule properties
SYNOPSIS
--------
-$GIT_WORK_DIR/.gitmodules
+$GIT_WORK_TREE/.gitmodules
DESCRIPTION
@@ -27,19 +27,19 @@ submodule.<name>.path::
Defines the path, relative to the top-level directory of the Git
working tree, where the submodule is expected to be checked out.
The path name must not end with a `/`. All submodule paths must
- be unique within the .gitmodules file.
+ be unique within the `.gitmodules` file.
submodule.<name>.url::
Defines a URL from which the submodule repository can be cloned.
This may be either an absolute URL ready to be passed to
- linkgit:git-clone[1] or (if it begins with ./ or ../) a location
+ linkgit:git-clone[1] or (if it begins with `./` or `../`) a location
relative to the superproject's origin repository.
In addition, there are a number of optional keys:
submodule.<name>.update::
Defines the default update procedure for the named submodule,
- i.e. how the submodule is updated by "git submodule update"
+ i.e. how the submodule is updated by the `git submodule update`
command in the superproject. This is only used by `git
submodule init` to initialize the configuration variable of
the same name. Allowed values here are 'checkout', 'rebase',
@@ -49,7 +49,7 @@ submodule.<name>.update::
submodule.<name>.branch::
A remote branch name for tracking updates in the upstream submodule.
- If the option is not specified, it defaults to the remote 'HEAD'.
+ If the option is not specified, it defaults to the remote `HEAD`.
A special value of `.` is used to indicate that the name of the branch
in the submodule should be the same name as the current branch in the
current repository. See the `--remote` documentation in
@@ -57,14 +57,14 @@ submodule.<name>.branch::
submodule.<name>.fetchRecurseSubmodules::
This option can be used to control recursive fetching of this
- submodule. If this option is also present in the submodules entry in
- .git/config of the superproject, the setting there will override the
- one found in .gitmodules.
+ submodule. If this option is also present in the submodule's entry in
+ `.git/config` of the superproject, the setting there will override the
+ one found in `.gitmodules`.
Both settings can be overridden on the command line by using the
- "--[no-]recurse-submodules" option to "git fetch" and "git pull".
+ `--[no-]recurse-submodules` option to `git fetch` and `git pull`.
submodule.<name>.ignore::
- Defines under what circumstances "git status" and the diff family show
+ Defines under what circumstances `git status` and the diff family show
a submodule as modified. The following values are supported:
+
--
@@ -73,7 +73,7 @@ submodule.<name>.ignore::
been staged).
dirty;; All changes to the submodule's work tree will be ignored, only
- committed differences between the HEAD of the submodule and its
+ committed differences between the `HEAD` of the submodule and its
recorded state in the superproject are taken into account.
untracked;; Only untracked files in submodules will be ignored.
@@ -84,12 +84,12 @@ submodule.<name>.ignore::
differences, and modifications to tracked and untracked files are
shown. This is the default option.
-If this option is also present in the submodules entry in .git/config
+If this option is also present in the submodule's entry in `.git/config`
of the superproject, the setting there will override the one found in
-.gitmodules.
+`.gitmodules`.
Both settings can be overridden on the command line by using the
-"--ignore-submodules" option. The 'git submodule' commands are not
+`--ignore-submodules` option. The `git submodule` commands are not
affected by this setting.
--
@@ -102,7 +102,7 @@ submodule.<name>.shallow::
EXAMPLES
--------
-Consider the following .gitmodules file:
+Consider the following `.gitmodules` file:
----
[submodule "libfoo"]
diff --git a/Documentation/technical/reftable.txt b/Documentation/technical/reftable.txt
index 2951840e9c..8095ab2590 100644
--- a/Documentation/technical/reftable.txt
+++ b/Documentation/technical/reftable.txt
@@ -446,7 +446,7 @@ especially if readers will not use the object name to ref mapping.
Object blocks use unique, abbreviated 2-32 object name keys, mapping to
ref blocks containing references pointing to that object directly, or as
the peeled value of an annotated tag. Like ref blocks, object blocks use
-the file's standard block size. The abbrevation length is available in
+the file's standard block size. The abbreviation length is available in
the footer as `obj_id_len`.
To save space in small files, object blocks may be omitted if the ref
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 19c7b377aa..840dbd7eb7 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -1917,7 +1917,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die_if_checked_out(buf.buf, 1);
options.head_name = xstrdup(buf.buf);
/* If not is it a valid ref (branch or commit)? */
- } else if (!get_oid(branch_name, &options.orig_head))
+ } else if (!get_oid(branch_name, &options.orig_head) &&
+ lookup_commit_reference(the_repository,
+ &options.orig_head))
options.head_name = NULL;
else
die(_("fatal: no such branch/commit '%s'"),
diff --git a/builtin/stash.c b/builtin/stash.c
index e1f8235fdd..9bc85f91cd 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -325,35 +325,6 @@ static void add_diff_to_buf(struct diff_queue_struct *q,
}
}
-static int get_newly_staged(struct strbuf *out, struct object_id *c_tree)
-{
- struct child_process cp = CHILD_PROCESS_INIT;
- const char *c_tree_hex = oid_to_hex(c_tree);
-
- /*
- * diff-index is very similar to diff-tree above, and should be
- * converted together with update_index.
- */
- cp.git_cmd = 1;
- strvec_pushl(&cp.args, "diff-index", "--cached", "--name-only",
- "--diff-filter=A", NULL);
- strvec_push(&cp.args, c_tree_hex);
- return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
-}
-
-static int update_index(struct strbuf *out)
-{
- struct child_process cp = CHILD_PROCESS_INIT;
-
- /*
- * Update-index is very complicated and may need to have a public
- * function exposed in order to remove this forking.
- */
- cp.git_cmd = 1;
- strvec_pushl(&cp.args, "update-index", "--add", "--stdin", NULL);
- return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
-}
-
static int restore_untracked(struct object_id *u_tree)
{
int res;
@@ -385,6 +356,121 @@ static int restore_untracked(struct object_id *u_tree)
return res;
}
+static void unstage_changes_unless_new(struct object_id *orig_tree)
+{
+ /*
+ * When we enter this function, there has been a clean merge of
+ * relevant trees, and the merge logic always stages whatever merges
+ * cleanly. We want to unstage those changes, unless it corresponds
+ * to a file that didn't exist as of orig_tree.
+ *
+ * However, if any SKIP_WORKTREE path is modified relative to
+ * orig_tree, then we want to clear the SKIP_WORKTREE bit and write
+ * it to the worktree before unstaging.
+ */
+
+ struct checkout state = CHECKOUT_INIT;
+ struct diff_options diff_opts;
+ struct lock_file lock = LOCK_INIT;
+ int i;
+
+ /* If any entries have skip_worktree set, we'll have to check 'em out */
+ state.force = 1;
+ state.quiet = 1;
+ state.refresh_cache = 1;
+ state.istate = &the_index;
+
+ /*
+ * Step 1: get a difference between orig_tree (which corresponding
+ * to the index before a merge was run) and the current index
+ * (reflecting the changes brought in by the merge).
+ */
+ diff_setup(&diff_opts);
+ diff_opts.flags.recursive = 1;
+ diff_opts.detect_rename = 0;
+ diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+ diff_setup_done(&diff_opts);
+
+ do_diff_cache(orig_tree, &diff_opts);
+ diffcore_std(&diff_opts);
+
+ /* Iterate over the paths that changed due to the merge... */
+ for (i = 0; i < diff_queued_diff.nr; i++) {
+ struct diff_filepair *p;
+ struct cache_entry *ce;
+ int pos;
+
+ /* Look up the path's position in the current index. */
+ p = diff_queued_diff.queue[i];
+ pos = index_name_pos(&the_index, p->two->path,
+ strlen(p->two->path));
+
+ /*
+ * Step 2: Place changes in the working tree
+ *
+ * Stash is about restoring changes *to the working tree*.
+ * So if the merge successfully got a new version of some
+ * path, but left it out of the working tree, then clear the
+ * SKIP_WORKTREE bit and write it to the working tree.
+ */
+ if (pos >= 0 && ce_skip_worktree(active_cache[pos])) {
+ struct stat st;
+
+ ce = active_cache[pos];
+ if (!lstat(ce->name, &st)) {
+ /* Conflicting path present; relocate it */
+ struct strbuf new_path = STRBUF_INIT;
+ int fd;
+
+ strbuf_addf(&new_path,
+ "%s.stash.XXXXXX", ce->name);
+ fd = xmkstemp(new_path.buf);
+ close(fd);
+ printf(_("WARNING: Untracked file in way of "
+ "tracked file! Renaming\n "
+ " %s -> %s\n"
+ " to make room.\n"),
+ ce->name, new_path.buf);
+ if (rename(ce->name, new_path.buf))
+ die("Failed to move %s to %s\n",
+ ce->name, new_path.buf);
+ strbuf_release(&new_path);
+ }
+ checkout_entry(ce, &state, NULL, NULL);
+ ce->ce_flags &= ~CE_SKIP_WORKTREE;
+ }
+
+ /*
+ * Step 3: "unstage" changes, as long as they are still tracked
+ */
+ if (p->one->oid_valid) {
+ /*
+ * Path existed in orig_tree; restore index entry
+ * from that tree in order to "unstage" the changes.
+ */
+ int option = ADD_CACHE_OK_TO_REPLACE;
+ if (pos < 0)
+ option = ADD_CACHE_OK_TO_ADD;
+
+ ce = make_cache_entry(&the_index,
+ p->one->mode,
+ &p->one->oid,
+ p->one->path,
+ 0, 0);
+ add_index_entry(&the_index, ce, option);
+ }
+ }
+ diff_flush(&diff_opts);
+
+ /*
+ * Step 4: write the new index to disk
+ */
+ repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR);
+ if (write_locked_index(&the_index, &lock,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
+ die(_("Unable to write index."));
+}
+
static int do_apply_stash(const char *prefix, struct stash_info *info,
int index, int quiet)
{
@@ -467,26 +553,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
if (reset_tree(&index_tree, 0, 0))
return -1;
} else {
- struct strbuf out = STRBUF_INIT;
-
- if (get_newly_staged(&out, &c_tree)) {
- strbuf_release(&out);
- return -1;
- }
-
- if (reset_tree(&c_tree, 0, 1)) {
- strbuf_release(&out);
- return -1;
- }
-
- ret = update_index(&out);
- strbuf_release(&out);
- if (ret)
- return -1;
-
- /* read back the result of update_index() back from the disk */
- discard_cache();
- read_cache();
+ unstage_changes_unless_new(&c_tree);
}
if (!quiet) {
diff --git a/submodule.c b/submodule.c
index b3bb59f066..b561445329 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1477,6 +1477,7 @@ static int get_next_submodule(struct child_process *cp,
strbuf_release(&submodule_prefix);
return 1;
} else {
+ struct strbuf empty_submodule_path = STRBUF_INIT;
fetch_task_release(task);
free(task);
@@ -1485,13 +1486,17 @@ static int get_next_submodule(struct child_process *cp,
* An empty directory is normal,
* the submodule is not initialized
*/
+ strbuf_addf(&empty_submodule_path, "%s/%s/",
+ spf->r->worktree,
+ ce->name);
if (S_ISGITLINK(ce->ce_mode) &&
- !is_empty_dir(ce->name)) {
+ !is_empty_dir(empty_submodule_path.buf)) {
spf->result = 1;
strbuf_addf(err,
_("Could not access submodule '%s'\n"),
ce->name);
}
+ strbuf_release(&empty_submodule_path);
}
}
diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
index bd3fa3c6da..4b714e9308 100644
--- a/t/lib-submodule-update.sh
+++ b/t/lib-submodule-update.sh
@@ -316,14 +316,7 @@ test_submodule_switch_common () {
command="$1"
######################### Appearing submodule #########################
# Switching to a commit letting a submodule appear creates empty dir ...
- if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
- then
- # Restoring stash fails to restore submodule index entry
- RESULT="failure"
- else
- RESULT="success"
- fi
- test_expect_$RESULT "$command: added submodule creates empty directory" '
+ test_expect_success "$command: added submodule creates empty directory" '
prolog &&
reset_work_tree_to no_submodule &&
(
@@ -337,6 +330,13 @@ test_submodule_switch_common () {
)
'
# ... and doesn't care if it already exists.
+ if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
+ then
+ # Restoring stash fails to restore submodule index entry
+ RESULT="failure"
+ else
+ RESULT="success"
+ fi
test_expect_$RESULT "$command: added submodule leaves existing empty directory alone" '
prolog &&
reset_work_tree_to no_submodule &&
diff --git a/t/perf/p7519-fsmonitor.sh b/t/perf/p7519-fsmonitor.sh
index 9b43342806..1e20a184c7 100755
--- a/t/perf/p7519-fsmonitor.sh
+++ b/t/perf/p7519-fsmonitor.sh
@@ -129,7 +129,12 @@ setup_for_fsmonitor() {
git config core.fsmonitor "$INTEGRATION_SCRIPT" &&
git update-index --fsmonitor 2>error &&
- test_must_be_empty error # ensure no silent error
+ if test_have_prereq WATCHMAN
+ then
+ test_must_be_empty error # ensure no silent error
+ else
+ grep "Empty last update token" error
+ fi
}
test_perf_w_drop_caches () {
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index a877dd145e..53d7b8ed75 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -722,4 +722,121 @@ test_expect_success 'fetch new submodule commit intermittently referenced by sup
)
'
+add_commit_push () {
+ dir="$1" &&
+ msg="$2" &&
+ shift 2 &&
+ git -C "$dir" add "$@" &&
+ git -C "$dir" commit -a -m "$msg" &&
+ git -C "$dir" push
+}
+
+compare_refs_in_dir () {
+ fail= &&
+ if test "x$1" = 'x!'
+ then
+ fail='!' &&
+ shift
+ fi &&
+ git -C "$1" rev-parse --verify "$2" >expect &&
+ git -C "$3" rev-parse --verify "$4" >actual &&
+ eval $fail test_cmp expect actual
+}
+
+
+test_expect_success 'setup nested submodule fetch test' '
+ # does not depend on any previous test setups
+
+ for repo in outer middle inner
+ do
+ git init --bare $repo &&
+ git clone $repo ${repo}_content &&
+ echo "$repo" >"${repo}_content/file" &&
+ add_commit_push ${repo}_content "initial" file ||
+ return 1
+ done &&
+
+ git clone outer A &&
+ git -C A submodule add "$pwd/middle" &&
+ git -C A/middle/ submodule add "$pwd/inner" &&
+ add_commit_push A/middle/ "adding inner sub" .gitmodules inner &&
+ add_commit_push A/ "adding middle sub" .gitmodules middle &&
+
+ git clone outer B &&
+ git -C B/ submodule update --init middle &&
+
+ compare_refs_in_dir A HEAD B HEAD &&
+ compare_refs_in_dir A/middle HEAD B/middle HEAD &&
+ test_path_is_file B/file &&
+ test_path_is_file B/middle/file &&
+ test_path_is_missing B/middle/inner/file &&
+
+ echo "change on inner repo of A" >"A/middle/inner/file" &&
+ add_commit_push A/middle/inner "change on inner" file &&
+ add_commit_push A/middle "change on inner" inner &&
+ add_commit_push A "change on inner" middle
+'
+
+test_expect_success 'fetching a superproject containing an uninitialized sub/sub project' '
+ # depends on previous test for setup
+
+ git -C B/ fetch &&
+ compare_refs_in_dir A origin/HEAD B origin/HEAD
+'
+
+fetch_with_recursion_abort () {
+ # In a regression the following git call will run into infinite recursion.
+ # To handle that, we connect the sed command to the git call by a pipe
+ # so that sed can kill the infinite recursion when detected.
+ # The recursion creates git output like:
+ # Fetching submodule sub
+ # Fetching submodule sub/sub <-- [1]
+ # Fetching submodule sub/sub/sub
+ # ...
+ # [1] sed will stop reading and cause git to eventually stop and die
+
+ git -C "$1" fetch --recurse-submodules 2>&1 |
+ sed "/Fetching submodule $2[^$]/q" >out &&
+ ! grep "Fetching submodule $2[^$]" out
+}
+
+test_expect_success 'setup recursive fetch with uninit submodule' '
+ # does not depend on any previous test setups
+
+ test_create_repo super &&
+ test_commit -C super initial &&
+ test_create_repo sub &&
+ test_commit -C sub initial &&
+ git -C sub rev-parse HEAD >expect &&
+
+ git -C super submodule add ../sub &&
+ git -C super commit -m "add sub" &&
+
+ git clone super superclone &&
+ git -C superclone submodule status >out &&
+ sed -e "s/^-//" -e "s/ sub.*$//" out >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'recursive fetch with uninit submodule' '
+ # depends on previous test for setup
+
+ fetch_with_recursion_abort superclone sub &&
+ git -C superclone submodule status >out &&
+ sed -e "s/^-//" -e "s/ sub$//" out >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'recursive fetch after deinit a submodule' '
+ # depends on previous test for setup
+
+ git -C superclone submodule update --init sub &&
+ git -C superclone submodule deinit -f sub &&
+
+ fetch_with_recursion_abort superclone sub &&
+ git -C superclone submodule status >out &&
+ sed -e "s/^-//" -e "s/ sub$//" out >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t7012-skip-worktree-writing.sh b/t/t7012-skip-worktree-writing.sh
index 7476781979..e5c6a038fb 100755
--- a/t/t7012-skip-worktree-writing.sh
+++ b/t/t7012-skip-worktree-writing.sh
@@ -149,6 +149,94 @@ test_expect_success '--ignore-skip-worktree-entries leaves worktree alone' '
--diff-filter=D -- keep-me.t
'
+test_expect_success 'stash restore in sparse checkout' '
+ test_create_repo stash-restore &&
+ (
+ cd stash-restore &&
+
+ mkdir subdir &&
+ echo A >subdir/A &&
+ echo untouched >untouched &&
+ echo removeme >removeme &&
+ echo modified >modified &&
+ git add . &&
+ git commit -m Initial &&
+
+ echo AA >>subdir/A &&
+ echo addme >addme &&
+ echo tweaked >>modified &&
+ rm removeme &&
+ git add addme &&
+
+ git stash push &&
+
+ git sparse-checkout set subdir &&
+
+ # Ensure after sparse-checkout we only have expected files
+ cat >expect <<-EOF &&
+ S modified
+ S removeme
+ H subdir/A
+ S untouched
+ EOF
+ git ls-files -t >actual &&
+ test_cmp expect actual &&
+
+ test_path_is_missing addme &&
+ test_path_is_missing modified &&
+ test_path_is_missing removeme &&
+ test_path_is_file subdir/A &&
+ test_path_is_missing untouched &&
+
+ # Put a file in the working directory in the way
+ echo in the way >modified &&
+ git stash apply &&
+
+ # Ensure stash vivifies modifies paths...
+ cat >expect <<-EOF &&
+ H addme
+ H modified
+ H removeme
+ H subdir/A
+ S untouched
+ EOF
+ git ls-files -t >actual &&
+ test_cmp expect actual &&
+
+ # ...and that the paths show up in status as changed...
+ cat >expect <<-EOF &&
+ A addme
+ M modified
+ D removeme
+ M subdir/A
+ ?? actual
+ ?? expect
+ ?? modified.stash.XXXXXX
+ EOF
+ git status --porcelain | \
+ sed -e s/stash......./stash.XXXXXX/ >actual &&
+ test_cmp expect actual &&
+
+ # ...and that working directory reflects the files correctly
+ test_path_is_file addme &&
+ test_path_is_file modified &&
+ test_path_is_missing removeme &&
+ test_path_is_file subdir/A &&
+ test_path_is_missing untouched &&
+
+ # ...including that we have the expected "modified" file...
+ cat >expect <<-EOF &&
+ modified
+ tweaked
+ EOF
+ test_cmp expect modified &&
+
+ # ...and that the other "modified" file is still present...
+ echo in the way >expect &&
+ test_cmp expect modified.stash.*
+ )
+'
+
#TODO test_expect_failure 'git-apply adds file' false
#TODO test_expect_failure 'git-apply updates file' false
#TODO test_expect_failure 'git-apply removes file' false
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 999982fe4a..2f08ce7cba 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -367,9 +367,14 @@ test_chmod () {
git update-index --add "--chmod=$@"
}
-# Get the modebits from a file or directory.
+# Get the modebits from a file or directory, ignoring the setgid bit (g+s).
+# This bit is inherited by subdirectories at their creation. So we remove it
+# from the returning string to prevent callers from having to worry about the
+# state of the bit in the test directory.
+#
test_modebits () {
- ls -ld "$1" | sed -e 's|^\(..........\).*|\1|'
+ ls -ld "$1" | sed -e 's|^\(..........\).*|\1|' \
+ -e 's|^\(......\)S|\1-|' -e 's|^\(......\)s|\1x|'
}
# Unset a configuration variable, but don't fail if it doesn't exist.