git-commit-vandalism/builtin/log.c

2253 lines
61 KiB
C
Raw Normal View History

/*
* Builtin "git log" and related commands (show, whatchanged)
*
* (C) Copyright 2006 Linus Torvalds
* 2006 Junio Hamano
*/
#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
#include "config.h"
#include "refs.h"
#include "object-store.h"
#include "color.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"
#include "log-tree.h"
#include "builtin.h"
#include "tag.h"
#include "reflog-walk.h"
#include "patch-ids.h"
#include "run-command.h"
#include "shortlog.h"
#include "remote.h"
#include "string-list.h"
#include "parse-options.h"
Implement line-history search (git log -L) This is a rewrite of much of Bo's work, mainly in an effort to split it into smaller, easier to understand routines. The algorithm is built around the struct range_set, which encodes a series of line ranges as intervals [a,b). This is used in two contexts: * A set of lines we are tracking (which will change as we dig through history). * To encode diffs, as pairs of ranges. The main routine is range_set_map_across_diff(). It processes the diff between a commit C and some parent P. It determines which diff hunks are relevant to the ranges tracked in C, and computes the new ranges for P. The algorithm is then simply to process history in topological order from newest to oldest, computing ranges and (partial) diffs. At branch points, we need to merge the ranges we are watching. We will find that many commits do not affect the chosen ranges, and mark them TREESAME (in addition to those already filtered by pathspec limiting). Another pass of history simplification then gets rid of such commits. This is wired as an extra filtering pass in the log machinery. This currently only reduces code duplication, but should allow for other simplifications and options to be used. Finally, we hook a diff printer into the output chain. Ideally we would wire directly into the diff logic, to optionally use features like word diff. However, that will require some major reworking of the diff chain, so we completely replace the output with our own diff for now. As this was a GSoC project, and has quite some history by now, many people have helped. In no particular order, thanks go to Jakub Narebski <jnareb@gmail.com> Jens Lehmann <Jens.Lehmann@web.de> Jonathan Nieder <jrnieder@gmail.com> Junio C Hamano <gitster@pobox.com> Ramsay Jones <ramsay@ramsay1.demon.co.uk> Will Palmer <wmpalmer@gmail.com> Apologies to everyone I forgot. Signed-off-by: Bo Yang <struggleyb.nku@gmail.com> Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-28 17:47:32 +01:00
#include "line-log.h"
#include "branch.h"
#include "streaming.h"
#include "version.h"
#include "mailmap.h"
#include "gpg-interface.h"
#include "progress.h"
#include "commit-slab.h"
#include "repository.h"
#include "commit-reach.h"
#include "interdiff.h"
#include "range-diff.h"
#define MAIL_DEFAULT_WRAP 72
#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
/* Set a default date-time format for git log ("log.date" config variable) */
static const char *default_date_mode = NULL;
static int default_abbrev_commit;
static int default_show_root = 1;
static int default_follow;
static int default_show_signature;
static int default_encode_email_headers = 1;
static int decoration_style;
static int decoration_given;
static int use_mailmap_config = 1;
static const char *fmt_patch_subject_prefix = "PATCH";
static const char *fmt_pretty;
static const char * const builtin_log_usage[] = {
N_("git log [<options>] [<revision-range>] [[--] <path>...]"),
N_("git show [<options>] <object>..."),
NULL
};
Implement line-history search (git log -L) This is a rewrite of much of Bo's work, mainly in an effort to split it into smaller, easier to understand routines. The algorithm is built around the struct range_set, which encodes a series of line ranges as intervals [a,b). This is used in two contexts: * A set of lines we are tracking (which will change as we dig through history). * To encode diffs, as pairs of ranges. The main routine is range_set_map_across_diff(). It processes the diff between a commit C and some parent P. It determines which diff hunks are relevant to the ranges tracked in C, and computes the new ranges for P. The algorithm is then simply to process history in topological order from newest to oldest, computing ranges and (partial) diffs. At branch points, we need to merge the ranges we are watching. We will find that many commits do not affect the chosen ranges, and mark them TREESAME (in addition to those already filtered by pathspec limiting). Another pass of history simplification then gets rid of such commits. This is wired as an extra filtering pass in the log machinery. This currently only reduces code duplication, but should allow for other simplifications and options to be used. Finally, we hook a diff printer into the output chain. Ideally we would wire directly into the diff logic, to optionally use features like word diff. However, that will require some major reworking of the diff chain, so we completely replace the output with our own diff for now. As this was a GSoC project, and has quite some history by now, many people have helped. In no particular order, thanks go to Jakub Narebski <jnareb@gmail.com> Jens Lehmann <Jens.Lehmann@web.de> Jonathan Nieder <jrnieder@gmail.com> Junio C Hamano <gitster@pobox.com> Ramsay Jones <ramsay@ramsay1.demon.co.uk> Will Palmer <wmpalmer@gmail.com> Apologies to everyone I forgot. Signed-off-by: Bo Yang <struggleyb.nku@gmail.com> Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-28 17:47:32 +01:00
struct line_opt_callback_data {
struct rev_info *rev;
const char *prefix;
struct string_list args;
};
static int session_is_interactive(void)
{
return isatty(1) || pager_in_use();
}
static int auto_decoration_style(void)
{
return session_is_interactive() ? DECORATE_SHORT_REFS : 0;
}
static int parse_decoration_style(const char *value)
{
switch (git_parse_maybe_bool(value)) {
case 1:
return DECORATE_SHORT_REFS;
case 0:
return 0;
default:
break;
}
if (!strcmp(value, "full"))
return DECORATE_FULL_REFS;
else if (!strcmp(value, "short"))
return DECORATE_SHORT_REFS;
else if (!strcmp(value, "auto"))
return auto_decoration_style();
/*
* Please update _git_log() in git-completion.bash when you
* add new decoration styles.
*/
return -1;
}
static int decorate_callback(const struct option *opt, const char *arg, int unset)
{
if (unset)
decoration_style = 0;
else if (arg)
decoration_style = parse_decoration_style(arg);
else
decoration_style = DECORATE_SHORT_REFS;
if (decoration_style < 0)
die(_("invalid --decorate option: %s"), arg);
decoration_given = 1;
return 0;
}
Implement line-history search (git log -L) This is a rewrite of much of Bo's work, mainly in an effort to split it into smaller, easier to understand routines. The algorithm is built around the struct range_set, which encodes a series of line ranges as intervals [a,b). This is used in two contexts: * A set of lines we are tracking (which will change as we dig through history). * To encode diffs, as pairs of ranges. The main routine is range_set_map_across_diff(). It processes the diff between a commit C and some parent P. It determines which diff hunks are relevant to the ranges tracked in C, and computes the new ranges for P. The algorithm is then simply to process history in topological order from newest to oldest, computing ranges and (partial) diffs. At branch points, we need to merge the ranges we are watching. We will find that many commits do not affect the chosen ranges, and mark them TREESAME (in addition to those already filtered by pathspec limiting). Another pass of history simplification then gets rid of such commits. This is wired as an extra filtering pass in the log machinery. This currently only reduces code duplication, but should allow for other simplifications and options to be used. Finally, we hook a diff printer into the output chain. Ideally we would wire directly into the diff logic, to optionally use features like word diff. However, that will require some major reworking of the diff chain, so we completely replace the output with our own diff for now. As this was a GSoC project, and has quite some history by now, many people have helped. In no particular order, thanks go to Jakub Narebski <jnareb@gmail.com> Jens Lehmann <Jens.Lehmann@web.de> Jonathan Nieder <jrnieder@gmail.com> Junio C Hamano <gitster@pobox.com> Ramsay Jones <ramsay@ramsay1.demon.co.uk> Will Palmer <wmpalmer@gmail.com> Apologies to everyone I forgot. Signed-off-by: Bo Yang <struggleyb.nku@gmail.com> Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-28 17:47:32 +01:00
static int log_line_range_callback(const struct option *option, const char *arg, int unset)
{
struct line_opt_callback_data *data = option->value;
assert NOARG/NONEG behavior of parse-options callbacks When we define a parse-options callback, the flags we put in the option struct must match what the callback expects. For example, a callback which does not handle the "unset" parameter should only be used with PARSE_OPT_NONEG. But since the callback and the option struct are not defined next to each other, it's easy to get this wrong (as earlier patches in this series show). Fortunately, the compiler can help us here: compiling with -Wunused-parameters can show us which callbacks ignore their "unset" parameters (and likewise, ones that ignore "arg" expect to be triggered with PARSE_OPT_NOARG). But after we've inspected a callback and determined that all of its callers use the right flags, what do we do next? We'd like to silence the compiler warning, but do so in a way that will catch any wrong calls in the future. We can do that by actually checking those variables and asserting that they match our expectations. Because this is such a common pattern, we'll introduce some helper macros. The resulting messages aren't as descriptive as we could make them, but the file/line information from BUG() is enough to identify the problem (and anyway, the point is that these should never be seen). Each of the annotated callbacks in this patch triggers -Wunused-parameters, and was manually inspected to make sure all callers use the correct options (so none of these BUGs should be triggerable). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 07:45:42 +01:00
BUG_ON_OPT_NEG(unset);
Implement line-history search (git log -L) This is a rewrite of much of Bo's work, mainly in an effort to split it into smaller, easier to understand routines. The algorithm is built around the struct range_set, which encodes a series of line ranges as intervals [a,b). This is used in two contexts: * A set of lines we are tracking (which will change as we dig through history). * To encode diffs, as pairs of ranges. The main routine is range_set_map_across_diff(). It processes the diff between a commit C and some parent P. It determines which diff hunks are relevant to the ranges tracked in C, and computes the new ranges for P. The algorithm is then simply to process history in topological order from newest to oldest, computing ranges and (partial) diffs. At branch points, we need to merge the ranges we are watching. We will find that many commits do not affect the chosen ranges, and mark them TREESAME (in addition to those already filtered by pathspec limiting). Another pass of history simplification then gets rid of such commits. This is wired as an extra filtering pass in the log machinery. This currently only reduces code duplication, but should allow for other simplifications and options to be used. Finally, we hook a diff printer into the output chain. Ideally we would wire directly into the diff logic, to optionally use features like word diff. However, that will require some major reworking of the diff chain, so we completely replace the output with our own diff for now. As this was a GSoC project, and has quite some history by now, many people have helped. In no particular order, thanks go to Jakub Narebski <jnareb@gmail.com> Jens Lehmann <Jens.Lehmann@web.de> Jonathan Nieder <jrnieder@gmail.com> Junio C Hamano <gitster@pobox.com> Ramsay Jones <ramsay@ramsay1.demon.co.uk> Will Palmer <wmpalmer@gmail.com> Apologies to everyone I forgot. Signed-off-by: Bo Yang <struggleyb.nku@gmail.com> Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-28 17:47:32 +01:00
if (!arg)
return -1;
data->rev->line_level_traverse = 1;
string_list_append(&data->args, arg);
return 0;
}
static void init_log_defaults(void)
{
init_grep_defaults(the_repository);
init_diff_ui_defaults();
decoration_style = auto_decoration_style();
}
static void cmd_log_init_defaults(struct rev_info *rev)
{
if (fmt_pretty)
get_commit_format(fmt_pretty, rev);
if (default_follow)
diff: make struct diff_flags members lowercase Now that the flags stored in struct diff_flags are being accessed directly and not through macros, change all struct members from being uppercase to lowercase. This conversion is done using the following semantic patch: @@ expression E; @@ - E.RECURSIVE + E.recursive @@ expression E; @@ - E.TREE_IN_RECURSIVE + E.tree_in_recursive @@ expression E; @@ - E.BINARY + E.binary @@ expression E; @@ - E.TEXT + E.text @@ expression E; @@ - E.FULL_INDEX + E.full_index @@ expression E; @@ - E.SILENT_ON_REMOVE + E.silent_on_remove @@ expression E; @@ - E.FIND_COPIES_HARDER + E.find_copies_harder @@ expression E; @@ - E.FOLLOW_RENAMES + E.follow_renames @@ expression E; @@ - E.RENAME_EMPTY + E.rename_empty @@ expression E; @@ - E.HAS_CHANGES + E.has_changes @@ expression E; @@ - E.QUICK + E.quick @@ expression E; @@ - E.NO_INDEX + E.no_index @@ expression E; @@ - E.ALLOW_EXTERNAL + E.allow_external @@ expression E; @@ - E.EXIT_WITH_STATUS + E.exit_with_status @@ expression E; @@ - E.REVERSE_DIFF + E.reverse_diff @@ expression E; @@ - E.CHECK_FAILED + E.check_failed @@ expression E; @@ - E.RELATIVE_NAME + E.relative_name @@ expression E; @@ - E.IGNORE_SUBMODULES + E.ignore_submodules @@ expression E; @@ - E.DIRSTAT_CUMULATIVE + E.dirstat_cumulative @@ expression E; @@ - E.DIRSTAT_BY_FILE + E.dirstat_by_file @@ expression E; @@ - E.ALLOW_TEXTCONV + E.allow_textconv @@ expression E; @@ - E.TEXTCONV_SET_VIA_CMDLINE + E.textconv_set_via_cmdline @@ expression E; @@ - E.DIFF_FROM_CONTENTS + E.diff_from_contents @@ expression E; @@ - E.DIRTY_SUBMODULES + E.dirty_submodules @@ expression E; @@ - E.IGNORE_UNTRACKED_IN_SUBMODULES + E.ignore_untracked_in_submodules @@ expression E; @@ - E.IGNORE_DIRTY_SUBMODULES + E.ignore_dirty_submodules @@ expression E; @@ - E.OVERRIDE_SUBMODULE_CONFIG + E.override_submodule_config @@ expression E; @@ - E.DIRSTAT_BY_LINE + E.dirstat_by_line @@ expression E; @@ - E.FUNCCONTEXT + E.funccontext @@ expression E; @@ - E.PICKAXE_IGNORE_CASE + E.pickaxe_ignore_case @@ expression E; @@ - E.DEFAULT_FOLLOW_RENAMES + E.default_follow_renames Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-31 19:19:11 +01:00
rev->diffopt.flags.default_follow_renames = 1;
rev->verbose_header = 1;
diff: make struct diff_flags members lowercase Now that the flags stored in struct diff_flags are being accessed directly and not through macros, change all struct members from being uppercase to lowercase. This conversion is done using the following semantic patch: @@ expression E; @@ - E.RECURSIVE + E.recursive @@ expression E; @@ - E.TREE_IN_RECURSIVE + E.tree_in_recursive @@ expression E; @@ - E.BINARY + E.binary @@ expression E; @@ - E.TEXT + E.text @@ expression E; @@ - E.FULL_INDEX + E.full_index @@ expression E; @@ - E.SILENT_ON_REMOVE + E.silent_on_remove @@ expression E; @@ - E.FIND_COPIES_HARDER + E.find_copies_harder @@ expression E; @@ - E.FOLLOW_RENAMES + E.follow_renames @@ expression E; @@ - E.RENAME_EMPTY + E.rename_empty @@ expression E; @@ - E.HAS_CHANGES + E.has_changes @@ expression E; @@ - E.QUICK + E.quick @@ expression E; @@ - E.NO_INDEX + E.no_index @@ expression E; @@ - E.ALLOW_EXTERNAL + E.allow_external @@ expression E; @@ - E.EXIT_WITH_STATUS + E.exit_with_status @@ expression E; @@ - E.REVERSE_DIFF + E.reverse_diff @@ expression E; @@ - E.CHECK_FAILED + E.check_failed @@ expression E; @@ - E.RELATIVE_NAME + E.relative_name @@ expression E; @@ - E.IGNORE_SUBMODULES + E.ignore_submodules @@ expression E; @@ - E.DIRSTAT_CUMULATIVE + E.dirstat_cumulative @@ expression E; @@ - E.DIRSTAT_BY_FILE + E.dirstat_by_file @@ expression E; @@ - E.ALLOW_TEXTCONV + E.allow_textconv @@ expression E; @@ - E.TEXTCONV_SET_VIA_CMDLINE + E.textconv_set_via_cmdline @@ expression E; @@ - E.DIFF_FROM_CONTENTS + E.diff_from_contents @@ expression E; @@ - E.DIRTY_SUBMODULES + E.dirty_submodules @@ expression E; @@ - E.IGNORE_UNTRACKED_IN_SUBMODULES + E.ignore_untracked_in_submodules @@ expression E; @@ - E.IGNORE_DIRTY_SUBMODULES + E.ignore_dirty_submodules @@ expression E; @@ - E.OVERRIDE_SUBMODULE_CONFIG + E.override_submodule_config @@ expression E; @@ - E.DIRSTAT_BY_LINE + E.dirstat_by_line @@ expression E; @@ - E.FUNCCONTEXT + E.funccontext @@ expression E; @@ - E.PICKAXE_IGNORE_CASE + E.pickaxe_ignore_case @@ expression E; @@ - E.DEFAULT_FOLLOW_RENAMES + E.default_follow_renames Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-31 19:19:11 +01:00
rev->diffopt.flags.recursive = 1;
rev->diffopt.stat_width = -1; /* use full terminal width */
rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */
rev->abbrev_commit = default_abbrev_commit;
rev->show_root_diff = default_show_root;
rev->subject_prefix = fmt_patch_subject_prefix;
rev->show_signature = default_show_signature;
rev->encode_email_headers = default_encode_email_headers;
diff: make struct diff_flags members lowercase Now that the flags stored in struct diff_flags are being accessed directly and not through macros, change all struct members from being uppercase to lowercase. This conversion is done using the following semantic patch: @@ expression E; @@ - E.RECURSIVE + E.recursive @@ expression E; @@ - E.TREE_IN_RECURSIVE + E.tree_in_recursive @@ expression E; @@ - E.BINARY + E.binary @@ expression E; @@ - E.TEXT + E.text @@ expression E; @@ - E.FULL_INDEX + E.full_index @@ expression E; @@ - E.SILENT_ON_REMOVE + E.silent_on_remove @@ expression E; @@ - E.FIND_COPIES_HARDER + E.find_copies_harder @@ expression E; @@ - E.FOLLOW_RENAMES + E.follow_renames @@ expression E; @@ - E.RENAME_EMPTY + E.rename_empty @@ expression E; @@ - E.HAS_CHANGES + E.has_changes @@ expression E; @@ - E.QUICK + E.quick @@ expression E; @@ - E.NO_INDEX + E.no_index @@ expression E; @@ - E.ALLOW_EXTERNAL + E.allow_external @@ expression E; @@ - E.EXIT_WITH_STATUS + E.exit_with_status @@ expression E; @@ - E.REVERSE_DIFF + E.reverse_diff @@ expression E; @@ - E.CHECK_FAILED + E.check_failed @@ expression E; @@ - E.RELATIVE_NAME + E.relative_name @@ expression E; @@ - E.IGNORE_SUBMODULES + E.ignore_submodules @@ expression E; @@ - E.DIRSTAT_CUMULATIVE + E.dirstat_cumulative @@ expression E; @@ - E.DIRSTAT_BY_FILE + E.dirstat_by_file @@ expression E; @@ - E.ALLOW_TEXTCONV + E.allow_textconv @@ expression E; @@ - E.TEXTCONV_SET_VIA_CMDLINE + E.textconv_set_via_cmdline @@ expression E; @@ - E.DIFF_FROM_CONTENTS + E.diff_from_contents @@ expression E; @@ - E.DIRTY_SUBMODULES + E.dirty_submodules @@ expression E; @@ - E.IGNORE_UNTRACKED_IN_SUBMODULES + E.ignore_untracked_in_submodules @@ expression E; @@ - E.IGNORE_DIRTY_SUBMODULES + E.ignore_dirty_submodules @@ expression E; @@ - E.OVERRIDE_SUBMODULE_CONFIG + E.override_submodule_config @@ expression E; @@ - E.DIRSTAT_BY_LINE + E.dirstat_by_line @@ expression E; @@ - E.FUNCCONTEXT + E.funccontext @@ expression E; @@ - E.PICKAXE_IGNORE_CASE + E.pickaxe_ignore_case @@ expression E; @@ - E.DEFAULT_FOLLOW_RENAMES + E.default_follow_renames Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-31 19:19:11 +01:00
rev->diffopt.flags.allow_textconv = 1;
if (default_date_mode)
convert "enum date_mode" into a struct In preparation for adding date modes that may carry extra information beyond the mode itself, this patch converts the date_mode enum into a struct. Most of the conversion is fairly straightforward; we pass the struct as a pointer and dereference the type field where necessary. Locations that declare a date_mode can use a "{}" constructor. However, the tricky case is where we use the enum labels as constants, like: show_date(t, tz, DATE_NORMAL); Ideally we could say: show_date(t, tz, &{ DATE_NORMAL }); but of course C does not allow that. Likewise, we cannot cast the constant to a struct, because we need to pass an actual address. Our options are basically: 1. Manually add a "struct date_mode d = { DATE_NORMAL }" definition to each caller, and pass "&d". This makes the callers uglier, because they sometimes do not even have their own scope (e.g., they are inside a switch statement). 2. Provide a pre-made global "date_normal" struct that can be passed by address. We'd also need "date_rfc2822", "date_iso8601", and so forth. But at least the ugliness is defined in one place. 3. Provide a wrapper that generates the correct struct on the fly. The big downside is that we end up pointing to a single global, which makes our wrapper non-reentrant. But show_date is already not reentrant, so it does not matter. This patch implements 3, along with a minor macro to keep the size of the callers sane. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-25 18:55:02 +02:00
parse_date_format(default_date_mode, &rev->date_mode);
}
static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
struct rev_info *rev, struct setup_revision_opt *opt)
{
struct userformat_want w;
int quiet = 0, source = 0, mailmap;
Implement line-history search (git log -L) This is a rewrite of much of Bo's work, mainly in an effort to split it into smaller, easier to understand routines. The algorithm is built around the struct range_set, which encodes a series of line ranges as intervals [a,b). This is used in two contexts: * A set of lines we are tracking (which will change as we dig through history). * To encode diffs, as pairs of ranges. The main routine is range_set_map_across_diff(). It processes the diff between a commit C and some parent P. It determines which diff hunks are relevant to the ranges tracked in C, and computes the new ranges for P. The algorithm is then simply to process history in topological order from newest to oldest, computing ranges and (partial) diffs. At branch points, we need to merge the ranges we are watching. We will find that many commits do not affect the chosen ranges, and mark them TREESAME (in addition to those already filtered by pathspec limiting). Another pass of history simplification then gets rid of such commits. This is wired as an extra filtering pass in the log machinery. This currently only reduces code duplication, but should allow for other simplifications and options to be used. Finally, we hook a diff printer into the output chain. Ideally we would wire directly into the diff logic, to optionally use features like word diff. However, that will require some major reworking of the diff chain, so we completely replace the output with our own diff for now. As this was a GSoC project, and has quite some history by now, many people have helped. In no particular order, thanks go to Jakub Narebski <jnareb@gmail.com> Jens Lehmann <Jens.Lehmann@web.de> Jonathan Nieder <jrnieder@gmail.com> Junio C Hamano <gitster@pobox.com> Ramsay Jones <ramsay@ramsay1.demon.co.uk> Will Palmer <wmpalmer@gmail.com> Apologies to everyone I forgot. Signed-off-by: Bo Yang <struggleyb.nku@gmail.com> Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-28 17:47:32 +01:00
static struct line_opt_callback_data line_cb = {NULL, NULL, STRING_LIST_INIT_DUP};
log: add option to choose which refs to decorate When `log --decorate` is used, git will decorate commits with all available refs. While in most cases this may give the desired effect, under some conditions it can lead to excessively verbose output. Introduce two command line options, `--decorate-refs=<pattern>` and `--decorate-refs-exclude=<pattern>` to allow the user to select which refs are used in decoration. When "--decorate-refs=<pattern>" is given, only the refs that match the pattern are used in decoration. The refs that match the pattern when "--decorate-refs-exclude=<pattern>" is given, are never used in decoration. These options follow the same convention for mixing negative and positive patterns across the system, assuming that the inclusive default is to match all refs available. (1) if there is no positive pattern given, pretend as if an inclusive default positive pattern was given; (2) for each candidate, reject it if it matches no positive pattern, or if it matches any one of the negative patterns. The rules for what is considered a match are slightly different from the rules used elsewhere. Commands like `log --glob` assume a trailing '/*' when glob chars are not present in the pattern. This makes it difficult to specify a single ref. On the other hand, commands like `describe --match --all` allow specifying exact refs, but do not have the convenience of allowing "shorthand refs" like 'refs/heads' or 'heads' to refer to 'refs/heads/*'. The commands introduced in this patch consider a match if: (a) the pattern contains globs chars, and regular pattern matching returns a match. (b) the pattern does not contain glob chars, and ref '<pattern>' exists, or if ref exists under '<pattern>/' This allows both behaviours (allowing single refs and shorthand refs) yet remaining compatible with existent commands. Helped-by: Kevin Daudt <me@ikke.info> Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Rafael Ascensão <rafa.almas@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-21 22:33:41 +01:00
static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
log: add log.excludeDecoration config option In 'git log', the --decorate-refs-exclude option appends a pattern to a string_list. This list is used to prevent showing some refs in the decoration output, or even by --simplify-by-decoration. Users may want to use their refs space to store utility refs that should not appear in the decoration output. For example, Scalar [1] runs a background fetch but places the "new" refs inside the refs/scalar/hidden/<remote>/* refspace instead of refs/<remote>/* to avoid updating remote refs when the user is not looking. However, these "hidden" refs appear during regular 'git log' queries. A similar idea to use "hidden" refs is under consideration for core Git [2]. Add the 'log.excludeDecoration' config option so users can exclude some refs from decorations by default instead of needing to use --decorate-refs-exclude manually. The config value is multi-valued much like the command-line option. The documentation is careful to point out that the config value can be overridden by the --decorate-refs option, even though --decorate-refs-exclude would always "win" over --decorate-refs. Since the 'log.excludeDecoration' takes lower precedence to --decorate-refs, and --decorate-refs-exclude takes higher precedence, the struct decoration_filter needed another field. This led also to new logic in load_ref_decorations() and ref_filter_match(). There are several tests in t4202-log.sh that test the --decorate-refs-(include|exclude) options, so these are extended. Since the expected output is already stored as a file, most tests could simply replace a "--decorate-refs-exclude" option with an in-line config setting. Other tests involve the precedence of the config option compared to command-line options and needed more modification. [1] https://github.com/microsoft/scalar [2] https://lore.kernel.org/git/77b1da5d3063a2404cd750adfe3bb8be9b6c497d.1585946894.git.gitgitgadget@gmail.com/ Helped-by: Junio C Hamano <gister@pobox.com> Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-16 16:15:49 +02:00
static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
log: add option to choose which refs to decorate When `log --decorate` is used, git will decorate commits with all available refs. While in most cases this may give the desired effect, under some conditions it can lead to excessively verbose output. Introduce two command line options, `--decorate-refs=<pattern>` and `--decorate-refs-exclude=<pattern>` to allow the user to select which refs are used in decoration. When "--decorate-refs=<pattern>" is given, only the refs that match the pattern are used in decoration. The refs that match the pattern when "--decorate-refs-exclude=<pattern>" is given, are never used in decoration. These options follow the same convention for mixing negative and positive patterns across the system, assuming that the inclusive default is to match all refs available. (1) if there is no positive pattern given, pretend as if an inclusive default positive pattern was given; (2) for each candidate, reject it if it matches no positive pattern, or if it matches any one of the negative patterns. The rules for what is considered a match are slightly different from the rules used elsewhere. Commands like `log --glob` assume a trailing '/*' when glob chars are not present in the pattern. This makes it difficult to specify a single ref. On the other hand, commands like `describe --match --all` allow specifying exact refs, but do not have the convenience of allowing "shorthand refs" like 'refs/heads' or 'heads' to refer to 'refs/heads/*'. The commands introduced in this patch consider a match if: (a) the pattern contains globs chars, and regular pattern matching returns a match. (b) the pattern does not contain glob chars, and ref '<pattern>' exists, or if ref exists under '<pattern>/' This allows both behaviours (allowing single refs and shorthand refs) yet remaining compatible with existent commands. Helped-by: Kevin Daudt <me@ikke.info> Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Rafael Ascensão <rafa.almas@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-21 22:33:41 +01:00
static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
struct decoration_filter decoration_filter = {&decorate_refs_include,
log: add log.excludeDecoration config option In 'git log', the --decorate-refs-exclude option appends a pattern to a string_list. This list is used to prevent showing some refs in the decoration output, or even by --simplify-by-decoration. Users may want to use their refs space to store utility refs that should not appear in the decoration output. For example, Scalar [1] runs a background fetch but places the "new" refs inside the refs/scalar/hidden/<remote>/* refspace instead of refs/<remote>/* to avoid updating remote refs when the user is not looking. However, these "hidden" refs appear during regular 'git log' queries. A similar idea to use "hidden" refs is under consideration for core Git [2]. Add the 'log.excludeDecoration' config option so users can exclude some refs from decorations by default instead of needing to use --decorate-refs-exclude manually. The config value is multi-valued much like the command-line option. The documentation is careful to point out that the config value can be overridden by the --decorate-refs option, even though --decorate-refs-exclude would always "win" over --decorate-refs. Since the 'log.excludeDecoration' takes lower precedence to --decorate-refs, and --decorate-refs-exclude takes higher precedence, the struct decoration_filter needed another field. This led also to new logic in load_ref_decorations() and ref_filter_match(). There are several tests in t4202-log.sh that test the --decorate-refs-(include|exclude) options, so these are extended. Since the expected output is already stored as a file, most tests could simply replace a "--decorate-refs-exclude" option with an in-line config setting. Other tests involve the precedence of the config option compared to command-line options and needed more modification. [1] https://github.com/microsoft/scalar [2] https://lore.kernel.org/git/77b1da5d3063a2404cd750adfe3bb8be9b6c497d.1585946894.git.gitgitgadget@gmail.com/ Helped-by: Junio C Hamano <gister@pobox.com> Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-16 16:15:49 +02:00
&decorate_refs_exclude,
&decorate_refs_exclude_config};
static struct revision_sources revision_sources;
const struct option builtin_log_options[] = {
OPT__QUIET(&quiet, N_("suppress diff output")),
OPT_BOOL(0, "source", &source, N_("show source")),
OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")),
OPT_ALIAS(0, "mailmap", "use-mailmap"),
log: add option to choose which refs to decorate When `log --decorate` is used, git will decorate commits with all available refs. While in most cases this may give the desired effect, under some conditions it can lead to excessively verbose output. Introduce two command line options, `--decorate-refs=<pattern>` and `--decorate-refs-exclude=<pattern>` to allow the user to select which refs are used in decoration. When "--decorate-refs=<pattern>" is given, only the refs that match the pattern are used in decoration. The refs that match the pattern when "--decorate-refs-exclude=<pattern>" is given, are never used in decoration. These options follow the same convention for mixing negative and positive patterns across the system, assuming that the inclusive default is to match all refs available. (1) if there is no positive pattern given, pretend as if an inclusive default positive pattern was given; (2) for each candidate, reject it if it matches no positive pattern, or if it matches any one of the negative patterns. The rules for what is considered a match are slightly different from the rules used elsewhere. Commands like `log --glob` assume a trailing '/*' when glob chars are not present in the pattern. This makes it difficult to specify a single ref. On the other hand, commands like `describe --match --all` allow specifying exact refs, but do not have the convenience of allowing "shorthand refs" like 'refs/heads' or 'heads' to refer to 'refs/heads/*'. The commands introduced in this patch consider a match if: (a) the pattern contains globs chars, and regular pattern matching returns a match. (b) the pattern does not contain glob chars, and ref '<pattern>' exists, or if ref exists under '<pattern>/' This allows both behaviours (allowing single refs and shorthand refs) yet remaining compatible with existent commands. Helped-by: Kevin Daudt <me@ikke.info> Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Rafael Ascensão <rafa.almas@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-21 22:33:41 +01:00
OPT_STRING_LIST(0, "decorate-refs", &decorate_refs_include,
N_("pattern"), N_("only decorate refs that match <pattern>")),
OPT_STRING_LIST(0, "decorate-refs-exclude", &decorate_refs_exclude,
N_("pattern"), N_("do not decorate refs that match <pattern>")),
OPT_CALLBACK_F(0, "decorate", NULL, NULL, N_("decorate options"),
PARSE_OPT_OPTARG, decorate_callback),
Implement line-history search (git log -L) This is a rewrite of much of Bo's work, mainly in an effort to split it into smaller, easier to understand routines. The algorithm is built around the struct range_set, which encodes a series of line ranges as intervals [a,b). This is used in two contexts: * A set of lines we are tracking (which will change as we dig through history). * To encode diffs, as pairs of ranges. The main routine is range_set_map_across_diff(). It processes the diff between a commit C and some parent P. It determines which diff hunks are relevant to the ranges tracked in C, and computes the new ranges for P. The algorithm is then simply to process history in topological order from newest to oldest, computing ranges and (partial) diffs. At branch points, we need to merge the ranges we are watching. We will find that many commits do not affect the chosen ranges, and mark them TREESAME (in addition to those already filtered by pathspec limiting). Another pass of history simplification then gets rid of such commits. This is wired as an extra filtering pass in the log machinery. This currently only reduces code duplication, but should allow for other simplifications and options to be used. Finally, we hook a diff printer into the output chain. Ideally we would wire directly into the diff logic, to optionally use features like word diff. However, that will require some major reworking of the diff chain, so we completely replace the output with our own diff for now. As this was a GSoC project, and has quite some history by now, many people have helped. In no particular order, thanks go to Jakub Narebski <jnareb@gmail.com> Jens Lehmann <Jens.Lehmann@web.de> Jonathan Nieder <jrnieder@gmail.com> Junio C Hamano <gitster@pobox.com> Ramsay Jones <ramsay@ramsay1.demon.co.uk> Will Palmer <wmpalmer@gmail.com> Apologies to everyone I forgot. Signed-off-by: Bo Yang <struggleyb.nku@gmail.com> Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-28 17:47:32 +01:00
OPT_CALLBACK('L', NULL, &line_cb, "n,m:file",
N_("Process line range n,m in file, counting from 1"),
Implement line-history search (git log -L) This is a rewrite of much of Bo's work, mainly in an effort to split it into smaller, easier to understand routines. The algorithm is built around the struct range_set, which encodes a series of line ranges as intervals [a,b). This is used in two contexts: * A set of lines we are tracking (which will change as we dig through history). * To encode diffs, as pairs of ranges. The main routine is range_set_map_across_diff(). It processes the diff between a commit C and some parent P. It determines which diff hunks are relevant to the ranges tracked in C, and computes the new ranges for P. The algorithm is then simply to process history in topological order from newest to oldest, computing ranges and (partial) diffs. At branch points, we need to merge the ranges we are watching. We will find that many commits do not affect the chosen ranges, and mark them TREESAME (in addition to those already filtered by pathspec limiting). Another pass of history simplification then gets rid of such commits. This is wired as an extra filtering pass in the log machinery. This currently only reduces code duplication, but should allow for other simplifications and options to be used. Finally, we hook a diff printer into the output chain. Ideally we would wire directly into the diff logic, to optionally use features like word diff. However, that will require some major reworking of the diff chain, so we completely replace the output with our own diff for now. As this was a GSoC project, and has quite some history by now, many people have helped. In no particular order, thanks go to Jakub Narebski <jnareb@gmail.com> Jens Lehmann <Jens.Lehmann@web.de> Jonathan Nieder <jrnieder@gmail.com> Junio C Hamano <gitster@pobox.com> Ramsay Jones <ramsay@ramsay1.demon.co.uk> Will Palmer <wmpalmer@gmail.com> Apologies to everyone I forgot. Signed-off-by: Bo Yang <struggleyb.nku@gmail.com> Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-28 17:47:32 +01:00
log_line_range_callback),
OPT_END()
};
Implement line-history search (git log -L) This is a rewrite of much of Bo's work, mainly in an effort to split it into smaller, easier to understand routines. The algorithm is built around the struct range_set, which encodes a series of line ranges as intervals [a,b). This is used in two contexts: * A set of lines we are tracking (which will change as we dig through history). * To encode diffs, as pairs of ranges. The main routine is range_set_map_across_diff(). It processes the diff between a commit C and some parent P. It determines which diff hunks are relevant to the ranges tracked in C, and computes the new ranges for P. The algorithm is then simply to process history in topological order from newest to oldest, computing ranges and (partial) diffs. At branch points, we need to merge the ranges we are watching. We will find that many commits do not affect the chosen ranges, and mark them TREESAME (in addition to those already filtered by pathspec limiting). Another pass of history simplification then gets rid of such commits. This is wired as an extra filtering pass in the log machinery. This currently only reduces code duplication, but should allow for other simplifications and options to be used. Finally, we hook a diff printer into the output chain. Ideally we would wire directly into the diff logic, to optionally use features like word diff. However, that will require some major reworking of the diff chain, so we completely replace the output with our own diff for now. As this was a GSoC project, and has quite some history by now, many people have helped. In no particular order, thanks go to Jakub Narebski <jnareb@gmail.com> Jens Lehmann <Jens.Lehmann@web.de> Jonathan Nieder <jrnieder@gmail.com> Junio C Hamano <gitster@pobox.com> Ramsay Jones <ramsay@ramsay1.demon.co.uk> Will Palmer <wmpalmer@gmail.com> Apologies to everyone I forgot. Signed-off-by: Bo Yang <struggleyb.nku@gmail.com> Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-28 17:47:32 +01:00
line_cb.rev = rev;
line_cb.prefix = prefix;
mailmap = use_mailmap_config;
argc = parse_options(argc, argv, prefix,
builtin_log_options, builtin_log_usage,
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
PARSE_OPT_KEEP_DASHDASH);
if (quiet)
rev->diffopt.output_format |= DIFF_FORMAT_NO_OUTPUT;
log: fix --quiet synonym for -s Originally the "--quiet" option was parsed by the diff-option parser into the internal QUICK option. This had the effect of silencing diff output from the log (which was not intended, but happened to work and people started to use it). But it also had other odd side effects at the diff level (for example, it would suppress the second commit in "git show A B"). To fix this, commit 1c40c36 converted log to parse-options and handled the "quiet" option separately, not passing it on to the diff code. However, it simply ignored the option, which was a regression for people using it as a synonym for "-s". Commit 01771a8 then fixed that by interpreting the option to add DIFF_FORMAT_NO_OUTPUT to the list of output formats. However, that commit did not fix it in all cases. It sets the flag after setup_revisions is called. Naively, this makes sense because you would expect the setup_revisions parser to overwrite our output format flag if "-p" or another output format flag is seen. However, that is not how the NO_OUTPUT flag works. We actually store it in the bit-field as just another format. At the end of setup_revisions, we call diff_setup_done, which post-processes the bitfield and clears any other formats if we have set NO_OUTPUT. By setting the flag after setup_revisions is done, diff_setup_done does not have a chance to make this tweak, and we end up with other format options still set. As a result, the flag would have no effect in "git log -p --quiet" or "git show --quiet". Fix it by setting the format flag before the call to setup_revisions. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-08-28 23:29:34 +02:00
argc = setup_revisions(argc, argv, rev, opt);
/* Any arguments at this point are not recognized */
if (argc > 1)
die(_("unrecognized argument: %s"), argv[1]);
memset(&w, 0, sizeof(w));
userformat_find_requirements(NULL, &w);
if (!rev->show_notes_given && (!rev->pretty_given || w.notes))
rev->show_notes = 1;
if (rev->show_notes)
load_display_notes(&rev->notes_opt);
if ((rev->diffopt.pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) ||
rev->diffopt.filter || rev->diffopt.flags.follow_renames)
rev->always_show_header = 0;
if (source || w.source) {
init_revision_sources(&revision_sources);
rev->sources = &revision_sources;
}
if (mailmap) {
rev->mailmap = xcalloc(1, sizeof(struct string_list));
read_mailmap(rev->mailmap, NULL);
}
if (rev->pretty_given && rev->commit_format == CMIT_FMT_RAW) {
/*
* "log --pretty=raw" is special; ignore UI oriented
* configuration variables such as decoration.
*/
if (!decoration_given)
decoration_style = 0;
if (!rev->abbrev_commit_given)
rev->abbrev_commit = 0;
}
if (decoration_style) {
log: add log.excludeDecoration config option In 'git log', the --decorate-refs-exclude option appends a pattern to a string_list. This list is used to prevent showing some refs in the decoration output, or even by --simplify-by-decoration. Users may want to use their refs space to store utility refs that should not appear in the decoration output. For example, Scalar [1] runs a background fetch but places the "new" refs inside the refs/scalar/hidden/<remote>/* refspace instead of refs/<remote>/* to avoid updating remote refs when the user is not looking. However, these "hidden" refs appear during regular 'git log' queries. A similar idea to use "hidden" refs is under consideration for core Git [2]. Add the 'log.excludeDecoration' config option so users can exclude some refs from decorations by default instead of needing to use --decorate-refs-exclude manually. The config value is multi-valued much like the command-line option. The documentation is careful to point out that the config value can be overridden by the --decorate-refs option, even though --decorate-refs-exclude would always "win" over --decorate-refs. Since the 'log.excludeDecoration' takes lower precedence to --decorate-refs, and --decorate-refs-exclude takes higher precedence, the struct decoration_filter needed another field. This led also to new logic in load_ref_decorations() and ref_filter_match(). There are several tests in t4202-log.sh that test the --decorate-refs-(include|exclude) options, so these are extended. Since the expected output is already stored as a file, most tests could simply replace a "--decorate-refs-exclude" option with an in-line config setting. Other tests involve the precedence of the config option compared to command-line options and needed more modification. [1] https://github.com/microsoft/scalar [2] https://lore.kernel.org/git/77b1da5d3063a2404cd750adfe3bb8be9b6c497d.1585946894.git.gitgitgadget@gmail.com/ Helped-by: Junio C Hamano <gister@pobox.com> Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-16 16:15:49 +02:00
const struct string_list *config_exclude =
repo_config_get_value_multi(the_repository,
"log.excludeDecoration");
if (config_exclude) {
struct string_list_item *item;
for_each_string_list_item(item, config_exclude)
string_list_append(&decorate_refs_exclude_config,
item->string);
}
rev->show_decorations = 1;
log: add log.excludeDecoration config option In 'git log', the --decorate-refs-exclude option appends a pattern to a string_list. This list is used to prevent showing some refs in the decoration output, or even by --simplify-by-decoration. Users may want to use their refs space to store utility refs that should not appear in the decoration output. For example, Scalar [1] runs a background fetch but places the "new" refs inside the refs/scalar/hidden/<remote>/* refspace instead of refs/<remote>/* to avoid updating remote refs when the user is not looking. However, these "hidden" refs appear during regular 'git log' queries. A similar idea to use "hidden" refs is under consideration for core Git [2]. Add the 'log.excludeDecoration' config option so users can exclude some refs from decorations by default instead of needing to use --decorate-refs-exclude manually. The config value is multi-valued much like the command-line option. The documentation is careful to point out that the config value can be overridden by the --decorate-refs option, even though --decorate-refs-exclude would always "win" over --decorate-refs. Since the 'log.excludeDecoration' takes lower precedence to --decorate-refs, and --decorate-refs-exclude takes higher precedence, the struct decoration_filter needed another field. This led also to new logic in load_ref_decorations() and ref_filter_match(). There are several tests in t4202-log.sh that test the --decorate-refs-(include|exclude) options, so these are extended. Since the expected output is already stored as a file, most tests could simply replace a "--decorate-refs-exclude" option with an in-line config setting. Other tests involve the precedence of the config option compared to command-line options and needed more modification. [1] https://github.com/microsoft/scalar [2] https://lore.kernel.org/git/77b1da5d3063a2404cd750adfe3bb8be9b6c497d.1585946894.git.gitgitgadget@gmail.com/ Helped-by: Junio C Hamano <gister@pobox.com> Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-16 16:15:49 +02:00
log: add option to choose which refs to decorate When `log --decorate` is used, git will decorate commits with all available refs. While in most cases this may give the desired effect, under some conditions it can lead to excessively verbose output. Introduce two command line options, `--decorate-refs=<pattern>` and `--decorate-refs-exclude=<pattern>` to allow the user to select which refs are used in decoration. When "--decorate-refs=<pattern>" is given, only the refs that match the pattern are used in decoration. The refs that match the pattern when "--decorate-refs-exclude=<pattern>" is given, are never used in decoration. These options follow the same convention for mixing negative and positive patterns across the system, assuming that the inclusive default is to match all refs available. (1) if there is no positive pattern given, pretend as if an inclusive default positive pattern was given; (2) for each candidate, reject it if it matches no positive pattern, or if it matches any one of the negative patterns. The rules for what is considered a match are slightly different from the rules used elsewhere. Commands like `log --glob` assume a trailing '/*' when glob chars are not present in the pattern. This makes it difficult to specify a single ref. On the other hand, commands like `describe --match --all` allow specifying exact refs, but do not have the convenience of allowing "shorthand refs" like 'refs/heads' or 'heads' to refer to 'refs/heads/*'. The commands introduced in this patch consider a match if: (a) the pattern contains globs chars, and regular pattern matching returns a match. (b) the pattern does not contain glob chars, and ref '<pattern>' exists, or if ref exists under '<pattern>/' This allows both behaviours (allowing single refs and shorthand refs) yet remaining compatible with existent commands. Helped-by: Kevin Daudt <me@ikke.info> Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Rafael Ascensão <rafa.almas@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-21 22:33:41 +01:00
load_ref_decorations(&decoration_filter, decoration_style);
}
Implement line-history search (git log -L) This is a rewrite of much of Bo's work, mainly in an effort to split it into smaller, easier to understand routines. The algorithm is built around the struct range_set, which encodes a series of line ranges as intervals [a,b). This is used in two contexts: * A set of lines we are tracking (which will change as we dig through history). * To encode diffs, as pairs of ranges. The main routine is range_set_map_across_diff(). It processes the diff between a commit C and some parent P. It determines which diff hunks are relevant to the ranges tracked in C, and computes the new ranges for P. The algorithm is then simply to process history in topological order from newest to oldest, computing ranges and (partial) diffs. At branch points, we need to merge the ranges we are watching. We will find that many commits do not affect the chosen ranges, and mark them TREESAME (in addition to those already filtered by pathspec limiting). Another pass of history simplification then gets rid of such commits. This is wired as an extra filtering pass in the log machinery. This currently only reduces code duplication, but should allow for other simplifications and options to be used. Finally, we hook a diff printer into the output chain. Ideally we would wire directly into the diff logic, to optionally use features like word diff. However, that will require some major reworking of the diff chain, so we completely replace the output with our own diff for now. As this was a GSoC project, and has quite some history by now, many people have helped. In no particular order, thanks go to Jakub Narebski <jnareb@gmail.com> Jens Lehmann <Jens.Lehmann@web.de> Jonathan Nieder <jrnieder@gmail.com> Junio C Hamano <gitster@pobox.com> Ramsay Jones <ramsay@ramsay1.demon.co.uk> Will Palmer <wmpalmer@gmail.com> Apologies to everyone I forgot. Signed-off-by: Bo Yang <struggleyb.nku@gmail.com> Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-28 17:47:32 +01:00
if (rev->line_level_traverse)
line_log_init(rev, line_cb.prefix, &line_cb.args);
setup_pager();
}
static void cmd_log_init(int argc, const char **argv, const char *prefix,
struct rev_info *rev, struct setup_revision_opt *opt)
{
cmd_log_init_defaults(rev);
cmd_log_init_finish(argc, argv, prefix, rev, opt);
}
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
/*
* This gives a rough estimate for how many commits we
* will print out in the list.
*/
static int estimate_commit_count(struct commit_list *list)
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
{
int n = 0;
while (list) {
struct commit *commit = list->item;
unsigned int flags = commit->object.flags;
list = list->next;
if (!(flags & (TREESAME | UNINTERESTING)))
n++;
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
}
return n;
}
static void show_early_header(struct rev_info *rev, const char *stage, int nr)
{
if (rev->shown_one) {
rev->shown_one = 0;
if (rev->commit_format != CMIT_FMT_ONELINE)
putchar(rev->diffopt.line_termination);
}
fprintf(rev->diffopt.file, _("Final output: %d %s\n"), nr, stage);
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
}
static struct itimerval early_output_timer;
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
static void log_show_early(struct rev_info *revs, struct commit_list *list)
{
int i = revs->early_output, close_file = revs->diffopt.close_file;
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
int show_header = 1;
revs->diffopt.close_file = 0;
toposort: rename "lifo" field The primary invariant of sort_in_topological_order() is that a parent commit is not emitted until all children of it are. When traversing a forked history like this with "git log C E": A----B----C \ D----E we ensure that A is emitted after all of B, C, D, and E are done, B has to wait until C is done, and D has to wait until E is done. In some applications, however, we would further want to control how these child commits B, C, D and E on two parallel ancestry chains are shown. Most of the time, we would want to see C and B emitted together, and then E and D, and finally A (i.e. the --topo-order output). The "lifo" parameter of the sort_in_topological_order() function is used to control this behaviour. We start the traversal by knowing two commits, C and E. While keeping in mind that we also need to inspect E later, we pick C first to inspect, and we notice and record that B needs to be inspected. By structuring the "work to be done" set as a LIFO stack, we ensure that B is inspected next, before other in-flight commits we had known that we will need to inspect, e.g. E. When showing in --date-order, we would want to see commits ordered by timestamps, i.e. show C, E, B and D in this order before showing A, possibly mixing commits from two parallel histories together. When "lifo" parameter is set to false, the function keeps the "work to be done" set sorted in the date order to realize this semantics. After inspecting C, we add B to the "work to be done" set, but the next commit we inspect from the set is E which is newer than B. The name "lifo", however, is too strongly tied to the way how the function implements its behaviour, and does not describe what the behaviour _means_. Replace this field with an enum rev_sort_order, with two possible values: REV_SORT_IN_GRAPH_ORDER and REV_SORT_BY_COMMIT_DATE, and update the existing code. The mechanical replacement rule is: "lifo == 0" is equivalent to "sort_order == REV_SORT_BY_COMMIT_DATE" "lifo == 1" is equivalent to "sort_order == REV_SORT_IN_GRAPH_ORDER" Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-06-07 01:07:14 +02:00
sort_in_topological_order(&list, revs->sort_order);
while (list && i) {
struct commit *commit = list->item;
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
switch (simplify_commit(revs, commit)) {
case commit_show:
if (show_header) {
int n = estimate_commit_count(list);
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
show_early_header(revs, "incomplete", n);
show_header = 0;
}
log_tree_commit(revs, commit);
i--;
break;
case commit_ignore:
break;
case commit_error:
if (close_file)
fclose(revs->diffopt.file);
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
return;
}
list = list->next;
}
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
/* Did we already get enough commits for the early output? */
if (!i) {
if (close_file)
fclose(revs->diffopt.file);
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
return;
}
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
/*
* ..if no, then repeat it twice a second until we
* do.
*
* NOTE! We don't use "it_interval", because if the
* reader isn't listening, we want our output to be
* throttled by the writing, and not have the timer
* trigger every second even if we're blocked on a
* reader!
*/
early_output_timer.it_value.tv_sec = 0;
early_output_timer.it_value.tv_usec = 500000;
setitimer(ITIMER_REAL, &early_output_timer, NULL);
}
static void early_output(int signal)
{
show_early_output = log_show_early;
}
static void setup_early_output(void)
{
struct sigaction sa;
/*
* Set up the signal handler, minimally intrusively:
* we only set a single volatile integer word (not
* using sigatomic_t - trying to avoid unnecessary
* system dependencies and headers), and using
* SA_RESTART.
*/
memset(&sa, 0, sizeof(sa));
sa.sa_handler = early_output;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGALRM, &sa, NULL);
/*
* If we can get the whole output in less than a
* tenth of a second, don't even bother doing the
* early-output thing..
*
* This is a one-time-only trigger.
*/
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
early_output_timer.it_value.tv_sec = 0;
early_output_timer.it_value.tv_usec = 100000;
setitimer(ITIMER_REAL, &early_output_timer, NULL);
}
static void finish_early_output(struct rev_info *rev)
{
int n = estimate_commit_count(rev->commits);
signal(SIGALRM, SIG_IGN);
Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-04 21:12:05 +01:00
show_early_header(rev, "done", n);
}
static int cmd_log_walk(struct rev_info *rev)
{
struct commit *commit;
int saved_nrl = 0;
int saved_dcctc = 0, close_file = rev->diffopt.close_file;
if (rev->early_output)
setup_early_output();
if (prepare_revision_walk(rev))
die(_("revision walk setup failed"));
if (rev->early_output)
finish_early_output(rev);
/*
* For --check and --exit-code, the exit code is based on CHECK_FAILED
* and HAS_CHANGES being accumulated in rev->diffopt, so be careful to
* retain that state information if replacing rev->diffopt in this loop
*/
rev->diffopt.close_file = 0;
while ((commit = get_revision(rev)) != NULL) {
if (!log_tree_commit(rev, commit) && rev->max_count >= 0)
/*
* We decremented max_count in get_revision,
* but we didn't actually show the commit.
*/
rev->max_count++;
if (!rev->reflog_info) {
/*
* We may show a given commit multiple times when
* walking the reflogs.
*/
free_commit_buffer(the_repository->parsed_objects,
commit);
free_commit_list(commit->parents);
commit->parents = NULL;
}
if (saved_nrl < rev->diffopt.needed_rename_limit)
saved_nrl = rev->diffopt.needed_rename_limit;
if (rev->diffopt.degraded_cc_to_c)
saved_dcctc = 1;
}
rev->diffopt.degraded_cc_to_c = saved_dcctc;
rev->diffopt.needed_rename_limit = saved_nrl;
if (close_file)
fclose(rev->diffopt.file);
if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
diff: make struct diff_flags members lowercase Now that the flags stored in struct diff_flags are being accessed directly and not through macros, change all struct members from being uppercase to lowercase. This conversion is done using the following semantic patch: @@ expression E; @@ - E.RECURSIVE + E.recursive @@ expression E; @@ - E.TREE_IN_RECURSIVE + E.tree_in_recursive @@ expression E; @@ - E.BINARY + E.binary @@ expression E; @@ - E.TEXT + E.text @@ expression E; @@ - E.FULL_INDEX + E.full_index @@ expression E; @@ - E.SILENT_ON_REMOVE + E.silent_on_remove @@ expression E; @@ - E.FIND_COPIES_HARDER + E.find_copies_harder @@ expression E; @@ - E.FOLLOW_RENAMES + E.follow_renames @@ expression E; @@ - E.RENAME_EMPTY + E.rename_empty @@ expression E; @@ - E.HAS_CHANGES + E.has_changes @@ expression E; @@ - E.QUICK + E.quick @@ expression E; @@ - E.NO_INDEX + E.no_index @@ expression E; @@ - E.ALLOW_EXTERNAL + E.allow_external @@ expression E; @@ - E.EXIT_WITH_STATUS + E.exit_with_status @@ expression E; @@ - E.REVERSE_DIFF + E.reverse_diff @@ expression E; @@ - E.CHECK_FAILED + E.check_failed @@ expression E; @@ - E.RELATIVE_NAME + E.relative_name @@ expression E; @@ - E.IGNORE_SUBMODULES + E.ignore_submodules @@ expression E; @@ - E.DIRSTAT_CUMULATIVE + E.dirstat_cumulative @@ expression E; @@ - E.DIRSTAT_BY_FILE + E.dirstat_by_file @@ expression E; @@ - E.ALLOW_TEXTCONV + E.allow_textconv @@ expression E; @@ - E.TEXTCONV_SET_VIA_CMDLINE + E.textconv_set_via_cmdline @@ expression E; @@ - E.DIFF_FROM_CONTENTS + E.diff_from_contents @@ expression E; @@ - E.DIRTY_SUBMODULES + E.dirty_submodules @@ expression E; @@ - E.IGNORE_UNTRACKED_IN_SUBMODULES + E.ignore_untracked_in_submodules @@ expression E; @@ - E.IGNORE_DIRTY_SUBMODULES + E.ignore_dirty_submodules @@ expression E; @@ - E.OVERRIDE_SUBMODULE_CONFIG + E.override_submodule_config @@ expression E; @@ - E.DIRSTAT_BY_LINE + E.dirstat_by_line @@ expression E; @@ - E.FUNCCONTEXT + E.funccontext @@ expression E; @@ - E.PICKAXE_IGNORE_CASE + E.pickaxe_ignore_case @@ expression E; @@ - E.DEFAULT_FOLLOW_RENAMES + E.default_follow_renames Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-31 19:19:11 +01:00
rev->diffopt.flags.check_failed) {
return 02;
}
return diff_result_code(&rev->diffopt, 0);
}
static int git_log_config(const char *var, const char *value, void *cb)
{
const char *slot_name;
if (!strcmp(var, "format.pretty"))
return git_config_string(&fmt_pretty, var, value);
if (!strcmp(var, "format.subjectprefix"))
return git_config_string(&fmt_patch_subject_prefix, var, value);
if (!strcmp(var, "format.encodeemailheaders")) {
default_encode_email_headers = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.abbrevcommit")) {
default_abbrev_commit = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.date"))
return git_config_string(&default_date_mode, var, value);
if (!strcmp(var, "log.decorate")) {
decoration_style = parse_decoration_style(value);
if (decoration_style < 0)
decoration_style = 0; /* maybe warn? */
return 0;
}
if (!strcmp(var, "log.showroot")) {
default_show_root = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.follow")) {
default_follow = git_config_bool(var, value);
return 0;
}
if (skip_prefix(var, "color.decorate.", &slot_name))
return parse_decorate_color_config(var, slot_name, value);
if (!strcmp(var, "log.mailmap")) {
use_mailmap_config = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.showsignature")) {
default_show_signature = git_config_bool(var, value);
return 0;
}
if (grep_config(var, value, cb) < 0)
return -1;
if (git_gpg_config(var, value, cb) < 0)
return -1;
return git_diff_ui_config(var, value, cb);
}
int cmd_whatchanged(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
struct setup_revision_opt opt;
init_log_defaults();
git_config(git_log_config, NULL);
repo_init_revisions(the_repository, &rev, prefix);
rev.diff = 1;
gitweb.cgi history not shown This does: - add a "rev.simplify_history" flag which defaults to on - it turns it off for "git whatchanged" (which thus now has real semantics outside of "git log") - it adds a command line flag ("--full-history") to turn it off for others (ie you can make "git log" and "gitk" etc get the semantics if you want to. Now, just as an example of _why_ you really really really want to simplify history by default, apply this patch, install it, and try these two command lines: gitk --full-history -- git.c gitk -- git.c and compare the output. So with this, you can also now do git whatchanged -p -- gitweb.cgi git log -p --full-history -- gitweb.cgi and it will show the old history of gitweb.cgi, even though it's not relevant to the _current_ state of the name "gitweb.cgi" NOTE NOTE NOTE! It will still actually simplify away merges that didn't change anything at all into either child. That creates these bogus strange discontinuities if you look at it with "gitk" (look at the --full-history gitk output for git.c, and you'll see a few strange cases). So the whole "--parent" thing ends up somewhat bogus with --full-history because of this, but I'm not sure it's worth even worrying about. I don't think you'd ever want to really use "--full-history" with the graphical representation, I just give it as an example exactly to show _why_ doing so would be insane. I think this is trivial enough and useful enough to be worth merging into the stable branch. Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-11 19:57:35 +02:00
rev.simplify_history = 0;
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.revarg_opt = REVARG_COMMITTISH;
cmd_log_init(argc, argv, prefix, &rev, &opt);
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
return cmd_log_walk(&rev);
}
static void show_tagger(const char *buf, struct rev_info *rev)
{
struct strbuf out = STRBUF_INIT;
struct pretty_print_context pp = {0};
pp.fmt = rev->commit_format;
pp.date_mode = rev->date_mode;
pp_user_info(&pp, "Tagger", &out, buf, get_log_output_encoding());
fprintf(rev->diffopt.file, "%s", out.buf);
strbuf_release(&out);
}
static int show_blob_object(const struct object_id *oid, struct rev_info *rev, const char *obj_name)
{
struct object_id oidc;
struct object_context obj_context;
char *buf;
unsigned long size;
fflush(rev->diffopt.file);
diff: make struct diff_flags members lowercase Now that the flags stored in struct diff_flags are being accessed directly and not through macros, change all struct members from being uppercase to lowercase. This conversion is done using the following semantic patch: @@ expression E; @@ - E.RECURSIVE + E.recursive @@ expression E; @@ - E.TREE_IN_RECURSIVE + E.tree_in_recursive @@ expression E; @@ - E.BINARY + E.binary @@ expression E; @@ - E.TEXT + E.text @@ expression E; @@ - E.FULL_INDEX + E.full_index @@ expression E; @@ - E.SILENT_ON_REMOVE + E.silent_on_remove @@ expression E; @@ - E.FIND_COPIES_HARDER + E.find_copies_harder @@ expression E; @@ - E.FOLLOW_RENAMES + E.follow_renames @@ expression E; @@ - E.RENAME_EMPTY + E.rename_empty @@ expression E; @@ - E.HAS_CHANGES + E.has_changes @@ expression E; @@ - E.QUICK + E.quick @@ expression E; @@ - E.NO_INDEX + E.no_index @@ expression E; @@ - E.ALLOW_EXTERNAL + E.allow_external @@ expression E; @@ - E.EXIT_WITH_STATUS + E.exit_with_status @@ expression E; @@ - E.REVERSE_DIFF + E.reverse_diff @@ expression E; @@ - E.CHECK_FAILED + E.check_failed @@ expression E; @@ - E.RELATIVE_NAME + E.relative_name @@ expression E; @@ - E.IGNORE_SUBMODULES + E.ignore_submodules @@ expression E; @@ - E.DIRSTAT_CUMULATIVE + E.dirstat_cumulative @@ expression E; @@ - E.DIRSTAT_BY_FILE + E.dirstat_by_file @@ expression E; @@ - E.ALLOW_TEXTCONV + E.allow_textconv @@ expression E; @@ - E.TEXTCONV_SET_VIA_CMDLINE + E.textconv_set_via_cmdline @@ expression E; @@ - E.DIFF_FROM_CONTENTS + E.diff_from_contents @@ expression E; @@ - E.DIRTY_SUBMODULES + E.dirty_submodules @@ expression E; @@ - E.IGNORE_UNTRACKED_IN_SUBMODULES + E.ignore_untracked_in_submodules @@ expression E; @@ - E.IGNORE_DIRTY_SUBMODULES + E.ignore_dirty_submodules @@ expression E; @@ - E.OVERRIDE_SUBMODULE_CONFIG + E.override_submodule_config @@ expression E; @@ - E.DIRSTAT_BY_LINE + E.dirstat_by_line @@ expression E; @@ - E.FUNCCONTEXT + E.funccontext @@ expression E; @@ - E.PICKAXE_IGNORE_CASE + E.pickaxe_ignore_case @@ expression E; @@ - E.DEFAULT_FOLLOW_RENAMES + E.default_follow_renames Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-31 19:19:11 +01:00
if (!rev->diffopt.flags.textconv_set_via_cmdline ||
!rev->diffopt.flags.allow_textconv)
return stream_blob_to_fd(1, oid, NULL, 0);
if (get_oid_with_context(the_repository, obj_name,
GET_OID_RECORD_PATH,
sha1_name: convert get_sha1* to get_oid* Now that all the callers of get_sha1 directly or indirectly use struct object_id, rename the functions starting with get_sha1 to start with get_oid. Convert the internals in sha1_name.c to use struct object_id as well, and eliminate explicit length checks where possible. Convert a use of 40 in get_oid_basic to GIT_SHA1_HEXSZ. Outside of sha1_name.c and cache.h, this transition was made with the following semantic patch: @@ expression E1, E2; @@ - get_sha1(E1, E2.hash) + get_oid(E1, &E2) @@ expression E1, E2; @@ - get_sha1(E1, E2->hash) + get_oid(E1, E2) @@ expression E1, E2; @@ - get_sha1_committish(E1, E2.hash) + get_oid_committish(E1, &E2) @@ expression E1, E2; @@ - get_sha1_committish(E1, E2->hash) + get_oid_committish(E1, E2) @@ expression E1, E2; @@ - get_sha1_treeish(E1, E2.hash) + get_oid_treeish(E1, &E2) @@ expression E1, E2; @@ - get_sha1_treeish(E1, E2->hash) + get_oid_treeish(E1, E2) @@ expression E1, E2; @@ - get_sha1_commit(E1, E2.hash) + get_oid_commit(E1, &E2) @@ expression E1, E2; @@ - get_sha1_commit(E1, E2->hash) + get_oid_commit(E1, E2) @@ expression E1, E2; @@ - get_sha1_tree(E1, E2.hash) + get_oid_tree(E1, &E2) @@ expression E1, E2; @@ - get_sha1_tree(E1, E2->hash) + get_oid_tree(E1, E2) @@ expression E1, E2; @@ - get_sha1_blob(E1, E2.hash) + get_oid_blob(E1, &E2) @@ expression E1, E2; @@ - get_sha1_blob(E1, E2->hash) + get_oid_blob(E1, E2) @@ expression E1, E2, E3, E4; @@ - get_sha1_with_context(E1, E2, E3.hash, E4) + get_oid_with_context(E1, E2, &E3, E4) @@ expression E1, E2, E3, E4; @@ - get_sha1_with_context(E1, E2, E3->hash, E4) + get_oid_with_context(E1, E2, E3, E4) Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-07-14 01:49:28 +02:00
&oidc, &obj_context))
die(_("not a valid object name %s"), obj_name);
if (!obj_context.path ||
!textconv_object(the_repository, obj_context.path,
obj_context.mode, &oidc, 1, &buf, &size)) {
free(obj_context.path);
return stream_blob_to_fd(1, oid, NULL, 0);
}
if (!buf)
die(_("git show %s: bad file"), obj_name);
write_or_die(1, buf, size);
free(obj_context.path);
return 0;
}
static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
{
unsigned long size;
enum object_type type;
char *buf = read_object_file(oid, &type, &size);
int offset = 0;
if (!buf)
return error(_("could not read object %s"), oid_to_hex(oid));
assert(type == OBJ_TAG);
while (offset < size && buf[offset] != '\n') {
int new_offset = offset + 1;
const char *ident;
while (new_offset < size && buf[new_offset++] != '\n')
; /* do nothing */
if (skip_prefix(buf + offset, "tagger ", &ident))
show_tagger(ident, rev);
offset = new_offset;
}
if (offset < size)
fwrite(buf + offset, size - offset, 1, rev->diffopt.file);
free(buf);
return 0;
}
static int show_tree_object(const struct object_id *oid,
struct strbuf *base,
const char *pathname, unsigned mode, int stage, void *context)
{
FILE *file = context;
fprintf(file, "%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
return 0;
}
static void show_setup_revisions_tweak(struct rev_info *rev,
struct setup_revision_opt *opt)
{
if (rev->ignore_merges) {
/* There was no "-m" on the command line */
rev->ignore_merges = 0;
if (!rev->first_parent_only && !rev->combine_merges) {
/* No "--first-parent", "-c", or "--cc" */
rev->combine_merges = 1;
rev->dense_combined_merges = 1;
}
}
if (!rev->diffopt.output_format)
rev->diffopt.output_format = DIFF_FORMAT_PATCH;
}
int cmd_show(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
struct object_array_entry *objects;
struct setup_revision_opt opt;
struct pathspec match_all;
int i, count, ret = 0;
init_log_defaults();
git_config(git_log_config, NULL);
memset(&match_all, 0, sizeof(match_all));
repo_init_revisions(the_repository, &rev, prefix);
rev.diff = 1;
rev.always_show_header = 1;
rev.no_walk = REVISION_WALK_NO_WALK_SORTED;
rev.diffopt.stat_width = -1; /* Scale to real terminal size */
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.tweak = show_setup_revisions_tweak;
cmd_log_init(argc, argv, prefix, &rev, &opt);
if (!rev.no_walk)
return cmd_log_walk(&rev);
count = rev.pending.nr;
objects = rev.pending.objects;
for (i = 0; i < count && !ret; i++) {
struct object *o = objects[i].item;
const char *name = objects[i].name;
switch (o->type) {
case OBJ_BLOB:
ret = show_blob_object(&o->oid, &rev, name);
break;
case OBJ_TAG: {
struct tag *t = (struct tag *)o;
struct object_id *oid = get_tagged_oid(t);
if (rev.shown_one)
putchar('\n');
fprintf(rev.diffopt.file, "%stag %s%s\n",
diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
t->tag,
diff_get_color_opt(&rev.diffopt, DIFF_RESET));
ret = show_tag_object(&o->oid, &rev);
rev.shown_one = 1;
if (ret)
break;
o = parse_object(the_repository, oid);
if (!o)
ret = error(_("could not read object %s"),
oid_to_hex(oid));
objects[i].item = o;
i--;
break;
}
case OBJ_TREE:
if (rev.shown_one)
putchar('\n');
fprintf(rev.diffopt.file, "%stree %s%s\n\n",
diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
name,
diff_get_color_opt(&rev.diffopt, DIFF_RESET));
read_tree_recursive(the_repository, (struct tree *)o, "",
0, 0, &match_all, show_tree_object,
rev.diffopt.file);
rev.shown_one = 1;
break;
case OBJ_COMMIT:
rev.pending.nr = rev.pending.alloc = 0;
rev.pending.objects = NULL;
add_object_array(o, name, &rev.pending);
ret = cmd_log_walk(&rev);
break;
default:
ret = error(_("unknown type: %d"), o->type);
}
}
free(objects);
return ret;
}
/*
* This is equivalent to "git log -g --abbrev-commit --pretty=oneline"
*/
int cmd_log_reflog(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
struct setup_revision_opt opt;
init_log_defaults();
git_config(git_log_config, NULL);
repo_init_revisions(the_repository, &rev, prefix);
init_reflog_walk(&rev.reflog_info);
rev.verbose_header = 1;
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
cmd_log_init_defaults(&rev);
rev.abbrev_commit = 1;
rev.commit_format = CMIT_FMT_ONELINE;
rev.use_terminator = 1;
rev.always_show_header = 1;
cmd_log_init_finish(argc, argv, prefix, &rev, &opt);
return cmd_log_walk(&rev);
}
static void log_setup_revisions_tweak(struct rev_info *rev,
struct setup_revision_opt *opt)
{
diff: make struct diff_flags members lowercase Now that the flags stored in struct diff_flags are being accessed directly and not through macros, change all struct members from being uppercase to lowercase. This conversion is done using the following semantic patch: @@ expression E; @@ - E.RECURSIVE + E.recursive @@ expression E; @@ - E.TREE_IN_RECURSIVE + E.tree_in_recursive @@ expression E; @@ - E.BINARY + E.binary @@ expression E; @@ - E.TEXT + E.text @@ expression E; @@ - E.FULL_INDEX + E.full_index @@ expression E; @@ - E.SILENT_ON_REMOVE + E.silent_on_remove @@ expression E; @@ - E.FIND_COPIES_HARDER + E.find_copies_harder @@ expression E; @@ - E.FOLLOW_RENAMES + E.follow_renames @@ expression E; @@ - E.RENAME_EMPTY + E.rename_empty @@ expression E; @@ - E.HAS_CHANGES + E.has_changes @@ expression E; @@ - E.QUICK + E.quick @@ expression E; @@ - E.NO_INDEX + E.no_index @@ expression E; @@ - E.ALLOW_EXTERNAL + E.allow_external @@ expression E; @@ - E.EXIT_WITH_STATUS + E.exit_with_status @@ expression E; @@ - E.REVERSE_DIFF + E.reverse_diff @@ expression E; @@ - E.CHECK_FAILED + E.check_failed @@ expression E; @@ - E.RELATIVE_NAME + E.relative_name @@ expression E; @@ - E.IGNORE_SUBMODULES + E.ignore_submodules @@ expression E; @@ - E.DIRSTAT_CUMULATIVE + E.dirstat_cumulative @@ expression E; @@ - E.DIRSTAT_BY_FILE + E.dirstat_by_file @@ expression E; @@ - E.ALLOW_TEXTCONV + E.allow_textconv @@ expression E; @@ - E.TEXTCONV_SET_VIA_CMDLINE + E.textconv_set_via_cmdline @@ expression E; @@ - E.DIFF_FROM_CONTENTS + E.diff_from_contents @@ expression E; @@ - E.DIRTY_SUBMODULES + E.dirty_submodules @@ expression E; @@ - E.IGNORE_UNTRACKED_IN_SUBMODULES + E.ignore_untracked_in_submodules @@ expression E; @@ - E.IGNORE_DIRTY_SUBMODULES + E.ignore_dirty_submodules @@ expression E; @@ - E.OVERRIDE_SUBMODULE_CONFIG + E.override_submodule_config @@ expression E; @@ - E.DIRSTAT_BY_LINE + E.dirstat_by_line @@ expression E; @@ - E.FUNCCONTEXT + E.funccontext @@ expression E; @@ - E.PICKAXE_IGNORE_CASE + E.pickaxe_ignore_case @@ expression E; @@ - E.DEFAULT_FOLLOW_RENAMES + E.default_follow_renames Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-31 19:19:11 +01:00
if (rev->diffopt.flags.default_follow_renames &&
rev->prune_data.nr == 1)
diff: make struct diff_flags members lowercase Now that the flags stored in struct diff_flags are being accessed directly and not through macros, change all struct members from being uppercase to lowercase. This conversion is done using the following semantic patch: @@ expression E; @@ - E.RECURSIVE + E.recursive @@ expression E; @@ - E.TREE_IN_RECURSIVE + E.tree_in_recursive @@ expression E; @@ - E.BINARY + E.binary @@ expression E; @@ - E.TEXT + E.text @@ expression E; @@ - E.FULL_INDEX + E.full_index @@ expression E; @@ - E.SILENT_ON_REMOVE + E.silent_on_remove @@ expression E; @@ - E.FIND_COPIES_HARDER + E.find_copies_harder @@ expression E; @@ - E.FOLLOW_RENAMES + E.follow_renames @@ expression E; @@ - E.RENAME_EMPTY + E.rename_empty @@ expression E; @@ - E.HAS_CHANGES + E.has_changes @@ expression E; @@ - E.QUICK + E.quick @@ expression E; @@ - E.NO_INDEX + E.no_index @@ expression E; @@ - E.ALLOW_EXTERNAL + E.allow_external @@ expression E; @@ - E.EXIT_WITH_STATUS + E.exit_with_status @@ expression E; @@ - E.REVERSE_DIFF + E.reverse_diff @@ expression E; @@ - E.CHECK_FAILED + E.check_failed @@ expression E; @@ - E.RELATIVE_NAME + E.relative_name @@ expression E; @@ - E.IGNORE_SUBMODULES + E.ignore_submodules @@ expression E; @@ - E.DIRSTAT_CUMULATIVE + E.dirstat_cumulative @@ expression E; @@ - E.DIRSTAT_BY_FILE + E.dirstat_by_file @@ expression E; @@ - E.ALLOW_TEXTCONV + E.allow_textconv @@ expression E; @@ - E.TEXTCONV_SET_VIA_CMDLINE + E.textconv_set_via_cmdline @@ expression E; @@ - E.DIFF_FROM_CONTENTS + E.diff_from_contents @@ expression E; @@ - E.DIRTY_SUBMODULES + E.dirty_submodules @@ expression E; @@ - E.IGNORE_UNTRACKED_IN_SUBMODULES + E.ignore_untracked_in_submodules @@ expression E; @@ - E.IGNORE_DIRTY_SUBMODULES + E.ignore_dirty_submodules @@ expression E; @@ - E.OVERRIDE_SUBMODULE_CONFIG + E.override_submodule_config @@ expression E; @@ - E.DIRSTAT_BY_LINE + E.dirstat_by_line @@ expression E; @@ - E.FUNCCONTEXT + E.funccontext @@ expression E; @@ - E.PICKAXE_IGNORE_CASE + E.pickaxe_ignore_case @@ expression E; @@ - E.DEFAULT_FOLLOW_RENAMES + E.default_follow_renames Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-31 19:19:11 +01:00
rev->diffopt.flags.follow_renames = 1;
/* Turn --cc/-c into -p --cc/-c when -p was not given */
if (!rev->diffopt.output_format && rev->combine_merges)
rev->diffopt.output_format = DIFF_FORMAT_PATCH;
/* Turn -m on when --cc/-c was given */
if (rev->combine_merges)
rev->ignore_merges = 0;
}
int cmd_log(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
struct setup_revision_opt opt;
init_log_defaults();
git_config(git_log_config, NULL);
repo_init_revisions(the_repository, &rev, prefix);
rev.always_show_header = 1;
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.revarg_opt = REVARG_COMMITTISH;
opt.tweak = log_setup_revisions_tweak;
cmd_log_init(argc, argv, prefix, &rev, &opt);
return cmd_log_walk(&rev);
}
/* format-patch */
static const char *fmt_patch_suffix = ".patch";
static int numbered = 0;
static int auto_number = 1;
static char *default_attach = NULL;
static struct string_list extra_hdr = STRING_LIST_INIT_NODUP;
static struct string_list extra_to = STRING_LIST_INIT_NODUP;
static struct string_list extra_cc = STRING_LIST_INIT_NODUP;
static void add_header(const char *value)
{
struct string_list_item *item;
int len = strlen(value);
while (len && value[len - 1] == '\n')
len--;
if (!strncasecmp(value, "to: ", 4)) {
item = string_list_append(&extra_to, value + 4);
len -= 4;
} else if (!strncasecmp(value, "cc: ", 4)) {
item = string_list_append(&extra_cc, value + 4);
len -= 4;
} else {
item = string_list_append(&extra_hdr, value);
}
item->string[len] = '\0';
}
enum cover_setting {
COVER_UNSET,
COVER_OFF,
COVER_ON,
COVER_AUTO
};
enum thread_level {
THREAD_UNSET,
THREAD_SHALLOW,
THREAD_DEEP
};
enum cover_from_description {
COVER_FROM_NONE,
COVER_FROM_MESSAGE,
COVER_FROM_SUBJECT,
COVER_FROM_AUTO
};
static enum thread_level thread;
static int do_signoff;
static int base_auto;
static char *from;
static const char *signature = git_version_string;
static const char *signature_file;
static enum cover_setting config_cover_letter;
static const char *config_output_directory;
static enum cover_from_description cover_from_description_mode = COVER_FROM_MESSAGE;
static int show_notes;
static struct display_notes_opt notes_opt;
static enum cover_from_description parse_cover_from_description(const char *arg)
{
if (!arg || !strcmp(arg, "default"))
return COVER_FROM_MESSAGE;
else if (!strcmp(arg, "none"))
return COVER_FROM_NONE;
else if (!strcmp(arg, "message"))
return COVER_FROM_MESSAGE;
else if (!strcmp(arg, "subject"))
return COVER_FROM_SUBJECT;
else if (!strcmp(arg, "auto"))
return COVER_FROM_AUTO;
else
die(_("%s: invalid cover from description mode"), arg);
}
static int git_format_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "format.headers")) {
if (!value)
die(_("format.headers without value"));
add_header(value);
return 0;
}
if (!strcmp(var, "format.suffix"))
return git_config_string(&fmt_patch_suffix, var, value);
if (!strcmp(var, "format.to")) {
if (!value)
return config_error_nonbool(var);
string_list_append(&extra_to, value);
return 0;
}
if (!strcmp(var, "format.cc")) {
if (!value)
return config_error_nonbool(var);
string_list_append(&extra_cc, value);
return 0;
}
if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff") ||
!strcmp(var, "color.ui") || !strcmp(var, "diff.submodule")) {
return 0;
}
if (!strcmp(var, "format.numbered")) {
if (value && !strcasecmp(value, "auto")) {
auto_number = 1;
return 0;
}
numbered = git_config_bool(var, value);
auto_number = auto_number && numbered;
return 0;
}
if (!strcmp(var, "format.attach")) {
if (value && *value)
default_attach = xstrdup(value);
else
default_attach = xstrdup(git_version_string);
return 0;
}
if (!strcmp(var, "format.thread")) {
if (value && !strcasecmp(value, "deep")) {
thread = THREAD_DEEP;
return 0;
}
if (value && !strcasecmp(value, "shallow")) {
thread = THREAD_SHALLOW;
return 0;
}
thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET;
return 0;
}
if (!strcmp(var, "format.signoff")) {
do_signoff = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "format.signature"))
return git_config_string(&signature, var, value);
if (!strcmp(var, "format.signaturefile"))
return git_config_pathname(&signature_file, var, value);
if (!strcmp(var, "format.coverletter")) {
if (value && !strcasecmp(value, "auto")) {
config_cover_letter = COVER_AUTO;
return 0;
}
config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
return 0;
}
if (!strcmp(var, "format.outputdirectory"))
return git_config_string(&config_output_directory, var, value);
if (!strcmp(var, "format.useautobase")) {
base_auto = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "format.from")) {
int b = git_parse_maybe_bool(value);
free(from);
if (b < 0)
from = xstrdup(value);
else if (b)
from = xstrdup(git_committer_info(IDENT_NO_DATE));
else
from = NULL;
return 0;
}
if (!strcmp(var, "format.notes")) {
int b = git_parse_maybe_bool(value);
notes: break set_display_notes() into smaller functions In 8164c961e1 (format-patch: use --notes behavior for format.notes, 2019-12-09), we introduced set_display_notes() which was a monolithic function with three mutually exclusive branches. Break the function up into three small and simple functions that each are only responsible for one task. This family of functions accepts an `int *show_notes` instead of returning a value suitable for assignment to `show_notes`. This is for two reasons. First of all, this guarantees that the external `show_notes` variable changes in lockstep with the `struct display_notes_opt`. Second, this prompts future developers to be careful about doing something meaningful with this value. In fact, a NULL check is intentionally omitted because causing a segfault here would tell the future developer that they are meant to use the value for something meaningful. One alternative was making the family of functions accept a `struct rev_info *` instead of the `struct display_notes_opt *`, since the former contains the `show_notes` field as well. This does not work because we have to call git_config() before repo_init_revisions(). However, if we had a `struct rev_info`, we'd need to initialize it before it gets assigned values from git_config(). As a result, we break the circular dependency by having standalone `int show_notes` and `struct display_notes_opt notes_opt` variables which temporarily hold values from git_config() until the values are copied over to `rev`. To implement this change, we need to get a pointer to `rev_info::show_notes`. Unfortunately, this is not possible with bitfields and only direct-assignment is possible. Change `rev_info::show_notes` to a non-bitfield int so that we can get its address. Signed-off-by: Denton Liu <liu.denton@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-12 01:49:50 +01:00
if (b < 0)
enable_ref_display_notes(&notes_opt, &show_notes, value);
else if (b)
enable_default_display_notes(&notes_opt, &show_notes);
else
disable_display_notes(&notes_opt, &show_notes);
return 0;
}
if (!strcmp(var, "format.coverfromdescription")) {
cover_from_description_mode = parse_cover_from_description(value);
return 0;
}
return git_log_config(var, value, cb);
}
static const char *output_directory = NULL;
static int outdir_offset;
static int open_next_file(struct commit *commit, const char *subject,
struct rev_info *rev, int quiet)
{
struct strbuf filename = STRBUF_INIT;
int suffix_len = strlen(rev->patch_suffix) + 1;
if (output_directory) {
strbuf_addstr(&filename, output_directory);
if (filename.len >=
PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len) {
strbuf_release(&filename);
return error(_("name of output directory is too long"));
}
2015-09-24 23:08:35 +02:00
strbuf_complete(&filename, '/');
}
if (rev->numbered_files)
strbuf_addf(&filename, "%d", rev->nr);
else if (commit)
fmt_output_commit(&filename, commit, rev);
else
fmt_output_subject(&filename, subject, rev);
if (!quiet)
printf("%s\n", filename.buf + outdir_offset);
if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL) {
error_errno(_("cannot open patch file %s"), filename.buf);
strbuf_release(&filename);
return -1;
}
strbuf_release(&filename);
return 0;
}
static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
{
struct rev_info check_rev;
struct commit *commit, *c1, *c2;
struct object *o1, *o2;
unsigned flags1, flags2;
if (rev->pending.nr != 2)
die(_("need exactly one range"));
o1 = rev->pending.objects[0].item;
o2 = rev->pending.objects[1].item;
flags1 = o1->flags;
flags2 = o2->flags;
c1 = lookup_commit_reference(the_repository, &o1->oid);
c2 = lookup_commit_reference(the_repository, &o2->oid);
if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
die(_("not a range"));
init_patch_ids(the_repository, ids);
/* given a range a..b get all patch ids for b..a */
repo_init_revisions(the_repository, &check_rev, rev->prefix);
check_rev.max_parents = 1;
o1->flags ^= UNINTERESTING;
o2->flags ^= UNINTERESTING;
add_pending_object(&check_rev, o1, "o1");
add_pending_object(&check_rev, o2, "o2");
if (prepare_revision_walk(&check_rev))
die(_("revision walk setup failed"));
while ((commit = get_revision(&check_rev)) != NULL) {
add_commit_patch_id(commit, ids);
}
/* reset for next revision walk */
clear_commit_marks(c1, SEEN | UNINTERESTING | SHOWN | ADDED);
clear_commit_marks(c2, SEEN | UNINTERESTING | SHOWN | ADDED);
o1->flags = flags1;
o2->flags = flags2;
}
static void gen_message_id(struct rev_info *info, char *base)
{
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "%s.%"PRItime".git.%s", base,
(timestamp_t) time(NULL),
git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));
info->message_id = strbuf_detach(&buf, NULL);
}
static void print_signature(FILE *file)
{
if (!signature || !*signature)
return;
fprintf(file, "-- \n%s", signature);
if (signature[strlen(signature)-1] != '\n')
putc('\n', file);
putc('\n', file);
}
static char *find_branch_name(struct rev_info *rev)
{
int i, positive = -1;
struct object_id branch_oid;
const struct object_id *tip_oid;
const char *ref, *v;
char *full_ref, *branch = NULL;
for (i = 0; i < rev->cmdline.nr; i++) {
if (rev->cmdline.rev[i].flags & UNINTERESTING)
continue;
if (positive < 0)
positive = i;
else
return NULL;
}
if (positive < 0)
return NULL;
ref = rev->cmdline.rev[positive].name;
tip_oid = &rev->cmdline.rev[positive].item->oid;
if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref) &&
skip_prefix(full_ref, "refs/heads/", &v) &&
oideq(tip_oid, &branch_oid))
branch = xstrdup(v);
free(full_ref);
return branch;
}
static void show_diffstat(struct rev_info *rev,
struct commit *origin, struct commit *head)
{
struct diff_options opts;
memcpy(&opts, &rev->diffopt, sizeof(opts));
opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
diff_setup_done(&opts);
diff_tree_oid(get_commit_tree_oid(origin),
get_commit_tree_oid(head),
"", &opts);
diffcore_std(&opts);
diff_flush(&opts);
fprintf(rev->diffopt.file, "\n");
}
static void prepare_cover_text(struct pretty_print_context *pp,
const char *branch_name,
struct strbuf *sb,
const char *encoding,
int need_8bit_cte)
{
const char *subject = "*** SUBJECT HERE ***";
const char *body = "*** BLURB HERE ***";
struct strbuf description_sb = STRBUF_INIT;
struct strbuf subject_sb = STRBUF_INIT;
if (cover_from_description_mode == COVER_FROM_NONE)
goto do_pp;
if (branch_name && *branch_name)
read_branch_desc(&description_sb, branch_name);
if (!description_sb.len)
goto do_pp;
if (cover_from_description_mode == COVER_FROM_SUBJECT ||
cover_from_description_mode == COVER_FROM_AUTO)
body = format_subject(&subject_sb, description_sb.buf, " ");
if (cover_from_description_mode == COVER_FROM_MESSAGE ||
(cover_from_description_mode == COVER_FROM_AUTO &&
subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
body = description_sb.buf;
else
subject = subject_sb.buf;
do_pp:
pp_title_line(pp, &subject, sb, encoding, need_8bit_cte);
pp_remainder(pp, &body, sb, 0);
strbuf_release(&description_sb);
strbuf_release(&subject_sb);
}
static int get_notes_refs(struct string_list_item *item, void *arg)
{
argv_array_pushf(arg, "--notes=%s", item->string);
return 0;
}
static void get_notes_args(struct argv_array *arg, struct rev_info *rev)
{
if (!rev->show_notes) {
argv_array_push(arg, "--no-notes");
} else if (rev->notes_opt.use_default_notes > 0 ||
(rev->notes_opt.use_default_notes == -1 &&
!rev->notes_opt.extra_notes_refs.nr)) {
argv_array_push(arg, "--notes");
} else {
for_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);
}
}
static void make_cover_letter(struct rev_info *rev, int use_stdout,
struct commit *origin,
int nr, struct commit **list,
const char *branch_name,
int quiet)
{
const char *committer;
struct shortlog log;
struct strbuf sb = STRBUF_INIT;
int i;
const char *encoding = "UTF-8";
int need_8bit_cte = 0;
struct pretty_print_context pp = {0};
struct commit *head = list[0];
if (!cmit_fmt_is_mail(rev->commit_format))
die(_("cover letter needs email format"));
committer = git_committer_info(0);
if (!use_stdout &&
open_next_file(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
die(_("failed to create cover-letter file"));
log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte, 0);
for (i = 0; !need_8bit_cte && i < nr; i++) {
const char *buf = get_commit_buffer(list[i], NULL);
if (has_non_ascii(buf))
need_8bit_cte = 1;
unuse_commit_buffer(list[i], buf);
}
if (!branch_name)
branch_name = find_branch_name(rev);
pp.fmt = CMIT_FMT_EMAIL;
convert "enum date_mode" into a struct In preparation for adding date modes that may carry extra information beyond the mode itself, this patch converts the date_mode enum into a struct. Most of the conversion is fairly straightforward; we pass the struct as a pointer and dereference the type field where necessary. Locations that declare a date_mode can use a "{}" constructor. However, the tricky case is where we use the enum labels as constants, like: show_date(t, tz, DATE_NORMAL); Ideally we could say: show_date(t, tz, &{ DATE_NORMAL }); but of course C does not allow that. Likewise, we cannot cast the constant to a struct, because we need to pass an actual address. Our options are basically: 1. Manually add a "struct date_mode d = { DATE_NORMAL }" definition to each caller, and pass "&d". This makes the callers uglier, because they sometimes do not even have their own scope (e.g., they are inside a switch statement). 2. Provide a pre-made global "date_normal" struct that can be passed by address. We'd also need "date_rfc2822", "date_iso8601", and so forth. But at least the ugliness is defined in one place. 3. Provide a wrapper that generates the correct struct on the fly. The big downside is that we end up pointing to a single global, which makes our wrapper non-reentrant. But show_date is already not reentrant, so it does not matter. This patch implements 3, along with a minor macro to keep the size of the callers sane. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-25 18:55:02 +02:00
pp.date_mode.type = DATE_RFC2822;
pp.rev = rev;
pp.print_email_subject = 1;
pp_user_info(&pp, NULL, &sb, committer, encoding);
prepare_cover_text(&pp, branch_name, &sb, encoding, need_8bit_cte);
fprintf(rev->diffopt.file, "%s\n", sb.buf);
strbuf_release(&sb);
shortlog_init(&log);
log.wrap_lines = 1;
log.wrap = MAIL_DEFAULT_WRAP;
log.in1 = 2;
log.in2 = 4;
log.file = rev->diffopt.file;
for (i = 0; i < nr; i++)
shortlog_add_commit(&log, list[i]);
shortlog_output(&log);
/* We can only do diffstat with a unique reference point */
if (origin)
show_diffstat(rev, origin, head);
if (rev->idiff_oid1) {
fprintf_ln(rev->diffopt.file, "%s", rev->idiff_title);
show_interdiff(rev, 0);
}
if (rev->rdiff1) {
/*
* Pass minimum required diff-options to range-diff; others
* can be added later if deemed desirable.
*/
struct diff_options opts;
struct argv_array other_arg = ARGV_ARRAY_INIT;
diff_setup(&opts);
opts.file = rev->diffopt.file;
opts.use_color = rev->diffopt.use_color;
diff_setup_done(&opts);
fprintf_ln(rev->diffopt.file, "%s", rev->rdiff_title);
get_notes_args(&other_arg, rev);
show_range_diff(rev->rdiff1, rev->rdiff2,
rev->creation_factor, 1, &opts, &other_arg);
argv_array_clear(&other_arg);
}
}
static const char *clean_message_id(const char *msg_id)
{
char ch;
const char *a, *z, *m;
m = msg_id;
while ((ch = *m) && (isspace(ch) || (ch == '<')))
m++;
a = m;
z = NULL;
while ((ch = *m)) {
if (!isspace(ch) && (ch != '>'))
z = m;
m++;
}
if (!z)
die(_("insane in-reply-to: %s"), msg_id);
if (++z == m)
return a;
return xmemdupz(a, z - a);
}
static const char *set_outdir(const char *prefix, const char *output_directory)
{
if (output_directory && is_absolute_path(output_directory))
return output_directory;
if (!prefix || !*prefix) {
if (output_directory)
return output_directory;
/* The user did not explicitly ask for "./" */
outdir_offset = 2;
return "./";
}
outdir_offset = strlen(prefix);
if (!output_directory)
return prefix;
return prefix_filename(prefix, output_directory);
}
static const char * const builtin_format_patch_usage[] = {
N_("git format-patch [<options>] [<since> | <revision-range>]"),
NULL
};
static int keep_subject = 0;
static int keep_callback(const struct option *opt, const char *arg, int unset)
{
assert NOARG/NONEG behavior of parse-options callbacks When we define a parse-options callback, the flags we put in the option struct must match what the callback expects. For example, a callback which does not handle the "unset" parameter should only be used with PARSE_OPT_NONEG. But since the callback and the option struct are not defined next to each other, it's easy to get this wrong (as earlier patches in this series show). Fortunately, the compiler can help us here: compiling with -Wunused-parameters can show us which callbacks ignore their "unset" parameters (and likewise, ones that ignore "arg" expect to be triggered with PARSE_OPT_NOARG). But after we've inspected a callback and determined that all of its callers use the right flags, what do we do next? We'd like to silence the compiler warning, but do so in a way that will catch any wrong calls in the future. We can do that by actually checking those variables and asserting that they match our expectations. Because this is such a common pattern, we'll introduce some helper macros. The resulting messages aren't as descriptive as we could make them, but the file/line information from BUG() is enough to identify the problem (and anyway, the point is that these should never be seen). Each of the annotated callbacks in this patch triggers -Wunused-parameters, and was manually inspected to make sure all callers use the correct options (so none of these BUGs should be triggerable). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 07:45:42 +01:00
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
((struct rev_info *)opt->value)->total = -1;
keep_subject = 1;
return 0;
}
static int subject_prefix = 0;
static int subject_prefix_callback(const struct option *opt, const char *arg,
int unset)
{
assert NOARG/NONEG behavior of parse-options callbacks When we define a parse-options callback, the flags we put in the option struct must match what the callback expects. For example, a callback which does not handle the "unset" parameter should only be used with PARSE_OPT_NONEG. But since the callback and the option struct are not defined next to each other, it's easy to get this wrong (as earlier patches in this series show). Fortunately, the compiler can help us here: compiling with -Wunused-parameters can show us which callbacks ignore their "unset" parameters (and likewise, ones that ignore "arg" expect to be triggered with PARSE_OPT_NOARG). But after we've inspected a callback and determined that all of its callers use the right flags, what do we do next? We'd like to silence the compiler warning, but do so in a way that will catch any wrong calls in the future. We can do that by actually checking those variables and asserting that they match our expectations. Because this is such a common pattern, we'll introduce some helper macros. The resulting messages aren't as descriptive as we could make them, but the file/line information from BUG() is enough to identify the problem (and anyway, the point is that these should never be seen). Each of the annotated callbacks in this patch triggers -Wunused-parameters, and was manually inspected to make sure all callers use the correct options (so none of these BUGs should be triggerable). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 07:45:42 +01:00
BUG_ON_OPT_NEG(unset);
subject_prefix = 1;
((struct rev_info *)opt->value)->subject_prefix = arg;
return 0;
}
static int rfc_callback(const struct option *opt, const char *arg, int unset)
{
assert NOARG/NONEG behavior of parse-options callbacks When we define a parse-options callback, the flags we put in the option struct must match what the callback expects. For example, a callback which does not handle the "unset" parameter should only be used with PARSE_OPT_NONEG. But since the callback and the option struct are not defined next to each other, it's easy to get this wrong (as earlier patches in this series show). Fortunately, the compiler can help us here: compiling with -Wunused-parameters can show us which callbacks ignore their "unset" parameters (and likewise, ones that ignore "arg" expect to be triggered with PARSE_OPT_NOARG). But after we've inspected a callback and determined that all of its callers use the right flags, what do we do next? We'd like to silence the compiler warning, but do so in a way that will catch any wrong calls in the future. We can do that by actually checking those variables and asserting that they match our expectations. Because this is such a common pattern, we'll introduce some helper macros. The resulting messages aren't as descriptive as we could make them, but the file/line information from BUG() is enough to identify the problem (and anyway, the point is that these should never be seen). Each of the annotated callbacks in this patch triggers -Wunused-parameters, and was manually inspected to make sure all callers use the correct options (so none of these BUGs should be triggerable). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 07:45:42 +01:00
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
return subject_prefix_callback(opt, "RFC PATCH", unset);
}
static int numbered_cmdline_opt = 0;
static int numbered_callback(const struct option *opt, const char *arg,
int unset)
{
assert NOARG/NONEG behavior of parse-options callbacks When we define a parse-options callback, the flags we put in the option struct must match what the callback expects. For example, a callback which does not handle the "unset" parameter should only be used with PARSE_OPT_NONEG. But since the callback and the option struct are not defined next to each other, it's easy to get this wrong (as earlier patches in this series show). Fortunately, the compiler can help us here: compiling with -Wunused-parameters can show us which callbacks ignore their "unset" parameters (and likewise, ones that ignore "arg" expect to be triggered with PARSE_OPT_NOARG). But after we've inspected a callback and determined that all of its callers use the right flags, what do we do next? We'd like to silence the compiler warning, but do so in a way that will catch any wrong calls in the future. We can do that by actually checking those variables and asserting that they match our expectations. Because this is such a common pattern, we'll introduce some helper macros. The resulting messages aren't as descriptive as we could make them, but the file/line information from BUG() is enough to identify the problem (and anyway, the point is that these should never be seen). Each of the annotated callbacks in this patch triggers -Wunused-parameters, and was manually inspected to make sure all callers use the correct options (so none of these BUGs should be triggerable). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 07:45:42 +01:00
BUG_ON_OPT_ARG(arg);
*(int *)opt->value = numbered_cmdline_opt = unset ? 0 : 1;
if (unset)
auto_number = 0;
return 0;
}
static int no_numbered_callback(const struct option *opt, const char *arg,
int unset)
{
assert NOARG/NONEG behavior of parse-options callbacks When we define a parse-options callback, the flags we put in the option struct must match what the callback expects. For example, a callback which does not handle the "unset" parameter should only be used with PARSE_OPT_NONEG. But since the callback and the option struct are not defined next to each other, it's easy to get this wrong (as earlier patches in this series show). Fortunately, the compiler can help us here: compiling with -Wunused-parameters can show us which callbacks ignore their "unset" parameters (and likewise, ones that ignore "arg" expect to be triggered with PARSE_OPT_NOARG). But after we've inspected a callback and determined that all of its callers use the right flags, what do we do next? We'd like to silence the compiler warning, but do so in a way that will catch any wrong calls in the future. We can do that by actually checking those variables and asserting that they match our expectations. Because this is such a common pattern, we'll introduce some helper macros. The resulting messages aren't as descriptive as we could make them, but the file/line information from BUG() is enough to identify the problem (and anyway, the point is that these should never be seen). Each of the annotated callbacks in this patch triggers -Wunused-parameters, and was manually inspected to make sure all callers use the correct options (so none of these BUGs should be triggerable). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 07:45:42 +01:00
BUG_ON_OPT_NEG(unset);
return numbered_callback(opt, arg, 1);
}
static int output_directory_callback(const struct option *opt, const char *arg,
int unset)
{
const char **dir = (const char **)opt->value;
assert NOARG/NONEG behavior of parse-options callbacks When we define a parse-options callback, the flags we put in the option struct must match what the callback expects. For example, a callback which does not handle the "unset" parameter should only be used with PARSE_OPT_NONEG. But since the callback and the option struct are not defined next to each other, it's easy to get this wrong (as earlier patches in this series show). Fortunately, the compiler can help us here: compiling with -Wunused-parameters can show us which callbacks ignore their "unset" parameters (and likewise, ones that ignore "arg" expect to be triggered with PARSE_OPT_NOARG). But after we've inspected a callback and determined that all of its callers use the right flags, what do we do next? We'd like to silence the compiler warning, but do so in a way that will catch any wrong calls in the future. We can do that by actually checking those variables and asserting that they match our expectations. Because this is such a common pattern, we'll introduce some helper macros. The resulting messages aren't as descriptive as we could make them, but the file/line information from BUG() is enough to identify the problem (and anyway, the point is that these should never be seen). Each of the annotated callbacks in this patch triggers -Wunused-parameters, and was manually inspected to make sure all callers use the correct options (so none of these BUGs should be triggerable). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 07:45:42 +01:00
BUG_ON_OPT_NEG(unset);
if (*dir)
die(_("two output directories?"));
*dir = arg;
return 0;
}
static int thread_callback(const struct option *opt, const char *arg, int unset)
{
enum thread_level *thread = (enum thread_level *)opt->value;
if (unset)
*thread = THREAD_UNSET;
else if (!arg || !strcmp(arg, "shallow"))
*thread = THREAD_SHALLOW;
else if (!strcmp(arg, "deep"))
*thread = THREAD_DEEP;
/*
* Please update _git_formatpatch() in git-completion.bash
* when you add new options.
*/
else
return 1;
return 0;
}
static int attach_callback(const struct option *opt, const char *arg, int unset)
{
struct rev_info *rev = (struct rev_info *)opt->value;
if (unset)
rev->mime_boundary = NULL;
else if (arg)
rev->mime_boundary = arg;
else
rev->mime_boundary = git_version_string;
rev->no_inline = unset ? 0 : 1;
return 0;
}
static int inline_callback(const struct option *opt, const char *arg, int unset)
{
struct rev_info *rev = (struct rev_info *)opt->value;
if (unset)
rev->mime_boundary = NULL;
else if (arg)
rev->mime_boundary = arg;
else
rev->mime_boundary = git_version_string;
rev->no_inline = 0;
return 0;
}
static int header_callback(const struct option *opt, const char *arg, int unset)
{
if (unset) {
string_list_clear(&extra_hdr, 0);
string_list_clear(&extra_to, 0);
string_list_clear(&extra_cc, 0);
} else {
add_header(arg);
}
return 0;
}
static int to_callback(const struct option *opt, const char *arg, int unset)
{
if (unset)
string_list_clear(&extra_to, 0);
else
string_list_append(&extra_to, arg);
return 0;
}
static int cc_callback(const struct option *opt, const char *arg, int unset)
{
if (unset)
string_list_clear(&extra_cc, 0);
else
string_list_append(&extra_cc, arg);
return 0;
}
static int from_callback(const struct option *opt, const char *arg, int unset)
{
char **from = opt->value;
free(*from);
if (unset)
*from = NULL;
else if (arg)
*from = xstrdup(arg);
else
*from = xstrdup(git_committer_info(IDENT_NO_DATE));
return 0;
}
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
struct base_tree_info {
struct object_id base_commit;
int nr_patch_id, alloc_patch_id;
struct object_id *patch_id;
};
static struct commit *get_base_commit(const char *base_commit,
struct commit **list,
int total)
{
struct commit *base = NULL;
struct commit **rev;
int i = 0, rev_nr = 0;
if (base_commit && strcmp(base_commit, "auto")) {
base = lookup_commit_reference_by_name(base_commit);
if (!base)
die(_("unknown commit %s"), base_commit);
} else if ((base_commit && !strcmp(base_commit, "auto"))) {
struct branch *curr_branch = branch_get(NULL);
const char *upstream = branch_get_upstream(curr_branch, NULL);
if (upstream) {
struct commit_list *base_list;
struct commit *commit;
struct object_id oid;
if (get_oid(upstream, &oid))
die(_("failed to resolve '%s' as a valid ref"), upstream);
Convert lookup_commit* to struct object_id Convert lookup_commit, lookup_commit_or_die, lookup_commit_reference, and lookup_commit_reference_gently to take struct object_id arguments. Introduce a temporary in parse_object buffer in order to convert this function. This is required since in order to convert parse_object and parse_object_buffer, lookup_commit_reference_gently and lookup_commit_or_die would need to be converted. Not introducing a temporary would therefore require that lookup_commit_or_die take a struct object_id *, but lookup_commit would take unsigned char *, leaving a confusing and hard-to-use interface. parse_object_buffer will lose this temporary in a later patch. This commit was created with manual changes to commit.c, commit.h, and object.c, plus the following semantic patch: @@ expression E1, E2; @@ - lookup_commit_reference_gently(E1.hash, E2) + lookup_commit_reference_gently(&E1, E2) @@ expression E1, E2; @@ - lookup_commit_reference_gently(E1->hash, E2) + lookup_commit_reference_gently(E1, E2) @@ expression E1; @@ - lookup_commit_reference(E1.hash) + lookup_commit_reference(&E1) @@ expression E1; @@ - lookup_commit_reference(E1->hash) + lookup_commit_reference(E1) @@ expression E1; @@ - lookup_commit(E1.hash) + lookup_commit(&E1) @@ expression E1; @@ - lookup_commit(E1->hash) + lookup_commit(E1) @@ expression E1, E2; @@ - lookup_commit_or_die(E1.hash, E2) + lookup_commit_or_die(&E1, E2) @@ expression E1, E2; @@ - lookup_commit_or_die(E1->hash, E2) + lookup_commit_or_die(E1, E2) Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-05-07 00:10:10 +02:00
commit = lookup_commit_or_die(&oid, "upstream base");
base_list = get_merge_bases_many(commit, total, list);
/* There should be one and only one merge base. */
if (!base_list || base_list->next)
die(_("could not find exact merge base"));
base = base_list->item;
free_commit_list(base_list);
} else {
die(_("failed to get upstream, if you want to record base commit automatically,\n"
"please use git branch --set-upstream-to to track a remote branch.\n"
"Or you could specify base commit by --base=<base-commit-id> manually"));
}
}
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
ALLOC_ARRAY(rev, total);
for (i = 0; i < total; i++)
rev[i] = list[i];
rev_nr = total;
/*
* Get merge base through pair-wise computations
* and store it in rev[0].
*/
while (rev_nr > 1) {
for (i = 0; i < rev_nr / 2; i++) {
struct commit_list *merge_base;
merge_base = get_merge_bases(rev[2 * i], rev[2 * i + 1]);
if (!merge_base || merge_base->next)
die(_("failed to find exact merge base"));
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
rev[i] = merge_base->item;
}
if (rev_nr % 2)
rev[i] = rev[2 * i];
rev_nr = DIV_ROUND_UP(rev_nr, 2);
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
}
if (!in_merge_bases(base, rev[0]))
die(_("base commit should be the ancestor of revision list"));
for (i = 0; i < total; i++) {
if (base == list[i])
die(_("base commit shouldn't be in revision list"));
}
free(rev);
return base;
}
define_commit_slab(commit_base, int);
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
static void prepare_bases(struct base_tree_info *bases,
struct commit *base,
struct commit **list,
int total)
{
struct commit *commit;
struct rev_info revs;
struct diff_options diffopt;
struct commit_base commit_base;
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
int i;
if (!base)
return;
init_commit_base(&commit_base);
repo_diff_setup(the_repository, &diffopt);
diff: make struct diff_flags members lowercase Now that the flags stored in struct diff_flags are being accessed directly and not through macros, change all struct members from being uppercase to lowercase. This conversion is done using the following semantic patch: @@ expression E; @@ - E.RECURSIVE + E.recursive @@ expression E; @@ - E.TREE_IN_RECURSIVE + E.tree_in_recursive @@ expression E; @@ - E.BINARY + E.binary @@ expression E; @@ - E.TEXT + E.text @@ expression E; @@ - E.FULL_INDEX + E.full_index @@ expression E; @@ - E.SILENT_ON_REMOVE + E.silent_on_remove @@ expression E; @@ - E.FIND_COPIES_HARDER + E.find_copies_harder @@ expression E; @@ - E.FOLLOW_RENAMES + E.follow_renames @@ expression E; @@ - E.RENAME_EMPTY + E.rename_empty @@ expression E; @@ - E.HAS_CHANGES + E.has_changes @@ expression E; @@ - E.QUICK + E.quick @@ expression E; @@ - E.NO_INDEX + E.no_index @@ expression E; @@ - E.ALLOW_EXTERNAL + E.allow_external @@ expression E; @@ - E.EXIT_WITH_STATUS + E.exit_with_status @@ expression E; @@ - E.REVERSE_DIFF + E.reverse_diff @@ expression E; @@ - E.CHECK_FAILED + E.check_failed @@ expression E; @@ - E.RELATIVE_NAME + E.relative_name @@ expression E; @@ - E.IGNORE_SUBMODULES + E.ignore_submodules @@ expression E; @@ - E.DIRSTAT_CUMULATIVE + E.dirstat_cumulative @@ expression E; @@ - E.DIRSTAT_BY_FILE + E.dirstat_by_file @@ expression E; @@ - E.ALLOW_TEXTCONV + E.allow_textconv @@ expression E; @@ - E.TEXTCONV_SET_VIA_CMDLINE + E.textconv_set_via_cmdline @@ expression E; @@ - E.DIFF_FROM_CONTENTS + E.diff_from_contents @@ expression E; @@ - E.DIRTY_SUBMODULES + E.dirty_submodules @@ expression E; @@ - E.IGNORE_UNTRACKED_IN_SUBMODULES + E.ignore_untracked_in_submodules @@ expression E; @@ - E.IGNORE_DIRTY_SUBMODULES + E.ignore_dirty_submodules @@ expression E; @@ - E.OVERRIDE_SUBMODULE_CONFIG + E.override_submodule_config @@ expression E; @@ - E.DIRSTAT_BY_LINE + E.dirstat_by_line @@ expression E; @@ - E.FUNCCONTEXT + E.funccontext @@ expression E; @@ - E.PICKAXE_IGNORE_CASE + E.pickaxe_ignore_case @@ expression E; @@ - E.DEFAULT_FOLLOW_RENAMES + E.default_follow_renames Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-31 19:19:11 +01:00
diffopt.flags.recursive = 1;
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
diff_setup_done(&diffopt);
oidcpy(&bases->base_commit, &base->object.oid);
repo_init_revisions(the_repository, &revs, NULL);
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
revs.max_parents = 1;
revs.topo_order = 1;
for (i = 0; i < total; i++) {
list[i]->object.flags &= ~UNINTERESTING;
add_pending_object(&revs, &list[i]->object, "rev_list");
*commit_base_at(&commit_base, list[i]) = 1;
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
}
base->object.flags |= UNINTERESTING;
add_pending_object(&revs, &base->object, "base");
if (prepare_revision_walk(&revs))
die(_("revision walk setup failed"));
/*
* Traverse the commits list, get prerequisite patch ids
* and stuff them in bases structure.
*/
while ((commit = get_revision(&revs)) != NULL) {
struct object_id oid;
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
struct object_id *patch_id;
if (*commit_base_at(&commit_base, commit))
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
continue;
if (commit_patch_id(commit, &diffopt, &oid, 0, 1))
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
die(_("cannot get patch id"));
ALLOC_GROW(bases->patch_id, bases->nr_patch_id + 1, bases->alloc_patch_id);
patch_id = bases->patch_id + bases->nr_patch_id;
oidcpy(patch_id, &oid);
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
bases->nr_patch_id++;
}
clear_commit_base(&commit_base);
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
}
static void print_bases(struct base_tree_info *bases, FILE *file)
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
{
int i;
/* Only do this once, either for the cover or for the first one */
if (is_null_oid(&bases->base_commit))
return;
/* Show the base commit */
fprintf(file, "\nbase-commit: %s\n", oid_to_hex(&bases->base_commit));
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
/* Show the prerequisite patches */
for (i = bases->nr_patch_id - 1; i >= 0; i--)
fprintf(file, "prerequisite-patch-id: %s\n", oid_to_hex(&bases->patch_id[i]));
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
free(bases->patch_id);
bases->nr_patch_id = 0;
bases->alloc_patch_id = 0;
oidclr(&bases->base_commit);
}
static const char *diff_title(struct strbuf *sb, int reroll_count,
const char *generic, const char *rerolled)
{
if (reroll_count <= 0)
strbuf_addstr(sb, generic);
else /* RFC may be v0, so allow -v1 to diff against v0 */
strbuf_addf(sb, rerolled, reroll_count - 1);
return sb->buf;
}
static void infer_range_diff_ranges(struct strbuf *r1,
struct strbuf *r2,
const char *prev,
struct commit *origin,
struct commit *head)
{
const char *head_oid = oid_to_hex(&head->object.oid);
if (!strstr(prev, "..")) {
strbuf_addf(r1, "%s..%s", head_oid, prev);
strbuf_addf(r2, "%s..%s", prev, head_oid);
} else if (!origin) {
die(_("failed to infer range-diff ranges"));
} else {
strbuf_addstr(r1, prev);
strbuf_addf(r2, "%s..%s",
oid_to_hex(&origin->object.oid), head_oid);
}
}
int cmd_format_patch(int argc, const char **argv, const char *prefix)
{
struct commit *commit;
struct commit **list = NULL;
struct rev_info rev;
struct setup_revision_opt s_r_opt;
int nr = 0, total, i;
int use_stdout = 0;
int start_number = -1;
int just_numbers = 0;
int ignore_if_in_upstream = 0;
int cover_letter = -1;
int boundary_count = 0;
int no_binary_diff = 0;
int zero_commit = 0;
struct commit *origin = NULL;
const char *in_reply_to = NULL;
struct patch_ids ids;
struct strbuf buf = STRBUF_INIT;
int use_patch_format = 0;
int quiet = 0;
int reroll_count = -1;
char *cover_from_description_arg = NULL;
char *branch_name = NULL;
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
char *base_commit = NULL;
struct base_tree_info bases;
int show_progress = 0;
struct progress *progress = NULL;
struct oid_array idiff_prev = OID_ARRAY_INIT;
struct strbuf idiff_title = STRBUF_INIT;
const char *rdiff_prev = NULL;
struct strbuf rdiff1 = STRBUF_INIT;
struct strbuf rdiff2 = STRBUF_INIT;
struct strbuf rdiff_title = STRBUF_INIT;
int creation_factor = -1;
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
const struct option builtin_format_patch_options[] = {
OPT_CALLBACK_F('n', "numbered", &numbered, NULL,
N_("use [PATCH n/m] even with a single patch"),
PARSE_OPT_NOARG, numbered_callback),
OPT_CALLBACK_F('N', "no-numbered", &numbered, NULL,
N_("use [PATCH] even with multiple patches"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, no_numbered_callback),
OPT_BOOL('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
OPT_BOOL(0, "stdout", &use_stdout,
N_("print patches to standard out")),
OPT_BOOL(0, "cover-letter", &cover_letter,
N_("generate a cover letter")),
OPT_BOOL(0, "numbered-files", &just_numbers,
N_("use simple number sequence for output file names")),
OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"),
N_("use <sfx> instead of '.patch'")),
OPT_INTEGER(0, "start-number", &start_number,
N_("start numbering patches at <n> instead of 1")),
OPT_INTEGER('v', "reroll-count", &reroll_count,
N_("mark the series as Nth re-roll")),
OPT_CALLBACK_F(0, "rfc", &rev, NULL,
N_("Use [RFC PATCH] instead of [PATCH]"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback),
OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
N_("cover-from-description-mode"),
N_("generate parts of a cover letter based on a branch's description")),
OPT_CALLBACK_F(0, "subject-prefix", &rev, N_("prefix"),
N_("Use [<prefix>] instead of [PATCH]"),
PARSE_OPT_NONEG, subject_prefix_callback),
OPT_CALLBACK_F('o', "output-directory", &output_directory,
N_("dir"), N_("store resulting files in <dir>"),
PARSE_OPT_NONEG, output_directory_callback),
OPT_CALLBACK_F('k', "keep-subject", &rev, NULL,
N_("don't strip/add [PATCH]"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback),
OPT_BOOL(0, "no-binary", &no_binary_diff,
N_("don't output binary diffs")),
OPT_BOOL(0, "zero-commit", &zero_commit,
N_("output all-zero hash in From header")),
OPT_BOOL(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
N_("don't include a patch matching a commit upstream")),
OPT_SET_INT_F('p', "no-stat", &use_patch_format,
N_("show patch format instead of default (patch + stat)"),
1, PARSE_OPT_NONEG),
OPT_GROUP(N_("Messaging")),
OPT_CALLBACK(0, "add-header", NULL, N_("header"),
N_("add email header"), header_callback),
OPT_CALLBACK(0, "to", NULL, N_("email"), N_("add To: header"), to_callback),
OPT_CALLBACK(0, "cc", NULL, N_("email"), N_("add Cc: header"), cc_callback),
OPT_CALLBACK_F(0, "from", &from, N_("ident"),
N_("set From address to <ident> (or committer ident if absent)"),
PARSE_OPT_OPTARG, from_callback),
OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"),
N_("make first mail a reply to <message-id>")),
OPT_CALLBACK_F(0, "attach", &rev, N_("boundary"),
N_("attach the patch"), PARSE_OPT_OPTARG,
attach_callback),
OPT_CALLBACK_F(0, "inline", &rev, N_("boundary"),
N_("inline the patch"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
inline_callback),
OPT_CALLBACK_F(0, "thread", &thread, N_("style"),
N_("enable message threading, styles: shallow, deep"),
PARSE_OPT_OPTARG, thread_callback),
OPT_STRING(0, "signature", &signature, N_("signature"),
N_("add a signature")),
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
OPT_STRING(0, "base", &base_commit, N_("base-commit"),
N_("add prerequisite tree info to the patch series")),
OPT_FILENAME(0, "signature-file", &signature_file,
N_("add a signature from a file")),
OPT__QUIET(&quiet, N_("don't print the patch filenames")),
OPT_BOOL(0, "progress", &show_progress,
N_("show progress while generating patches")),
OPT_CALLBACK(0, "interdiff", &idiff_prev, N_("rev"),
N_("show changes against <rev> in cover letter or single patch"),
parse_opt_object_name),
OPT_STRING(0, "range-diff", &rdiff_prev, N_("refspec"),
N_("show changes against <refspec> in cover letter or single patch")),
OPT_INTEGER(0, "creation-factor", &creation_factor,
N_("percentage by which creation is weighted")),
OPT_END()
};
extra_hdr.strdup_strings = 1;
extra_to.strdup_strings = 1;
extra_cc.strdup_strings = 1;
init_log_defaults();
init_display_notes(&notes_opt);
git_config(git_format_config, NULL);
repo_init_revisions(the_repository, &rev, prefix);
rev.show_notes = show_notes;
memcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));
rev.commit_format = CMIT_FMT_EMAIL;
rev.encode_email_headers = default_encode_email_headers;
rev.expand_tabs_in_log_default = 0;
rev.verbose_header = 1;
rev.diff = 1;
rev.max_parents = 1;
diff: make struct diff_flags members lowercase Now that the flags stored in struct diff_flags are being accessed directly and not through macros, change all struct members from being uppercase to lowercase. This conversion is done using the following semantic patch: @@ expression E; @@ - E.RECURSIVE + E.recursive @@ expression E; @@ - E.TREE_IN_RECURSIVE + E.tree_in_recursive @@ expression E; @@ - E.BINARY + E.binary @@ expression E; @@ - E.TEXT + E.text @@ expression E; @@ - E.FULL_INDEX + E.full_index @@ expression E; @@ - E.SILENT_ON_REMOVE + E.silent_on_remove @@ expression E; @@ - E.FIND_COPIES_HARDER + E.find_copies_harder @@ expression E; @@ - E.FOLLOW_RENAMES + E.follow_renames @@ expression E; @@ - E.RENAME_EMPTY + E.rename_empty @@ expression E; @@ - E.HAS_CHANGES + E.has_changes @@ expression E; @@ - E.QUICK + E.quick @@ expression E; @@ - E.NO_INDEX + E.no_index @@ expression E; @@ - E.ALLOW_EXTERNAL + E.allow_external @@ expression E; @@ - E.EXIT_WITH_STATUS + E.exit_with_status @@ expression E; @@ - E.REVERSE_DIFF + E.reverse_diff @@ expression E; @@ - E.CHECK_FAILED + E.check_failed @@ expression E; @@ - E.RELATIVE_NAME + E.relative_name @@ expression E; @@ - E.IGNORE_SUBMODULES + E.ignore_submodules @@ expression E; @@ - E.DIRSTAT_CUMULATIVE + E.dirstat_cumulative @@ expression E; @@ - E.DIRSTAT_BY_FILE + E.dirstat_by_file @@ expression E; @@ - E.ALLOW_TEXTCONV + E.allow_textconv @@ expression E; @@ - E.TEXTCONV_SET_VIA_CMDLINE + E.textconv_set_via_cmdline @@ expression E; @@ - E.DIFF_FROM_CONTENTS + E.diff_from_contents @@ expression E; @@ - E.DIRTY_SUBMODULES + E.dirty_submodules @@ expression E; @@ - E.IGNORE_UNTRACKED_IN_SUBMODULES + E.ignore_untracked_in_submodules @@ expression E; @@ - E.IGNORE_DIRTY_SUBMODULES + E.ignore_dirty_submodules @@ expression E; @@ - E.OVERRIDE_SUBMODULE_CONFIG + E.override_submodule_config @@ expression E; @@ - E.DIRSTAT_BY_LINE + E.dirstat_by_line @@ expression E; @@ - E.FUNCCONTEXT + E.funccontext @@ expression E; @@ - E.PICKAXE_IGNORE_CASE + E.pickaxe_ignore_case @@ expression E; @@ - E.DEFAULT_FOLLOW_RENAMES + E.default_follow_renames Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-31 19:19:11 +01:00
rev.diffopt.flags.recursive = 1;
rev.subject_prefix = fmt_patch_subject_prefix;
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.def = "HEAD";
s_r_opt.revarg_opt = REVARG_COMMITTISH;
if (base_auto)
base_commit = "auto";
if (default_attach) {
rev.mime_boundary = default_attach;
rev.no_inline = 1;
}
/*
* Parse the arguments before setup_revisions(), or something
* like "git format-patch -o a123 HEAD^.." may fail; a123 is
* possibly a valid SHA1.
*/
argc = parse_options(argc, argv, prefix, builtin_format_patch_options,
builtin_format_patch_usage,
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
PARSE_OPT_KEEP_DASHDASH);
if (cover_from_description_arg)
cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
if (0 < reroll_count) {
struct strbuf sprefix = STRBUF_INIT;
strbuf_addf(&sprefix, "%s v%d",
rev.subject_prefix, reroll_count);
rev.reroll_count = reroll_count;
rev.subject_prefix = strbuf_detach(&sprefix, NULL);
}
for (i = 0; i < extra_hdr.nr; i++) {
strbuf_addstr(&buf, extra_hdr.items[i].string);
strbuf_addch(&buf, '\n');
}
if (extra_to.nr)
strbuf_addstr(&buf, "To: ");
for (i = 0; i < extra_to.nr; i++) {
if (i)
strbuf_addstr(&buf, " ");
strbuf_addstr(&buf, extra_to.items[i].string);
if (i + 1 < extra_to.nr)
strbuf_addch(&buf, ',');
strbuf_addch(&buf, '\n');
}
if (extra_cc.nr)
strbuf_addstr(&buf, "Cc: ");
for (i = 0; i < extra_cc.nr; i++) {
if (i)
strbuf_addstr(&buf, " ");
strbuf_addstr(&buf, extra_cc.items[i].string);
if (i + 1 < extra_cc.nr)
strbuf_addch(&buf, ',');
strbuf_addch(&buf, '\n');
}
rev.extra_headers = strbuf_detach(&buf, NULL);
if (from) {
if (split_ident_line(&rev.from_ident, from, strlen(from)))
die(_("invalid ident line: %s"), from);
}
if (start_number < 0)
start_number = 1;
/*
* If numbered is set solely due to format.numbered in config,
* and it would conflict with --keep-subject (-k) from the
* command line, reset "numbered".
*/
if (numbered && keep_subject && !numbered_cmdline_opt)
numbered = 0;
if (numbered && keep_subject)
die(_("-n and -k are mutually exclusive"));
if (keep_subject && subject_prefix)
die(_("--subject-prefix/--rfc and -k are mutually exclusive"));
rev.preserve_subject = keep_subject;
argc = setup_revisions(argc, argv, &rev, &s_r_opt);
if (argc > 1)
die(_("unrecognized argument: %s"), argv[1]);
if (rev.diffopt.output_format & DIFF_FORMAT_NAME)
die(_("--name-only does not make sense"));
if (rev.diffopt.output_format & DIFF_FORMAT_NAME_STATUS)
die(_("--name-status does not make sense"));
if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
die(_("--check does not make sense"));
if (!use_patch_format &&
(!rev.diffopt.output_format ||
rev.diffopt.output_format == DIFF_FORMAT_PATCH))
rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY;
if (!rev.diffopt.stat_width)
rev.diffopt.stat_width = MAIL_DEFAULT_WRAP;
/* Always generate a patch */
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
rev.zero_commit = zero_commit;
diff: make struct diff_flags members lowercase Now that the flags stored in struct diff_flags are being accessed directly and not through macros, change all struct members from being uppercase to lowercase. This conversion is done using the following semantic patch: @@ expression E; @@ - E.RECURSIVE + E.recursive @@ expression E; @@ - E.TREE_IN_RECURSIVE + E.tree_in_recursive @@ expression E; @@ - E.BINARY + E.binary @@ expression E; @@ - E.TEXT + E.text @@ expression E; @@ - E.FULL_INDEX + E.full_index @@ expression E; @@ - E.SILENT_ON_REMOVE + E.silent_on_remove @@ expression E; @@ - E.FIND_COPIES_HARDER + E.find_copies_harder @@ expression E; @@ - E.FOLLOW_RENAMES + E.follow_renames @@ expression E; @@ - E.RENAME_EMPTY + E.rename_empty @@ expression E; @@ - E.HAS_CHANGES + E.has_changes @@ expression E; @@ - E.QUICK + E.quick @@ expression E; @@ - E.NO_INDEX + E.no_index @@ expression E; @@ - E.ALLOW_EXTERNAL + E.allow_external @@ expression E; @@ - E.EXIT_WITH_STATUS + E.exit_with_status @@ expression E; @@ - E.REVERSE_DIFF + E.reverse_diff @@ expression E; @@ - E.CHECK_FAILED + E.check_failed @@ expression E; @@ - E.RELATIVE_NAME + E.relative_name @@ expression E; @@ - E.IGNORE_SUBMODULES + E.ignore_submodules @@ expression E; @@ - E.DIRSTAT_CUMULATIVE + E.dirstat_cumulative @@ expression E; @@ - E.DIRSTAT_BY_FILE + E.dirstat_by_file @@ expression E; @@ - E.ALLOW_TEXTCONV + E.allow_textconv @@ expression E; @@ - E.TEXTCONV_SET_VIA_CMDLINE + E.textconv_set_via_cmdline @@ expression E; @@ - E.DIFF_FROM_CONTENTS + E.diff_from_contents @@ expression E; @@ - E.DIRTY_SUBMODULES + E.dirty_submodules @@ expression E; @@ - E.IGNORE_UNTRACKED_IN_SUBMODULES + E.ignore_untracked_in_submodules @@ expression E; @@ - E.IGNORE_DIRTY_SUBMODULES + E.ignore_dirty_submodules @@ expression E; @@ - E.OVERRIDE_SUBMODULE_CONFIG + E.override_submodule_config @@ expression E; @@ - E.DIRSTAT_BY_LINE + E.dirstat_by_line @@ expression E; @@ - E.FUNCCONTEXT + E.funccontext @@ expression E; @@ - E.PICKAXE_IGNORE_CASE + E.pickaxe_ignore_case @@ expression E; @@ - E.DEFAULT_FOLLOW_RENAMES + E.default_follow_renames Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-31 19:19:11 +01:00
if (!rev.diffopt.flags.text && !no_binary_diff)
rev.diffopt.flags.binary = 1;
if (rev.show_notes)
load_display_notes(&rev.notes_opt);
if (!output_directory && !use_stdout)
output_directory = config_output_directory;
if (!use_stdout)
output_directory = set_outdir(prefix, output_directory);
else
setup_pager();
if (output_directory) {
int saved;
if (rev.diffopt.use_color != GIT_COLOR_ALWAYS)
rev.diffopt.use_color = GIT_COLOR_NEVER;
if (use_stdout)
die(_("standard output, or directory, which one?"));
/*
* We consider <outdir> as 'outside of gitdir', therefore avoid
* applying adjust_shared_perm in s-c-l-d.
*/
saved = get_shared_repository();
set_shared_repository(0);
switch (safe_create_leading_directories_const(output_directory)) {
case SCLD_OK:
case SCLD_EXISTS:
break;
default:
die(_("could not create leading directories "
"of '%s'"), output_directory);
}
set_shared_repository(saved);
if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
die_errno(_("could not create directory '%s'"),
output_directory);
}
Add "named object array" concept We've had this notion of a "object_list" for a long time, which eventually grew a "name" member because some users (notably git-rev-list) wanted to name each object as it is generated. That object_list is great for some things, but it isn't all that wonderful for others, and the "name" member is generally not used by everybody. This patch splits the users of the object_list array up into two: the traditional list users, who want the list-like format, and who don't actually use or want the name. And another class of users that really used the list as an extensible array, and generally wanted to name the objects. The patch is fairly straightforward, but it's also biggish. Most of it really just cleans things up: switching the revision parsing and listing over to the array makes things like the builtin-diff usage much simpler (we now see exactly how many members the array has, and we don't get the objects reversed from the order they were on the command line). One of the main reasons for doing this at all is that the malloc overhead of the simple object list was actually pretty high, and the array is just a lot denser. So this patch brings down memory usage by git-rev-list by just under 3% (on top of all the other memory use optimizations) on the mozilla archive. It does add more lines than it removes, and more importantly, it adds a whole new infrastructure for maintaining lists of objects, but on the other hand, the new dynamic array code is pretty obvious. The change to builtin-diff-tree.c shows a fairly good example of why an array interface is sometimes more natural, and just much simpler for everybody. Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-20 02:42:35 +02:00
if (rev.pending.nr == 1) {
int check_head = 0;
if (rev.max_count < 0 && !rev.show_root_diff) {
/*
* This is traditional behaviour of "git format-patch
* origin" that prepares what the origin side still
* does not have.
*/
rev.pending.objects[0].item->flags |= UNINTERESTING;
add_head_to_pending(&rev);
check_head = 1;
}
/*
* Otherwise, it is "format-patch -22 HEAD", and/or
* "format-patch --root HEAD". The user wants
* get_revision() to do the usual traversal.
*/
if (!strcmp(rev.pending.objects[0].name, "HEAD"))
check_head = 1;
if (check_head) {
const char *ref, *v;
ref = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
NULL, NULL);
if (ref && skip_prefix(ref, "refs/heads/", &v))
branch_name = xstrdup(v);
else
branch_name = xstrdup(""); /* no branch */
}
}
/*
* We cannot move this anywhere earlier because we do want to
* know if --root was given explicitly from the command line.
*/
rev.show_root_diff = 1;
if (ignore_if_in_upstream) {
/* Don't say anything if head and upstream are the same. */
if (rev.pending.nr == 2) {
struct object_array_entry *o = rev.pending.objects;
if (oideq(&o[0].item->oid, &o[1].item->oid))
goto done;
}
get_patch_ids(&rev, &ids);
}
if (prepare_revision_walk(&rev))
die(_("revision walk setup failed"));
rev.boundary = 1;
while ((commit = get_revision(&rev)) != NULL) {
if (commit->object.flags & BOUNDARY) {
boundary_count++;
origin = (boundary_count == 1) ? commit : NULL;
continue;
}
if (ignore_if_in_upstream && has_commit_patch_id(commit, &ids))
continue;
nr++;
REALLOC_ARRAY(list, nr);
list[nr - 1] = commit;
}
if (nr == 0)
/* nothing to do */
goto done;
total = nr;
if (cover_letter == -1) {
if (config_cover_letter == COVER_AUTO)
cover_letter = (total > 1);
else
cover_letter = (config_cover_letter == COVER_ON);
}
if (!keep_subject && auto_number && (total > 1 || cover_letter))
numbered = 1;
if (numbered)
rev.total = total + start_number - 1;
if (idiff_prev.nr) {
if (!cover_letter && total != 1)
die(_("--interdiff requires --cover-letter or single patch"));
rev.idiff_oid1 = &idiff_prev.oid[idiff_prev.nr - 1];
rev.idiff_oid2 = get_commit_tree_oid(list[0]);
rev.idiff_title = diff_title(&idiff_title, reroll_count,
_("Interdiff:"),
_("Interdiff against v%d:"));
}
if (creation_factor < 0)
creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
else if (!rdiff_prev)
die(_("--creation-factor requires --range-diff"));
if (rdiff_prev) {
if (!cover_letter && total != 1)
die(_("--range-diff requires --cover-letter or single patch"));
infer_range_diff_ranges(&rdiff1, &rdiff2, rdiff_prev,
origin, list[0]);
rev.rdiff1 = rdiff1.buf;
rev.rdiff2 = rdiff2.buf;
rev.creation_factor = creation_factor;
rev.rdiff_title = diff_title(&rdiff_title, reroll_count,
_("Range-diff:"),
_("Range-diff against v%d:"));
}
if (!signature) {
; /* --no-signature inhibits all signatures */
} else if (signature && signature != git_version_string) {
; /* non-default signature already set */
} else if (signature_file) {
struct strbuf buf = STRBUF_INIT;
if (strbuf_read_file(&buf, signature_file, 128) < 0)
die_errno(_("unable to read signature file '%s'"), signature_file);
signature = strbuf_detach(&buf, NULL);
}
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
memset(&bases, 0, sizeof(bases));
if (base_commit) {
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
struct commit *base = get_base_commit(base_commit, list, nr);
reset_revision_walk();
clear_object_flags(UNINTERESTING);
format-patch: add '--base' option to record base tree info Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series). The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied. The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name. A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command. Imagine that on top of the public commit P, you applied well-known patches X, Y and Z from somebody else, and then built your three-patch series A, B, C, the history would be like: ---P---X---Y---Z---A---B---C With "git format-patch --base=P -3 C" (or variants thereof, e.g. with "--cover-letter" of using "Z..C" instead of "-3 C" to specify the range), the base tree information block is shown at the end of the first message the command outputs (either the first patch, or the cover letter), like this: base-commit: P prerequisite-patch-id: X prerequisite-patch-id: Y prerequisite-patch-id: Z Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-26 09:51:22 +02:00
prepare_bases(&bases, base, list, nr);
}
if (in_reply_to || thread || cover_letter)
rev.ref_message_ids = xcalloc(1, sizeof(struct string_list));
if (in_reply_to) {
const char *msgid = clean_message_id(in_reply_to);
string_list_append(rev.ref_message_ids, msgid);
}
rev.numbered_files = just_numbers;
rev.patch_suffix = fmt_patch_suffix;
if (cover_letter) {
if (thread)
gen_message_id(&rev, "cover");
make_cover_letter(&rev, use_stdout,
origin, nr, list, branch_name, quiet);
print_bases(&bases, rev.diffopt.file);
print_signature(rev.diffopt.file);
total++;
start_number--;
/* interdiff/range-diff in cover-letter; omit from patches */
rev.idiff_oid1 = NULL;
rev.rdiff1 = NULL;
}
rev.add_signoff = do_signoff;
if (show_progress)
progress = start_delayed_progress(_("Generating patches"), total);
while (0 <= --nr) {
int shown;
display_progress(progress, total - nr);
commit = list[nr];
rev.nr = total - nr + (start_number - 1);
/* Make the second and subsequent mails replies to the first */
if (thread) {
/* Have we already had a message ID? */
if (rev.message_id) {
/*
* For deep threading: make every mail
* a reply to the previous one, no
* matter what other options are set.
*
* For shallow threading:
*
* Without --cover-letter and
* --in-reply-to, make every mail a
* reply to the one before.
*
* With --in-reply-to but no
* --cover-letter, make every mail a
* reply to the <reply-to>.
*
* With --cover-letter, make every
* mail but the cover letter a reply
* to the cover letter. The cover
* letter is a reply to the
* --in-reply-to, if specified.
*/
if (thread == THREAD_SHALLOW
&& rev.ref_message_ids->nr > 0
&& (!cover_letter || rev.nr > 1))
free(rev.message_id);
else
string_list_append(rev.ref_message_ids,
rev.message_id);
}
gen_message_id(&rev, oid_to_hex(&commit->object.oid));
}
if (!use_stdout &&
open_next_file(rev.numbered_files ? NULL : commit, NULL, &rev, quiet))
die(_("failed to create output files"));
shown = log_tree_commit(&rev, commit);
free_commit_buffer(the_repository->parsed_objects,
commit);
/* We put one extra blank line between formatted
* patches and this flag is used by log-tree code
* to see if it needs to emit a LF before showing
* the log; when using one file per patch, we do
* not want the extra blank line.
*/
if (!use_stdout)
rev.shown_one = 0;
if (shown) {
print_bases(&bases, rev.diffopt.file);
if (rev.mime_boundary)
fprintf(rev.diffopt.file, "\n--%s%s--\n\n\n",
mime_boundary_leader,
rev.mime_boundary);
else
print_signature(rev.diffopt.file);
}
if (!use_stdout)
fclose(rev.diffopt.file);
}
stop_progress(&progress);
free(list);
free(branch_name);
string_list_clear(&extra_to, 0);
string_list_clear(&extra_cc, 0);
string_list_clear(&extra_hdr, 0);
if (ignore_if_in_upstream)
free_patch_ids(&ids);
done:
oid_array_clear(&idiff_prev);
strbuf_release(&idiff_title);
strbuf_release(&rdiff1);
strbuf_release(&rdiff2);
strbuf_release(&rdiff_title);
return 0;
}
static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
{
struct object_id oid;
if (get_oid(arg, &oid) == 0) {
struct commit *commit = lookup_commit_reference(the_repository,
&oid);
if (commit) {
commit->object.flags |= flags;
add_pending_object(revs, &commit->object, arg);
return 0;
}
}
return -1;
}
static const char * const cherry_usage[] = {
N_("git cherry [-v] [<upstream> [<head> [<limit>]]]"),
NULL
};
static void print_commit(char sign, struct commit *commit, int verbose,
int abbrev, FILE *file)
{
if (!verbose) {
fprintf(file, "%c %s\n", sign,
find_unique_abbrev(&commit->object.oid, abbrev));
} else {
struct strbuf buf = STRBUF_INIT;
pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
fprintf(file, "%c %s %s\n", sign,
find_unique_abbrev(&commit->object.oid, abbrev),
buf.buf);
strbuf_release(&buf);
}
}
int cmd_cherry(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
struct patch_ids ids;
struct commit *commit;
struct commit_list *list = NULL;
struct branch *current_branch;
const char *upstream;
const char *head = "HEAD";
const char *limit = NULL;
int verbose = 0, abbrev = 0;
struct option options[] = {
OPT__ABBREV(&abbrev),
OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_END()
};
argc = parse_options(argc, argv, prefix, options, cherry_usage, 0);
switch (argc) {
case 3:
limit = argv[2];
/* FALLTHROUGH */
case 2:
head = argv[1];
/* FALLTHROUGH */
case 1:
upstream = argv[0];
break;
default:
current_branch = branch_get(NULL);
upstream = branch_get_upstream(current_branch, NULL);
if (!upstream) {
fprintf(stderr, _("Could not find a tracked"
" remote branch, please"
" specify <upstream> manually.\n"));
usage_with_options(cherry_usage, options);
}
}
repo_init_revisions(the_repository, &revs, prefix);
revs.max_parents = 1;
if (add_pending_commit(head, &revs, 0))
die(_("unknown commit %s"), head);
if (add_pending_commit(upstream, &revs, UNINTERESTING))
die(_("unknown commit %s"), upstream);
/* Don't say anything if head and upstream are the same. */
if (revs.pending.nr == 2) {
struct object_array_entry *o = revs.pending.objects;
if (oideq(&o[0].item->oid, &o[1].item->oid))
return 0;
}
get_patch_ids(&revs, &ids);
if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
die(_("unknown commit %s"), limit);
/* reverse the list of commits */
if (prepare_revision_walk(&revs))
die(_("revision walk setup failed"));
while ((commit = get_revision(&revs)) != NULL) {
commit_list_insert(commit, &list);
}
while (list) {
char sign = '+';
commit = list->item;
if (has_commit_patch_id(commit, &ids))
sign = '-';
print_commit(sign, commit, verbose, abbrev, revs.diffopt.file);
list = list->next;
}
free_patch_ids(&ids);
return 0;
}