summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/git2/diff.h3
-rw-r--r--src/diff.c22
-rw-r--r--src/diff_output.c17
-rw-r--r--src/iterator.c12
-rw-r--r--src/iterator.h8
5 files changed, 57 insertions, 5 deletions
diff --git a/include/git2/diff.h b/include/git2/diff.h
index 1f7f8ab2a..121c40307 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -47,7 +47,8 @@ enum {
GIT_DIFF_INCLUDE_UNMODIFIED = (1 << 9),
GIT_DIFF_RECURSE_UNTRACKED_DIRS = (1 << 10),
GIT_DIFF_DISABLE_PATHSPEC_MATCH = (1 << 11),
- GIT_DIFF_DELTAS_ARE_ICASE = (1 << 12)
+ GIT_DIFF_DELTAS_ARE_ICASE = (1 << 12),
+ GIT_DIFF_INCLUDE_UNTRACKED_CONTENT = (1 << 13),
};
/**
diff --git a/src/diff.c b/src/diff.c
index 7a0051ae3..8718e5ada 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -669,7 +669,8 @@ static int diff_from_iterators(
/* check if contained in ignored parent directory */
if (git_buf_len(&ignore_prefix) &&
- ITERATOR_PREFIXCMP(*old_iter, nitem->path, git_buf_cstr(&ignore_prefix)) == 0)
+ ITERATOR_PREFIXCMP(*old_iter, nitem->path,
+ git_buf_cstr(&ignore_prefix)) == 0)
delta_type = GIT_DELTA_IGNORED;
if (S_ISDIR(nitem->mode)) {
@@ -677,10 +678,23 @@ static int diff_from_iterators(
* it or if the user requested the contents of untracked
* directories and it is not under an ignored directory.
*/
- if ((oitem && ITERATOR_PREFIXCMP(*old_iter, oitem->path, nitem->path) == 0) ||
+ bool contains_tracked =
+ (oitem &&
+ !ITERATOR_PREFIXCMP(*old_iter, oitem->path, nitem->path));
+ bool recurse_untracked =
(delta_type == GIT_DELTA_UNTRACKED &&
- (diff->opts.flags & GIT_DIFF_RECURSE_UNTRACKED_DIRS) != 0))
- {
+ (diff->opts.flags & GIT_DIFF_RECURSE_UNTRACKED_DIRS) != 0);
+
+ /* do not advance into directories that contain a .git file */
+ if (!contains_tracked && recurse_untracked) {
+ git_buf *full = NULL;
+ if (git_iterator_current_workdir_path(new_iter, &full) < 0)
+ goto fail;
+ if (git_path_contains_dir(full, DOT_GIT))
+ recurse_untracked = false;
+ }
+
+ if (contains_tracked || recurse_untracked) {
/* if this directory is ignored, remember it as the
* "ignore_prefix" for processing contained items
*/
diff --git a/src/diff_output.c b/src/diff_output.c
index f5f6c381e..9fee127c6 100644
--- a/src/diff_output.c
+++ b/src/diff_output.c
@@ -321,6 +321,9 @@ static int get_workdir_content(
if (file->mode == GIT_FILEMODE_COMMIT)
return get_workdir_sm_content(ctxt, file, map);
+ if (S_ISDIR(file->mode))
+ return 0;
+
if (git_buf_joinpath(&path, wd, file->path) < 0)
return -1;
@@ -535,6 +538,11 @@ static int diff_patch_load(
break;
case GIT_DELTA_MODIFIED:
break;
+ case GIT_DELTA_UNTRACKED:
+ delta->old_file.flags |= GIT_DIFF_FILE_NO_DATA;
+ if ((ctxt->opts->flags & GIT_DIFF_INCLUDE_UNTRACKED_CONTENT) == 0)
+ delta->new_file.flags |= GIT_DIFF_FILE_NO_DATA;
+ break;
default:
delta->new_file.flags |= GIT_DIFF_FILE_NO_DATA;
delta->old_file.flags |= GIT_DIFF_FILE_NO_DATA;
@@ -1070,6 +1078,9 @@ static int print_patch_file(
GIT_UNUSED(progress);
+ if (S_ISDIR(delta->new_file.mode))
+ return 0;
+
if (!oldpfx)
oldpfx = DIFF_OLD_PREFIX_DEFAULT;
@@ -1134,6 +1145,9 @@ static int print_patch_hunk(
{
diff_print_info *pi = data;
+ if (S_ISDIR(d->new_file.mode))
+ return 0;
+
git_buf_clear(pi->buf);
if (git_buf_printf(pi->buf, "%.*s", (int)header_len, header) < 0)
return -1;
@@ -1158,6 +1172,9 @@ static int print_patch_line(
{
diff_print_info *pi = data;
+ if (S_ISDIR(delta->new_file.mode))
+ return 0;
+
git_buf_clear(pi->buf);
if (line_origin == GIT_DIFF_LINE_ADDITION ||
diff --git a/src/iterator.c b/src/iterator.c
index e52554d4f..267687e01 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -905,3 +905,15 @@ int git_iterator_cmp(
return ITERATOR_PREFIXCMP(*iter, entry->path, path_prefix);
}
+int git_iterator_current_workdir_path(git_iterator *iter, git_buf **path)
+{
+ workdir_iterator *wi = (workdir_iterator *)iter;
+
+ if (iter->type != GIT_ITERATOR_WORKDIR || !wi->entry.path)
+ *path = NULL;
+ else
+ *path = &wi->path;
+
+ return 0;
+}
+
diff --git a/src/iterator.h b/src/iterator.h
index 11cd2182c..29c8985d4 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -10,6 +10,7 @@
#include "common.h"
#include "git2/index.h"
#include "vector.h"
+#include "buffer.h"
#define ITERATOR_PREFIXCMP(ITER, STR, PREFIX) (((ITER).ignore_case) ? \
git__prefixcmp_icase((STR), (PREFIX)) : \
@@ -166,4 +167,11 @@ extern int git_iterator_advance_into_directory(
extern int git_iterator_cmp(
git_iterator *iter, const char *path_prefix);
+/**
+ * Get the full path of the current item from a workdir iterator.
+ * This will return NULL for a non-workdir iterator.
+ */
+extern int git_iterator_current_workdir_path(
+ git_iterator *iter, git_buf **path);
+
#endif