summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2015-06-20 19:33:15 -0400
committerEdward Thomson <ethomson@edwardthomson.com>2015-06-25 18:34:38 -0400
commitb7f5cb8dd767063719919780d90fc3470d340ac7 (patch)
treec142b8ae2604f57a93d95198eaa20bf8497e312a /src
parent8960dc1ec69dd87d33e99e5e26b9982132b05113 (diff)
downloadlibgit2-b7f5cb8dd767063719919780d90fc3470d340ac7.tar.gz
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.
Diffstat (limited to 'src')
-rw-r--r--src/stash.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/src/stash.c b/src/stash.c
index 14cbeb642..59ecd3b07 100644
--- a/src/stash.c
+++ b/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);