Merge branch 'ps/config-error'

Many codepaths forget to check return value from git_config_set();
the function is made to die() to make sure we do not proceed when
setting a configuration variable failed.

* ps/config-error:
  config: rename git_config_set_or_die to git_config_set
  config: rename git_config_set to git_config_set_gently
  compat: die when unable to set core.precomposeunicode
  sequencer: die on config error when saving replay opts
  init-db: die on config errors when initializing empty repo
  clone: die on config error in cmd_clone
  remote: die on config error when manipulating remotes
  remote: die on config error when setting/adding branches
  remote: die on config error when setting URL
  submodule--helper: die on config error when cloning module
  submodule: die on config error when linking modules
  branch: die on config error when editing branch description
  branch: die on config error when unsetting upstream
  branch: report errors in tracking branch setup
  config: introduce set_or_die wrappers
This commit is contained in:
Junio C Hamano 2016-02-26 13:37:19 -08:00
Родитель 56d4e7e6c3 3d1806487a
Коммит 225caa73f2
13 изменённых файлов: 159 добавлений и 105 удалений

Просмотреть файл

@ -49,7 +49,13 @@ static int should_setup_rebase(const char *origin)
return 0;
}
void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
static const char tracking_advice[] =
N_("\n"
"After fixing the error cause you may try to fix up\n"
"the remote tracking information by invoking\n"
"\"git branch --set-upstream-to=%s%s%s\".");
int install_branch_config(int flag, const char *local, const char *origin, const char *remote)
{
const char *shortname = NULL;
struct strbuf key = STRBUF_INIT;
@ -60,20 +66,23 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
&& !origin) {
warning(_("Not setting branch %s as its own upstream."),
local);
return;
return 0;
}
strbuf_addf(&key, "branch.%s.remote", local);
git_config_set(key.buf, origin ? origin : ".");
if (git_config_set_gently(key.buf, origin ? origin : ".") < 0)
goto out_err;
strbuf_reset(&key);
strbuf_addf(&key, "branch.%s.merge", local);
git_config_set(key.buf, remote);
if (git_config_set_gently(key.buf, remote) < 0)
goto out_err;
if (rebasing) {
strbuf_reset(&key);
strbuf_addf(&key, "branch.%s.rebase", local);
git_config_set(key.buf, "true");
if (git_config_set_gently(key.buf, "true") < 0)
goto out_err;
}
strbuf_release(&key);
@ -102,6 +111,19 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
local, remote);
}
}
return 0;
out_err:
strbuf_release(&key);
error(_("Unable to write upstream branch configuration"));
advise(_(tracking_advice),
origin ? origin : "",
origin ? "/" : "",
shortname ? shortname : remote);
return -1;
}
/*
@ -109,8 +131,8 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
* to infer the settings for branch.<new_ref>.{remote,merge} from the
* config.
*/
static int setup_tracking(const char *new_ref, const char *orig_ref,
enum branch_track track, int quiet)
static void setup_tracking(const char *new_ref, const char *orig_ref,
enum branch_track track, int quiet)
{
struct tracking tracking;
int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
@ -118,7 +140,7 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
memset(&tracking, 0, sizeof(tracking));
tracking.spec.dst = (char *)orig_ref;
if (for_each_remote(find_tracked_branch, &tracking))
return 1;
return;
if (!tracking.matches)
switch (track) {
@ -127,18 +149,18 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
case BRANCH_TRACK_OVERRIDE:
break;
default:
return 1;
return;
}
if (tracking.matches > 1)
return error(_("Not tracking: ambiguous information for ref %s"),
orig_ref);
die(_("Not tracking: ambiguous information for ref %s"),
orig_ref);
install_branch_config(config_flags, new_ref, tracking.remote,
tracking.src ? tracking.src : orig_ref);
if (install_branch_config(config_flags, new_ref, tracking.remote,
tracking.src ? tracking.src : orig_ref) < 0)
exit(-1);
free(tracking.src);
return 0;
}
int read_branch_desc(struct strbuf *buf, const char *branch_name)

Просмотреть файл

@ -43,9 +43,10 @@ void remove_branch_state(void);
/*
* Configure local branch "local" as downstream to branch "remote"
* from remote "origin". Used by git branch --set-upstream.
* Returns 0 on success.
*/
#define BRANCH_CONFIG_VERBOSE 01
extern void install_branch_config(int flag, const char *local, const char *origin, const char *remote);
extern int install_branch_config(int flag, const char *local, const char *origin, const char *remote);
/*
* Read branch description

Просмотреть файл

@ -570,7 +570,6 @@ static const char edit_description[] = "BRANCH_DESCRIPTION";
static int edit_branch_description(const char *branch_name)
{
int status;
struct strbuf buf = STRBUF_INIT;
struct strbuf name = STRBUF_INIT;
@ -595,11 +594,11 @@ static int edit_branch_description(const char *branch_name)
strbuf_stripspace(&buf, 1);
strbuf_addf(&name, "branch.%s.description", branch_name);
status = git_config_set(name.buf, buf.len ? buf.buf : NULL);
git_config_set(name.buf, buf.len ? buf.buf : NULL);
strbuf_release(&name);
strbuf_release(&buf);
return status;
return 0;
}
int cmd_branch(int argc, const char **argv, const char *prefix)

Просмотреть файл

@ -740,7 +740,7 @@ static int checkout(void)
static int write_one_config(const char *key, const char *value, void *data)
{
return git_config_set_multivar(key, value ? value : "true", "^$", 0);
return git_config_set_multivar_gently(key, value ? value : "true", "^$", 0);
}
static void write_config(struct string_list *config)

Просмотреть файл

@ -615,7 +615,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_write();
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
ret = git_config_set_in_file(given_config_source.file, argv[0], value);
ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
if (ret == CONFIG_NOTHING_SET)
error("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s.", argv[0]);
@ -625,23 +625,23 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_write();
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
return git_config_set_multivar_in_file(given_config_source.file,
argv[0], value, argv[2], 0);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], value, argv[2], 0);
}
else if (actions == ACTION_ADD) {
check_write();
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
return git_config_set_multivar_in_file(given_config_source.file,
argv[0], value,
CONFIG_REGEX_NONE, 0);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], value,
CONFIG_REGEX_NONE, 0);
}
else if (actions == ACTION_REPLACE_ALL) {
check_write();
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
return git_config_set_multivar_in_file(given_config_source.file,
argv[0], value, argv[2], 1);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], value, argv[2], 1);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
@ -667,17 +667,17 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_write();
check_argc(argc, 1, 2);
if (argc == 2)
return git_config_set_multivar_in_file(given_config_source.file,
argv[0], NULL, argv[1], 0);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], NULL, argv[1], 0);
else
return git_config_set_in_file(given_config_source.file,
argv[0], NULL);
return git_config_set_in_file_gently(given_config_source.file,
argv[0], NULL);
}
else if (actions == ACTION_UNSET_ALL) {
check_write();
check_argc(argc, 1, 2);
return git_config_set_multivar_in_file(given_config_source.file,
argv[0], NULL, argv[1], 1);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], NULL, argv[1], 1);
}
else if (actions == ACTION_RENAME_SECTION) {
int ret;

Просмотреть файл

@ -250,7 +250,7 @@ static int create_default_files(const char *template_path)
git_config_set("core.bare", "false");
/* allow template config file to override the default */
if (log_all_ref_updates == -1)
git_config_set("core.logallrefupdates", "true");
git_config_set("core.logallrefupdates", "true");
if (needs_work_tree_config(get_git_dir(), work_tree))
git_config_set("core.worktree", work_tree);
}

Просмотреть файл

@ -108,8 +108,8 @@ enum {
#define MIRROR_PUSH 2
#define MIRROR_BOTH (MIRROR_FETCH|MIRROR_PUSH)
static int add_branch(const char *key, const char *branchname,
const char *remotename, int mirror, struct strbuf *tmp)
static void add_branch(const char *key, const char *branchname,
const char *remotename, int mirror, struct strbuf *tmp)
{
strbuf_reset(tmp);
strbuf_addch(tmp, '+');
@ -119,7 +119,7 @@ static int add_branch(const char *key, const char *branchname,
else
strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s",
branchname, remotename, branchname);
return git_config_set_multivar(key, tmp->buf, "^$", 0);
git_config_set_multivar(key, tmp->buf, "^$", 0);
}
static const char mirror_advice[] =
@ -194,8 +194,7 @@ static int add(int argc, const char **argv)
die(_("'%s' is not a valid remote name"), name);
strbuf_addf(&buf, "remote.%s.url", name);
if (git_config_set(buf.buf, url))
return 1;
git_config_set(buf.buf, url);
if (!mirror || mirror & MIRROR_FETCH) {
strbuf_reset(&buf);
@ -203,25 +202,22 @@ static int add(int argc, const char **argv)
if (track.nr == 0)
string_list_append(&track, "*");
for (i = 0; i < track.nr; i++) {
if (add_branch(buf.buf, track.items[i].string,
name, mirror, &buf2))
return 1;
add_branch(buf.buf, track.items[i].string,
name, mirror, &buf2);
}
}
if (mirror & MIRROR_PUSH) {
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.mirror", name);
if (git_config_set(buf.buf, "true"))
return 1;
git_config_set(buf.buf, "true");
}
if (fetch_tags != TAGS_DEFAULT) {
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.tagopt", name);
if (git_config_set(buf.buf,
fetch_tags == TAGS_SET ? "--tags" : "--no-tags"))
return 1;
git_config_set(buf.buf,
fetch_tags == TAGS_SET ? "--tags" : "--no-tags");
}
if (fetch && fetch_remote(name))
@ -589,25 +585,20 @@ static int migrate_file(struct remote *remote)
strbuf_addf(&buf, "remote.%s.url", remote->name);
for (i = 0; i < remote->url_nr; i++)
if (git_config_set_multivar(buf.buf, remote->url[i], "^$", 0))
return error(_("Could not append '%s' to '%s'"),
remote->url[i], buf.buf);
git_config_set_multivar(buf.buf, remote->url[i], "^$", 0);
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.push", remote->name);
for (i = 0; i < remote->push_refspec_nr; i++)
if (git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0))
return error(_("Could not append '%s' to '%s'"),
remote->push_refspec[i], buf.buf);
git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0);
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", remote->name);
for (i = 0; i < remote->fetch_refspec_nr; i++)
if (git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0))
return error(_("Could not append '%s' to '%s'"),
remote->fetch_refspec[i], buf.buf);
git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0);
if (remote->origin == REMOTE_REMOTES)
unlink_or_warn(git_path("remotes/%s", remote->name));
else if (remote->origin == REMOTE_BRANCHES)
unlink_or_warn(git_path("branches/%s", remote->name));
return 0;
}
@ -654,8 +645,7 @@ static int mv(int argc, const char **argv)
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", rename.new);
if (git_config_set_multivar(buf.buf, NULL, NULL, 1))
return error(_("Could not remove config section '%s'"), buf.buf);
git_config_set_multivar(buf.buf, NULL, NULL, 1);
strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old);
for (i = 0; i < oldremote->fetch_refspec_nr; i++) {
char *ptr;
@ -675,8 +665,7 @@ static int mv(int argc, const char **argv)
"\tPlease update the configuration manually if necessary."),
buf2.buf);
if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
return error(_("Could not append '%s'"), buf.buf);
git_config_set_multivar(buf.buf, buf2.buf, "^$", 0);
}
read_branches();
@ -686,9 +675,7 @@ static int mv(int argc, const char **argv)
if (info->remote_name && !strcmp(info->remote_name, rename.old)) {
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.remote", item->string);
if (git_config_set(buf.buf, rename.new)) {
return error(_("Could not set '%s'"), buf.buf);
}
git_config_set(buf.buf, rename.new);
}
}
@ -786,10 +773,7 @@ static int rm(int argc, const char **argv)
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.%s",
item->string, *k);
if (git_config_set(buf.buf, NULL)) {
strbuf_release(&buf);
return -1;
}
git_config_set(buf.buf, NULL);
}
}
}
@ -1410,24 +1394,20 @@ static int update(int argc, const char **argv)
static int remove_all_fetch_refspecs(const char *remote, const char *key)
{
return git_config_set_multivar(key, NULL, NULL, 1);
return git_config_set_multivar_gently(key, NULL, NULL, 1);
}
static int add_branches(struct remote *remote, const char **branches,
const char *key)
static void add_branches(struct remote *remote, const char **branches,
const char *key)
{
const char *remotename = remote->name;
int mirror = remote->mirror;
struct strbuf refspec = STRBUF_INIT;
for (; *branches; branches++)
if (add_branch(key, *branches, remotename, mirror, &refspec)) {
strbuf_release(&refspec);
return 1;
}
add_branch(key, *branches, remotename, mirror, &refspec);
strbuf_release(&refspec);
return 0;
}
static int set_remote_branches(const char *remotename, const char **branches,
@ -1446,10 +1426,7 @@ static int set_remote_branches(const char *remotename, const char **branches,
strbuf_release(&key);
return 1;
}
if (add_branches(remote, branches, key.buf)) {
strbuf_release(&key);
return 1;
}
add_branches(remote, branches, key.buf);
strbuf_release(&key);
return 0;
@ -1581,10 +1558,11 @@ static int set_url(int argc, const char **argv)
if ((!oldurl && !delete_mode) || add_mode) {
if (add_mode)
git_config_set_multivar(name_buf.buf, newurl,
"^$", 0);
"^$", 0);
else
git_config_set(name_buf.buf, newurl);
strbuf_release(&name_buf);
return 0;
}

14
cache.h
Просмотреть файл

@ -1489,7 +1489,7 @@ extern int update_server_info(int);
/* git_config_parse_key() returns these negated: */
#define CONFIG_INVALID_KEY 1
#define CONFIG_NO_SECTION_OR_NAME 2
/* git_config_set(), git_config_set_multivar() return the above or these: */
/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */
#define CONFIG_NO_LOCK -1
#define CONFIG_INVALID_FILE 3
#define CONFIG_NO_WRITE 4
@ -1527,12 +1527,16 @@ extern int git_config_bool(const char *, const char *);
extern int git_config_maybe_bool(const char *, const char *);
extern int git_config_string(const char **, const char *, const char *);
extern int git_config_pathname(const char **, const char *, const char *);
extern int git_config_set_in_file(const char *, const char *, const char *);
extern int git_config_set(const char *, const char *);
extern int git_config_set_in_file_gently(const char *, const char *, const char *);
extern void git_config_set_in_file(const char *, const char *, const char *);
extern int git_config_set_gently(const char *, const char *);
extern void git_config_set(const char *, const char *);
extern int git_config_parse_key(const char *, char **, int *);
extern int git_config_key_is_valid(const char *key);
extern int git_config_set_multivar(const char *, const char *, const char *, int);
extern int git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
extern int git_config_set_multivar_gently(const char *, const char *, const char *, int);
extern void git_config_set_multivar(const char *, const char *, const char *, int);
extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);
extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
extern int git_config_rename_section(const char *, const char *);
extern int git_config_rename_section_in_file(const char *, const char *, const char *);
extern const char *git_etc_gitconfig(void);

Просмотреть файл

@ -50,7 +50,8 @@ void probe_utf8_pathname_composition(void)
close(output_fd);
git_path_buf(&path, "%s", auml_nfd);
precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;
git_config_set("core.precomposeunicode", precomposed_unicode ? "true" : "false");
git_config_set("core.precomposeunicode",
precomposed_unicode ? "true" : "false");
git_path_buf(&path, "%s", auml_nfc);
if (unlink(path.buf))
die_errno(_("failed to unlink '%s'"), path.buf);

Просмотреть файл

@ -1853,15 +1853,26 @@ contline:
return offset;
}
int git_config_set_in_file(const char *config_filename,
const char *key, const char *value)
int git_config_set_in_file_gently(const char *config_filename,
const char *key, const char *value)
{
return git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, 0);
}
int git_config_set(const char *key, const char *value)
void git_config_set_in_file(const char *config_filename,
const char *key, const char *value)
{
return git_config_set_multivar(key, value, NULL, 0);
git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
}
int git_config_set_gently(const char *key, const char *value)
{
return git_config_set_multivar_gently(key, value, NULL, 0);
}
void git_config_set(const char *key, const char *value)
{
git_config_set_multivar(key, value, NULL, 0);
}
/*
@ -1976,9 +1987,10 @@ int git_config_key_is_valid(const char *key)
* - the config file is removed and the lock file rename()d to it.
*
*/
int git_config_set_multivar_in_file(const char *config_filename,
const char *key, const char *value,
const char *value_regex, int multi_replace)
int git_config_set_multivar_in_file_gently(const char *config_filename,
const char *key, const char *value,
const char *value_regex,
int multi_replace)
{
int fd = -1, in_fd = -1;
int ret;
@ -2205,11 +2217,27 @@ write_err_out:
}
int git_config_set_multivar(const char *key, const char *value,
const char *value_regex, int multi_replace)
void git_config_set_multivar_in_file(const char *config_filename,
const char *key, const char *value,
const char *value_regex, int multi_replace)
{
return git_config_set_multivar_in_file(NULL, key, value, value_regex,
multi_replace);
if (git_config_set_multivar_in_file_gently(config_filename, key, value,
value_regex, multi_replace) < 0)
die(_("Could not set '%s' to '%s'"), key, value);
}
int git_config_set_multivar_gently(const char *key, const char *value,
const char *value_regex, int multi_replace)
{
return git_config_set_multivar_in_file_gently(NULL, key, value, value_regex,
multi_replace);
}
void git_config_set_multivar(const char *key, const char *value,
const char *value_regex, int multi_replace)
{
git_config_set_multivar_in_file(NULL, key, value, value_regex,
multi_replace);
}
static int section_name_match (const char *buf, const char *name)

Просмотреть файл

@ -69,7 +69,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)
strbuf_addstr(&entry, "submodule.");
strbuf_addstr(&entry, submodule->name);
strbuf_addstr(&entry, ".path");
if (git_config_set_in_file(".gitmodules", entry.buf, newpath) < 0) {
if (git_config_set_in_file_gently(".gitmodules", entry.buf, newpath) < 0) {
/* Maybe the user already did that, don't error out here */
warning(_("Could not update .gitmodules entry %s"), entry.buf);
strbuf_release(&entry);
@ -1087,11 +1087,9 @@ void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir)
/* Update core.worktree setting */
strbuf_reset(&file_name);
strbuf_addf(&file_name, "%s/config", git_dir);
if (git_config_set_in_file(file_name.buf, "core.worktree",
relative_path(real_work_tree, git_dir,
&rel_path)))
die(_("Could not set core.worktree in %s"),
file_name.buf);
git_config_set_in_file(file_name.buf, "core.worktree",
relative_path(real_work_tree, git_dir,
&rel_path));
strbuf_release(&file_name);
strbuf_release(&rel_path);

Просмотреть файл

@ -446,6 +446,13 @@ test_expect_success '--set-upstream-to fails on a non-ref' '
test_must_fail git branch --set-upstream-to HEAD^{}
'
test_expect_success '--set-upstream-to fails on locked config' '
test_when_finished "rm -f .git/config.lock" &&
>.git/config.lock &&
git branch locked &&
test_must_fail git branch --set-upstream-to locked
'
test_expect_success 'use --set-upstream-to modify HEAD' '
test_config branch.master.remote foo &&
test_config branch.master.merge foo &&
@ -466,6 +473,13 @@ test_expect_success '--unset-upstream should fail if given a non-existent branch
test_must_fail git branch --unset-upstream i-dont-exist
'
test_expect_success '--unset-upstream should fail if config is locked' '
test_when_finished "rm -f .git/config.lock" &&
git branch --set-upstream-to locked &&
>.git/config.lock &&
test_must_fail git branch --unset-upstream
'
test_expect_success 'test --unset-upstream on HEAD' '
git branch my14 &&
test_config branch.master.remote foo &&
@ -579,7 +593,7 @@ test_expect_success 'avoid ambiguous track' '
git config remote.ambi1.fetch refs/heads/lalala:refs/heads/master &&
git config remote.ambi2.url lilili &&
git config remote.ambi2.fetch refs/heads/lilili:refs/heads/master &&
git branch all1 master &&
test_must_fail git branch all1 master &&
test -z "$(git config branch.all1.merge)"
'

Просмотреть файл

@ -970,6 +970,15 @@ test_expect_success 'get-url on new remote' '
echo foo | get_url_test --push --all someremote
'
test_expect_success 'remote set-url with locked config' '
test_when_finished "rm -f .git/config.lock" &&
git config --get-all remote.someremote.url >expect &&
>.git/config.lock &&
test_must_fail git remote set-url someremote baz &&
git config --get-all remote.someremote.url >actual &&
cmp expect actual
'
test_expect_success 'remote set-url bar' '
git remote set-url someremote bar &&
echo bar >expect &&