diff options
Diffstat (limited to 'sequencer.c')
-rw-r--r-- | sequencer.c | 87 |
1 files changed, 62 insertions, 25 deletions
diff --git a/sequencer.c b/sequencer.c index 7dc13fdcca..3c5fdd68f4 100644 --- a/sequencer.c +++ b/sequencer.c @@ -51,6 +51,15 @@ #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" +/* + * To accommodate common filesystem limitations, where the loose refs' file + * names must not exceed `NAME_MAX`, the labels generated by `git rebase + * --rebase-merges` need to be truncated if the corresponding commit subjects + * are too long. + * Add some margin to stay clear from reaching `NAME_MAX`. + */ +#define GIT_MAX_LABEL_LENGTH ((NAME_MAX) - (LOCK_SUFFIX_LEN) - 16) + static const char sign_off_header[] = "Signed-off-by: "; static const char cherry_picked_prefix[] = "(cherry picked from commit "; @@ -424,10 +433,9 @@ struct commit_message { const char *message; }; -static const char *short_commit_name(struct commit *commit) +static const char *short_commit_name(struct repository *r, struct commit *commit) { - return repo_find_unique_abbrev(the_repository, &commit->object.oid, - DEFAULT_ABBREV); + return repo_find_unique_abbrev(r, &commit->object.oid, DEFAULT_ABBREV); } static int get_message(struct commit *commit, struct commit_message *out) @@ -437,7 +445,7 @@ static int get_message(struct commit *commit, struct commit_message *out) out->message = repo_logmsg_reencode(the_repository, commit, NULL, get_commit_output_encoding()); - abbrev = short_commit_name(commit); + abbrev = short_commit_name(the_repository, commit); subject_len = find_commit_subject(out->message, &subject); @@ -2322,7 +2330,7 @@ static int do_pick_commit(struct repository *r, const char *dest = git_path_squash_msg(r); unlink(dest); if (copy_file(dest, rebase_path_squash_msg(), 0666)) { - res = error(_("could not rename '%s' to '%s'"), + res = error(_("could not copy '%s' to '%s'"), rebase_path_squash_msg(), dest); goto leave; } @@ -2385,7 +2393,7 @@ static int do_pick_commit(struct repository *r, error(command == TODO_REVERT ? _("could not revert %s... %s") : _("could not apply %s... %s"), - short_commit_name(commit), msg.subject); + short_commit_name(r, commit), msg.subject); print_advice(r, res == 1, opts); repo_rerere(r, opts->allow_rerere_auto); goto leave; @@ -2652,7 +2660,7 @@ static int parse_insn_line(struct repository *r, struct todo_item *item, return item->commit ? 0 : -1; } -int sequencer_get_last_command(struct repository *r, enum replay_action *action) +int sequencer_get_last_command(struct repository *r UNUSED, enum replay_action *action) { const char *todo_file, *bol; struct strbuf buf = STRBUF_INIT; @@ -3174,7 +3182,8 @@ static int walk_revs_populate_todo(struct todo_list *todo_list, item->offset_in_buf = todo_list->buf.len; subject_len = find_commit_subject(commit_buffer, &subject); strbuf_addf(&todo_list->buf, "%s %s %.*s\n", command_string, - short_commit_name(commit), subject_len, subject); + short_commit_name(the_repository, commit), + subject_len, subject); repo_unuse_commit_buffer(the_repository, commit, commit_buffer); } @@ -3595,7 +3604,7 @@ static int error_with_patch(struct repository *r, } else if (exit_code) { if (commit) fprintf_ln(stderr, _("Could not apply %s... %.*s"), - short_commit_name(commit), subject_len, subject); + short_commit_name(r, commit), subject_len, subject); else /* * We don't have the hash of the parent so @@ -4730,7 +4739,7 @@ static int pick_commits(struct repository *r, term_clear_line(); fprintf(stderr, _("Stopped at %s... %.*s\n"), - short_commit_name(commit), + short_commit_name(r, commit), item->arg_len, arg); } return error_with_patch(r, commit, @@ -5363,6 +5372,7 @@ struct label_state { struct oidmap commit2label; struct hashmap labels; struct strbuf buf; + int max_label_length; }; static const char *label_oid(struct object_id *oid, const char *label, @@ -5419,6 +5429,8 @@ static const char *label_oid(struct object_id *oid, const char *label, } } else { struct strbuf *buf = &state->buf; + int label_is_utf8 = 1; /* start with this assumption */ + size_t max_len = buf->len + state->max_label_length; /* * Sanitize labels by replacing non-alpha-numeric characters @@ -5427,14 +5439,34 @@ static const char *label_oid(struct object_id *oid, const char *label, * * Note that we retain non-ASCII UTF-8 characters (identified * via the most significant bit). They should be all acceptable - * in file names. We do not validate the UTF-8 here, that's not - * the job of this function. + * in file names. + * + * As we will use the labels as names of (loose) refs, it is + * vital that the name not be longer than the maximum component + * size of the file system (`NAME_MAX`). We are careful to + * truncate the label accordingly, allowing for the `.lock` + * suffix and for the label to be UTF-8 encoded (i.e. we avoid + * truncating in the middle of a character). */ - for (; *label; label++) - if ((*label & 0x80) || isalnum(*label)) + for (; *label && buf->len + 1 < max_len; label++) + if (isalnum(*label) || + (!label_is_utf8 && (*label & 0x80))) strbuf_addch(buf, *label); + else if (*label & 0x80) { + const char *p = label; + + utf8_width(&p, NULL); + if (p) { + if (buf->len + (p - label) > max_len) + break; + strbuf_add(buf, label, p - label); + label = p - 1; + } else { + label_is_utf8 = 0; + strbuf_addch(buf, *label); + } /* avoid leading dash and double-dashes */ - else if (buf->len && buf->buf[buf->len - 1] != '-') + } else if (buf->len && buf->buf[buf->len - 1] != '-') strbuf_addch(buf, '-'); if (!buf->len) { strbuf_addstr(buf, "rev-"); @@ -5496,7 +5528,8 @@ static int make_script_with_merges(struct pretty_print_context *pp, struct string_entry *entry; struct oidset interesting = OIDSET_INIT, child_seen = OIDSET_INIT, shown = OIDSET_INIT; - struct label_state state = { OIDMAP_INIT, { NULL }, STRBUF_INIT }; + struct label_state state = + { OIDMAP_INIT, { NULL }, STRBUF_INIT, GIT_MAX_LABEL_LENGTH }; int abbr = flags & TODO_LIST_ABBREVIATE_CMDS; const char *cmd_pick = abbr ? "p" : "pick", @@ -5504,6 +5537,8 @@ static int make_script_with_merges(struct pretty_print_context *pp, *cmd_reset = abbr ? "t" : "reset", *cmd_merge = abbr ? "m" : "merge"; + git_config_get_int("rebase.maxlabellength", &state.max_label_length); + oidmap_init(&commit2todo, 0); oidmap_init(&state.commit2label, 0); hashmap_init(&state.labels, labels_cmp, NULL, 0); @@ -5540,7 +5575,7 @@ static int make_script_with_merges(struct pretty_print_context *pp, if (!is_empty && (commit->object.flags & PATCHSAME)) { if (flags & TODO_LIST_WARN_SKIPPED_CHERRY_PICKS) warning(_("skipped previously applied commit %s"), - short_commit_name(commit)); + short_commit_name(the_repository, commit)); skipped_commit = 1; continue; } @@ -5776,7 +5811,7 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc, if (!is_empty && (commit->object.flags & PATCHSAME)) { if (flags & TODO_LIST_WARN_SKIPPED_CHERRY_PICKS) warning(_("skipped previously applied commit %s"), - short_commit_name(commit)); + short_commit_name(r, commit)); skipped_commit = 1; continue; } @@ -5868,7 +5903,8 @@ static void todo_list_add_exec_commands(struct todo_list *todo_list, todo_list->alloc = alloc; } -static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_list, +static void todo_list_to_strbuf(struct repository *r, + struct todo_list *todo_list, struct strbuf *buf, int num, unsigned flags) { struct todo_item *item; @@ -5897,7 +5933,7 @@ static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_lis /* add commit id */ if (item->commit) { const char *oid = flags & TODO_LIST_SHORTEN_IDS ? - short_commit_name(item->commit) : + short_commit_name(r, item->commit) : oid_to_hex(&item->commit->object.oid); if (item->command == TODO_FIXUP) { @@ -6205,7 +6241,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla if (checkout_onto(r, opts, onto_name, &oid, orig_head)) goto cleanup; - if (require_clean_work_tree(r, "rebase", "", 1, 1)) + if (require_clean_work_tree(r, "rebase", NULL, 1, 1)) goto cleanup; todo_list_write_total_nr(&new_todo); @@ -6256,7 +6292,7 @@ static int skip_fixupish(const char *subject, const char **p) { int todo_list_rearrange_squash(struct todo_list *todo_list) { struct hashmap subject2item; - int rearranged = 0, *next, *tail, i, nr = 0, alloc = 0; + int rearranged = 0, *next, *tail, i, nr = 0; char **subjects; struct commit_todo_item commit_todo; struct todo_item *items = NULL; @@ -6368,6 +6404,8 @@ int todo_list_rearrange_squash(struct todo_list *todo_list) } if (rearranged) { + ALLOC_ARRAY(items, todo_list->nr); + for (i = 0; i < todo_list->nr; i++) { enum todo_command command = todo_list->items[i].command; int cur = i; @@ -6380,16 +6418,15 @@ int todo_list_rearrange_squash(struct todo_list *todo_list) continue; while (cur >= 0) { - ALLOC_GROW(items, nr + 1, alloc); items[nr++] = todo_list->items[cur]; cur = next[cur]; } } + assert(nr == todo_list->nr); + todo_list->alloc = nr; FREE_AND_NULL(todo_list->items); todo_list->items = items; - todo_list->nr = nr; - todo_list->alloc = alloc; } free(next); |