sequencer: refactor rearrange_squash() to work on a todo_list
This refactors rearrange_squash() to work on a todo_list to avoid redundant reads and writes. The function is renamed todo_list_rearrange_squash(). The old version created a new buffer, which was directly written to the disk. This new version creates a new item list by just copying items from the old item list, without creating a new buffer. This eliminates the need to reparse the todo list, but this also means its buffer cannot be directly written to the disk. As rebase -p still need to check the todo list from the disk, a new function is introduced, rearrange_squash_in_todo_file(). complete_action() still uses rearrange_squash_in_todo_file() for now. This will be changed in a future commit. Signed-off-by: Alban Gruin <alban.gruin@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
683153a438
commit
f2a04904be
@ -268,7 +268,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
|
|||||||
ret = check_todo_list_from_file(the_repository);
|
ret = check_todo_list_from_file(the_repository);
|
||||||
break;
|
break;
|
||||||
case REARRANGE_SQUASH:
|
case REARRANGE_SQUASH:
|
||||||
ret = rearrange_squash(the_repository);
|
ret = rearrange_squash_in_todo_file(the_repository);
|
||||||
break;
|
break;
|
||||||
case ADD_EXEC:
|
case ADD_EXEC:
|
||||||
ret = sequencer_add_exec_commands(the_repository, &commands);
|
ret = sequencer_add_exec_commands(the_repository, &commands);
|
||||||
|
92
sequencer.c
92
sequencer.c
@ -4840,7 +4840,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
|
|||||||
write_message("noop\n", 5, todo_file, 0))
|
write_message("noop\n", 5, todo_file, 0))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (autosquash && rearrange_squash(r))
|
if (autosquash && rearrange_squash_in_todo_file(r))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (commands->nr)
|
if (commands->nr)
|
||||||
@ -4946,21 +4946,13 @@ define_commit_slab(commit_todo_item, struct todo_item *);
|
|||||||
* message will have to be retrieved from the commit (as the oneline in the
|
* message will have to be retrieved from the commit (as the oneline in the
|
||||||
* script cannot be trusted) in order to normalize the autosquash arrangement.
|
* script cannot be trusted) in order to normalize the autosquash arrangement.
|
||||||
*/
|
*/
|
||||||
int rearrange_squash(struct repository *r)
|
static int todo_list_rearrange_squash(struct todo_list *todo_list)
|
||||||
{
|
{
|
||||||
const char *todo_file = rebase_path_todo();
|
|
||||||
struct todo_list todo_list = TODO_LIST_INIT;
|
|
||||||
struct hashmap subject2item;
|
struct hashmap subject2item;
|
||||||
int res = 0, rearranged = 0, *next, *tail, i;
|
int rearranged = 0, *next, *tail, i, nr = 0, alloc = 0;
|
||||||
char **subjects;
|
char **subjects;
|
||||||
struct commit_todo_item commit_todo;
|
struct commit_todo_item commit_todo;
|
||||||
|
struct todo_item *items = NULL;
|
||||||
if (strbuf_read_file_or_whine(&todo_list.buf, todo_file) < 0)
|
|
||||||
return -1;
|
|
||||||
if (todo_list_parse_insn_buffer(r, todo_list.buf.buf, &todo_list) < 0) {
|
|
||||||
todo_list_release(&todo_list);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_commit_todo_item(&commit_todo);
|
init_commit_todo_item(&commit_todo);
|
||||||
/*
|
/*
|
||||||
@ -4973,13 +4965,13 @@ int rearrange_squash(struct repository *r)
|
|||||||
* be moved to appear after the i'th.
|
* be moved to appear after the i'th.
|
||||||
*/
|
*/
|
||||||
hashmap_init(&subject2item, (hashmap_cmp_fn) subject2item_cmp,
|
hashmap_init(&subject2item, (hashmap_cmp_fn) subject2item_cmp,
|
||||||
NULL, todo_list.nr);
|
NULL, todo_list->nr);
|
||||||
ALLOC_ARRAY(next, todo_list.nr);
|
ALLOC_ARRAY(next, todo_list->nr);
|
||||||
ALLOC_ARRAY(tail, todo_list.nr);
|
ALLOC_ARRAY(tail, todo_list->nr);
|
||||||
ALLOC_ARRAY(subjects, todo_list.nr);
|
ALLOC_ARRAY(subjects, todo_list->nr);
|
||||||
for (i = 0; i < todo_list.nr; i++) {
|
for (i = 0; i < todo_list->nr; i++) {
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
struct todo_item *item = todo_list.items + i;
|
struct todo_item *item = todo_list->items + i;
|
||||||
const char *commit_buffer, *subject, *p;
|
const char *commit_buffer, *subject, *p;
|
||||||
size_t subject_len;
|
size_t subject_len;
|
||||||
int i2 = -1;
|
int i2 = -1;
|
||||||
@ -4992,7 +4984,6 @@ int rearrange_squash(struct repository *r)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_fixup(item->command)) {
|
if (is_fixup(item->command)) {
|
||||||
todo_list_release(&todo_list);
|
|
||||||
clear_commit_todo_item(&commit_todo);
|
clear_commit_todo_item(&commit_todo);
|
||||||
return error(_("the script was already rearranged."));
|
return error(_("the script was already rearranged."));
|
||||||
}
|
}
|
||||||
@ -5027,7 +5018,7 @@ int rearrange_squash(struct repository *r)
|
|||||||
*commit_todo_item_at(&commit_todo, commit2))
|
*commit_todo_item_at(&commit_todo, commit2))
|
||||||
/* found by commit name */
|
/* found by commit name */
|
||||||
i2 = *commit_todo_item_at(&commit_todo, commit2)
|
i2 = *commit_todo_item_at(&commit_todo, commit2)
|
||||||
- todo_list.items;
|
- todo_list->items;
|
||||||
else {
|
else {
|
||||||
/* copy can be a prefix of the commit subject */
|
/* copy can be a prefix of the commit subject */
|
||||||
for (i2 = 0; i2 < i; i2++)
|
for (i2 = 0; i2 < i; i2++)
|
||||||
@ -5040,7 +5031,7 @@ int rearrange_squash(struct repository *r)
|
|||||||
}
|
}
|
||||||
if (i2 >= 0) {
|
if (i2 >= 0) {
|
||||||
rearranged = 1;
|
rearranged = 1;
|
||||||
todo_list.items[i].command =
|
todo_list->items[i].command =
|
||||||
starts_with(subject, "fixup!") ?
|
starts_with(subject, "fixup!") ?
|
||||||
TODO_FIXUP : TODO_SQUASH;
|
TODO_FIXUP : TODO_SQUASH;
|
||||||
if (next[i2] < 0)
|
if (next[i2] < 0)
|
||||||
@ -5058,10 +5049,8 @@ int rearrange_squash(struct repository *r)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rearranged) {
|
if (rearranged) {
|
||||||
struct strbuf buf = STRBUF_INIT;
|
for (i = 0; i < todo_list->nr; i++) {
|
||||||
|
enum todo_command command = todo_list->items[i].command;
|
||||||
for (i = 0; i < todo_list.nr; i++) {
|
|
||||||
enum todo_command command = todo_list.items[i].command;
|
|
||||||
int cur = i;
|
int cur = i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -5072,37 +5061,50 @@ int rearrange_squash(struct repository *r)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
while (cur >= 0) {
|
while (cur >= 0) {
|
||||||
const char *bol =
|
ALLOC_GROW(items, nr + 1, alloc);
|
||||||
get_item_line(&todo_list, cur);
|
items[nr++] = todo_list->items[cur];
|
||||||
const char *eol =
|
|
||||||
get_item_line(&todo_list, cur + 1);
|
|
||||||
|
|
||||||
/* replace 'pick', by 'fixup' or 'squash' */
|
|
||||||
command = todo_list.items[cur].command;
|
|
||||||
if (is_fixup(command)) {
|
|
||||||
strbuf_addstr(&buf,
|
|
||||||
todo_command_info[command].str);
|
|
||||||
bol += strcspn(bol, " \t");
|
|
||||||
}
|
|
||||||
|
|
||||||
strbuf_add(&buf, bol, eol - bol);
|
|
||||||
|
|
||||||
cur = next[cur];
|
cur = next[cur];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res = rewrite_file(todo_file, buf.buf, buf.len);
|
FREE_AND_NULL(todo_list->items);
|
||||||
strbuf_release(&buf);
|
todo_list->items = items;
|
||||||
|
todo_list->nr = nr;
|
||||||
|
todo_list->alloc = alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(next);
|
free(next);
|
||||||
free(tail);
|
free(tail);
|
||||||
for (i = 0; i < todo_list.nr; i++)
|
for (i = 0; i < todo_list->nr; i++)
|
||||||
free(subjects[i]);
|
free(subjects[i]);
|
||||||
free(subjects);
|
free(subjects);
|
||||||
hashmap_free(&subject2item, 1);
|
hashmap_free(&subject2item, 1);
|
||||||
todo_list_release(&todo_list);
|
|
||||||
|
|
||||||
clear_commit_todo_item(&commit_todo);
|
clear_commit_todo_item(&commit_todo);
|
||||||
return res;
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rearrange_squash_in_todo_file(struct repository *r)
|
||||||
|
{
|
||||||
|
const char *todo_file = rebase_path_todo();
|
||||||
|
struct todo_list todo_list = TODO_LIST_INIT;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
if (strbuf_read_file_or_whine(&todo_list.buf, todo_file) < 0)
|
||||||
|
return -1;
|
||||||
|
if (todo_list_parse_insn_buffer(r, todo_list.buf.buf, &todo_list) < 0) {
|
||||||
|
todo_list_release(&todo_list);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = todo_list_rearrange_squash(&todo_list);
|
||||||
|
if (!res)
|
||||||
|
res = todo_list_write_to_file(r, &todo_list, todo_file, NULL, NULL, -1, 0);
|
||||||
|
|
||||||
|
todo_list_release(&todo_list);
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
return error_errno(_("could not write '%s'."), todo_file);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
|
|||||||
const char *shortrevisions, const char *onto_name,
|
const char *shortrevisions, const char *onto_name,
|
||||||
const char *onto, const char *orig_head, struct string_list *commands,
|
const char *onto, const char *orig_head, struct string_list *commands,
|
||||||
unsigned autosquash);
|
unsigned autosquash);
|
||||||
int rearrange_squash(struct repository *r);
|
int rearrange_squash_in_todo_file(struct repository *r);
|
||||||
|
|
||||||
extern const char sign_off_header[];
|
extern const char sign_off_header[];
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user