Skip to content

Commit d4833b2

Browse files
committed
Merge branch 'vd/for-each-ref-sort-with-formatted-timestamp'
"git branch" and friends learned to use the formatted text as sorting key, not the underlying timestamp value, when the --sort option is used with author or committer timestamp with a format specifier (e.g., "--sort=creatordate:format:%H:%M:%S"). * vd/for-each-ref-sort-with-formatted-timestamp: ref-filter.c: sort formatted dates by byte value
2 parents b3370dd + 46176d7 commit d4833b2

File tree

3 files changed

+57
-3
lines changed

3 files changed

+57
-3
lines changed

Documentation/git-for-each-ref.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,11 @@ In any case, a field name that refers to a field inapplicable to
359359
the object referred by the ref does not cause an error. It
360360
returns an empty string instead.
361361

362-
As a special case for the date-type fields, you may specify a format for
363-
the date by adding `:` followed by date format name (see the
364-
values the `--date` option to linkgit:git-rev-list[1] takes).
362+
As a special case for the date-type fields, you may specify a format for the
363+
date by adding `:` followed by date format name (see the values the `--date`
364+
option to linkgit:git-rev-list[1] takes). If this formatting is provided in
365+
a `--sort` key, references will be sorted according to the byte-value of the
366+
formatted string rather than the numeric value of the underlying timestamp.
365367

366368
Some atoms like %(align) and %(if) always require a matching %(end).
367369
We call them "opening atoms" and sometimes denote them as %($open).

ref-filter.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,6 +1611,12 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam
16111611
if (formatp) {
16121612
formatp++;
16131613
parse_date_format(formatp, &date_mode);
1614+
1615+
/*
1616+
* If this is a sort field and a format was specified, we'll
1617+
* want to compare formatted date by string value.
1618+
*/
1619+
v->atom->type = FIELD_STR;
16141620
}
16151621

16161622
if (!eoemail)

t/t6300-for-each-ref.sh

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,6 +1356,52 @@ test_expect_success '--no-sort without subsequent --sort prints expected refs' '
13561356
test_cmp expected actual
13571357
'
13581358

1359+
test_expect_success 'set up custom date sorting' '
1360+
# Dates:
1361+
# - Wed Feb 07 2024 21:34:20 +0000
1362+
# - Tue Dec 14 1999 00:05:22 +0000
1363+
# - Fri Jun 04 2021 11:26:51 +0000
1364+
# - Mon Jan 22 2007 16:44:01 GMT+0000
1365+
i=1 &&
1366+
for when in 1707341660 945129922 1622806011 1169484241
1367+
do
1368+
GIT_COMMITTER_DATE="@$when +0000" \
1369+
GIT_COMMITTER_EMAIL="[email protected]" \
1370+
git tag -m "tag $when" custom-dates-$i &&
1371+
i=$(($i+1)) || return 1
1372+
done
1373+
'
1374+
1375+
test_expect_success 'sort by date defaults to full timestamp' '
1376+
cat >expected <<-\EOF &&
1377+
945129922 refs/tags/custom-dates-2
1378+
1169484241 refs/tags/custom-dates-4
1379+
1622806011 refs/tags/custom-dates-3
1380+
1707341660 refs/tags/custom-dates-1
1381+
EOF
1382+
1383+
git for-each-ref \
1384+
--format="%(creatordate:unix) %(refname)" \
1385+
--sort=creatordate \
1386+
"refs/tags/custom-dates-*" >actual &&
1387+
test_cmp expected actual
1388+
'
1389+
1390+
test_expect_success 'sort by custom date format' '
1391+
cat >expected <<-\EOF &&
1392+
00:05:22 refs/tags/custom-dates-2
1393+
11:26:51 refs/tags/custom-dates-3
1394+
16:44:01 refs/tags/custom-dates-4
1395+
21:34:20 refs/tags/custom-dates-1
1396+
EOF
1397+
1398+
git for-each-ref \
1399+
--format="%(creatordate:format:%H:%M:%S) %(refname)" \
1400+
--sort="creatordate:format:%H:%M:%S" \
1401+
"refs/tags/custom-dates-*" >actual &&
1402+
test_cmp expected actual
1403+
'
1404+
13591405
test_expect_success 'do not dereference NULL upon %(HEAD) on unborn branch' '
13601406
test_when_finished "git checkout main" &&
13611407
git for-each-ref --format="%(HEAD) %(refname:short)" refs/heads/ >actual &&

0 commit comments

Comments
 (0)