sequencer: stop exporting GIT_REFLOG_ACTION

Each time it picks a commit the sequencer copies the GIT_REFLOG_ACITON
environment variable so it can temporarily change it and then restore
the previous value. This results in code that is hard to follow and also
leaks memory because (i) we fail to free the copy when we've finished
with it and (ii) each call to setenv() leaks the previous value. Instead
pass the reflog action around in a variable and use it to set
GIT_REFLOG_ACTION in the child environment when running "git commit".

Within the sequencer GIT_REFLOG_ACTION is no longer set and is only read
by sequencer_reflog_action(). It is still set by rebase before calling
the sequencer, that will be addressed in the next commit. cherry-pick
and revert are unaffected as they do not set GIT_REFLOG_ACTION before
calling the sequencer.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Reviewed-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
This commit is contained in:
Phillip Wood 2022-11-09 14:21:57 +00:00 committed by Taylor Blau
parent 3b08839926
commit d188a60d72
2 changed files with 31 additions and 20 deletions

View File

@ -375,6 +375,7 @@ int sequencer_remove_state(struct replay_opts *opts)
}
free(opts->gpg_sign);
free(opts->reflog_action);
free(opts->default_strategy);
free(opts->strategy);
for (i = 0; i < opts->xopts_nr; i++)
@ -1050,6 +1051,8 @@ static int run_git_commit(const char *defmsg,
gpg_opt, gpg_opt);
}
strvec_pushf(&cmd.env, GIT_REFLOG_ACTION "=%s", opts->reflog_message);
if (opts->committer_date_is_author_date)
strvec_pushf(&cmd.env, "GIT_COMMITTER_DATE=%s",
opts->ignore_date ?
@ -1589,8 +1592,8 @@ static int try_to_commit(struct repository *r,
goto out;
}
if (update_head_with_reflog(current_head, oid,
getenv("GIT_REFLOG_ACTION"), msg, &err)) {
if (update_head_with_reflog(current_head, oid, opts->reflog_message,
msg, &err)) {
res = error("%s", err.buf);
goto out;
}
@ -3674,17 +3677,28 @@ static int do_label(struct repository *r, const char *name, int len)
return ret;
}
static const char *sequencer_reflog_action(struct replay_opts *opts)
{
if (!opts->reflog_action) {
opts->reflog_action = getenv(GIT_REFLOG_ACTION);
opts->reflog_action =
xstrdup(opts->reflog_action ? opts->reflog_action
: action_name(opts));
}
return opts->reflog_action;
}
__attribute__((format (printf, 3, 4)))
static const char *reflog_message(struct replay_opts *opts,
const char *sub_action, const char *fmt, ...)
{
va_list ap;
static struct strbuf buf = STRBUF_INIT;
char *reflog_action = getenv(GIT_REFLOG_ACTION);
va_start(ap, fmt);
strbuf_reset(&buf);
strbuf_addstr(&buf, reflog_action ? reflog_action : action_name(opts));
strbuf_addstr(&buf, sequencer_reflog_action(opts));
if (sub_action)
strbuf_addf(&buf, " (%s)", sub_action);
if (fmt) {
@ -4497,7 +4511,7 @@ static int checkout_onto(struct repository *r, struct replay_opts *opts,
RESET_HEAD_RUN_POST_CHECKOUT_HOOK,
.head_msg = reflog_message(opts, "start", "checkout %s",
onto_name),
.default_reflog_action = "rebase"
.default_reflog_action = sequencer_reflog_action(opts)
};
if (reset_head(r, &ropts)) {
apply_autostash(rebase_path_autostash());
@ -4566,11 +4580,8 @@ static int pick_commits(struct repository *r,
struct replay_opts *opts)
{
int res = 0, reschedule = 0;
char *prev_reflog_action;
/* Note that 0 for 3rd parameter of setenv means set only if not set */
setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
prev_reflog_action = xstrdup(getenv(GIT_REFLOG_ACTION));
opts->reflog_message = sequencer_reflog_action(opts);
if (opts->allow_ff)
assert(!(opts->signoff || opts->no_commit ||
opts->record_origin || should_edit(opts) ||
@ -4618,14 +4629,12 @@ static int pick_commits(struct repository *r,
}
if (item->command <= TODO_SQUASH) {
if (is_rebase_i(opts))
setenv(GIT_REFLOG_ACTION, reflog_message(opts,
command_to_string(item->command), NULL),
1);
opts->reflog_message = reflog_message(opts,
command_to_string(item->command), NULL);
res = do_pick_commit(r, item, opts,
is_final_fixup(todo_list),
&check_todo);
if (is_rebase_i(opts))
setenv(GIT_REFLOG_ACTION, prev_reflog_action, 1);
if (is_rebase_i(opts) && res < 0) {
/* Reschedule */
advise(_(rescheduled_advice),
@ -5050,8 +5059,6 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts)
if (read_populate_opts(opts))
return -1;
if (is_rebase_i(opts)) {
char *previous_reflog_action;
if ((res = read_populate_todo(r, &todo_list, opts)))
goto release_todo_list;
@ -5062,13 +5069,11 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts)
unlink(rebase_path_dropped());
}
previous_reflog_action = xstrdup(getenv(GIT_REFLOG_ACTION));
setenv(GIT_REFLOG_ACTION, reflog_message(opts, "continue", NULL), 1);
opts->reflog_message = reflog_message(opts, "continue", NULL);
if (commit_staged_changes(r, opts, &todo_list)) {
res = -1;
goto release_todo_list;
}
setenv(GIT_REFLOG_ACTION, previous_reflog_action, 1);
} else if (!file_exists(get_todo_path(opts)))
return continue_single_pick(r, opts);
else if ((res = read_populate_todo(r, &todo_list, opts)))
@ -5116,7 +5121,7 @@ static int single_pick(struct repository *r,
TODO_PICK : TODO_REVERT;
item.commit = cmit;
setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
opts->reflog_message = sequencer_reflog_action(opts);
return do_pick_commit(r, &item, opts, 0, &check_todo);
}

View File

@ -63,6 +63,9 @@ struct replay_opts {
char **xopts;
size_t xopts_nr, xopts_alloc;
/* Reflog */
char *reflog_action;
/* Used by fixup/squash */
struct strbuf current_fixups;
int current_fixup_count;
@ -73,6 +76,9 @@ struct replay_opts {
/* Only used by REPLAY_NONE */
struct rev_info *revs;
/* Private use */
const char *reflog_message;
};
#define REPLAY_OPTS_INIT { .edit = -1, .action = -1, .current_fixups = STRBUF_INIT }