зеркало из https://github.com/microsoft/git.git
Merge branch 'nd/ita-wt-renames-in-status' into maint
"git status" after moving a path in the working tree (hence making it appear "removed") and then adding with the -N option (hence making that appear "added") detected it as a rename, but did not report the old and new pathnames correctly. * nd/ita-wt-renames-in-status: wt-status.c: handle worktree renames wt-status.c: rename rename-related fields in wt_status_change_data wt-status.c: catch unhandled diff status codes wt-status.c: coding style fix Use DIFF_DETECT_RENAME for detect_rename assignments t2203: test status output with porcelain v2 format
This commit is contained in:
Коммит
12accdc023
|
@ -149,14 +149,15 @@ the status.relativePaths config option below.
|
||||||
Short Format
|
Short Format
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
In the short-format, the status of each path is shown as
|
In the short-format, the status of each path is shown as one of these
|
||||||
|
forms
|
||||||
|
|
||||||
XY PATH1 -> PATH2
|
XY PATH
|
||||||
|
XY ORIG_PATH -> PATH
|
||||||
|
|
||||||
where `PATH1` is the path in the `HEAD`, and the " `-> PATH2`" part is
|
where `ORIG_PATH` is where the renamed/copied contents came
|
||||||
shown only when `PATH1` corresponds to a different path in the
|
from. `ORIG_PATH` is only shown when the entry is renamed or
|
||||||
index/worktree (i.e. the file is renamed). The `XY` is a two-letter
|
copied. The `XY` is a two-letter status code.
|
||||||
status code.
|
|
||||||
|
|
||||||
The fields (including the `->`) are separated from each other by a
|
The fields (including the `->`) are separated from each other by a
|
||||||
single space. If a filename contains whitespace or other nonprintable
|
single space. If a filename contains whitespace or other nonprintable
|
||||||
|
@ -192,6 +193,8 @@ in which case `XY` are `!!`.
|
||||||
[MARC] index and work tree matches
|
[MARC] index and work tree matches
|
||||||
[ MARC] M work tree changed since index
|
[ MARC] M work tree changed since index
|
||||||
[ MARC] D deleted in work tree
|
[ MARC] D deleted in work tree
|
||||||
|
[ D] R renamed in work tree
|
||||||
|
[ D] C copied in work tree
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
D D unmerged, both deleted
|
D D unmerged, both deleted
|
||||||
A U unmerged, added by us
|
A U unmerged, added by us
|
||||||
|
@ -309,13 +312,13 @@ Renamed or copied entries have the following format:
|
||||||
of similarity between the source and target of the
|
of similarity between the source and target of the
|
||||||
move or copy). For example "R100" or "C75".
|
move or copy). For example "R100" or "C75".
|
||||||
<path> The pathname. In a renamed/copied entry, this
|
<path> The pathname. In a renamed/copied entry, this
|
||||||
is the path in the index and in the working tree.
|
is the target path.
|
||||||
<sep> When the `-z` option is used, the 2 pathnames are separated
|
<sep> When the `-z` option is used, the 2 pathnames are separated
|
||||||
with a NUL (ASCII 0x00) byte; otherwise, a tab (ASCII 0x09)
|
with a NUL (ASCII 0x00) byte; otherwise, a tab (ASCII 0x09)
|
||||||
byte separates them.
|
byte separates them.
|
||||||
<origPath> The pathname in the commit at HEAD. This is only
|
<origPath> The pathname in the commit at HEAD or in the index.
|
||||||
present in a renamed/copied entry, and tells
|
This is only present in a renamed/copied entry, and
|
||||||
where the renamed/copied contents came from.
|
tells where the renamed/copied contents came from.
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|
||||||
Unmerged entries have the following format; the first character is
|
Unmerged entries have the following format; the first character is
|
||||||
|
|
|
@ -1507,7 +1507,7 @@ static void print_summary(const char *prefix, const struct object_id *oid,
|
||||||
rev.show_root_diff = 1;
|
rev.show_root_diff = 1;
|
||||||
get_commit_format(format.buf, &rev);
|
get_commit_format(format.buf, &rev);
|
||||||
rev.always_show_header = 0;
|
rev.always_show_header = 0;
|
||||||
rev.diffopt.detect_rename = 1;
|
rev.diffopt.detect_rename = DIFF_DETECT_RENAME;
|
||||||
rev.diffopt.break_opt = 0;
|
rev.diffopt.break_opt = 0;
|
||||||
diff_setup_done(&rev.diffopt);
|
diff_setup_done(&rev.diffopt);
|
||||||
|
|
||||||
|
|
2
diff.c
2
diff.c
|
@ -246,7 +246,7 @@ static int parse_ws_error_highlight(const char *arg)
|
||||||
*/
|
*/
|
||||||
void init_diff_ui_defaults(void)
|
void init_diff_ui_defaults(void)
|
||||||
{
|
{
|
||||||
diff_detect_rename_default = 1;
|
diff_detect_rename_default = DIFF_DETECT_RENAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_diff_heuristic_config(const char *var, const char *value, void *cb)
|
int git_diff_heuristic_config(const char *var, const char *value, void *cb)
|
||||||
|
|
|
@ -25,6 +25,18 @@ test_expect_success 'git status' '
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git status with porcelain v2' '
|
||||||
|
git status --porcelain=v2 | grep -v "^?" >actual &&
|
||||||
|
nam1=d00491fd7e5bb6fa28c517a0bb32b8b506539d4d &&
|
||||||
|
nam2=ce013625030ba8dba906f756967f9e9ca394464a &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
1 DA N... 100644 000000 100644 $nam1 $_z40 1.t
|
||||||
|
1 A. N... 000000 100644 100644 $_z40 $nam2 elif
|
||||||
|
1 .A N... 000000 000000 100644 $_z40 $_z40 file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'check result of "add -N"' '
|
test_expect_success 'check result of "add -N"' '
|
||||||
git ls-files -s file >actual &&
|
git ls-files -s file >actual &&
|
||||||
empty=$(git hash-object --stdin </dev/null) &&
|
empty=$(git hash-object --stdin </dev/null) &&
|
||||||
|
@ -150,5 +162,65 @@ test_expect_success 'commit: ita entries ignored in empty commit check' '
|
||||||
)
|
)
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'rename detection finds the right names' '
|
||||||
|
git init rename-detection &&
|
||||||
|
(
|
||||||
|
cd rename-detection &&
|
||||||
|
echo contents >first &&
|
||||||
|
git add first &&
|
||||||
|
git commit -m first &&
|
||||||
|
mv first third &&
|
||||||
|
git add -N third &&
|
||||||
|
|
||||||
|
git status | grep -v "^?" >actual.1 &&
|
||||||
|
test_i18ngrep "renamed: *first -> third" actual.1 &&
|
||||||
|
|
||||||
|
git status --porcelain | grep -v "^?" >actual.2 &&
|
||||||
|
cat >expected.2 <<-\EOF &&
|
||||||
|
R first -> third
|
||||||
|
EOF
|
||||||
|
test_cmp expected.2 actual.2 &&
|
||||||
|
|
||||||
|
hash=12f00e90b6ef79117ce6e650416b8cf517099b78 &&
|
||||||
|
git status --porcelain=v2 | grep -v "^?" >actual.3 &&
|
||||||
|
cat >expected.3 <<-EOF &&
|
||||||
|
2 .R N... 100644 100644 100644 $hash $hash R100 third first
|
||||||
|
EOF
|
||||||
|
test_cmp expected.3 actual.3
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'double rename detection in status' '
|
||||||
|
git init rename-detection-2 &&
|
||||||
|
(
|
||||||
|
cd rename-detection-2 &&
|
||||||
|
echo contents >first &&
|
||||||
|
git add first &&
|
||||||
|
git commit -m first &&
|
||||||
|
git mv first second &&
|
||||||
|
mv second third &&
|
||||||
|
git add -N third &&
|
||||||
|
|
||||||
|
git status | grep -v "^?" >actual.1 &&
|
||||||
|
test_i18ngrep "renamed: *first -> second" actual.1 &&
|
||||||
|
test_i18ngrep "renamed: *second -> third" actual.1 &&
|
||||||
|
|
||||||
|
git status --porcelain | grep -v "^?" >actual.2 &&
|
||||||
|
cat >expected.2 <<-\EOF &&
|
||||||
|
R first -> second
|
||||||
|
R second -> third
|
||||||
|
EOF
|
||||||
|
test_cmp expected.2 actual.2 &&
|
||||||
|
|
||||||
|
hash=12f00e90b6ef79117ce6e650416b8cf517099b78 &&
|
||||||
|
git status --porcelain=v2 | grep -v "^?" >actual.3 &&
|
||||||
|
cat >expected.3 <<-EOF &&
|
||||||
|
2 R. N... 100644 100644 100644 $hash $hash R100 second first
|
||||||
|
2 .R N... 100644 100644 100644 $hash $hash R100 third second
|
||||||
|
EOF
|
||||||
|
test_cmp expected.3 actual.3
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
||||||
|
|
83
wt-status.c
83
wt-status.c
|
@ -360,8 +360,6 @@ static void wt_longstatus_print_change_data(struct wt_status *s,
|
||||||
switch (change_type) {
|
switch (change_type) {
|
||||||
case WT_STATUS_UPDATED:
|
case WT_STATUS_UPDATED:
|
||||||
status = d->index_status;
|
status = d->index_status;
|
||||||
if (d->head_path)
|
|
||||||
one_name = d->head_path;
|
|
||||||
break;
|
break;
|
||||||
case WT_STATUS_CHANGED:
|
case WT_STATUS_CHANGED:
|
||||||
if (d->new_submodule_commits || d->dirty_submodule) {
|
if (d->new_submodule_commits || d->dirty_submodule) {
|
||||||
|
@ -382,6 +380,14 @@ static void wt_longstatus_print_change_data(struct wt_status *s,
|
||||||
change_type);
|
change_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only pick up the rename it's relevant. If the rename is for
|
||||||
|
* the changed section and we're printing the updated section,
|
||||||
|
* ignore it.
|
||||||
|
*/
|
||||||
|
if (d->rename_status == status)
|
||||||
|
one_name = d->rename_source;
|
||||||
|
|
||||||
one = quote_path(one_name, s->prefix, &onebuf);
|
one = quote_path(one_name, s->prefix, &onebuf);
|
||||||
two = quote_path(two_name, s->prefix, &twobuf);
|
two = quote_path(two_name, s->prefix, &twobuf);
|
||||||
|
|
||||||
|
@ -391,7 +397,7 @@ static void wt_longstatus_print_change_data(struct wt_status *s,
|
||||||
die("BUG: unhandled diff status %c", status);
|
die("BUG: unhandled diff status %c", status);
|
||||||
len = label_width - utf8_strwidth(what);
|
len = label_width - utf8_strwidth(what);
|
||||||
assert(len >= 0);
|
assert(len >= 0);
|
||||||
if (status == DIFF_STATUS_COPIED || status == DIFF_STATUS_RENAMED)
|
if (one_name != two_name)
|
||||||
status_printf_more(s, c, "%s%.*s%s -> %s",
|
status_printf_more(s, c, "%s%.*s%s -> %s",
|
||||||
what, len, padding, one, two);
|
what, len, padding, one, two);
|
||||||
else
|
else
|
||||||
|
@ -406,7 +412,8 @@ static void wt_longstatus_print_change_data(struct wt_status *s,
|
||||||
strbuf_release(&twobuf);
|
strbuf_release(&twobuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char short_submodule_status(struct wt_status_change_data *d) {
|
static char short_submodule_status(struct wt_status_change_data *d)
|
||||||
|
{
|
||||||
if (d->new_submodule_commits)
|
if (d->new_submodule_commits)
|
||||||
return 'M';
|
return 'M';
|
||||||
if (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
|
if (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
|
||||||
|
@ -432,7 +439,7 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
|
||||||
struct wt_status_change_data *d;
|
struct wt_status_change_data *d;
|
||||||
|
|
||||||
p = q->queue[i];
|
p = q->queue[i];
|
||||||
it = string_list_insert(&s->change, p->one->path);
|
it = string_list_insert(&s->change, p->two->path);
|
||||||
d = it->util;
|
d = it->util;
|
||||||
if (!d) {
|
if (!d) {
|
||||||
d = xcalloc(1, sizeof(*d));
|
d = xcalloc(1, sizeof(*d));
|
||||||
|
@ -459,6 +466,14 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
|
||||||
/* mode_worktree is zero for a delete. */
|
/* mode_worktree is zero for a delete. */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DIFF_STATUS_COPIED:
|
||||||
|
case DIFF_STATUS_RENAMED:
|
||||||
|
if (d->rename_status)
|
||||||
|
die("BUG: multiple renames on the same target? how?");
|
||||||
|
d->rename_source = xstrdup(p->one->path);
|
||||||
|
d->rename_score = p->score * 100 / MAX_SCORE;
|
||||||
|
d->rename_status = p->status;
|
||||||
|
/* fallthru */
|
||||||
case DIFF_STATUS_MODIFIED:
|
case DIFF_STATUS_MODIFIED:
|
||||||
case DIFF_STATUS_TYPE_CHANGED:
|
case DIFF_STATUS_TYPE_CHANGED:
|
||||||
case DIFF_STATUS_UNMERGED:
|
case DIFF_STATUS_UNMERGED:
|
||||||
|
@ -467,8 +482,8 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
|
||||||
oidcpy(&d->oid_index, &p->one->oid);
|
oidcpy(&d->oid_index, &p->one->oid);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DIFF_STATUS_UNKNOWN:
|
default:
|
||||||
die("BUG: worktree status unknown???");
|
die("BUG: unhandled diff-files status '%c'", p->status);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,8 +545,11 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
|
||||||
|
|
||||||
case DIFF_STATUS_COPIED:
|
case DIFF_STATUS_COPIED:
|
||||||
case DIFF_STATUS_RENAMED:
|
case DIFF_STATUS_RENAMED:
|
||||||
d->head_path = xstrdup(p->one->path);
|
if (d->rename_status)
|
||||||
d->score = p->score * 100 / MAX_SCORE;
|
die("BUG: multiple renames on the same target? how?");
|
||||||
|
d->rename_source = xstrdup(p->one->path);
|
||||||
|
d->rename_score = p->score * 100 / MAX_SCORE;
|
||||||
|
d->rename_status = p->status;
|
||||||
/* fallthru */
|
/* fallthru */
|
||||||
case DIFF_STATUS_MODIFIED:
|
case DIFF_STATUS_MODIFIED:
|
||||||
case DIFF_STATUS_TYPE_CHANGED:
|
case DIFF_STATUS_TYPE_CHANGED:
|
||||||
|
@ -548,6 +566,10 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
|
||||||
* values in these fields.
|
* values in these fields.
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
die("BUG: unhandled diff-index status '%c'", p->status);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -602,7 +624,7 @@ static void wt_status_collect_changes_index(struct wt_status *s)
|
||||||
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
|
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
|
||||||
rev.diffopt.format_callback = wt_status_collect_updated_cb;
|
rev.diffopt.format_callback = wt_status_collect_updated_cb;
|
||||||
rev.diffopt.format_callback_data = s;
|
rev.diffopt.format_callback_data = s;
|
||||||
rev.diffopt.detect_rename = 1;
|
rev.diffopt.detect_rename = DIFF_DETECT_RENAME;
|
||||||
rev.diffopt.rename_limit = 200;
|
rev.diffopt.rename_limit = 200;
|
||||||
rev.diffopt.break_opt = 0;
|
rev.diffopt.break_opt = 0;
|
||||||
copy_pathspec(&rev.prune_data, &s->pathspec);
|
copy_pathspec(&rev.prune_data, &s->pathspec);
|
||||||
|
@ -962,7 +984,7 @@ static void wt_longstatus_print_verbose(struct wt_status *s)
|
||||||
setup_revisions(0, NULL, &rev, &opt);
|
setup_revisions(0, NULL, &rev, &opt);
|
||||||
|
|
||||||
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
|
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
|
||||||
rev.diffopt.detect_rename = 1;
|
rev.diffopt.detect_rename = DIFF_DETECT_RENAME;
|
||||||
rev.diffopt.file = s->fp;
|
rev.diffopt.file = s->fp;
|
||||||
rev.diffopt.close_file = 0;
|
rev.diffopt.close_file = 0;
|
||||||
/*
|
/*
|
||||||
|
@ -1719,13 +1741,14 @@ static void wt_shortstatus_status(struct string_list_item *it,
|
||||||
putchar(' ');
|
putchar(' ');
|
||||||
if (s->null_termination) {
|
if (s->null_termination) {
|
||||||
fprintf(stdout, "%s%c", it->string, 0);
|
fprintf(stdout, "%s%c", it->string, 0);
|
||||||
if (d->head_path)
|
if (d->rename_source)
|
||||||
fprintf(stdout, "%s%c", d->head_path, 0);
|
fprintf(stdout, "%s%c", d->rename_source, 0);
|
||||||
} else {
|
} else {
|
||||||
struct strbuf onebuf = STRBUF_INIT;
|
struct strbuf onebuf = STRBUF_INIT;
|
||||||
const char *one;
|
const char *one;
|
||||||
if (d->head_path) {
|
|
||||||
one = quote_path(d->head_path, s->prefix, &onebuf);
|
if (d->rename_source) {
|
||||||
|
one = quote_path(d->rename_source, s->prefix, &onebuf);
|
||||||
if (*one != '"' && strchr(one, ' ') != NULL) {
|
if (*one != '"' && strchr(one, ' ') != NULL) {
|
||||||
putchar('"');
|
putchar('"');
|
||||||
strbuf_addch(&onebuf, '"');
|
strbuf_addch(&onebuf, '"');
|
||||||
|
@ -2030,10 +2053,10 @@ static void wt_porcelain_v2_print_changed_entry(
|
||||||
struct wt_status *s)
|
struct wt_status *s)
|
||||||
{
|
{
|
||||||
struct wt_status_change_data *d = it->util;
|
struct wt_status_change_data *d = it->util;
|
||||||
struct strbuf buf_index = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
struct strbuf buf_head = STRBUF_INIT;
|
struct strbuf buf_from = STRBUF_INIT;
|
||||||
const char *path_index = NULL;
|
const char *path = NULL;
|
||||||
const char *path_head = NULL;
|
const char *path_from = NULL;
|
||||||
char key[3];
|
char key[3];
|
||||||
char submodule_token[5];
|
char submodule_token[5];
|
||||||
char sep_char, eol_char;
|
char sep_char, eol_char;
|
||||||
|
@ -2052,8 +2075,8 @@ static void wt_porcelain_v2_print_changed_entry(
|
||||||
*/
|
*/
|
||||||
sep_char = '\0';
|
sep_char = '\0';
|
||||||
eol_char = '\0';
|
eol_char = '\0';
|
||||||
path_index = it->string;
|
path = it->string;
|
||||||
path_head = d->head_path;
|
path_from = d->rename_source;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Path(s) are C-quoted if necessary. Current path is ALWAYS first.
|
* Path(s) are C-quoted if necessary. Current path is ALWAYS first.
|
||||||
|
@ -2063,27 +2086,27 @@ static void wt_porcelain_v2_print_changed_entry(
|
||||||
*/
|
*/
|
||||||
sep_char = '\t';
|
sep_char = '\t';
|
||||||
eol_char = '\n';
|
eol_char = '\n';
|
||||||
path_index = quote_path(it->string, s->prefix, &buf_index);
|
path = quote_path(it->string, s->prefix, &buf);
|
||||||
if (d->head_path)
|
if (d->rename_source)
|
||||||
path_head = quote_path(d->head_path, s->prefix, &buf_head);
|
path_from = quote_path(d->rename_source, s->prefix, &buf_from);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path_head)
|
if (path_from)
|
||||||
fprintf(s->fp, "2 %s %s %06o %06o %06o %s %s %c%d %s%c%s%c",
|
fprintf(s->fp, "2 %s %s %06o %06o %06o %s %s %c%d %s%c%s%c",
|
||||||
key, submodule_token,
|
key, submodule_token,
|
||||||
d->mode_head, d->mode_index, d->mode_worktree,
|
d->mode_head, d->mode_index, d->mode_worktree,
|
||||||
oid_to_hex(&d->oid_head), oid_to_hex(&d->oid_index),
|
oid_to_hex(&d->oid_head), oid_to_hex(&d->oid_index),
|
||||||
key[0], d->score,
|
d->rename_status, d->rename_score,
|
||||||
path_index, sep_char, path_head, eol_char);
|
path, sep_char, path_from, eol_char);
|
||||||
else
|
else
|
||||||
fprintf(s->fp, "1 %s %s %06o %06o %06o %s %s %s%c",
|
fprintf(s->fp, "1 %s %s %06o %06o %06o %s %s %s%c",
|
||||||
key, submodule_token,
|
key, submodule_token,
|
||||||
d->mode_head, d->mode_index, d->mode_worktree,
|
d->mode_head, d->mode_index, d->mode_worktree,
|
||||||
oid_to_hex(&d->oid_head), oid_to_hex(&d->oid_index),
|
oid_to_hex(&d->oid_head), oid_to_hex(&d->oid_index),
|
||||||
path_index, eol_char);
|
path, eol_char);
|
||||||
|
|
||||||
strbuf_release(&buf_index);
|
strbuf_release(&buf);
|
||||||
strbuf_release(&buf_head);
|
strbuf_release(&buf_from);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -44,10 +44,11 @@ struct wt_status_change_data {
|
||||||
int worktree_status;
|
int worktree_status;
|
||||||
int index_status;
|
int index_status;
|
||||||
int stagemask;
|
int stagemask;
|
||||||
int score;
|
|
||||||
int mode_head, mode_index, mode_worktree;
|
int mode_head, mode_index, mode_worktree;
|
||||||
struct object_id oid_head, oid_index;
|
struct object_id oid_head, oid_index;
|
||||||
char *head_path;
|
int rename_status;
|
||||||
|
int rename_score;
|
||||||
|
char *rename_source;
|
||||||
unsigned dirty_submodule : 2;
|
unsigned dirty_submodule : 2;
|
||||||
unsigned new_submodule_commits : 1;
|
unsigned new_submodule_commits : 1;
|
||||||
};
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче