Commit dfbff793 by Russell Belfer

Fix a few diff bugs with directory content

There are a few cases where diff should leave directories in
the diff list if we want to match core git, such as when the
directory contains a .git dir.  That feature was lost when I
introduced some of the new submodule handling.

This restores that and then fixes a couple of related to diff
output that are triggered by having diffs with directories in
them.

Also, this adds a new flag that can be passed to diff if you
want diff output to actually include the file content of any
untracked files.
parent 543864b6
......@@ -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),
};
/**
......
......@@ -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
*/
......
......@@ -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 ||
......
......@@ -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;
}
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment