Skip to content

Commit f9775a3

Browse files
committed
Add ignore_submodules to diff options
This adds correct support for an equivalent to --ignore-submodules in diff, where an actual ignore value can be passed to diff to override the per submodule settings in the configuration. This required tweaking the constants for ignore values so that zero would not be used and could represent an unset option to the diff. This was an opportunity to move the submodule values into include/git2/types.h and to rename the poorly named DEFAULT values for ignore and update constants to RESET instead. Now the GIT_DIFF_IGNORE_SUBMODULES flag is exactly the same as setting the ignore_submodules option to GIT_SUBMODULE_IGNORE_ALL (which is actually a minor change from the old behavior in that submodules will now be treated as UNMODIFIED deltas instead of being left out totally - if you set GIT_DIFF_INCLUDE_UNMODIFIED). This includes tests for the various new settings.
1 parent 2e3e273 commit f9775a3

File tree

9 files changed

+245
-122
lines changed

9 files changed

+245
-122
lines changed

include/git2/diff.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ typedef enum {
7878
GIT_DIFF_IGNORE_WHITESPACE_CHANGE = (1 << 3),
7979
/** Ignore whitespace at end of line */
8080
GIT_DIFF_IGNORE_WHITESPACE_EOL = (1 << 4),
81-
/** Exclude submodules from the diff completely */
81+
/** Treat all submodules as unmodified */
8282
GIT_DIFF_IGNORE_SUBMODULES = (1 << 5),
8383
/** Use the "patience diff" algorithm (currently unimplemented) */
8484
GIT_DIFF_PATIENCE = (1 << 6),
@@ -314,6 +314,8 @@ typedef int (*git_diff_notify_cb)(
314314
* - `notify_cb` is an optional callback function, notifying the consumer of
315315
* which files are being examined as the diff is generated
316316
* - `notify_payload` is the payload data to pass to the `notify_cb` function
317+
* - `ignore_submodules` overrides the submodule ignore setting for all
318+
* submodules in the diff.
317319
*/
318320
typedef struct {
319321
unsigned int version; /**< version for the struct */
@@ -326,6 +328,7 @@ typedef struct {
326328
git_off_t max_size; /**< defaults to 512MB */
327329
git_diff_notify_cb notify_cb;
328330
void *notify_payload;
331+
git_submodule_ignore_t ignore_submodules; /** << submodule ignore rule */
329332
} git_diff_options;
330333

331334
#define GIT_DIFF_OPTIONS_VERSION 1

include/git2/submodule.h

Lines changed: 10 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,51 +14,18 @@
1414
/**
1515
* @file git2/submodule.h
1616
* @brief Git submodule management utilities
17-
* @defgroup git_submodule Git submodule management routines
18-
* @ingroup Git
19-
* @{
20-
*/
21-
GIT_BEGIN_DECL
22-
23-
/**
24-
* Opaque structure representing a submodule.
2517
*
2618
* Submodule support in libgit2 builds a list of known submodules and keeps
2719
* it in the repository. The list is built from the .gitmodules file, the
2820
* .git/config file, the index, and the HEAD tree. Items in the working
2921
* directory that look like submodules (i.e. a git repo) but are not
3022
* mentioned in those places won't be tracked.
31-
*/
32-
typedef struct git_submodule git_submodule;
33-
34-
/**
35-
* Values that could be specified for the update rule of a submodule.
3623
*
37-
* Use the DEFAULT value if you have altered the update value via
38-
* `git_submodule_set_update()` and wish to reset to the original default.
39-
*/
40-
typedef enum {
41-
GIT_SUBMODULE_UPDATE_DEFAULT = -1,
42-
GIT_SUBMODULE_UPDATE_CHECKOUT = 0,
43-
GIT_SUBMODULE_UPDATE_REBASE = 1,
44-
GIT_SUBMODULE_UPDATE_MERGE = 2,
45-
GIT_SUBMODULE_UPDATE_NONE = 3
46-
} git_submodule_update_t;
47-
48-
/**
49-
* Values that could be specified for how closely to examine the
50-
* working directory when getting submodule status.
51-
*
52-
* Use the DEFUALT value if you have altered the ignore value via
53-
* `git_submodule_set_ignore()` and wish to reset to the original value.
24+
* @defgroup git_submodule Git submodule management routines
25+
* @ingroup Git
26+
* @{
5427
*/
55-
typedef enum {
56-
GIT_SUBMODULE_IGNORE_DEFAULT = -1, /* reset to default */
57-
GIT_SUBMODULE_IGNORE_NONE = 0, /* any change or untracked == dirty */
58-
GIT_SUBMODULE_IGNORE_UNTRACKED = 1, /* dirty if tracked files change */
59-
GIT_SUBMODULE_IGNORE_DIRTY = 2, /* only dirty if HEAD moved */
60-
GIT_SUBMODULE_IGNORE_ALL = 3 /* never dirty */
61-
} git_submodule_ignore_t;
28+
GIT_BEGIN_DECL
6229

6330
/**
6431
* Return codes for submodule status.
@@ -377,9 +344,9 @@ GIT_EXTERN(git_submodule_ignore_t) git_submodule_ignore(
377344
* submodule is in memory. You should call `git_submodule_save()` if you
378345
* want to persist the new ignore role.
379346
*
380-
* Calling this again with GIT_SUBMODULE_IGNORE_DEFAULT or calling
381-
* `git_submodule_reload()` will revert the rule to the value that was in the
382-
* original config.
347+
* Calling this again with GIT_SUBMODULE_IGNORE_RESET or calling
348+
* `git_submodule_reload()` will revert the rule to the value that was in
349+
* the original config.
383350
*
384351
* @return old value for ignore
385352
*/
@@ -399,9 +366,9 @@ GIT_EXTERN(git_submodule_update_t) git_submodule_update(
399366
* This sets the update rule in memory for the submodule. You should call
400367
* `git_submodule_save()` if you want to persist the new update rule.
401368
*
402-
* Calling this again with GIT_SUBMODULE_UPDATE_DEFAULT or calling
403-
* `git_submodule_reload()` will revert the rule to the value that was in the
404-
* original config.
369+
* Calling this again with GIT_SUBMODULE_UPDATE_RESET or calling
370+
* `git_submodule_reload()` will revert the rule to the value that was in
371+
* the original config.
405372
*
406373
* @return old value for update
407374
*/

include/git2/types.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,40 @@ typedef struct git_transfer_progress {
229229
*/
230230
typedef int (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload);
231231

232+
/**
233+
* Opaque structure representing a submodule.
234+
*/
235+
typedef struct git_submodule git_submodule;
236+
237+
/**
238+
* Values that could be specified for the update rule of a submodule.
239+
*
240+
* Use the RESET value if you have altered the in-memory update value via
241+
* `git_submodule_set_update()` and wish to reset to the original default.
242+
*/
243+
typedef enum {
244+
GIT_SUBMODULE_UPDATE_RESET = -1,
245+
GIT_SUBMODULE_UPDATE_CHECKOUT = 1,
246+
GIT_SUBMODULE_UPDATE_REBASE = 2,
247+
GIT_SUBMODULE_UPDATE_MERGE = 3,
248+
GIT_SUBMODULE_UPDATE_NONE = 4
249+
} git_submodule_update_t;
250+
251+
/**
252+
* Values that could be specified for how closely to examine the
253+
* working directory when getting submodule status.
254+
*
255+
* Use the RESET value if you have altered the in-memory ignore value via
256+
* `git_submodule_set_ignore()` and wish to reset to the original value.
257+
*/
258+
typedef enum {
259+
GIT_SUBMODULE_IGNORE_RESET = -1, /* reset to on-disk value */
260+
GIT_SUBMODULE_IGNORE_NONE = 1, /* any change or untracked == dirty */
261+
GIT_SUBMODULE_IGNORE_UNTRACKED = 2, /* dirty if tracked files change */
262+
GIT_SUBMODULE_IGNORE_DIRTY = 3, /* only dirty if HEAD moved */
263+
GIT_SUBMODULE_IGNORE_ALL = 4 /* never dirty */
264+
} git_submodule_ignore_t;
265+
232266
/** @} */
233267
GIT_END_DECL
234268

src/diff.c

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,6 @@ static int diff_delta__from_one(
7878
DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNTRACKED))
7979
return 0;
8080

81-
if (entry->mode == GIT_FILEMODE_COMMIT &&
82-
DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES))
83-
return 0;
84-
8581
if (!git_pathspec__match(
8682
&diff->pathspec, entry->path,
8783
DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH),
@@ -141,11 +137,6 @@ static int diff_delta__from_two(
141137
DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNMODIFIED))
142138
return 0;
143139

144-
if (old_entry->mode == GIT_FILEMODE_COMMIT &&
145-
new_entry->mode == GIT_FILEMODE_COMMIT &&
146-
DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES))
147-
return 0;
148-
149140
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) {
150141
uint32_t temp_mode = old_mode;
151142
const git_index_entry *temp_entry = old_entry;
@@ -431,8 +422,18 @@ static int diff_list_apply_options(
431422
if (!opts) {
432423
diff->opts.context_lines = config_int(cfg, "diff.context", 3);
433424

434-
if (config_bool(cfg, "diff.ignoreSubmodules", 0))
435-
diff->opts.flags |= GIT_DIFF_IGNORE_SUBMODULES;
425+
/* add other defaults here */
426+
}
427+
428+
/* if ignore_submodules not explicitly set, check diff config */
429+
if (diff->opts.ignore_submodules <= 0) {
430+
const char *str;
431+
432+
if (git_config_get_string(&str , cfg, "diff.ignoreSubmodules") < 0)
433+
giterr_clear();
434+
else if (str != NULL &&
435+
git_submodule_parse_ignore(&diff->opts.ignore_submodules, str) < 0)
436+
giterr_clear();
436437
}
437438

438439
/* if either prefix is not set, figure out appropriate value */
@@ -596,36 +597,44 @@ static int maybe_modified_submodule(
596597
int error = 0;
597598
git_submodule *sub;
598599
unsigned int sm_status = 0;
600+
git_submodule_ignore_t ign = diff->opts.ignore_submodules;
599601

600602
*status = GIT_DELTA_UNMODIFIED;
601603

602-
if (!DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES) &&
603-
!(error = git_submodule_lookup(
604-
&sub, diff->repo, info->nitem->path)) &&
605-
git_submodule_ignore(sub) != GIT_SUBMODULE_IGNORE_ALL &&
606-
!(error = git_submodule__status(
607-
&sm_status, NULL, NULL, found_oid, sub,
608-
GIT_SUBMODULE_IGNORE_DEFAULT)))
609-
{
610-
/* check IS_WD_UNMODIFIED because this case is only used
611-
* when the new side of the diff is the working directory
612-
*/
613-
if (!GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(sm_status))
614-
*status = GIT_DELTA_MODIFIED;
604+
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES) ||
605+
ign == GIT_SUBMODULE_IGNORE_ALL)
606+
return 0;
615607

616-
/* now that we have a HEAD OID, check if HEAD moved */
617-
if ((sm_status & GIT_SUBMODULE_STATUS_IN_WD) != 0 &&
618-
!git_oid_equal(&info->oitem->oid, found_oid))
619-
*status = GIT_DELTA_MODIFIED;
620-
}
608+
if ((error = git_submodule_lookup(
609+
&sub, diff->repo, info->nitem->path)) < 0) {
621610

622-
/* GIT_EEXISTS means a dir with .git in it was found - ignore it */
623-
if (error == GIT_EEXISTS) {
624-
giterr_clear();
625-
error = 0;
611+
/* GIT_EEXISTS means dir with .git in it was found - ignore it */
612+
if (error == GIT_EEXISTS) {
613+
giterr_clear();
614+
error = 0;
615+
}
616+
return error;
626617
}
627618

628-
return error;
619+
if (ign <= 0 && git_submodule_ignore(sub) == GIT_SUBMODULE_IGNORE_ALL)
620+
return 0;
621+
622+
if ((error = git_submodule__status(
623+
&sm_status, NULL, NULL, found_oid, sub, ign)) < 0)
624+
return error;
625+
626+
/* check IS_WD_UNMODIFIED because this case is only used
627+
* when the new side of the diff is the working directory
628+
*/
629+
if (!GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(sm_status))
630+
*status = GIT_DELTA_MODIFIED;
631+
632+
/* now that we have a HEAD OID, check if HEAD moved */
633+
if ((sm_status & GIT_SUBMODULE_STATUS_IN_WD) != 0 &&
634+
!git_oid_equal(&info->oitem->oid, found_oid))
635+
*status = GIT_DELTA_MODIFIED;
636+
637+
return 0;
629638
}
630639

631640
static int maybe_modified(

0 commit comments

Comments
 (0)