Skip to content

Commit b5c259f

Browse files
ao2gitster
authored andcommitted
submodule: add a helper to check if it is safe to write to .gitmodules
Introduce a helper function named is_writing_gitmodules_ok() to verify that the .gitmodules file is safe to write. The function name follows the scheme of is_staging_gitmodules_ok(). The two symbolic constants GITMODULES_INDEX and GITMODULES_HEAD are used to get help from the C preprocessor in preventing typos, especially for future users. This is in preparation for a future change which teaches git how to read .gitmodules from the index or from the current branch if the file is not available in the working tree. The rationale behind the check is that writing to .gitmodules requires the file to be present in the working tree, unless a brand new .gitmodules is being created (in which case the .gitmodules file would not exist at all: neither in the working tree nor in the index or in the current branch). Expose the functionality also via a "submodule-helper config --check-writeable" command, as git scripts may want to perform the check before modifying submodules configuration. Signed-off-by: Antonio Ospite <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 23dd8f5 commit b5c259f

File tree

5 files changed

+75
-1
lines changed

5 files changed

+75
-1
lines changed

builtin/submodule--helper.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2005,6 +2005,28 @@ static int check_name(int argc, const char **argv, const char *prefix)
20052005

20062006
static int module_config(int argc, const char **argv, const char *prefix)
20072007
{
2008+
enum {
2009+
CHECK_WRITEABLE = 1
2010+
} command = 0;
2011+
2012+
struct option module_config_options[] = {
2013+
OPT_CMDMODE(0, "check-writeable", &command,
2014+
N_("check if it is safe to write to the .gitmodules file"),
2015+
CHECK_WRITEABLE),
2016+
OPT_END()
2017+
};
2018+
const char *const git_submodule_helper_usage[] = {
2019+
N_("git submodule--helper config name [value]"),
2020+
N_("git submodule--helper config --check-writeable"),
2021+
NULL
2022+
};
2023+
2024+
argc = parse_options(argc, argv, prefix, module_config_options,
2025+
git_submodule_helper_usage, PARSE_OPT_KEEP_ARGV0);
2026+
2027+
if (argc == 1 && command == CHECK_WRITEABLE)
2028+
return is_writing_gitmodules_ok() ? 0 : -1;
2029+
20082030
/* Equivalent to ACTION_GET in builtin/config.c */
20092031
if (argc == 2)
20102032
return print_config_from_gitmodules(the_repository, argv[1]);
@@ -2013,7 +2035,7 @@ static int module_config(int argc, const char **argv, const char *prefix)
20132035
if (argc == 3)
20142036
return config_set_in_gitmodules_file_gently(argv[1], argv[2]);
20152037

2016-
die("submodule--helper config takes 1 or 2 arguments: name [value]");
2038+
usage_with_options(git_submodule_helper_usage, module_config_options);
20172039
}
20182040

20192041
#define SUPPORT_SUPER_PREFIX (1<<0)

cache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,8 @@ static inline enum object_type object_type(unsigned int mode)
486486
#define INFOATTRIBUTES_FILE "info/attributes"
487487
#define ATTRIBUTE_MACRO_PREFIX "[attr]"
488488
#define GITMODULES_FILE ".gitmodules"
489+
#define GITMODULES_INDEX ":.gitmodules"
490+
#define GITMODULES_HEAD "HEAD:.gitmodules"
489491
#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
490492
#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
491493
#define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"

submodule.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,24 @@ int is_gitmodules_unmerged(const struct index_state *istate)
5050
return 0;
5151
}
5252

53+
/*
54+
* Check if the .gitmodules file is safe to write.
55+
*
56+
* Writing to the .gitmodules file requires that the file exists in the
57+
* working tree or, if it doesn't, that a brand new .gitmodules file is going
58+
* to be created (i.e. it's neither in the index nor in the current branch).
59+
*
60+
* It is not safe to write to .gitmodules if it's not in the working tree but
61+
* it is in the index or in the current branch, because writing new values
62+
* (and staging them) would blindly overwrite ALL the old content.
63+
*/
64+
int is_writing_gitmodules_ok(void)
65+
{
66+
struct object_id oid;
67+
return file_exists(GITMODULES_FILE) ||
68+
(get_oid(GITMODULES_INDEX, &oid) < 0 && get_oid(GITMODULES_HEAD, &oid) < 0);
69+
}
70+
5371
/*
5472
* Check if the .gitmodules file has unstaged modifications. This must be
5573
* checked before allowing modifications to the .gitmodules file with the

submodule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ struct submodule_update_strategy {
4040
#define SUBMODULE_UPDATE_STRATEGY_INIT {SM_UPDATE_UNSPECIFIED, NULL}
4141

4242
int is_gitmodules_unmerged(const struct index_state *istate);
43+
int is_writing_gitmodules_ok(void);
4344
int is_staging_gitmodules_ok(struct index_state *istate);
4445
int update_path_in_gitmodules(const char *oldpath, const char *newpath);
4546
int remove_path_from_gitmodules(const char *path);

t/t7411-submodule-config.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,35 @@ test_expect_success 'overwriting unstaged submodules config with "submodule--hel
161161
)
162162
'
163163

164+
test_expect_success 'writeable .gitmodules when it is in the working tree' '
165+
git -C super submodule--helper config --check-writeable
166+
'
167+
168+
test_expect_success 'writeable .gitmodules when it is nowhere in the repository' '
169+
ORIG=$(git -C super rev-parse HEAD) &&
170+
test_when_finished "git -C super reset --hard $ORIG" &&
171+
(cd super &&
172+
git rm .gitmodules &&
173+
git commit -m "remove .gitmodules from the current branch" &&
174+
git submodule--helper config --check-writeable
175+
)
176+
'
177+
178+
test_expect_success 'non-writeable .gitmodules when it is in the index but not in the working tree' '
179+
test_when_finished "git -C super checkout .gitmodules" &&
180+
(cd super &&
181+
rm -f .gitmodules &&
182+
test_must_fail git submodule--helper config --check-writeable
183+
)
184+
'
185+
186+
test_expect_success 'non-writeable .gitmodules when it is in the current branch but not in the index' '
187+
ORIG=$(git -C super rev-parse HEAD) &&
188+
test_when_finished "git -C super reset --hard $ORIG" &&
189+
(cd super &&
190+
git rm .gitmodules &&
191+
test_must_fail git submodule--helper config --check-writeable
192+
)
193+
'
194+
164195
test_done

0 commit comments

Comments
 (0)