Skip to content

Commit c21754a

Browse files
committed
Merge branch 'ds/rebase-update-refs' into seen
source: <[email protected]> * ds/rebase-update-refs: rebase: add rebase.updateRefs config option sequencer: implement 'update-refs' command rebase: add --update-refs option sequencer: add update-refs command sequencer: define array with enum values branch: add branch_checked_out() helper log-tree: create for_each_decoration()
2 parents 587e8bc + 6a5d5ef commit c21754a

File tree

10 files changed

+432
-58
lines changed

10 files changed

+432
-58
lines changed

Documentation/config/rebase.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ rebase.autoStash::
2121
`--autostash` options of linkgit:git-rebase[1].
2222
Defaults to false.
2323

24+
rebase.updateRefs::
25+
If set to true enable `--update-refs` option by default.
26+
2427
rebase.missingCommitsCheck::
2528
If set to "warn", git rebase -i will print a warning if some
2629
commits are removed (e.g. a line was deleted), however the

Documentation/git-rebase.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,17 @@ provided. Otherwise an explicit `--no-reschedule-failed-exec` at the
609609
start would be overridden by the presence of
610610
`rebase.rescheduleFailedExec=true` configuration.
611611

612+
--update-refs::
613+
--no-update-refs::
614+
Automatically force-update any branches that point to commits that
615+
are being rebased. Any branches that are checked out in a worktree
616+
or point to a `squash! ...` or `fixup! ...` commit are not updated
617+
in this way.
618+
+
619+
If the `--update-refs` option is enabled by default using the
620+
configuration variable `rebase.updateRefs`, this option can be
621+
used to override and disable this setting.
622+
612623
INCOMPATIBLE OPTIONS
613624
--------------------
614625

@@ -632,6 +643,7 @@ are incompatible with the following options:
632643
* --empty=
633644
* --reapply-cherry-picks
634645
* --edit-todo
646+
* --update-refs
635647
* --root when used in combination with --onto
636648

637649
In addition, the following pairs of options are incompatible:

branch.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,19 @@ int validate_branchname(const char *name, struct strbuf *ref)
369369
return ref_exists(ref->buf);
370370
}
371371

372+
int branch_checked_out(const char *refname, char **path)
373+
{
374+
struct worktree **worktrees = get_worktrees();
375+
const struct worktree *wt = find_shared_symref(worktrees, "HEAD", refname);
376+
int result = wt && !wt->is_bare;
377+
378+
if (result && path)
379+
*path = xstrdup(wt->path);
380+
381+
free_worktrees(worktrees);
382+
return result;
383+
}
384+
372385
/*
373386
* Check if a branch 'name' can be created as a new branch; die otherwise.
374387
* 'force' can be used when it is OK for the named branch already exists.
@@ -377,23 +390,18 @@ int validate_branchname(const char *name, struct strbuf *ref)
377390
*/
378391
int validate_new_branchname(const char *name, struct strbuf *ref, int force)
379392
{
380-
struct worktree **worktrees;
381-
const struct worktree *wt;
382-
393+
char *path;
383394
if (!validate_branchname(name, ref))
384395
return 0;
385396

386397
if (!force)
387398
die(_("a branch named '%s' already exists"),
388399
ref->buf + strlen("refs/heads/"));
389400

390-
worktrees = get_worktrees();
391-
wt = find_shared_symref(worktrees, "HEAD", ref->buf);
392-
if (wt && !wt->is_bare)
401+
if (branch_checked_out(ref->buf, &path))
393402
die(_("cannot force update the branch '%s' "
394403
"checked out at '%s'"),
395-
ref->buf + strlen("refs/heads/"), wt->path);
396-
free_worktrees(worktrees);
404+
ref->buf + strlen("refs/heads/"), path);
397405

398406
return 1;
399407
}

branch.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ void create_branches_recursively(struct repository *r, const char *name,
101101
const char *tracking_name, int force,
102102
int reflog, int quiet, enum branch_track track,
103103
int dry_run);
104+
105+
/*
106+
* Returns true if the branch at 'refname' is checked out at any
107+
* non-bare worktree. The path of the worktree is stored in the
108+
* given 'path', if provided.
109+
*/
110+
int branch_checked_out(const char *refname, char **path);
111+
104112
/*
105113
* Check if 'name' can be a valid name for a branch; die otherwise.
106114
* Return 1 if the named branch already exists; return 0 otherwise.

builtin/rebase.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ struct rebase_options {
102102
int reschedule_failed_exec;
103103
int reapply_cherry_picks;
104104
int fork_point;
105+
int update_refs;
105106
};
106107

107108
#define REBASE_OPTIONS_INIT { \
@@ -298,6 +299,7 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
298299
ret = complete_action(the_repository, &replay, flags,
299300
shortrevisions, opts->onto_name, opts->onto,
300301
&opts->orig_head, &commands, opts->autosquash,
302+
opts->update_refs,
301303
&todo_list);
302304
}
303305

@@ -800,6 +802,11 @@ static int rebase_config(const char *var, const char *value, void *data)
800802
return 0;
801803
}
802804

805+
if (!strcmp(var, "rebase.updaterefs")) {
806+
opts->update_refs = git_config_bool(var, value);
807+
return 0;
808+
}
809+
803810
if (!strcmp(var, "rebase.reschedulefailedexec")) {
804811
opts->reschedule_failed_exec = git_config_bool(var, value);
805812
return 0;
@@ -1124,6 +1131,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
11241131
OPT_BOOL(0, "autosquash", &options.autosquash,
11251132
N_("move commits that begin with "
11261133
"squash!/fixup! under -i")),
1134+
OPT_BOOL(0, "update-refs", &options.update_refs,
1135+
N_("update local refs that point to commits "
1136+
"that are being rebased")),
11271137
{ OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"),
11281138
N_("GPG-sign commits"),
11291139
PARSE_OPT_OPTARG, NULL, (intptr_t) "" },

log-tree.c

Lines changed: 76 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,54 @@ static void show_name(struct strbuf *sb, const struct name_decoration *decoratio
282282
strbuf_addstr(sb, decoration->name);
283283
}
284284

285+
struct format_decorations_context {
286+
struct strbuf *sb;
287+
int use_color;
288+
const char *prefix;
289+
const char *separator;
290+
const char *suffix;
291+
const char *color_commit;
292+
const char *color_reset;
293+
const struct name_decoration *current_and_HEAD;
294+
};
295+
296+
static int append_decoration(const struct name_decoration *d,
297+
void *data)
298+
{
299+
struct format_decorations_context *ctx = data;
300+
/*
301+
* When both current and HEAD are there, only
302+
* show HEAD->current where HEAD would have
303+
* appeared, skipping the entry for current.
304+
*/
305+
if (d != ctx->current_and_HEAD) {
306+
strbuf_addstr(ctx->sb, ctx->color_commit);
307+
strbuf_addstr(ctx->sb, ctx->prefix);
308+
strbuf_addstr(ctx->sb, ctx->color_reset);
309+
strbuf_addstr(ctx->sb, decorate_get_color(ctx->use_color, d->type));
310+
if (d->type == DECORATION_REF_TAG)
311+
strbuf_addstr(ctx->sb, "tag: ");
312+
313+
show_name(ctx->sb, d);
314+
315+
if (ctx->current_and_HEAD &&
316+
d->type == DECORATION_REF_HEAD) {
317+
strbuf_addstr(ctx->sb, " -> ");
318+
strbuf_addstr(ctx->sb, ctx->color_reset);
319+
strbuf_addstr(ctx->sb,
320+
decorate_get_color(
321+
ctx->use_color,
322+
ctx->current_and_HEAD->type));
323+
show_name(ctx->sb, ctx->current_and_HEAD);
324+
}
325+
strbuf_addstr(ctx->sb, ctx->color_reset);
326+
327+
ctx->prefix = ctx->separator;
328+
}
329+
330+
return 0;
331+
}
332+
285333
/*
286334
* The caller makes sure there is no funny color before calling.
287335
* format_decorations_extended makes sure the same after return.
@@ -294,49 +342,42 @@ void format_decorations_extended(struct strbuf *sb,
294342
const char *suffix)
295343
{
296344
const struct name_decoration *decoration;
297-
const struct name_decoration *current_and_HEAD;
298-
const char *color_commit =
299-
diff_get_color(use_color, DIFF_COMMIT);
300-
const char *color_reset =
301-
decorate_get_color(use_color, DECORATION_NONE);
345+
struct format_decorations_context ctx = {
346+
.sb = sb,
347+
.use_color = use_color,
348+
.prefix = prefix,
349+
.separator = separator,
350+
.suffix = suffix,
351+
.color_commit = diff_get_color(use_color, DIFF_COMMIT),
352+
.color_reset = decorate_get_color(use_color, DECORATION_NONE),
353+
};
302354

303355
decoration = get_name_decoration(&commit->object);
304356
if (!decoration)
305357
return;
306358

307-
current_and_HEAD = current_pointed_by_HEAD(decoration);
308-
while (decoration) {
309-
/*
310-
* When both current and HEAD are there, only
311-
* show HEAD->current where HEAD would have
312-
* appeared, skipping the entry for current.
313-
*/
314-
if (decoration != current_and_HEAD) {
315-
strbuf_addstr(sb, color_commit);
316-
strbuf_addstr(sb, prefix);
317-
strbuf_addstr(sb, color_reset);
318-
strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
319-
if (decoration->type == DECORATION_REF_TAG)
320-
strbuf_addstr(sb, "tag: ");
321-
322-
show_name(sb, decoration);
323-
324-
if (current_and_HEAD &&
325-
decoration->type == DECORATION_REF_HEAD) {
326-
strbuf_addstr(sb, " -> ");
327-
strbuf_addstr(sb, color_reset);
328-
strbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));
329-
show_name(sb, current_and_HEAD);
330-
}
331-
strbuf_addstr(sb, color_reset);
359+
ctx.current_and_HEAD = current_pointed_by_HEAD(decoration);
332360

333-
prefix = separator;
334-
}
361+
for_each_decoration(commit, append_decoration, &ctx);
362+
363+
strbuf_addstr(sb, ctx.color_commit);
364+
strbuf_addstr(sb, ctx.suffix);
365+
strbuf_addstr(sb, ctx.color_reset);
366+
}
367+
368+
int for_each_decoration(const struct commit *c, decoration_fn fn, void *data)
369+
{
370+
const struct name_decoration *decoration;
371+
372+
decoration = get_name_decoration(&c->object);
373+
while (decoration) {
374+
int res;
375+
if ((res = fn(decoration, data)))
376+
return res;
335377
decoration = decoration->next;
336378
}
337-
strbuf_addstr(sb, color_commit);
338-
strbuf_addstr(sb, suffix);
339-
strbuf_addstr(sb, color_reset);
379+
380+
return 0;
340381
}
341382

342383
void show_decorations(struct rev_info *opt, struct commit *commit)

log-tree.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,8 @@ void fmt_output_commit(struct strbuf *, struct commit *, struct rev_info *);
3535
void fmt_output_subject(struct strbuf *, const char *subject, struct rev_info *);
3636
void fmt_output_email_subject(struct strbuf *, struct rev_info *);
3737

38+
typedef int decoration_fn(const struct name_decoration *d,
39+
void *data);
40+
int for_each_decoration(const struct commit *c, decoration_fn fn, void *data);
41+
3842
#endif

0 commit comments

Comments
 (0)