git/sequencer.h
Junio C Hamano 43966ab315 revert: optionally refer to commit in the "reference" format
A typical "git revert" commit uses the full title of the original
commit in its title, and starts its body of the message with:

    This reverts commit 8fa7f667cf61386257c00d6e954855cc3215ae91.

This does not encourage the best practice of describing not just
"what" (i.e. "Revert X" on the title says what we did) but "why"
(i.e. and it does not say why X was undesirable).

We can instead phrase this first line of the body to be more like

    This reverts commit 8fa7f667 (do this and that, 2022-04-25)

so that the title does not have to be

    Revert "do this and that"

We can instead use the title to describe "why" we are reverting the
original commit.

Introduce the "--reference" option to "git revert", and also the
revert.reference configuration variable, which defaults to false, to
tweak the title and the first line of the draft commit message for
when creating a "revert" commit.

When this option is in use, the first line of the pre-filled editor
buffer becomes a comment line that tells the user to say _why_.  If
the user exits the editor without touching this line by mistake,
what we prepare to become the first line of the body, i.e. "This
reverts commit 8fa7f667 (do this and that, 2022-04-25)", ends up to
be the title of the resulting commit.  This behaviour is designed to
help such a user to identify such a revert in "git log --oneline"
easily so that it can be further reworded with "git rebase -i" later.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-05-26 23:05:03 -07:00

237 lines
7.4 KiB
C

#ifndef SEQUENCER_H
#define SEQUENCER_H
#include "cache.h"
#include "strbuf.h"
#include "wt-status.h"
struct commit;
struct repository;
const char *git_path_commit_editmsg(void);
const char *rebase_path_todo(void);
const char *rebase_path_todo_backup(void);
const char *rebase_path_dropped(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;
/* Tri-state options: unspecified, false, or true */
int edit;
/* Boolean options */
int record_origin;
int no_commit;
int signoff;
int allow_ff;
int allow_rerere_auto;
int allow_empty;
int allow_empty_message;
int drop_redundant_commits;
int keep_redundant_commits;
int verbose;
int quiet;
int reschedule_failed_exec;
int committer_date_is_author_date;
int ignore_date;
int commit_use_reference;
int mainline;
char *gpg_sign;
enum commit_msg_cleanup_mode default_msg_cleanup;
int explicit_cleanup;
/* Merge strategy */
char *default_strategy; /* from config options */
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 { .edit = -1, .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;
};
#define TODO_LIST_INIT { \
.buf = 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);
#define TODO_LIST_KEEP_EMPTY (1U << 0)
#define TODO_LIST_SHORTEN_IDS (1U << 1)
#define TODO_LIST_ABBREVIATE_CMDS (1U << 2)
#define TODO_LIST_REBASE_MERGES (1U << 3)
/*
* 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)
#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,
const char **argv, unsigned flags);
int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
const char *shortrevisions, const char *onto_name,
struct commit *onto, const struct object_id *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);
void create_autostash(struct repository *r, const char *path);
int save_autostash(const char *path);
int apply_autostash(const char *path);
int apply_autostash_oid(const char *stash_oid);
#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,
unsigned int flags);
#define READ_ONELINER_SKIP_IF_EMPTY (1 << 0)
#define READ_ONELINER_WARN_MISSING (1 << 1)
/*
* Reads a file that was presumably written by a shell script, i.e. with an
* end-of-line marker that needs to be stripped.
*
* Note that only the last end-of-line marker is stripped, consistent with the
* behavior of "$(cat path)" in a shell script.
*
* Returns 1 if the file was read, 0 if it could not be read or does not exist.
*/
int read_oneliner(struct strbuf *buf,
const char *path, unsigned 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 struct object_id *orig_head);
void sequencer_post_commit_cleanup(struct repository *r, int verbose);
int sequencer_get_last_command(struct repository* r,
enum replay_action *action);
int sequencer_determine_whence(struct repository *r, enum commit_whence *whence);
#endif /* SEQUENCER_H */