sequencer: advise if skipping cherry-picked commit
Silently skipping commits when rebasing with --no-reapply-cherry-picks (currently the default behavior) can cause user confusion. Issue warnings when this happens, as well as advice on how to preserve the skipped commits. These warnings and advice are displayed only when using the (default) "merge" rebase backend. Update the git-rebase docs to mention the warnings and advice. Signed-off-by: Josh Steadmon <steadmon@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
2d755dfac9
commit
767a4ca648
@ -44,6 +44,9 @@ advice.*::
|
|||||||
Shown when linkgit:git-push[1] rejects a forced update of
|
Shown when linkgit:git-push[1] rejects a forced update of
|
||||||
a branch when its remote-tracking ref has updates that we
|
a branch when its remote-tracking ref has updates that we
|
||||||
do not have locally.
|
do not have locally.
|
||||||
|
skippedCherryPicks::
|
||||||
|
Shown when linkgit:git-rebase[1] skips a commit that has already
|
||||||
|
been cherry-picked onto the upstream branch.
|
||||||
statusAheadBehind::
|
statusAheadBehind::
|
||||||
Shown when linkgit:git-status[1] computes the ahead/behind
|
Shown when linkgit:git-status[1] computes the ahead/behind
|
||||||
counts for a local ref compared to its remote tracking ref,
|
counts for a local ref compared to its remote tracking ref,
|
||||||
|
@ -79,9 +79,10 @@ remain the checked-out branch.
|
|||||||
|
|
||||||
If the upstream branch already contains a change you have made (e.g.,
|
If the upstream branch already contains a change you have made (e.g.,
|
||||||
because you mailed a patch which was applied upstream), then that commit
|
because you mailed a patch which was applied upstream), then that commit
|
||||||
will be skipped. For example, running `git rebase master` on the
|
will be skipped and warnings will be issued (if the `merge` backend is
|
||||||
following history (in which `A'` and `A` introduce the same set of changes,
|
used). For example, running `git rebase master` on the following
|
||||||
but have different committer information):
|
history (in which `A'` and `A` introduce the same set of changes, but
|
||||||
|
have different committer information):
|
||||||
|
|
||||||
------------
|
------------
|
||||||
A---B---C topic
|
A---B---C topic
|
||||||
@ -312,7 +313,10 @@ See also INCOMPATIBLE OPTIONS below.
|
|||||||
By default (or if `--no-reapply-cherry-picks` is given), these commits
|
By default (or if `--no-reapply-cherry-picks` is given), these commits
|
||||||
will be automatically dropped. Because this necessitates reading all
|
will be automatically dropped. Because this necessitates reading all
|
||||||
upstream commits, this can be expensive in repos with a large number
|
upstream commits, this can be expensive in repos with a large number
|
||||||
of upstream commits that need to be read.
|
of upstream commits that need to be read. When using the `merge`
|
||||||
|
backend, warnings will be issued for each dropped commit (unless
|
||||||
|
`--quiet` is given). Advice will also be issued unless
|
||||||
|
`advice.skippedCherryPicks` is set to false (see linkgit:git-config[1]).
|
||||||
+
|
+
|
||||||
`--reapply-cherry-picks` allows rebase to forgo reading all upstream
|
`--reapply-cherry-picks` allows rebase to forgo reading all upstream
|
||||||
commits, potentially improving performance.
|
commits, potentially improving performance.
|
||||||
|
3
advice.c
3
advice.c
@ -34,6 +34,7 @@ int advice_checkout_ambiguous_remote_branch_name = 1;
|
|||||||
int advice_submodule_alternate_error_strategy_die = 1;
|
int advice_submodule_alternate_error_strategy_die = 1;
|
||||||
int advice_add_ignored_file = 1;
|
int advice_add_ignored_file = 1;
|
||||||
int advice_add_empty_pathspec = 1;
|
int advice_add_empty_pathspec = 1;
|
||||||
|
int advice_skipped_cherry_picks = 1;
|
||||||
|
|
||||||
static int advice_use_color = -1;
|
static int advice_use_color = -1;
|
||||||
static char advice_colors[][COLOR_MAXLEN] = {
|
static char advice_colors[][COLOR_MAXLEN] = {
|
||||||
@ -96,6 +97,7 @@ static struct {
|
|||||||
{ "submoduleAlternateErrorStrategyDie", &advice_submodule_alternate_error_strategy_die },
|
{ "submoduleAlternateErrorStrategyDie", &advice_submodule_alternate_error_strategy_die },
|
||||||
{ "addIgnoredFile", &advice_add_ignored_file },
|
{ "addIgnoredFile", &advice_add_ignored_file },
|
||||||
{ "addEmptyPathspec", &advice_add_empty_pathspec },
|
{ "addEmptyPathspec", &advice_add_empty_pathspec },
|
||||||
|
{ "skippedCherryPicks", &advice_skipped_cherry_picks },
|
||||||
|
|
||||||
/* make this an alias for backward compatibility */
|
/* make this an alias for backward compatibility */
|
||||||
{ "pushNonFastForward", &advice_push_update_rejected }
|
{ "pushNonFastForward", &advice_push_update_rejected }
|
||||||
@ -133,6 +135,7 @@ static struct {
|
|||||||
[ADVICE_RM_HINTS] = { "rmHints", 1 },
|
[ADVICE_RM_HINTS] = { "rmHints", 1 },
|
||||||
[ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse", 1 },
|
[ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse", 1 },
|
||||||
[ADVICE_SET_UPSTREAM_FAILURE] = { "setUpstreamFailure", 1 },
|
[ADVICE_SET_UPSTREAM_FAILURE] = { "setUpstreamFailure", 1 },
|
||||||
|
[ADVICE_SKIPPED_CHERRY_PICKS] = { "skippedCherryPicks", 1 },
|
||||||
[ADVICE_STATUS_AHEAD_BEHIND_WARNING] = { "statusAheadBehindWarning", 1 },
|
[ADVICE_STATUS_AHEAD_BEHIND_WARNING] = { "statusAheadBehindWarning", 1 },
|
||||||
[ADVICE_STATUS_HINTS] = { "statusHints", 1 },
|
[ADVICE_STATUS_HINTS] = { "statusHints", 1 },
|
||||||
[ADVICE_STATUS_U_OPTION] = { "statusUoption", 1 },
|
[ADVICE_STATUS_U_OPTION] = { "statusUoption", 1 },
|
||||||
|
2
advice.h
2
advice.h
@ -35,6 +35,7 @@ extern int advice_checkout_ambiguous_remote_branch_name;
|
|||||||
extern int advice_submodule_alternate_error_strategy_die;
|
extern int advice_submodule_alternate_error_strategy_die;
|
||||||
extern int advice_add_ignored_file;
|
extern int advice_add_ignored_file;
|
||||||
extern int advice_add_empty_pathspec;
|
extern int advice_add_empty_pathspec;
|
||||||
|
extern int advice_skipped_cherry_picks;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To add a new advice, you need to:
|
* To add a new advice, you need to:
|
||||||
@ -75,6 +76,7 @@ extern int advice_add_empty_pathspec;
|
|||||||
ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE,
|
ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE,
|
||||||
ADVICE_UPDATE_SPARSE_PATH,
|
ADVICE_UPDATE_SPARSE_PATH,
|
||||||
ADVICE_WAITING_FOR_EDITOR,
|
ADVICE_WAITING_FOR_EDITOR,
|
||||||
|
ADVICE_SKIPPED_CHERRY_PICKS,
|
||||||
};
|
};
|
||||||
|
|
||||||
int git_default_advice_config(const char *var, const char *value);
|
int git_default_advice_config(const char *var, const char *value);
|
||||||
|
@ -405,6 +405,7 @@ static int run_sequencer_rebase(struct rebase_options *opts,
|
|||||||
flags |= opts->root_with_onto ? TODO_LIST_ROOT_WITH_ONTO : 0;
|
flags |= opts->root_with_onto ? TODO_LIST_ROOT_WITH_ONTO : 0;
|
||||||
flags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;
|
flags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;
|
||||||
flags |= opts->reapply_cherry_picks ? TODO_LIST_REAPPLY_CHERRY_PICKS : 0;
|
flags |= opts->reapply_cherry_picks ? TODO_LIST_REAPPLY_CHERRY_PICKS : 0;
|
||||||
|
flags |= opts->flags & REBASE_NO_QUIET ? TODO_LIST_WARN_SKIPPED_CHERRY_PICKS : 0;
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case ACTION_NONE: {
|
case ACTION_NONE: {
|
||||||
|
22
sequencer.c
22
sequencer.c
@ -5099,6 +5099,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
|
|||||||
int keep_empty = flags & TODO_LIST_KEEP_EMPTY;
|
int keep_empty = flags & TODO_LIST_KEEP_EMPTY;
|
||||||
int rebase_cousins = flags & TODO_LIST_REBASE_COUSINS;
|
int rebase_cousins = flags & TODO_LIST_REBASE_COUSINS;
|
||||||
int root_with_onto = flags & TODO_LIST_ROOT_WITH_ONTO;
|
int root_with_onto = flags & TODO_LIST_ROOT_WITH_ONTO;
|
||||||
|
int skipped_commit = 0;
|
||||||
struct strbuf buf = STRBUF_INIT, oneline = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT, oneline = STRBUF_INIT;
|
||||||
struct strbuf label = STRBUF_INIT;
|
struct strbuf label = STRBUF_INIT;
|
||||||
struct commit_list *commits = NULL, **tail = &commits, *iter;
|
struct commit_list *commits = NULL, **tail = &commits, *iter;
|
||||||
@ -5149,8 +5150,13 @@ static int make_script_with_merges(struct pretty_print_context *pp,
|
|||||||
oidset_insert(&interesting, &commit->object.oid);
|
oidset_insert(&interesting, &commit->object.oid);
|
||||||
|
|
||||||
is_empty = is_original_commit_empty(commit);
|
is_empty = is_original_commit_empty(commit);
|
||||||
if (!is_empty && (commit->object.flags & PATCHSAME))
|
if (!is_empty && (commit->object.flags & PATCHSAME)) {
|
||||||
|
if (flags & TODO_LIST_WARN_SKIPPED_CHERRY_PICKS)
|
||||||
|
warning(_("skipped previously applied commit %s"),
|
||||||
|
short_commit_name(commit));
|
||||||
|
skipped_commit = 1;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if (is_empty && !keep_empty)
|
if (is_empty && !keep_empty)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -5214,6 +5220,9 @@ static int make_script_with_merges(struct pretty_print_context *pp,
|
|||||||
oidcpy(&entry->entry.oid, &commit->object.oid);
|
oidcpy(&entry->entry.oid, &commit->object.oid);
|
||||||
oidmap_put(&commit2todo, entry);
|
oidmap_put(&commit2todo, entry);
|
||||||
}
|
}
|
||||||
|
if (skipped_commit)
|
||||||
|
advise_if_enabled(ADVICE_SKIPPED_CHERRY_PICKS,
|
||||||
|
_("use --reapply-cherry-picks to include skipped commits"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Second phase:
|
* Second phase:
|
||||||
@ -5334,6 +5343,7 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
|
|||||||
const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick";
|
const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick";
|
||||||
int rebase_merges = flags & TODO_LIST_REBASE_MERGES;
|
int rebase_merges = flags & TODO_LIST_REBASE_MERGES;
|
||||||
int reapply_cherry_picks = flags & TODO_LIST_REAPPLY_CHERRY_PICKS;
|
int reapply_cherry_picks = flags & TODO_LIST_REAPPLY_CHERRY_PICKS;
|
||||||
|
int skipped_commit = 0;
|
||||||
|
|
||||||
repo_init_revisions(r, &revs, NULL);
|
repo_init_revisions(r, &revs, NULL);
|
||||||
revs.verbose_header = 1;
|
revs.verbose_header = 1;
|
||||||
@ -5369,8 +5379,13 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
|
|||||||
while ((commit = get_revision(&revs))) {
|
while ((commit = get_revision(&revs))) {
|
||||||
int is_empty = is_original_commit_empty(commit);
|
int is_empty = is_original_commit_empty(commit);
|
||||||
|
|
||||||
if (!is_empty && (commit->object.flags & PATCHSAME))
|
if (!is_empty && (commit->object.flags & PATCHSAME)) {
|
||||||
|
if (flags & TODO_LIST_WARN_SKIPPED_CHERRY_PICKS)
|
||||||
|
warning(_("skipped previously applied commit %s"),
|
||||||
|
short_commit_name(commit));
|
||||||
|
skipped_commit = 1;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if (is_empty && !keep_empty)
|
if (is_empty && !keep_empty)
|
||||||
continue;
|
continue;
|
||||||
strbuf_addf(out, "%s %s ", insn,
|
strbuf_addf(out, "%s %s ", insn,
|
||||||
@ -5380,6 +5395,9 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
|
|||||||
strbuf_addf(out, " %c empty", comment_line_char);
|
strbuf_addf(out, " %c empty", comment_line_char);
|
||||||
strbuf_addch(out, '\n');
|
strbuf_addch(out, '\n');
|
||||||
}
|
}
|
||||||
|
if (skipped_commit)
|
||||||
|
advise_if_enabled(ADVICE_SKIPPED_CHERRY_PICKS,
|
||||||
|
_("use --reapply-cherry-picks to include skipped commits"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,6 +156,7 @@ int sequencer_remove_state(struct replay_opts *opts);
|
|||||||
*/
|
*/
|
||||||
#define TODO_LIST_ROOT_WITH_ONTO (1U << 6)
|
#define TODO_LIST_ROOT_WITH_ONTO (1U << 6)
|
||||||
#define TODO_LIST_REAPPLY_CHERRY_PICKS (1U << 7)
|
#define TODO_LIST_REAPPLY_CHERRY_PICKS (1U << 7)
|
||||||
|
#define TODO_LIST_WARN_SKIPPED_CHERRY_PICKS (1U << 8)
|
||||||
|
|
||||||
int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
|
int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
|
||||||
const char **argv, unsigned flags);
|
const char **argv, unsigned flags);
|
||||||
|
Loading…
Reference in New Issue
Block a user