Skip to content

Commit aaf0a42

Browse files
committed
Merge branch 'mp/rebase-label-length-limit'
Overly long label names used in the sequencer machinery are now chopped to fit under filesystem limitation. * mp/rebase-label-length-limit: rebase: allow overriding the maximal length of the generated labels sequencer: truncate labels to accommodate loose refs
2 parents 84d7900 + ac300bd commit aaf0a42

File tree

4 files changed

+62
-6
lines changed

4 files changed

+62
-6
lines changed

Documentation/config/rebase.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,9 @@ rebase.rebaseMerges::
7777
equivalent to `--no-rebase-merges`. Passing `--rebase-merges` on the
7878
command line, with or without an argument, overrides any
7979
`rebase.rebaseMerges` configuration.
80+
81+
rebase.maxLabelLength::
82+
When generating label names from commit subjects, truncate the names to
83+
this length. By default, the names are truncated to a little less than
84+
`NAME_MAX` (to allow e.g. `.lock` files to be written for the
85+
corresponding loose refs).

git-compat-util.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,10 @@ char *gitdirname(char *);
422422
#define PATH_MAX 4096
423423
#endif
424424

425+
#ifndef NAME_MAX
426+
#define NAME_MAX 255
427+
#endif
428+
425429
typedef uintmax_t timestamp_t;
426430
#define PRItime PRIuMAX
427431
#define parse_timestamp strtoumax

sequencer.c

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@
5151

5252
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
5353

54+
/*
55+
* To accommodate common filesystem limitations, where the loose refs' file
56+
* names must not exceed `NAME_MAX`, the labels generated by `git rebase
57+
* --rebase-merges` need to be truncated if the corresponding commit subjects
58+
* are too long.
59+
* Add some margin to stay clear from reaching `NAME_MAX`.
60+
*/
61+
#define GIT_MAX_LABEL_LENGTH ((NAME_MAX) - (LOCK_SUFFIX_LEN) - 16)
62+
5463
static const char sign_off_header[] = "Signed-off-by: ";
5564
static const char cherry_picked_prefix[] = "(cherry picked from commit ";
5665

@@ -5352,6 +5361,7 @@ struct label_state {
53525361
struct oidmap commit2label;
53535362
struct hashmap labels;
53545363
struct strbuf buf;
5364+
int max_label_length;
53555365
};
53565366

53575367
static const char *label_oid(struct object_id *oid, const char *label,
@@ -5408,6 +5418,8 @@ static const char *label_oid(struct object_id *oid, const char *label,
54085418
}
54095419
} else {
54105420
struct strbuf *buf = &state->buf;
5421+
int label_is_utf8 = 1; /* start with this assumption */
5422+
size_t max_len = buf->len + state->max_label_length;
54115423

54125424
/*
54135425
* Sanitize labels by replacing non-alpha-numeric characters
@@ -5416,14 +5428,34 @@ static const char *label_oid(struct object_id *oid, const char *label,
54165428
*
54175429
* Note that we retain non-ASCII UTF-8 characters (identified
54185430
* via the most significant bit). They should be all acceptable
5419-
* in file names. We do not validate the UTF-8 here, that's not
5420-
* the job of this function.
5431+
* in file names.
5432+
*
5433+
* As we will use the labels as names of (loose) refs, it is
5434+
* vital that the name not be longer than the maximum component
5435+
* size of the file system (`NAME_MAX`). We are careful to
5436+
* truncate the label accordingly, allowing for the `.lock`
5437+
* suffix and for the label to be UTF-8 encoded (i.e. we avoid
5438+
* truncating in the middle of a character).
54215439
*/
5422-
for (; *label; label++)
5423-
if ((*label & 0x80) || isalnum(*label))
5440+
for (; *label && buf->len + 1 < max_len; label++)
5441+
if (isalnum(*label) ||
5442+
(!label_is_utf8 && (*label & 0x80)))
54245443
strbuf_addch(buf, *label);
5444+
else if (*label & 0x80) {
5445+
const char *p = label;
5446+
5447+
utf8_width(&p, NULL);
5448+
if (p) {
5449+
if (buf->len + (p - label) > max_len)
5450+
break;
5451+
strbuf_add(buf, label, p - label);
5452+
label = p - 1;
5453+
} else {
5454+
label_is_utf8 = 0;
5455+
strbuf_addch(buf, *label);
5456+
}
54255457
/* avoid leading dash and double-dashes */
5426-
else if (buf->len && buf->buf[buf->len - 1] != '-')
5458+
} else if (buf->len && buf->buf[buf->len - 1] != '-')
54275459
strbuf_addch(buf, '-');
54285460
if (!buf->len) {
54295461
strbuf_addstr(buf, "rev-");
@@ -5485,14 +5517,17 @@ static int make_script_with_merges(struct pretty_print_context *pp,
54855517
struct string_entry *entry;
54865518
struct oidset interesting = OIDSET_INIT, child_seen = OIDSET_INIT,
54875519
shown = OIDSET_INIT;
5488-
struct label_state state = { OIDMAP_INIT, { NULL }, STRBUF_INIT };
5520+
struct label_state state =
5521+
{ OIDMAP_INIT, { NULL }, STRBUF_INIT, GIT_MAX_LABEL_LENGTH };
54895522

54905523
int abbr = flags & TODO_LIST_ABBREVIATE_CMDS;
54915524
const char *cmd_pick = abbr ? "p" : "pick",
54925525
*cmd_label = abbr ? "l" : "label",
54935526
*cmd_reset = abbr ? "t" : "reset",
54945527
*cmd_merge = abbr ? "m" : "merge";
54955528

5529+
git_config_get_int("rebase.maxlabellength", &state.max_label_length);
5530+
54965531
oidmap_init(&commit2todo, 0);
54975532
oidmap_init(&state.commit2label, 0);
54985533
hashmap_init(&state.labels, labels_cmp, NULL, 0);

t/t3430-rebase-merges.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,4 +586,15 @@ test_expect_success 'progress shows the correct total' '
586586
test_line_count = 14 progress
587587
'
588588

589+
test_expect_success 'truncate label names' '
590+
commit=$(git commit-tree -p HEAD^ -p HEAD -m "0123456789 我 123" HEAD^{tree}) &&
591+
git merge --ff-only $commit &&
592+
593+
done="$(git rev-parse --git-path rebase-merge/done)" &&
594+
git -c rebase.maxLabelLength=14 rebase --rebase-merges -x "cp \"$done\" out" --root &&
595+
grep "label 0123456789-我$" out &&
596+
git -c rebase.maxLabelLength=13 rebase --rebase-merges -x "cp \"$done\" out" --root &&
597+
grep "label 0123456789-$" out
598+
'
599+
589600
test_done

0 commit comments

Comments
 (0)