diff options
-rw-r--r-- | include/git2/diff.h | 24 | ||||
-rw-r--r-- | src/checkout.c | 77 |
2 files changed, 64 insertions, 37 deletions
diff --git a/include/git2/diff.h b/include/git2/diff.h index 24556db73..551e525ef 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -32,6 +32,30 @@ GIT_BEGIN_DECL /** * Flags for diff options. A combination of these flags can be passed * in via the `flags` value in the `git_diff_options`. + * + * The flags are: + * + * - GIT_DIFF_NORMAL: normal diff, the default. + * - GIT_DIFF_REVERSE: reverse the sides of the diff. + * - GIT_DIFF_FORCE_TEXT: treat all as text, no binary attributes / detection. + * - GIT_DIFF_IGNORE_WHITESPACE: ignore all whitespace. + * - GIT_DIFF_IGNORE_WHITESPACE_CHANGE: ignore changes in amount of whitespace. + * - GIT_DIFF_IGNORE_WHITESPACE_EOL: ignore whitespace only at end-of-line. + * - GIT_DIFF_IGNORE_SUBMODULES: exclude submodules from diff completely. + * - GIT_DIFF_PATIENCE: use "patience diff" algorithm + * - GIT_DIFF_INCLUDE_IGNORED: include ignored files in the diff list + * - GIT_DIFF_INCLUDE_UNTRACKED: include untracked files in the diff list + * - GIT_DIFF_INCLUDE_UNMODIFIED: include unmodified files in the diff list + * - GIT_DIFF_RECURSE_UNTRACKED_DIRS: even with the INCLUDE_UNTRACKED flag, + * when am untracked directory is found, only a single entry for the directory + * will be included in the diff list; with this flag, all files under the + * directory will be included, too. + * - GIT_DIFF_DISABLE_PATHSPEC_MATCH: if the pathspec is set in the diff + * options, this flags means to interpret it exactly instead of fnmatch. + * - GIT_DIFF_DELTAS_ARE_ICASE: use case insensitive filename comparisons + * - GIT_DIFF_DONT_SPLIT_TYPECHANGE: normally, a type change between files + * will be converted into a DELETED record for the old file and an ADDED + * record for the new one; this option enabled TYPECHANGE records. */ enum { GIT_DIFF_NORMAL = 0, diff --git a/src/checkout.c b/src/checkout.c index 819994718..ee6e043d5 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -156,71 +156,74 @@ static int checkout_diff_fn( { struct checkout_diff_data *data = cb_data; int error = 0; - git_checkout_opts *opts; + git_checkout_opts *opts = data->checkout_opts; + bool do_delete = false, do_checkout_blob = false; data->stats->processed = (unsigned int)(data->stats->total * progress); - git_buf_truncate(data->path, data->workdir_len); - if (git_buf_joinpath(data->path, git_buf_cstr(data->path), delta->new_file.path) < 0) - return -1; - - opts = data->checkout_opts; - switch (delta->status) { case GIT_DELTA_UNTRACKED: - if (!(opts->checkout_strategy & GIT_CHECKOUT_REMOVE_UNTRACKED)) - return 0; - - if (!git__suffixcmp(delta->new_file.path, "/")) - error = git_futils_rmdir_r(git_buf_cstr(data->path), GIT_DIRREMOVAL_FILES_AND_DIRS); - else - error = p_unlink(git_buf_cstr(data->path)); + if ((opts->checkout_strategy & GIT_CHECKOUT_REMOVE_UNTRACKED) != 0) + do_delete = true; break; case GIT_DELTA_MODIFIED: case GIT_DELTA_TYPECHANGE: if (!(opts->checkout_strategy & GIT_CHECKOUT_OVERWRITE_MODIFIED)) { - if ((opts->skipped_notify_cb != NULL) - && (opts->skipped_notify_cb( + if (opts->skipped_notify_cb != NULL && + opts->skipped_notify_cb( delta->new_file.path, &delta->old_file.oid, delta->old_file.mode, - opts->notify_payload))) { - giterr_clear(); - error = GIT_EUSER; + opts->notify_payload) != 0) + { + giterr_clear(); + error = GIT_EUSER; } + + goto cleanup; } - else - error = checkout_blob( - data->owner, - &delta->old_file.oid, - git_buf_cstr(data->path), - delta->old_file.mode, - data->can_symlink, - opts); + do_checkout_blob = true; + + if (delta->status == GIT_DELTA_TYPECHANGE) + do_delete = true; break; case GIT_DELTA_DELETED: - if (!(opts->checkout_strategy & GIT_CHECKOUT_CREATE_MISSING)) - return 0; - - error = checkout_blob( - data->owner, - &delta->old_file.oid, - git_buf_cstr(data->path), - delta->old_file.mode, - data->can_symlink, - opts); + if ((opts->checkout_strategy & GIT_CHECKOUT_CREATE_MISSING) != 0) + do_checkout_blob = true; break; default: giterr_set(GITERR_INVALID, "Unexpected status (%d) for path '%s'.", delta->status, delta->new_file.path); error = -1; + goto cleanup; } + git_buf_truncate(data->path, data->workdir_len); + + if ((error = git_buf_joinpath( + data->path, git_buf_cstr(data->path), delta->new_file.path)) < 0) + goto cleanup; + + if (do_delete && + (error = git_futils_rmdir_r( + git_buf_cstr(data->path), GIT_DIRREMOVAL_FILES_AND_DIRS)) < 0) + goto cleanup; + + if (do_checkout_blob) + error = checkout_blob( + data->owner, + &delta->old_file.oid, + git_buf_cstr(data->path), + delta->old_file.mode, + data->can_symlink, + opts); + +cleanup: if (error) data->error = error; /* preserve real error */ |