summaryrefslogtreecommitdiff
path: root/src/stash.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stash.c')
-rw-r--r--src/stash.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/src/stash.c b/src/stash.c
index 8f512d4ad..9010c476d 100644
--- a/src/stash.c
+++ b/src/stash.c
@@ -22,6 +22,7 @@
#include "signature.h"
#include "iterator.h"
#include "merge.h"
+#include "diff.h"
static int create_error(int error, const char *msg)
{
@@ -292,6 +293,25 @@ cleanup:
return error;
}
+static git_diff_delta *stash_delta_merge(
+ const git_diff_delta *a,
+ const git_diff_delta *b,
+ git_pool *pool)
+{
+ /* Special case for stash: if a file is deleted in the index, but exists
+ * in the working tree, we need to stash the workdir copy for the workdir.
+ */
+ if (a->status == GIT_DELTA_DELETED && b->status == GIT_DELTA_UNTRACKED) {
+ git_diff_delta *dup = git_diff__delta_dup(b, pool);
+
+ if (dup)
+ dup->status = GIT_DELTA_MODIFIED;
+ return dup;
+ }
+
+ return git_diff__merge_like_cgit(a, b, pool);
+}
+
static int build_workdir_tree(
git_tree **tree_out,
git_index *index,
@@ -299,17 +319,19 @@ static int build_workdir_tree(
{
git_repository *repo = git_index_owner(index);
git_tree *b_tree = NULL;
- git_diff *diff = NULL;
+ git_diff *diff = NULL, *idx_to_wd = NULL;
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
struct stash_update_rules data = {0};
int error;
- opts.flags = GIT_DIFF_IGNORE_SUBMODULES;
+ opts.flags = GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_INCLUDE_UNTRACKED;
if ((error = git_commit_tree(&b_tree, b_commit)) < 0)
goto cleanup;
- if ((error = git_diff_tree_to_workdir(&diff, repo, b_tree, &opts)) < 0)
+ if ((error = git_diff_tree_to_index(&diff, repo, b_tree, index, &opts)) < 0 ||
+ (error = git_diff_index_to_workdir(&idx_to_wd, repo, index, &opts)) < 0 ||
+ (error = git_diff__merge(diff, idx_to_wd, stash_delta_merge)) < 0)
goto cleanup;
data.include_changed = true;
@@ -320,6 +342,7 @@ static int build_workdir_tree(
error = build_tree_from_index(tree_out, index);
cleanup:
+ git_diff_free(idx_to_wd);
git_diff_free(diff);
git_tree_free(b_tree);