rev-parse: avoid writing to const string for parent marks

The previous commit cleared up some const confusion in handling parent marks in revision.c, but we have roughly the same code duplicated in rev-parse. This one is much easier to fix, because the handling of the shortened string is all done in one place, after detecting any marks (but without shortening the string between marks). As a side note, I suspect this means that it behaves differently than the revision.c parser for weird stuff like "foo^!^@^-", but that is outside the scope of this patch. While we are here, let's also rename the variable "dotdot", which is totally misleading (and which we already fixed in revision.c long ago via f632dedd8d (handle_revision_arg: stop using "dotdot" as a generic pointer, 2017-05-19)). Doing that here makes the diff a little messier, but it also lets the compiler help us make sure we did not miss any stray mentions of the variable while we are changing its semantics. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Mar 26, 2026 at 15:14 UTC 213b2138770d820bc28fde839f3e4df90a5d5d81
1 file changed +13 -12
builtin/rev-parse.c
+13 -12
@@ -326,7 +326,7 @@ static int try_difference(const char *arg)
326
327 static int try_parent_shorthands(const char *arg)
328 {
329 - char *dotdot;
329 + const char *mark;
330 struct object_id oid;
331 struct commit *commit;
332 struct commit_list *parents;
@@ -334,38 +334,39 @@ static int try_parent_shorthands(const char *arg)
334 int include_rev = 0;
335 int include_parents = 0;
336 int exclude_parent = 0;
337 + char *to_free;
338
338 - if ((dotdot = strstr(arg, "^!"))) {
339 + if ((mark = strstr(arg, "^!"))) {
340 include_rev = 1;
340 - if (dotdot[2])
341 + if (mark[2])
342 return 0;
342 - } else if ((dotdot = strstr(arg, "^@"))) {
343 + } else if ((mark = strstr(arg, "^@"))) {
344 include_parents = 1;
344 - if (dotdot[2])
345 + if (mark[2])
346 return 0;
346 - } else if ((dotdot = strstr(arg, "^-"))) {
347 + } else if ((mark = strstr(arg, "^-"))) {
348 include_rev = 1;
349 exclude_parent = 1;
350
350 - if (dotdot[2]) {
351 + if (mark[2]) {
352 char *end;
352 - exclude_parent = strtoul(dotdot + 2, &end, 10);
353 + exclude_parent = strtoul(mark + 2, &end, 10);
354 if (*end != '\0' || !exclude_parent)
355 return 0;
356 }
357 } else
358 return 0;
359
359 - *dotdot = 0;
360 + arg = to_free = xmemdupz(arg, mark - arg);
361 if (repo_get_oid_committish(the_repository, arg, &oid) ||
362 !(commit = lookup_commit_reference(the_repository, &oid))) {
362 - *dotdot = '^';
363 + free(to_free);
364 return 0;
365 }
366
367 if (exclude_parent &&
368 exclude_parent > commit_list_count(commit->parents)) {
368 - *dotdot = '^';
369 + free(to_free);
370 return 0;
371 }
372
@@ -386,7 +387,7 @@ static int try_parent_shorthands(const char *arg)
387 free(name);
388 }
389
389 - *dotdot = '^';
390 + free(to_free);
391 return 1;
392 }
393