mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-24 05:21:25 +00:00
stash: stage new files when unstashing them
Files that were new (staged additions) in the stash tree should be staged when unstashing, even when not applying the index.
This commit is contained in:
parent
8960dc1ec6
commit
b7f5cb8dd7
78
src/stash.c
78
src/stash.c
@ -671,6 +671,31 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int merge_indexes(
|
||||
git_index **out,
|
||||
git_repository *repo,
|
||||
git_tree *ancestor_tree,
|
||||
git_index *ours_index,
|
||||
git_index *theirs_index)
|
||||
{
|
||||
git_iterator *ancestor = NULL, *ours = NULL, *theirs = NULL;
|
||||
const git_iterator_flag_t flags = GIT_ITERATOR_DONT_IGNORE_CASE;
|
||||
int error;
|
||||
|
||||
if ((error = git_iterator_for_tree(&ancestor, ancestor_tree, flags, NULL, NULL)) < 0 ||
|
||||
(error = git_iterator_for_index(&ours, ours_index, flags, NULL, NULL)) < 0 ||
|
||||
(error = git_iterator_for_index(&theirs, theirs_index, flags, NULL, NULL)) < 0)
|
||||
goto done;
|
||||
|
||||
error = git_merge__iterators(out, repo, ancestor, ours, theirs, NULL);
|
||||
|
||||
done:
|
||||
git_iterator_free(ancestor);
|
||||
git_iterator_free(ours);
|
||||
git_iterator_free(theirs);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int merge_index_and_tree(
|
||||
git_index **out,
|
||||
git_repository *repo,
|
||||
@ -756,6 +781,47 @@ done:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int stage_new_file(const git_index_entry **entries, void *data)
|
||||
{
|
||||
git_index *index = data;
|
||||
|
||||
if(entries[0] == NULL)
|
||||
return git_index_add(index, entries[1]);
|
||||
else
|
||||
return git_index_add(index, entries[0]);
|
||||
}
|
||||
|
||||
static int stage_new_files(
|
||||
git_index **out,
|
||||
git_repository *repo,
|
||||
git_tree *parent_tree,
|
||||
git_tree *tree)
|
||||
{
|
||||
git_iterator *iterators[2] = { NULL, NULL };
|
||||
git_index *index = NULL;
|
||||
int error;
|
||||
|
||||
if ((error = git_index_new(&index)) < 0 ||
|
||||
(error = git_iterator_for_tree(&iterators[0], parent_tree,
|
||||
GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
|
||||
(error = git_iterator_for_tree(&iterators[1], tree,
|
||||
GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0)
|
||||
goto done;
|
||||
|
||||
error = git_iterator_walk(iterators, 2, stage_new_file, index);
|
||||
|
||||
done:
|
||||
if (error < 0)
|
||||
git_index_free(index);
|
||||
else
|
||||
*out = index;
|
||||
|
||||
git_iterator_free(iterators[0]);
|
||||
git_iterator_free(iterators[1]);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_stash_apply(
|
||||
git_repository *repo,
|
||||
size_t index,
|
||||
@ -769,6 +835,7 @@ int git_stash_apply(
|
||||
git_tree *index_tree = NULL;
|
||||
git_tree *index_parent_tree = NULL;
|
||||
git_tree *untracked_tree = NULL;
|
||||
git_index *stash_adds = NULL;
|
||||
git_index *repo_index = NULL;
|
||||
git_index *unstashed_index = NULL;
|
||||
git_index *modified_index = NULL;
|
||||
@ -813,6 +880,16 @@ int git_stash_apply(
|
||||
error = GIT_ECONFLICT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Otherwise, stage any new files in the stash tree. (Note: their
|
||||
* previously unstaged contents are staged, not the previously staged.)
|
||||
*/
|
||||
} else if ((opts.flags & GIT_STASH_APPLY_REINSTATE_INDEX) == 0) {
|
||||
if ((error = stage_new_files(
|
||||
&stash_adds, repo, stash_parent_tree, stash_tree)) < 0 ||
|
||||
(error = merge_indexes(
|
||||
&unstashed_index, repo, stash_parent_tree, repo_index, stash_adds)) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED);
|
||||
@ -874,6 +951,7 @@ cleanup:
|
||||
git_index_free(untracked_index);
|
||||
git_index_free(modified_index);
|
||||
git_index_free(unstashed_index);
|
||||
git_index_free(stash_adds);
|
||||
git_index_free(repo_index);
|
||||
git_tree_free(untracked_tree);
|
||||
git_tree_free(index_parent_tree);
|
||||
|
@ -17,6 +17,7 @@ void test_stash_apply__initialize(void)
|
||||
cl_git_mkfile("stash/what", "hello\n");
|
||||
cl_git_mkfile("stash/how", "small\n");
|
||||
cl_git_mkfile("stash/who", "world\n");
|
||||
cl_git_mkfile("stash/where", "meh\n");
|
||||
|
||||
cl_git_pass(git_index_add_bypath(repo_index, "what"));
|
||||
cl_git_pass(git_index_add_bypath(repo_index, "how"));
|
||||
@ -28,9 +29,14 @@ void test_stash_apply__initialize(void)
|
||||
cl_git_rewritefile("stash/who", "funky world\n");
|
||||
cl_git_mkfile("stash/when", "tomorrow\n");
|
||||
cl_git_mkfile("stash/why", "would anybody use stash?\n");
|
||||
cl_git_mkfile("stash/where", "????\n");
|
||||
|
||||
cl_git_pass(git_index_add_bypath(repo_index, "who"));
|
||||
cl_git_pass(git_index_add_bypath(repo_index, "why"));
|
||||
cl_git_pass(git_index_add_bypath(repo_index, "where"));
|
||||
git_index_write(repo_index);
|
||||
|
||||
cl_git_rewritefile("stash/where", "....\n");
|
||||
|
||||
/* Pre-stash state */
|
||||
assert_status(repo, "what", GIT_STATUS_WT_MODIFIED);
|
||||
@ -38,6 +44,7 @@ void test_stash_apply__initialize(void)
|
||||
assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED);
|
||||
assert_status(repo, "when", GIT_STATUS_WT_NEW);
|
||||
assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
|
||||
assert_status(repo, "where", GIT_STATUS_INDEX_NEW|GIT_STATUS_WT_MODIFIED);
|
||||
|
||||
cl_git_pass(git_stash_save(&oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED));
|
||||
|
||||
@ -47,6 +54,7 @@ void test_stash_apply__initialize(void)
|
||||
assert_status(repo, "who", GIT_STATUS_CURRENT);
|
||||
assert_status(repo, "when", GIT_ENOTFOUND);
|
||||
assert_status(repo, "why", GIT_ENOTFOUND);
|
||||
assert_status(repo, "where", GIT_ENOTFOUND);
|
||||
}
|
||||
|
||||
void test_stash_apply__cleanup(void)
|
||||
@ -62,6 +70,8 @@ void test_stash_apply__cleanup(void)
|
||||
|
||||
void test_stash_apply__with_default(void)
|
||||
{
|
||||
git_buf where = GIT_BUF_INIT;
|
||||
|
||||
cl_git_pass(git_stash_apply(repo, 0, NULL));
|
||||
|
||||
cl_assert_equal_i(git_index_has_conflicts(repo_index), 0);
|
||||
@ -69,11 +79,42 @@ void test_stash_apply__with_default(void)
|
||||
assert_status(repo, "how", GIT_STATUS_CURRENT);
|
||||
assert_status(repo, "who", GIT_STATUS_WT_MODIFIED);
|
||||
assert_status(repo, "when", GIT_STATUS_WT_NEW);
|
||||
assert_status(repo, "why", GIT_STATUS_WT_NEW);
|
||||
assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
|
||||
assert_status(repo, "where", GIT_STATUS_INDEX_NEW);
|
||||
|
||||
cl_git_pass(git_futils_readbuffer(&where, "stash/where"));
|
||||
cl_assert_equal_s("....\n", where.ptr);
|
||||
|
||||
git_buf_free(&where);
|
||||
}
|
||||
|
||||
void test_stash_apply__with_existing_file(void)
|
||||
{
|
||||
cl_git_mkfile("stash/where", "oops!\n");
|
||||
cl_git_fail(git_stash_apply(repo, 0, NULL));
|
||||
}
|
||||
|
||||
void test_stash_apply__merges_new_file(void)
|
||||
{
|
||||
git_index_entry *ancestor, *our, *their;
|
||||
|
||||
cl_git_mkfile("stash/where", "committed before stash\n");
|
||||
cl_git_pass(git_index_add_bypath(repo_index, "where"));
|
||||
cl_repo_commit_from_index(NULL, repo, signature, 0, "Other commit");
|
||||
|
||||
cl_git_pass(git_stash_apply(repo, 0, NULL));
|
||||
|
||||
cl_assert_equal_i(1, git_index_has_conflicts(repo_index));
|
||||
assert_status(repo, "what", GIT_STATUS_INDEX_MODIFIED);
|
||||
cl_git_pass(git_index_conflict_get(&ancestor, &our, &their, repo_index, "where")); /* unmerged */
|
||||
assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED);
|
||||
assert_status(repo, "when", GIT_STATUS_WT_NEW);
|
||||
assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
|
||||
}
|
||||
|
||||
void test_stash_apply__with_reinstate_index(void)
|
||||
{
|
||||
git_buf where = GIT_BUF_INIT;
|
||||
git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT;
|
||||
|
||||
opts.flags = GIT_STASH_APPLY_REINSTATE_INDEX;
|
||||
@ -86,6 +127,12 @@ void test_stash_apply__with_reinstate_index(void)
|
||||
assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED);
|
||||
assert_status(repo, "when", GIT_STATUS_WT_NEW);
|
||||
assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
|
||||
assert_status(repo, "where", GIT_STATUS_INDEX_NEW | GIT_STATUS_WT_MODIFIED);
|
||||
|
||||
cl_git_pass(git_futils_readbuffer(&where, "stash/where"));
|
||||
cl_assert_equal_s("....\n", where.ptr);
|
||||
|
||||
git_buf_free(&where);
|
||||
}
|
||||
|
||||
void test_stash_apply__conflict_index_with_default(void)
|
||||
@ -312,7 +359,8 @@ void test_stash_apply__executes_notify_cb(void)
|
||||
assert_status(repo, "how", GIT_STATUS_CURRENT);
|
||||
assert_status(repo, "who", GIT_STATUS_WT_MODIFIED);
|
||||
assert_status(repo, "when", GIT_STATUS_WT_NEW);
|
||||
assert_status(repo, "why", GIT_STATUS_WT_NEW);
|
||||
assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
|
||||
assert_status(repo, "where", GIT_STATUS_INDEX_NEW);
|
||||
|
||||
cl_assert_equal_b(true, seen_paths.what);
|
||||
cl_assert_equal_b(false, seen_paths.how);
|
||||
|
Loading…
Reference in New Issue
Block a user