Skip to content

Commit f61164b

Browse files
edith007gitster
authored andcommitted
replay: add replay.refAction config option
Add a configuration option to control the default behavior of git replay for updating references. This allows users who prefer the traditional pipeline output to set it once in their config instead of passing --ref-action=print with every command. The config option uses string values that mirror the behavior modes: * replay.refAction = update (default): atomic ref updates * replay.refAction = print: output commands for pipeline The command-line --ref-action option always overrides the config setting, allowing users to temporarily change behavior for a single invocation. Implementation details: In cmd_replay(), after parsing command-line options, we check if --ref-action was provided. If not, we read the configuration using repo_config_get_string_tmp(). If the config variable is set, we validate the value and use it to set the ref_action_str: Config value Internal mode Behavior ────────────────────────────────────────────────────────────── "update" "update" Atomic ref updates (default) "print" "print" Pipeline output (not set) "update" Atomic ref updates (default) (invalid) error Die with helpful message If an invalid value is provided, we die() immediately with an error message explaining the valid options. This catches configuration errors early and provides clear guidance to users. The command-line --ref-action option, when provided, overrides the config value. This precedence allows users to set their preferred default while still having per-invocation control: git config replay.refAction print # Set default git replay --ref-action=update --onto main topic # Override once The config and command-line option use the same value names ('update' and 'print') for consistency and clarity. This makes it immediately obvious how the config maps to the command-line option, addressing feedback about the relationship between configuration and command-line options being clear to users. Examples: $ git config --global replay.refAction print $ git replay --onto main topic1..topic2 | git update-ref --stdin $ git replay --ref-action=update --onto main topic1..topic2 $ git config replay.refAction update $ git replay --onto main topic1..topic2 # Updates refs directly The implementation follows Git's standard configuration precedence: command-line options override config values, which matches user expectations across all Git commands. Helped-by: Junio C Hamano <[email protected]> Helped-by: Elijah Newren <[email protected]> Helped-by: Christian Couder <[email protected]> Helped-by: Phillip Wood <[email protected]> Signed-off-by: Siddharth Asthana <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ab4e057 commit f61164b

File tree

3 files changed

+87
-12
lines changed

3 files changed

+87
-12
lines changed

Documentation/config/replay.adoc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
replay.refAction::
2+
Specifies the default mode for handling reference updates in
3+
`git replay`. The value can be:
4+
+
5+
--
6+
* `update`: Update refs directly using an atomic transaction (default behavior).
7+
* `print`: Output update-ref commands for pipeline use.
8+
--
9+
+
10+
This setting can be overridden with the `--ref-action` command-line option.
11+
When not configured, `git replay` defaults to `update` mode.

builtin/replay.c

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "git-compat-util.h"
99

1010
#include "builtin.h"
11+
#include "config.h"
1112
#include "environment.h"
1213
#include "hex.h"
1314
#include "lockfile.h"
@@ -289,6 +290,31 @@ static struct commit *pick_regular_commit(struct repository *repo,
289290
return create_commit(repo, result->tree, pickme, replayed_base);
290291
}
291292

293+
static enum ref_action_mode parse_ref_action_mode(const char *mode_str, const char *source)
294+
{
295+
if (!mode_str || !strcmp(mode_str, "update"))
296+
return REF_ACTION_UPDATE;
297+
if (!strcmp(mode_str, "print"))
298+
return REF_ACTION_PRINT;
299+
die(_("invalid %s value: '%s'"), source, mode_str);
300+
}
301+
302+
static enum ref_action_mode get_ref_action_mode(struct repository *repo, const char *ref_action_str)
303+
{
304+
const char *config_value = NULL;
305+
306+
/* Command line option takes precedence */
307+
if (ref_action_str)
308+
return parse_ref_action_mode(ref_action_str, "--ref-action");
309+
310+
/* Check config value */
311+
if (!repo_config_get_string_tmp(repo, "replay.refAction", &config_value))
312+
return parse_ref_action_mode(config_value, "replay.refAction");
313+
314+
/* Default to update mode */
315+
return REF_ACTION_UPDATE;
316+
}
317+
292318
static int handle_ref_update(enum ref_action_mode mode,
293319
struct ref_transaction *transaction,
294320
const char *refname,
@@ -367,17 +393,8 @@ int cmd_replay(int argc,
367393
die_for_incompatible_opt2(!!advance_name_opt, "--advance",
368394
contained, "--contained");
369395

370-
/* Default to update mode if not specified */
371-
if (!ref_action_str)
372-
ref_action_str = "update";
373-
374-
/* Parse ref action mode */
375-
if (!strcmp(ref_action_str, "update"))
376-
ref_action = REF_ACTION_UPDATE;
377-
else if (!strcmp(ref_action_str, "print"))
378-
ref_action = REF_ACTION_PRINT;
379-
else
380-
die(_("unknown --ref-action mode '%s'"), ref_action_str);
396+
/* Parse ref action mode from command line or config */
397+
ref_action = get_ref_action_mode(repo, ref_action_str);
381398

382399
advance_name = xstrdup_or_null(advance_name_opt);
383400

t/t3650-replay-basics.sh

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ test_expect_success 'merge.directoryRenames=false' '
219219

220220
test_expect_success 'default atomic behavior updates refs directly' '
221221
# Store original state for cleanup
222-
test_when_finished "git branch -f topic2 topic1" &&
222+
START=$(git rev-parse topic2) &&
223+
test_when_finished "git branch -f topic2 $START" &&
223224
224225
# Test default atomic behavior (no output, refs updated)
225226
git replay --onto main topic1..topic2 >output &&
@@ -232,6 +233,10 @@ test_expect_success 'default atomic behavior updates refs directly' '
232233
'
233234

234235
test_expect_success 'atomic behavior in bare repository' '
236+
# Store original state for cleanup
237+
START=$(git rev-parse topic2) &&
238+
test_when_finished "git branch -f topic2 $START" &&
239+
235240
# Test atomic updates work in bare repo
236241
git -C bare replay --onto main topic1..topic2 >output &&
237242
test_must_be_empty output &&
@@ -245,4 +250,46 @@ test_expect_success 'atomic behavior in bare repository' '
245250
git -C bare update-ref refs/heads/topic2 $(git -C bare rev-parse topic1)
246251
'
247252

253+
test_expect_success 'replay.refAction config option' '
254+
# Store original state
255+
START=$(git rev-parse topic2) &&
256+
test_when_finished "git branch -f topic2 $START" &&
257+
test_when_finished "git config --unset replay.refAction || true" &&
258+
259+
# Set config to print
260+
git config replay.refAction print &&
261+
git replay --onto main topic1..topic2 >output &&
262+
test_line_count = 1 output &&
263+
test_grep "^update refs/heads/topic2 " output &&
264+
265+
# Reset and test update mode
266+
git branch -f topic2 $START &&
267+
git config replay.refAction update &&
268+
git replay --onto main topic1..topic2 >output &&
269+
test_must_be_empty output &&
270+
271+
# Verify ref was updated
272+
git log --format=%s topic2 >actual &&
273+
test_write_lines E D M L B A >expect &&
274+
test_cmp expect actual
275+
'
276+
277+
test_expect_success 'command-line --ref-action overrides config' '
278+
# Store original state
279+
START=$(git rev-parse topic2) &&
280+
test_when_finished "git branch -f topic2 $START" &&
281+
282+
# Set config to update but use --ref-action=print
283+
test_config replay.refAction update &&
284+
git replay --ref-action=print --onto main topic1..topic2 >output &&
285+
test_line_count = 1 output &&
286+
test_grep "^update refs/heads/topic2 " output
287+
'
288+
289+
test_expect_success 'invalid replay.refAction value' '
290+
test_config replay.refAction invalid &&
291+
test_must_fail git replay --onto main topic1..topic2 2>error &&
292+
test_grep "invalid.*replay.refAction.*value" error
293+
'
294+
248295
test_done

0 commit comments

Comments
 (0)