git/sequencer.h

212 строки
6.6 KiB
C
Исходник Обычный вид История

#ifndef SEQUENCER_H
#define SEQUENCER_H
#include "cache.h"
#include "strbuf.h"
struct commit;
struct repository;
const char *git_path_commit_editmsg(void);
const char *git_path_seq_dir(void);
const char *rebase_path_todo(void);
const char *rebase_path_todo_backup(void);
#define APPEND_SIGNOFF_DEDUP (1u << 0)
enum replay_action {
REPLAY_REVERT,
REPLAY_PICK,
REPLAY_INTERACTIVE_REBASE
};
enum commit_msg_cleanup_mode {
COMMIT_MSG_CLEANUP_SPACE,
COMMIT_MSG_CLEANUP_NONE,
COMMIT_MSG_CLEANUP_SCISSORS,
COMMIT_MSG_CLEANUP_ALL
};
struct replay_opts {
enum replay_action action;
/* Boolean options */
int edit;
int record_origin;
int no_commit;
int signoff;
int allow_ff;
int allow_rerere_auto;
int allow_empty;
int allow_empty_message;
int keep_redundant_commits;
int verbose;
int quiet;
int reschedule_failed_exec;
int mainline;
char *gpg_sign;
enum commit_msg_cleanup_mode default_msg_cleanup;
int explicit_cleanup;
/* Merge strategy */
char *strategy;
char **xopts;
size_t xopts_nr, xopts_alloc;
/* Used by fixup/squash */
struct strbuf current_fixups;
int current_fixup_count;
/* placeholder commit for -i --root */
struct object_id squash_onto;
int have_squash_onto;
/* Only used by REPLAY_NONE */
struct rev_info *revs;
};
#define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT }
/*
* Note that ordering matters in this enum. Not only must it match the mapping
* of todo_command_info (in sequencer.c), it is also divided into several
* sections that matter. When adding new commands, make sure you add it in the
* right section.
*/
enum todo_command {
/* commands that handle commits */
TODO_PICK = 0,
TODO_REVERT,
TODO_EDIT,
TODO_REWORD,
TODO_FIXUP,
TODO_SQUASH,
/* commands that do something else than handling a single commit */
TODO_EXEC,
TODO_BREAK,
TODO_LABEL,
TODO_RESET,
TODO_MERGE,
/* commands that do nothing but are counted for reporting progress */
TODO_NOOP,
TODO_DROP,
/* comments (not counted for reporting progress) */
TODO_COMMENT
};
struct todo_item {
enum todo_command command;
struct commit *commit;
unsigned int flags;
int arg_len;
/* The offset of the command and its argument in the strbuf */
size_t offset_in_buf, arg_offset;
};
struct todo_list {
struct strbuf buf;
struct todo_item *items;
int nr, alloc, current;
int done_nr, total_nr;
struct stat_data stat;
};
#define TODO_LIST_INIT { STRBUF_INIT }
int todo_list_parse_insn_buffer(struct repository *r, char *buf,
struct todo_list *todo_list);
int todo_list_write_to_file(struct repository *r, struct todo_list *todo_list,
const char *file, const char *shortrevisions,
const char *shortonto, int num, unsigned flags);
void todo_list_release(struct todo_list *todo_list);
const char *todo_item_get_arg(struct todo_list *todo_list,
struct todo_item *item);
/* Call this to setup defaults before parsing command line options */
void sequencer_init_config(struct replay_opts *opts);
int sequencer_pick_revisions(struct repository *repo,
struct replay_opts *opts);
int sequencer_continue(struct repository *repo, struct replay_opts *opts);
int sequencer_rollback(struct repository *repo, struct replay_opts *opts);
int sequencer_skip(struct repository *repo, struct replay_opts *opts);
int sequencer_remove_state(struct replay_opts *opts);
rebase (interactive-backend): make --keep-empty the default Different rebase backends have different treatment for commits which start empty (i.e. have no changes relative to their parent), and the --keep-empty option was added at some point to allow adjusting behavior. The handling of commits which start empty is actually quite similar to commit b00bf1c9a8dd (git-rebase: make --allow-empty-message the default, 2018-06-27), which pointed out that the behavior for various backends is often more happenstance than design. The specific change made in that commit is actually quite relevant as well and much of the logic there directly applies here. It makes a lot of sense in 'git commit' to error out on the creation of empty commits, unless an override flag is provided. However, once someone determines that there is a rare case that merits using the manual override to create such a commit, it is somewhere between annoying and harmful to have to take extra steps to keep such intentional commits around. Granted, empty commits are quite rare, which is why handling of them doesn't get considered much and folks tend to defer to existing (accidental) behavior and assume there was a reason for it, leading them to just add flags (--keep-empty in this case) that allow them to override the bad defaults. Fix the interactive backend so that --keep-empty is the default, much like we did with --allow-empty-message. The am backend should also be fixed to have --keep-empty semantics for commits that start empty, but that is not included in this patch other than a testcase documenting the failure. Note that there was one test in t3421 which appears to have been written expecting --keep-empty to not be the default as correct behavior. This test was introduced in commit 00b8be5a4d38 ("add tests for rebasing of empty commits", 2013-06-06), which was part of a series focusing on rebase topology and which had an interesting original cover letter at https://lore.kernel.org/git/1347949878-12578-1-git-send-email-martinvonz@gmail.com/ which noted Your input especially appreciated on whether you agree with the intent of the test cases. and then went into a long example about how one of the many tests added had several questions about whether it was correct. As such, I believe most the tests in that series were about testing rebase topology with as many different flags as possible and were not trying to state in general how those flags should behave otherwise. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-16 00:36:24 +03:00
/* #define TODO_LIST_KEEP_EMPTY (1U << 0) */ /* No longer used */
#define TODO_LIST_SHORTEN_IDS (1U << 1)
#define TODO_LIST_ABBREVIATE_CMDS (1U << 2)
#define TODO_LIST_REBASE_MERGES (1U << 3)
rebase -i: introduce --rebase-merges=[no-]rebase-cousins When running `git rebase --rebase-merges` non-interactively with an ancestor of HEAD as <upstream> (or leaving the todo list unmodified), we would ideally recreate the exact same commits as before the rebase. However, if there are commits in the commit range <upstream>.. that do not have <upstream> as direct ancestor (i.e. if `git log <upstream>..` would show commits that are omitted by `git log --ancestry-path <upstream>..`), this is currently not the case: we would turn them into commits that have <upstream> as direct ancestor. Let's illustrate that with a diagram: C / \ A - B - E - F \ / D Currently, after running `git rebase -i --rebase-merges B`, the new branch structure would be (pay particular attention to the commit `D`): --- C' -- / \ A - B ------ E' - F' \ / D' This is not really preserving the branch topology from before! The reason is that the commit `D` does not have `B` as ancestor, and therefore it gets rebased onto `B`. This is unintuitive behavior. Even worse, when recreating branch structure, most use cases would appear to want cousins *not* to be rebased onto the new base commit. For example, Git for Windows (the heaviest user of the Git garden shears, which served as the blueprint for --rebase-merges) frequently merges branches from `next` early, and these branches certainly do *not* want to be rebased. In the example above, the desired outcome would look like this: --- C' -- / \ A - B ------ E' - F' \ / -- D' -- Let's introduce the term "cousins" for such commits ("D" in the example), and let's not rebase them by default. For hypothetical use cases where cousins *do* need to be rebased, `git rebase --rebase=merges=rebase-cousins` needs to be used. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-25 15:29:40 +03:00
/*
* When rebasing merges, commits that do have the base commit as ancestor
* ("cousins") are *not* rebased onto the new base by default. If those
* commits should be rebased onto the new base, this flag needs to be passed.
*/
#define TODO_LIST_REBASE_COUSINS (1U << 4)
#define TODO_LIST_APPEND_TODO_HELP (1U << 5)
/*
* When generating a script that rebases merges with `--root` *and* with
* `--onto`, we do not want to re-generate the root commits.
*/
#define TODO_LIST_ROOT_WITH_ONTO (1U << 6)
int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
const char **argv, unsigned flags);
void todo_list_add_exec_commands(struct todo_list *todo_list,
struct string_list *commands);
int check_todo_list_from_file(struct repository *r);
int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
const char *shortrevisions, const char *onto_name,
struct commit *onto, const char *orig_head, struct string_list *commands,
unsigned autosquash, struct todo_list *todo_list);
int todo_list_rearrange_squash(struct todo_list *todo_list);
/*
* Append a signoff to the commit message in "msgbuf". The ignore_footer
* parameter specifies the number of bytes at the end of msgbuf that should
* not be considered at all. I.e., they are not checked for existing trailers,
* and the new signoff will be spliced into the buffer before those bytes.
*/
void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
void append_conflicts_hint(struct index_state *istate,
struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode);
enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
int use_editor);
void cleanup_message(struct strbuf *msgbuf,
enum commit_msg_cleanup_mode cleanup_mode, int verbose);
int message_is_empty(const struct strbuf *sb,
enum commit_msg_cleanup_mode cleanup_mode);
int template_untouched(const struct strbuf *sb, const char *template_file,
enum commit_msg_cleanup_mode cleanup_mode);
int update_head_with_reflog(const struct commit *old_head,
const struct object_id *new_head,
const char *action, const struct strbuf *msg,
struct strbuf *err);
void commit_post_rewrite(struct repository *r,
const struct commit *current_head,
const struct object_id *new_head);
int prepare_branch_to_be_rebased(struct repository *r, struct replay_opts *opts,
const char *commit);
commit: move print_commit_summary() to libgit Move print_commit_summary() from builtin/commit.c to sequencer.c so it can be shared with other commands. The function is modified by changing the last argument to a flag so callers can specify whether they want to show the author date in addition to specifying if this is an initial commit. If the sequencer dies in print_commit_summary() (which can only happen when cherry-picking or reverting) then neither the todo list nor the abort safety file are updated to reflect the commit that was just made. print_commit_summary() can die if: - The commit that was just created cannot be found or parsed. - HEAD cannot be resolved either because some other process is updating it (which is bad news in the middle of a cherry-pick) or because it is corrupt. - log_tree_commit() cannot read some objects. In all those cases dying will leave the sequencer in a sane state for aborting; 'git cherry-pick --abort' will rewind HEAD to the last successful commit before there was a problem with HEAD or the object database. If the user somehow fixes the problem and runs 'git cherry-pick --continue' then the sequencer will try and pick the same commit again which may or may not be what the user wants depending on what caused print_commit_summary() to die. If print_commit_summary() returned an error instead then update_abort_safety_file() would try to resolve HEAD which may or may not be successful. If it is successful then running 'git rebase --abort' would not rewind HEAD to the last successful commit which is not what we want. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-24 14:07:54 +03:00
#define SUMMARY_INITIAL_COMMIT (1 << 0)
#define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)
void print_commit_summary(struct repository *repo,
const char *prefix,
const struct object_id *oid,
commit: move print_commit_summary() to libgit Move print_commit_summary() from builtin/commit.c to sequencer.c so it can be shared with other commands. The function is modified by changing the last argument to a flag so callers can specify whether they want to show the author date in addition to specifying if this is an initial commit. If the sequencer dies in print_commit_summary() (which can only happen when cherry-picking or reverting) then neither the todo list nor the abort safety file are updated to reflect the commit that was just made. print_commit_summary() can die if: - The commit that was just created cannot be found or parsed. - HEAD cannot be resolved either because some other process is updating it (which is bad news in the middle of a cherry-pick) or because it is corrupt. - log_tree_commit() cannot read some objects. In all those cases dying will leave the sequencer in a sane state for aborting; 'git cherry-pick --abort' will rewind HEAD to the last successful commit before there was a problem with HEAD or the object database. If the user somehow fixes the problem and runs 'git cherry-pick --continue' then the sequencer will try and pick the same commit again which may or may not be what the user wants depending on what caused print_commit_summary() to die. If print_commit_summary() returned an error instead then update_abort_safety_file() would try to resolve HEAD which may or may not be successful. If it is successful then running 'git rebase --abort' would not rewind HEAD to the last successful commit which is not what we want. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-24 14:07:54 +03:00
unsigned int flags);
int read_author_script(const char *path, char **name, char **email, char **date,
int allow_missing);
void parse_strategy_opts(struct replay_opts *opts, char *raw_opts);
int write_basic_state(struct replay_opts *opts, const char *head_name,
struct commit *onto, const char *orig_head);
void sequencer_post_commit_cleanup(struct repository *r, int verbose);
int sequencer_get_last_command(struct repository* r,
enum replay_action *action);
#endif /* SEQUENCER_H */