Skip to content

Commit

Permalink
Merge branch 'jl/submodule-ignore-diff'
Browse files Browse the repository at this point in the history
* jl/submodule-ignore-diff:
  Add tests for the diff.ignoreSubmodules config option
  Add the 'diff.ignoreSubmodules' config setting
  Submodules: Use "ignore" settings from .gitmodules too for diff and status
  Submodules: Add the new "ignore" config option for diff and status

Conflicts:
	diff.c
  • Loading branch information
Junio C Hamano committed Aug 18, 2010
2 parents 06d11b2 + 90e1452 commit cc34bb0
Show file tree
Hide file tree
Showing 17 changed files with 526 additions and 21 deletions.
18 changes: 18 additions & 0 deletions Documentation/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,11 @@ diff.renames::
will enable basic rename detection. If set to "copies" or
"copy", it will detect copies, as well.

diff.ignoreSubmodules::
Sets the default value of --ignore-submodules. Note that this
affects only 'git diff' Porcelain, and not lower level 'diff'
commands such as 'git diff-files'.

diff.suppressBlankEmpty::
A boolean to inhibit the standard behavior of printing a space
before each empty output line. Defaults to false.
Expand Down Expand Up @@ -1749,6 +1754,19 @@ submodule.<name>.update::
URL and other values found in the `.gitmodules` file. See
linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.

submodule.<name>.ignore::
Defines under what circumstances "git status" and the diff family show
a submodule as modified. When set to "all", it will never be considered
modified, "dirty" will ignore all changes to the submodules work tree and
takes only differences between the HEAD of the submodule and the commit
recorded in the superproject into account. "untracked" will additionally
let submodules with modified tracked files in their work tree show up.
Using "none" (the default when this option is not set) also shows
submodules that have untracked files in their work tree as changed.
This setting overrides any setting made in .gitmodules for this submodule,
both settings can be overriden on the command line by using the
"--ignore-submodules" option.

tar.umask::
This variable can be used to restrict the permission bits of
tar archive entries. The default is 0002, which turns off the
Expand Down
6 changes: 5 additions & 1 deletion Documentation/diff-options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,11 @@ endif::git-format-patch[]

--ignore-submodules[=<when>]::
Ignore changes to submodules in the diff generation. <when> can be
either "untracked", "dirty" or "all", which is the default. When
either "none", "untracked", "dirty" or "all", which is the default
Using "none" will consider the submodule modified when it either contains
untracked or modified files or its HEAD differs from the commit recorded
in the superproject and can be used to override any settings of the
'ignore' option in linkgit:git-config[1] or linkgit:gitmodules[5]. When
"untracked" is used submodules are not considered dirty when they only
contain untracked content (but they are still scanned for modified
content). Using "dirty" ignores all changes to the work tree of submodules,
Expand Down
6 changes: 5 additions & 1 deletion Documentation/git-status.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ specified.

--ignore-submodules[=<when>]::
Ignore changes to submodules when looking for changes. <when> can be
either "untracked", "dirty" or "all", which is the default. When
either "none", "untracked", "dirty" or "all", which is the default.
Using "none" will consider the submodule modified when it either contains
untracked or modified files or its HEAD differs from the commit recorded
in the superproject and can be used to override any settings of the
'ignore' option in linkgit:git-config[1] or linkgit:gitmodules[5]. When
"untracked" is used submodules are not considered dirty when they only
contain untracked content (but they are still scanned for modified
content). Using "dirty" ignores all changes to the work tree of submodules,
Expand Down
15 changes: 15 additions & 0 deletions Documentation/gitmodules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,21 @@ submodule.<name>.update::
This config option is overridden if 'git submodule update' is given
the '--merge' or '--rebase' options.

submodule.<name>.ignore::
Defines under what circumstances "git status" and the diff family show
a submodule as modified. When set to "all", it will never be considered
modified, "dirty" will ignore all changes to the submodules work tree and
takes only differences between the HEAD of the submodule and the commit
recorded in the superproject into account. "untracked" will additionally
let submodules with modified tracked files in their work tree show up.
Using "none" (the default when this option is not set) also shows
submodules that have untracked files in their work tree as changed.
If this option is also present in the submodules entry in .git/config of
the superproject, the setting there will override the one found in
.gitmodules.
Both settings can be overriden on the command line by using the
"--ignore-submodule" option.


EXAMPLES
--------
Expand Down
2 changes: 2 additions & 0 deletions builtin/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "rerere.h"
#include "unpack-trees.h"
#include "quote.h"
#include "submodule.h"

static const char * const builtin_commit_usage[] = {
"git commit [options] [--] <filepattern>...",
Expand Down Expand Up @@ -1073,6 +1074,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
status_format = STATUS_FORMAT_PORCELAIN;

wt_status_prepare(&s);
gitmodules_config();
git_config(git_status_config, &s);
in_merge = file_exists(git_path("MERGE_HEAD"));
argc = parse_options(argc, argv, prefix,
Expand Down
2 changes: 2 additions & 0 deletions builtin/diff-files.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "commit.h"
#include "revision.h"
#include "builtin.h"
#include "submodule.h"

static const char diff_files_usage[] =
"git diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
Expand All @@ -20,6 +21,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
unsigned options = 0;

init_revisions(&rev, prefix);
gitmodules_config();
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
rev.abbrev = 0;

Expand Down
2 changes: 2 additions & 0 deletions builtin/diff-index.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "commit.h"
#include "revision.h"
#include "builtin.h"
#include "submodule.h"

static const char diff_cache_usage[] =
"git diff-index [-m] [--cached] "
Expand All @@ -17,6 +18,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
int result;

init_revisions(&rev, prefix);
gitmodules_config();
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
rev.abbrev = 0;

Expand Down
2 changes: 2 additions & 0 deletions builtin/diff-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "commit.h"
#include "log-tree.h"
#include "builtin.h"
#include "submodule.h"

static struct rev_info log_tree_opt;

Expand Down Expand Up @@ -112,6 +113,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
int read_stdin = 0;

init_revisions(opt, prefix);
gitmodules_config();
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
opt->abbrev = 0;
opt->diff = 1;
Expand Down
2 changes: 2 additions & 0 deletions builtin/diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "revision.h"
#include "log-tree.h"
#include "builtin.h"
#include "submodule.h"

struct blobinfo {
unsigned char sha1[20];
Expand Down Expand Up @@ -279,6 +280,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
*/

prefix = setup_git_directory_gently(&nongit);
gitmodules_config();
git_config(git_diff_ui_config, NULL);

if (diff_use_color_default == -1)
Expand Down
15 changes: 10 additions & 5 deletions diff-lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,16 @@ static int match_stat_with_submodule(struct diff_options *diffopt,
unsigned ce_option, unsigned *dirty_submodule)
{
int changed = ce_match_stat(ce, st, ce_option);
if (S_ISGITLINK(ce->ce_mode)
&& !DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES)
&& !DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES)
&& (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES))) {
*dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES));
if (S_ISGITLINK(ce->ce_mode)) {
unsigned orig_flags = diffopt->flags;
if (!DIFF_OPT_TST(diffopt, OVERRIDE_SUBMODULE_CONFIG))
set_diffopt_flags_from_submodule_config(diffopt, ce->name);
if (DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES))
changed = 0;
else if (!DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES)
&& (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES)))
*dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES));
diffopt->flags = orig_flags;
}
return changed;
}
Expand Down
41 changes: 34 additions & 7 deletions diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ static const char *external_diff_cmd_cfg;
int diff_auto_refresh_index = 1;
static int diff_mnemonic_prefix;
static int diff_no_prefix;
static struct diff_options default_diff_options;

static char diff_colors[][COLOR_MAXLEN] = {
GIT_COLOR_RESET,
Expand Down Expand Up @@ -107,6 +108,9 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "diff.wordregex"))
return git_config_string(&diff_word_regex_cfg, var, value);

if (!strcmp(var, "diff.ignoresubmodules"))
handle_ignore_submodules_arg(&default_diff_options, value);

return git_diff_basic_config(var, value, cb);
}

Expand Down Expand Up @@ -141,6 +145,9 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
return 0;
}

if (!prefixcmp(var, "submodule."))
return parse_submodule_config_option(var, value);

return git_color_default_config(var, value, cb);
}

Expand Down Expand Up @@ -2819,7 +2826,7 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)

void diff_setup(struct diff_options *options)
{
memset(options, 0, sizeof(*options));
memcpy(options, &default_diff_options, sizeof(*options));

options->file = stdout;

Expand Down Expand Up @@ -3171,11 +3178,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
DIFF_OPT_SET(options, ALLOW_TEXTCONV);
else if (!strcmp(arg, "--no-textconv"))
DIFF_OPT_CLR(options, ALLOW_TEXTCONV);
else if (!strcmp(arg, "--ignore-submodules"))
else if (!strcmp(arg, "--ignore-submodules")) {
DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
handle_ignore_submodules_arg(options, "all");
else if (!prefixcmp(arg, "--ignore-submodules="))
} else if (!prefixcmp(arg, "--ignore-submodules=")) {
DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
handle_ignore_submodules_arg(options, arg + 20);
else if (!strcmp(arg, "--submodule"))
} else if (!strcmp(arg, "--submodule"))
DIFF_OPT_SET(options, SUBMODULE_LOG);
else if (!prefixcmp(arg, "--submodule=")) {
if (!strcmp(arg + 12, "log"))
Expand Down Expand Up @@ -4108,14 +4117,32 @@ int diff_result_code(struct diff_options *opt, int status)
return result;
}

/*
* Shall changes to this submodule be ignored?
*
* Submodule changes can be configured to be ignored separately for each path,
* but that configuration can be overridden from the command line.
*/
static int is_submodule_ignored(const char *path, struct diff_options *options)
{
int ignored = 0;
unsigned orig_flags = options->flags;
if (!DIFF_OPT_TST(options, OVERRIDE_SUBMODULE_CONFIG))
set_diffopt_flags_from_submodule_config(options, path);
if (DIFF_OPT_TST(options, IGNORE_SUBMODULES))
ignored = 1;
options->flags = orig_flags;
return ignored;
}

void diff_addremove(struct diff_options *options,
int addremove, unsigned mode,
const unsigned char *sha1,
const char *concatpath, unsigned dirty_submodule)
{
struct diff_filespec *one, *two;

if (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(mode))
if (S_ISGITLINK(mode) && is_submodule_ignored(concatpath, options))
return;

/* This may look odd, but it is a preparation for
Expand Down Expand Up @@ -4162,8 +4189,8 @@ void diff_change(struct diff_options *options,
{
struct diff_filespec *one, *two;

if (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(old_mode)
&& S_ISGITLINK(new_mode))
if (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) &&
is_submodule_ignored(concatpath, options))
return;

if (DIFF_OPT_TST(options, REVERSE_DIFF)) {
Expand Down
1 change: 1 addition & 0 deletions diff.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)
#define DIFF_OPT_DIRTY_SUBMODULES (1 << 24)
#define DIFF_OPT_IGNORE_UNTRACKED_IN_SUBMODULES (1 << 25)
#define DIFF_OPT_IGNORE_DIRTY_SUBMODULES (1 << 26)
#define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27)

#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
Expand Down
80 changes: 79 additions & 1 deletion submodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
#include "revision.h"
#include "run-command.h"
#include "diffcore.h"
#include "string-list.h"

struct string_list config_name_for_path;
struct string_list config_ignore_for_name;

static int add_submodule_odb(const char *path)
{
Expand Down Expand Up @@ -46,16 +50,90 @@ static int add_submodule_odb(const char *path)
return ret;
}

void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
const char *path)
{
struct string_list_item *path_option, *ignore_option;
path_option = unsorted_string_list_lookup(&config_name_for_path, path);
if (path_option) {
ignore_option = unsorted_string_list_lookup(&config_ignore_for_name, path_option->util);
if (ignore_option)
handle_ignore_submodules_arg(diffopt, ignore_option->util);
}
}

static int submodule_config(const char *var, const char *value, void *cb)
{
if (!prefixcmp(var, "submodule."))
return parse_submodule_config_option(var, value);
return 0;
}

void gitmodules_config(void)
{
const char *work_tree = get_git_work_tree();
if (work_tree) {
struct strbuf gitmodules_path = STRBUF_INIT;
strbuf_addstr(&gitmodules_path, work_tree);
strbuf_addstr(&gitmodules_path, "/.gitmodules");
git_config_from_file(submodule_config, gitmodules_path.buf, NULL);
strbuf_release(&gitmodules_path);
}
}

int parse_submodule_config_option(const char *var, const char *value)
{
int len;
struct string_list_item *config;
struct strbuf submodname = STRBUF_INIT;

var += 10; /* Skip "submodule." */

len = strlen(var);
if ((len > 5) && !strcmp(var + len - 5, ".path")) {
strbuf_add(&submodname, var, len - 5);
config = unsorted_string_list_lookup(&config_name_for_path, value);
if (config)
free(config->util);
else
config = string_list_append(&config_name_for_path, xstrdup(value));
config->util = strbuf_detach(&submodname, NULL);
strbuf_release(&submodname);
} else if ((len > 7) && !strcmp(var + len - 7, ".ignore")) {
if (strcmp(value, "untracked") && strcmp(value, "dirty") &&
strcmp(value, "all") && strcmp(value, "none")) {
warning("Invalid parameter \"%s\" for config option \"submodule.%s.ignore\"", value, var);
return 0;
}

strbuf_add(&submodname, var, len - 7);
config = unsorted_string_list_lookup(&config_ignore_for_name, submodname.buf);
if (config)
free(config->util);
else
config = string_list_append(&config_ignore_for_name,
strbuf_detach(&submodname, NULL));
strbuf_release(&submodname);
config->util = xstrdup(value);
return 0;
}
return 0;
}

void handle_ignore_submodules_arg(struct diff_options *diffopt,
const char *arg)
{
DIFF_OPT_CLR(diffopt, IGNORE_SUBMODULES);
DIFF_OPT_CLR(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
DIFF_OPT_CLR(diffopt, IGNORE_DIRTY_SUBMODULES);

if (!strcmp(arg, "all"))
DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
else if (!strcmp(arg, "untracked"))
DIFF_OPT_SET(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
else if (!strcmp(arg, "dirty"))
DIFF_OPT_SET(diffopt, IGNORE_DIRTY_SUBMODULES);
else
else if (strcmp(arg, "none"))
die("bad --ignore-submodules argument: %s", arg);
}

Expand Down
Loading

0 comments on commit cc34bb0

Please sign in to comment.