2006-04-09 16:11:11 +08:00
|
|
|
#include "cache.h"
|
show, log: provide a --remerge-diff capability
When this option is specified, we remerge all (two parent) merge commits
and diff the actual merge commit to the automatically created version,
in order to show how users removed conflict markers, resolved the
different conflict versions, and potentially added new changes outside
of conflict regions in order to resolve semantic merge problems (or,
possibly, just to hide other random changes).
This capability works by creating a temporary object directory and
marking it as the primary object store. This makes it so that any blobs
or trees created during the automatic merge are easily removable
afterwards by just deleting all objects from the temporary object
directory.
There are a few ways that this implementation is suboptimal:
* `log --remerge-diff` becomes slow, because the temporary object
directory can fill with many loose objects while running
* the log output can be muddied with misplaced "warning: cannot merge
binary files" messages, since ll-merge.c unconditionally writes those
messages to stderr while running instead of allowing callers to
manage them.
* important conflict and warning messages are simply dropped; thus for
conflicts like modify/delete or rename/rename or file/directory which
are not representable with content conflict markers, there may be no
way for a user of --remerge-diff to know that there had been a
conflict which was resolved (and which possibly motivated other
changes in the merge commit).
* when fixing the previous issue, note that some unimportant conflict
and warning messages might start being included. We should instead
make sure these remain dropped.
Subsequent commits will address these issues.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-02 10:37:28 +08:00
|
|
|
#include "commit-reach.h"
|
2017-06-15 02:07:36 +08:00
|
|
|
#include "config.h"
|
2006-04-09 16:11:11 +08:00
|
|
|
#include "diff.h"
|
2018-05-16 07:42:15 +08:00
|
|
|
#include "object-store.h"
|
2018-06-29 09:21:51 +08:00
|
|
|
#include "repository.h"
|
2022-02-02 10:37:29 +08:00
|
|
|
#include "tmp-objdir.h"
|
2006-04-09 16:11:11 +08:00
|
|
|
#include "commit.h"
|
2008-09-05 05:39:21 +08:00
|
|
|
#include "tag.h"
|
2008-05-04 18:36:54 +08:00
|
|
|
#include "graph.h"
|
2006-04-09 16:11:11 +08:00
|
|
|
#include "log-tree.h"
|
show, log: provide a --remerge-diff capability
When this option is specified, we remerge all (two parent) merge commits
and diff the actual merge commit to the automatically created version,
in order to show how users removed conflict markers, resolved the
different conflict versions, and potentially added new changes outside
of conflict regions in order to resolve semantic merge problems (or,
possibly, just to hide other random changes).
This capability works by creating a temporary object directory and
marking it as the primary object store. This makes it so that any blobs
or trees created during the automatic merge are easily removable
afterwards by just deleting all objects from the temporary object
directory.
There are a few ways that this implementation is suboptimal:
* `log --remerge-diff` becomes slow, because the temporary object
directory can fill with many loose objects while running
* the log output can be muddied with misplaced "warning: cannot merge
binary files" messages, since ll-merge.c unconditionally writes those
messages to stderr while running instead of allowing callers to
manage them.
* important conflict and warning messages are simply dropped; thus for
conflicts like modify/delete or rename/rename or file/directory which
are not representable with content conflict markers, there may be no
way for a user of --remerge-diff to know that there had been a
conflict which was resolved (and which possibly motivated other
changes in the merge commit).
* when fixing the previous issue, note that some unimportant conflict
and warning messages might start being included. We should instead
make sure these remain dropped.
Subsequent commits will address these issues.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-02 10:37:28 +08:00
|
|
|
#include "merge-ort.h"
|
2007-01-11 18:47:48 +08:00
|
|
|
#include "reflog-walk.h"
|
2008-09-05 05:39:21 +08:00
|
|
|
#include "refs.h"
|
2009-02-20 05:26:31 +08:00
|
|
|
#include "string-list.h"
|
2010-06-19 09:37:35 +08:00
|
|
|
#include "color.h"
|
2011-10-19 06:53:23 +08:00
|
|
|
#include "gpg-interface.h"
|
2013-02-12 18:17:39 +08:00
|
|
|
#include "sequencer.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-29 00:47:32 +08:00
|
|
|
#include "line-log.h"
|
2018-05-26 21:55:24 +08:00
|
|
|
#include "help.h"
|
2018-07-22 17:57:17 +08:00
|
|
|
#include "range-diff.h"
|
2022-02-02 10:37:35 +08:00
|
|
|
#include "strmap.h"
|
2006-04-09 16:11:11 +08:00
|
|
|
|
2014-08-26 18:23:54 +08:00
|
|
|
static struct decoration name_decoration = { "object names" };
|
log: decorate HEAD with branch name under --decorate=full, too
The previous step to teach "log --decorate" to show "HEAD -> master"
instead of "HEAD, master" when showing the commit at the tip of the
'master' branch, when the 'master' branch is checked out, did not
work for "log --decorate=full".
The commands in the "log" family prepare commit decorations for all
refs upfront, and the actual string used in a decoration depends on
how load_ref_decorations() is called very early in the process. By
default, "git log --decorate" stores names with common prefixes such
as "refs/heads" stripped; "git log --decorate=full" stores the full
refnames.
When the current_pointed_by_HEAD() function has to decide if "HEAD"
points at the branch a decoration describes, however, what was
passed to load_ref_decorations() to decide to strip (or keep) such a
common prefix is long lost. This makes it impossible to reliably
tell if a decoration that stores "refs/heads/master", for example,
is the 'master' branch (under "--decorate" with prefix omitted) or
'refs/heads/master' branch (under "--decorate=full").
Keep what was passed to load_ref_decorations() in a global next to
the global variable name_decoration, and use that to decide how to
match what was read from "HEAD" and what is in a decoration.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-05-14 01:25:18 +08:00
|
|
|
static int decoration_loaded;
|
|
|
|
static int decoration_flags;
|
2010-06-19 09:37:34 +08:00
|
|
|
|
2010-06-19 09:37:35 +08:00
|
|
|
static char decoration_colors[][COLOR_MAXLEN] = {
|
|
|
|
GIT_COLOR_RESET,
|
|
|
|
GIT_COLOR_BOLD_GREEN, /* REF_LOCAL */
|
|
|
|
GIT_COLOR_BOLD_RED, /* REF_REMOTE */
|
|
|
|
GIT_COLOR_BOLD_YELLOW, /* REF_TAG */
|
|
|
|
GIT_COLOR_BOLD_MAGENTA, /* REF_STASH */
|
|
|
|
GIT_COLOR_BOLD_CYAN, /* REF_HEAD */
|
2011-08-18 20:29:37 +08:00
|
|
|
GIT_COLOR_BOLD_BLUE, /* GRAFTED */
|
2010-06-19 09:37:35 +08:00
|
|
|
};
|
|
|
|
|
2018-05-26 21:55:21 +08:00
|
|
|
static const char *color_decorate_slots[] = {
|
|
|
|
[DECORATION_REF_LOCAL] = "branch",
|
|
|
|
[DECORATION_REF_REMOTE] = "remoteBranch",
|
|
|
|
[DECORATION_REF_TAG] = "tag",
|
|
|
|
[DECORATION_REF_STASH] = "stash",
|
|
|
|
[DECORATION_REF_HEAD] = "HEAD",
|
2018-05-26 21:55:31 +08:00
|
|
|
[DECORATION_GRAFTED] = "grafted",
|
2018-05-26 21:55:21 +08:00
|
|
|
};
|
|
|
|
|
2010-06-19 09:37:35 +08:00
|
|
|
static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)
|
|
|
|
{
|
color: delay auto-color decision until point of use
When we read a color value either from a config file or from
the command line, we use git_config_colorbool to convert it
from the tristate always/never/auto into a single yes/no
boolean value.
This has some timing implications with respect to starting
a pager.
If we start (or decide not to start) the pager before
checking the colorbool, everything is fine. Either isatty(1)
will give us the right information, or we will properly
check for pager_in_use().
However, if we decide to start a pager after we have checked
the colorbool, things are not so simple. If stdout is a tty,
then we will have already decided to use color. However, the
user may also have configured color.pager not to use color
with the pager. In this case, we need to actually turn off
color. Unfortunately, the pager code has no idea which color
variables were turned on (and there are many of them
throughout the code, and they may even have been manipulated
after the colorbool selection by something like "--color" on
the command line).
This bug can be seen any time a pager is started after
config and command line options are checked. This has
affected "git diff" since 89d07f7 (diff: don't run pager if
user asked for a diff style exit code, 2007-08-12). It has
also affect the log family since 1fda91b (Fix 'git log'
early pager startup error case, 2010-08-24).
This patch splits the notion of parsing a colorbool and
actually checking the configuration. The "use_color"
variables now have an additional possible value,
GIT_COLOR_AUTO. Users of the variable should use the new
"want_color()" wrapper, which will lazily determine and
cache the auto-color decision.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-18 13:04:23 +08:00
|
|
|
if (want_color(decorate_use_color))
|
2010-06-19 09:37:35 +08:00
|
|
|
return decoration_colors[ix];
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2018-05-26 21:55:24 +08:00
|
|
|
define_list_config_array(color_decorate_slots);
|
2010-06-24 08:21:16 +08:00
|
|
|
|
2014-10-08 03:16:57 +08:00
|
|
|
int parse_decorate_color_config(const char *var, const char *slot_name, const char *value)
|
2010-06-24 08:21:16 +08:00
|
|
|
{
|
2018-05-26 21:55:21 +08:00
|
|
|
int slot = LOOKUP_CONFIG(color_decorate_slots, slot_name);
|
2010-06-24 08:21:16 +08:00
|
|
|
if (slot < 0)
|
|
|
|
return 0;
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
2014-10-08 03:33:09 +08:00
|
|
|
return color_parse(value, decoration_colors[slot]);
|
2010-06-24 08:21:16 +08:00
|
|
|
}
|
|
|
|
|
2010-06-19 09:37:35 +08:00
|
|
|
/*
|
|
|
|
* log-tree.c uses DIFF_OPT_TST for determining whether to use color
|
|
|
|
* for showing the commit sha1, use the same check for --decorate
|
|
|
|
*/
|
|
|
|
#define decorate_get_color_opt(o, ix) \
|
2011-08-18 13:03:12 +08:00
|
|
|
decorate_get_color((o)->use_color, ix)
|
2010-06-19 09:37:35 +08:00
|
|
|
|
2014-08-26 18:23:36 +08:00
|
|
|
void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
|
2008-09-05 05:39:21 +08:00
|
|
|
{
|
2016-02-23 06:44:32 +08:00
|
|
|
struct name_decoration *res;
|
|
|
|
FLEX_ALLOC_STR(res, name, name);
|
2010-06-19 09:37:34 +08:00
|
|
|
res->type = type;
|
2008-09-05 05:39:21 +08:00
|
|
|
res->next = add_decoration(&name_decoration, obj, res);
|
|
|
|
}
|
|
|
|
|
2014-08-26 18:23:54 +08:00
|
|
|
const struct name_decoration *get_name_decoration(const struct object *obj)
|
|
|
|
{
|
2019-09-09 01:58:51 +08:00
|
|
|
load_ref_decorations(NULL, DECORATE_SHORT_REFS);
|
2014-08-26 18:23:54 +08:00
|
|
|
return lookup_decoration(&name_decoration, obj);
|
|
|
|
}
|
|
|
|
|
2020-04-16 22:15:48 +08:00
|
|
|
static int match_ref_pattern(const char *refname,
|
|
|
|
const struct string_list_item *item)
|
|
|
|
{
|
|
|
|
int matched = 0;
|
2022-05-03 00:50:37 +08:00
|
|
|
if (!item->util) {
|
2020-04-16 22:15:48 +08:00
|
|
|
if (!wildmatch(item->string, refname, 0))
|
|
|
|
matched = 1;
|
|
|
|
} else {
|
|
|
|
const char *rest;
|
|
|
|
if (skip_prefix(refname, item->string, &rest) &&
|
|
|
|
(!*rest || *rest == '/'))
|
|
|
|
matched = 1;
|
|
|
|
}
|
|
|
|
return matched;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ref_filter_match(const char *refname,
|
|
|
|
const struct decoration_filter *filter)
|
|
|
|
{
|
|
|
|
struct string_list_item *item;
|
|
|
|
const struct string_list *exclude_patterns = filter->exclude_ref_pattern;
|
|
|
|
const struct string_list *include_patterns = filter->include_ref_pattern;
|
2020-04-16 22:15:49 +08:00
|
|
|
const struct string_list *exclude_patterns_config =
|
|
|
|
filter->exclude_ref_config_pattern;
|
2020-04-16 22:15:48 +08:00
|
|
|
|
|
|
|
if (exclude_patterns && exclude_patterns->nr) {
|
|
|
|
for_each_string_list_item(item, exclude_patterns) {
|
|
|
|
if (match_ref_pattern(refname, item))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (include_patterns && include_patterns->nr) {
|
|
|
|
for_each_string_list_item(item, include_patterns) {
|
2020-04-16 22:15:49 +08:00
|
|
|
if (match_ref_pattern(refname, item))
|
|
|
|
return 1;
|
2020-04-16 22:15:48 +08:00
|
|
|
}
|
2020-04-16 22:15:49 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2020-04-16 22:15:48 +08:00
|
|
|
|
2020-04-16 22:15:49 +08:00
|
|
|
if (exclude_patterns_config && exclude_patterns_config->nr) {
|
|
|
|
for_each_string_list_item(item, exclude_patterns_config) {
|
|
|
|
if (match_ref_pattern(refname, item))
|
|
|
|
return 0;
|
|
|
|
}
|
2020-04-16 22:15:48 +08:00
|
|
|
}
|
2020-04-16 22:15:49 +08:00
|
|
|
|
2020-04-16 22:15:48 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-05-26 02:38:57 +08:00
|
|
|
static int add_ref_decoration(const char *refname, const struct object_id *oid,
|
|
|
|
int flags, void *cb_data)
|
2008-09-05 05:39:21 +08:00
|
|
|
{
|
2011-08-19 20:43:50 +08:00
|
|
|
struct object *obj;
|
load_ref_decorations(): avoid parsing non-tag objects
When we load the ref decorations, we parse the object pointed to by each
ref in order to get a "struct object". This is unnecessarily expensive;
we really only need the object struct, and don't even look at the parsed
contents. The exception is tags, which we do need to peel.
We can improve this by looking up the object type first (which is much
cheaper), and skipping the parse entirely for non-tags. This increases
the work slightly for annotated tags (which now do a type lookup _and_ a
parse), but decreases it a lot for other types. On balance, this seems
to be a good tradeoff.
In my git.git clone, with ~2k refs, most of which are branches, the time
to run "git log -1 --decorate" drops from 34ms to 11ms. Even on my
linux.git clone, which contains mostly tags and only a handful of
branches, the time drops from 30ms to 19ms. And on a more extreme
real-world case with ~220k refs, mostly non-tags, the time drops from
2.6s to 650ms.
That command is a lop-sided example, of course, because it does as
little non-loading work as possible. But it does show the absolute time
improvement. Even in something like a full "git log --decorate" on that
extreme repo, we'd still be saving 2s of CPU time.
Ideally we could push this even further, and avoid parsing even tags, by
relying on the packed-refs "peel" optimization (which we could do by
calling peel_iterated_oid() instead of peeling manually). But we can't
do that here. The packed-refs file only stores the bottom-layer of the
peel (so in a "tag->tag->commit" chain, it stores only the commit as the
peel result). But the decoration code wants to peel the layers
individually, annotating the middle layers of the chain.
If the packed-refs file ever learns to store all of the peeled layers,
then we could switch to it. Or even if it stored a flag to indicate the
peel was not multi-layer (because most of them aren't), then we could
use it most of the time and fall back to a manual peel for the rare
cases.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-06-23 01:06:48 +08:00
|
|
|
enum object_type objtype;
|
2021-06-23 01:09:26 +08:00
|
|
|
enum decoration_type deco_type = DECORATION_NONE;
|
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-22 05:33:41 +08:00
|
|
|
struct decoration_filter *filter = (struct decoration_filter *)cb_data;
|
2011-08-19 20:43:50 +08:00
|
|
|
|
2020-04-16 22:15:48 +08:00
|
|
|
if (filter && !ref_filter_match(refname, filter))
|
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-22 05:33:41 +08:00
|
|
|
return 0;
|
2015-05-14 03:40:35 +08:00
|
|
|
|
2015-06-12 05:34:59 +08:00
|
|
|
if (starts_with(refname, git_replace_ref_base)) {
|
2015-05-26 02:38:58 +08:00
|
|
|
struct object_id original_oid;
|
2018-07-19 04:45:20 +08:00
|
|
|
if (!read_replace_refs)
|
2011-08-25 23:09:30 +08:00
|
|
|
return 0;
|
2015-08-04 02:01:10 +08:00
|
|
|
if (get_oid_hex(refname + strlen(git_replace_ref_base),
|
|
|
|
&original_oid)) {
|
2011-08-19 20:43:50 +08:00
|
|
|
warning("invalid replace ref %s", refname);
|
|
|
|
return 0;
|
|
|
|
}
|
2018-06-29 09:21:51 +08:00
|
|
|
obj = parse_object(the_repository, &original_oid);
|
2011-08-19 20:43:50 +08:00
|
|
|
if (obj)
|
|
|
|
add_name_decoration(DECORATION_GRAFTED, "replaced", obj);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
load_ref_decorations(): avoid parsing non-tag objects
When we load the ref decorations, we parse the object pointed to by each
ref in order to get a "struct object". This is unnecessarily expensive;
we really only need the object struct, and don't even look at the parsed
contents. The exception is tags, which we do need to peel.
We can improve this by looking up the object type first (which is much
cheaper), and skipping the parse entirely for non-tags. This increases
the work slightly for annotated tags (which now do a type lookup _and_ a
parse), but decreases it a lot for other types. On balance, this seems
to be a good tradeoff.
In my git.git clone, with ~2k refs, most of which are branches, the time
to run "git log -1 --decorate" drops from 34ms to 11ms. Even on my
linux.git clone, which contains mostly tags and only a handful of
branches, the time drops from 30ms to 19ms. And on a more extreme
real-world case with ~220k refs, mostly non-tags, the time drops from
2.6s to 650ms.
That command is a lop-sided example, of course, because it does as
little non-loading work as possible. But it does show the absolute time
improvement. Even in something like a full "git log --decorate" on that
extreme repo, we'd still be saving 2s of CPU time.
Ideally we could push this even further, and avoid parsing even tags, by
relying on the packed-refs "peel" optimization (which we could do by
calling peel_iterated_oid() instead of peeling manually). But we can't
do that here. The packed-refs file only stores the bottom-layer of the
peel (so in a "tag->tag->commit" chain, it stores only the commit as the
peel result). But the decoration code wants to peel the layers
individually, annotating the middle layers of the chain.
If the packed-refs file ever learns to store all of the peeled layers,
then we could switch to it. Or even if it stored a flag to indicate the
peel was not multi-layer (because most of them aren't), then we could
use it most of the time and fall back to a manual peel for the rare
cases.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-06-23 01:06:48 +08:00
|
|
|
objtype = oid_object_info(the_repository, oid, NULL);
|
|
|
|
if (objtype < 0)
|
2008-09-05 05:39:21 +08:00
|
|
|
return 0;
|
load_ref_decorations(): avoid parsing non-tag objects
When we load the ref decorations, we parse the object pointed to by each
ref in order to get a "struct object". This is unnecessarily expensive;
we really only need the object struct, and don't even look at the parsed
contents. The exception is tags, which we do need to peel.
We can improve this by looking up the object type first (which is much
cheaper), and skipping the parse entirely for non-tags. This increases
the work slightly for annotated tags (which now do a type lookup _and_ a
parse), but decreases it a lot for other types. On balance, this seems
to be a good tradeoff.
In my git.git clone, with ~2k refs, most of which are branches, the time
to run "git log -1 --decorate" drops from 34ms to 11ms. Even on my
linux.git clone, which contains mostly tags and only a handful of
branches, the time drops from 30ms to 19ms. And on a more extreme
real-world case with ~220k refs, mostly non-tags, the time drops from
2.6s to 650ms.
That command is a lop-sided example, of course, because it does as
little non-loading work as possible. But it does show the absolute time
improvement. Even in something like a full "git log --decorate" on that
extreme repo, we'd still be saving 2s of CPU time.
Ideally we could push this even further, and avoid parsing even tags, by
relying on the packed-refs "peel" optimization (which we could do by
calling peel_iterated_oid() instead of peeling manually). But we can't
do that here. The packed-refs file only stores the bottom-layer of the
peel (so in a "tag->tag->commit" chain, it stores only the commit as the
peel result). But the decoration code wants to peel the layers
individually, annotating the middle layers of the chain.
If the packed-refs file ever learns to store all of the peeled layers,
then we could switch to it. Or even if it stored a flag to indicate the
peel was not multi-layer (because most of them aren't), then we could
use it most of the time and fall back to a manual peel for the rare
cases.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-06-23 01:06:48 +08:00
|
|
|
obj = lookup_object_by_type(the_repository, oid, objtype);
|
2010-06-19 09:37:34 +08:00
|
|
|
|
2013-12-01 04:55:40 +08:00
|
|
|
if (starts_with(refname, "refs/heads/"))
|
2021-06-23 01:09:26 +08:00
|
|
|
deco_type = DECORATION_REF_LOCAL;
|
2013-12-01 04:55:40 +08:00
|
|
|
else if (starts_with(refname, "refs/remotes/"))
|
2021-06-23 01:09:26 +08:00
|
|
|
deco_type = DECORATION_REF_REMOTE;
|
2013-12-01 04:55:40 +08:00
|
|
|
else if (starts_with(refname, "refs/tags/"))
|
2021-06-23 01:09:26 +08:00
|
|
|
deco_type = DECORATION_REF_TAG;
|
2012-01-05 20:39:40 +08:00
|
|
|
else if (!strcmp(refname, "refs/stash"))
|
2021-06-23 01:09:26 +08:00
|
|
|
deco_type = DECORATION_REF_STASH;
|
2012-01-05 20:39:40 +08:00
|
|
|
else if (!strcmp(refname, "HEAD"))
|
2021-06-23 01:09:26 +08:00
|
|
|
deco_type = DECORATION_REF_HEAD;
|
2010-06-19 09:37:34 +08:00
|
|
|
|
2021-06-23 01:09:26 +08:00
|
|
|
add_name_decoration(deco_type, refname, obj);
|
2008-09-05 05:39:21 +08:00
|
|
|
while (obj->type == OBJ_TAG) {
|
load_ref_decorations(): fix decoration with tags
Commit 88473c8bae ("load_ref_decorations(): avoid parsing non-tag
objects", 2021-06-22) introduced a shortcut to `add_ref_decoration()`:
Rather than calling `parse_object()`, we go for `oid_object_info()` and
then `lookup_object_by_type()` using the type just discovered. As
detailed in the commit message, this provides a significant time saving.
Unfortunately, it also changes the behavior: We lose all annotated tags
from the decoration.
The reason this happens is in the loop where we try to peel the tags, we
won't necessarily have parsed that first object. If we haven't, its
`tagged` field will be NULL, so we won't actually add a decoration for
the pointed-to object.
Make sure to parse the tag object at the top of the peeling loop. This
effectively restores the pre-88473c8bae parsing -- but only of tags,
allowing us to keep most of the possible speedup from 88473c8bae.
On my big ~220k ref test case (where it's mostly non-tags), the
timings [using "git log -1 --decorate"] are:
- before either patch: 2.945s
- with my broken patch: 0.707s
- with [this patch]: 0.788s
The simplest way to do this is to just conditionally parse before the
loop:
if (obj->type == OBJ_TAG)
parse_object(&obj->oid);
But we can observe that our tag-peeling loop needs to peel already, to
examine recursive tags-of-tags. So instead of introducing a new call to
parse_object(), we can simply move the parsing higher in the loop:
instead of parsing the new object before we loop, parse each tag object
before we look at its "tagged" field.
This has another beneficial side effect: if a tag points at a commit (or
other non-tag type), we do not bother to parse the commit at all now.
And we know it is a commit without calling oid_object_info(), because
parsing the surrounding tag object will have created the correct in-core
object based on the "type" field of the tag.
Our test coverage for --decorate was obviously not good, since we missed
this quite-basic regression. The new tests covers an annotated tag
(showing the fix), but also that we correctly show annotations for
lightweight tags and double-annotated tag-of-tags.
Reported-by: Martin Ågren <martin.agren@gmail.com>
Helped-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-07-15 00:31:36 +08:00
|
|
|
if (!obj->parsed)
|
|
|
|
parse_object(the_repository, &obj->oid);
|
2008-09-05 05:39:21 +08:00
|
|
|
obj = ((struct tag *)obj)->tagged;
|
|
|
|
if (!obj)
|
|
|
|
break;
|
2010-06-19 09:37:34 +08:00
|
|
|
add_name_decoration(DECORATION_REF_TAG, refname, obj);
|
2008-09-05 05:39:21 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-08-18 20:29:37 +08:00
|
|
|
static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
|
|
|
|
{
|
2018-06-29 09:21:59 +08:00
|
|
|
struct commit *commit = lookup_commit(the_repository, &graft->oid);
|
2011-08-18 20:29:37 +08:00
|
|
|
if (!commit)
|
|
|
|
return 0;
|
|
|
|
add_name_decoration(DECORATION_GRAFTED, "grafted", &commit->object);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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-22 05:33:41 +08:00
|
|
|
void load_ref_decorations(struct decoration_filter *filter, int flags)
|
2008-09-05 05:39:21 +08:00
|
|
|
{
|
log: decorate HEAD with branch name under --decorate=full, too
The previous step to teach "log --decorate" to show "HEAD -> master"
instead of "HEAD, master" when showing the commit at the tip of the
'master' branch, when the 'master' branch is checked out, did not
work for "log --decorate=full".
The commands in the "log" family prepare commit decorations for all
refs upfront, and the actual string used in a decoration depends on
how load_ref_decorations() is called very early in the process. By
default, "git log --decorate" stores names with common prefixes such
as "refs/heads" stripped; "git log --decorate=full" stores the full
refnames.
When the current_pointed_by_HEAD() function has to decide if "HEAD"
points at the branch a decoration describes, however, what was
passed to load_ref_decorations() to decide to strip (or keep) such a
common prefix is long lost. This makes it impossible to reliably
tell if a decoration that stores "refs/heads/master", for example,
is the 'master' branch (under "--decorate" with prefix omitted) or
'refs/heads/master' branch (under "--decorate=full").
Keep what was passed to load_ref_decorations() in a global next to
the global variable name_decoration, and use that to decide how to
match what was read from "HEAD" and what is in a decoration.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-05-14 01:25:18 +08:00
|
|
|
if (!decoration_loaded) {
|
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-22 05:33:41 +08:00
|
|
|
if (filter) {
|
|
|
|
struct string_list_item *item;
|
|
|
|
for_each_string_list_item(item, filter->exclude_ref_pattern) {
|
|
|
|
normalize_glob_ref(item, NULL, item->string);
|
|
|
|
}
|
|
|
|
for_each_string_list_item(item, filter->include_ref_pattern) {
|
|
|
|
normalize_glob_ref(item, NULL, item->string);
|
|
|
|
}
|
2020-04-16 22:15:49 +08:00
|
|
|
for_each_string_list_item(item, filter->exclude_ref_config_pattern) {
|
|
|
|
normalize_glob_ref(item, NULL, item->string);
|
|
|
|
}
|
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-22 05:33:41 +08:00
|
|
|
}
|
log: decorate HEAD with branch name under --decorate=full, too
The previous step to teach "log --decorate" to show "HEAD -> master"
instead of "HEAD, master" when showing the commit at the tip of the
'master' branch, when the 'master' branch is checked out, did not
work for "log --decorate=full".
The commands in the "log" family prepare commit decorations for all
refs upfront, and the actual string used in a decoration depends on
how load_ref_decorations() is called very early in the process. By
default, "git log --decorate" stores names with common prefixes such
as "refs/heads" stripped; "git log --decorate=full" stores the full
refnames.
When the current_pointed_by_HEAD() function has to decide if "HEAD"
points at the branch a decoration describes, however, what was
passed to load_ref_decorations() to decide to strip (or keep) such a
common prefix is long lost. This makes it impossible to reliably
tell if a decoration that stores "refs/heads/master", for example,
is the 'master' branch (under "--decorate" with prefix omitted) or
'refs/heads/master' branch (under "--decorate=full").
Keep what was passed to load_ref_decorations() in a global next to
the global variable name_decoration, and use that to decide how to
match what was read from "HEAD" and what is in a decoration.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-05-14 01:25:18 +08:00
|
|
|
decoration_loaded = 1;
|
|
|
|
decoration_flags = flags;
|
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-22 05:33:41 +08:00
|
|
|
for_each_ref(add_ref_decoration, filter);
|
|
|
|
head_ref(add_ref_decoration, filter);
|
|
|
|
for_each_commit_graft(add_graft_decoration, filter);
|
2008-09-05 05:39:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-22 23:01:32 +08:00
|
|
|
static void show_parents(struct commit *commit, int abbrev, FILE *file)
|
2006-05-03 22:59:00 +08:00
|
|
|
{
|
|
|
|
struct commit_list *p;
|
|
|
|
for (p = commit->parents; p ; p = p->next) {
|
|
|
|
struct commit *parent = p->item;
|
2018-03-12 10:27:30 +08:00
|
|
|
fprintf(file, " %s", find_unique_abbrev(&parent->object.oid, abbrev));
|
2006-05-03 22:59:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-04 22:02:03 +08:00
|
|
|
static void show_children(struct rev_info *opt, struct commit *commit, int abbrev)
|
|
|
|
{
|
|
|
|
struct commit_list *p = lookup_decoration(&opt->children, &commit->object);
|
|
|
|
for ( ; p; p = p->next) {
|
2018-03-12 10:27:30 +08:00
|
|
|
fprintf(opt->diffopt.file, " %s", find_unique_abbrev(&p->item->object.oid, abbrev));
|
2011-10-04 22:02:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-10 21:53:21 +08:00
|
|
|
/*
|
|
|
|
* Do we have HEAD in the output, and also the branch it points at?
|
|
|
|
* If so, find that decoration entry for that current branch.
|
|
|
|
*/
|
|
|
|
static const struct name_decoration *current_pointed_by_HEAD(const struct name_decoration *decoration)
|
|
|
|
{
|
|
|
|
const struct name_decoration *list, *head = NULL;
|
|
|
|
const char *branch_name = NULL;
|
|
|
|
int rru_flags;
|
|
|
|
|
|
|
|
/* First find HEAD */
|
|
|
|
for (list = decoration; list; list = list->next)
|
|
|
|
if (list->type == DECORATION_REF_HEAD) {
|
|
|
|
head = list;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!head)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Now resolve and find the matching current branch */
|
2017-09-23 17:45:04 +08:00
|
|
|
branch_name = resolve_ref_unsafe("HEAD", 0, NULL, &rru_flags);
|
2017-10-20 01:49:01 +08:00
|
|
|
if (!branch_name || !(rru_flags & REF_ISSYMREF))
|
2015-03-10 21:53:21 +08:00
|
|
|
return NULL;
|
log: decorate HEAD with branch name under --decorate=full, too
The previous step to teach "log --decorate" to show "HEAD -> master"
instead of "HEAD, master" when showing the commit at the tip of the
'master' branch, when the 'master' branch is checked out, did not
work for "log --decorate=full".
The commands in the "log" family prepare commit decorations for all
refs upfront, and the actual string used in a decoration depends on
how load_ref_decorations() is called very early in the process. By
default, "git log --decorate" stores names with common prefixes such
as "refs/heads" stripped; "git log --decorate=full" stores the full
refnames.
When the current_pointed_by_HEAD() function has to decide if "HEAD"
points at the branch a decoration describes, however, what was
passed to load_ref_decorations() to decide to strip (or keep) such a
common prefix is long lost. This makes it impossible to reliably
tell if a decoration that stores "refs/heads/master", for example,
is the 'master' branch (under "--decorate" with prefix omitted) or
'refs/heads/master' branch (under "--decorate=full").
Keep what was passed to load_ref_decorations() in a global next to
the global variable name_decoration, and use that to decide how to
match what was read from "HEAD" and what is in a decoration.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-05-14 01:25:18 +08:00
|
|
|
|
2015-05-14 03:40:35 +08:00
|
|
|
if (!starts_with(branch_name, "refs/"))
|
2015-03-10 21:53:21 +08:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* OK, do we have that ref in the list? */
|
|
|
|
for (list = decoration; list; list = list->next)
|
|
|
|
if ((list->type == DECORATION_REF_LOCAL) &&
|
|
|
|
!strcmp(branch_name, list->name)) {
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-05-14 03:40:35 +08:00
|
|
|
static void show_name(struct strbuf *sb, const struct name_decoration *decoration)
|
|
|
|
{
|
|
|
|
if (decoration_flags == DECORATE_SHORT_REFS)
|
|
|
|
strbuf_addstr(sb, prettify_refname(decoration->name));
|
|
|
|
else
|
|
|
|
strbuf_addstr(sb, decoration->name);
|
|
|
|
}
|
|
|
|
|
2013-04-19 07:08:43 +08:00
|
|
|
/*
|
2014-09-19 04:53:53 +08:00
|
|
|
* The caller makes sure there is no funny color before calling.
|
|
|
|
* format_decorations_extended makes sure the same after return.
|
2013-04-19 07:08:43 +08:00
|
|
|
*/
|
2014-09-19 04:53:53 +08:00
|
|
|
void format_decorations_extended(struct strbuf *sb,
|
2013-04-19 07:08:43 +08:00
|
|
|
const struct commit *commit,
|
2014-09-19 04:53:53 +08:00
|
|
|
int use_color,
|
|
|
|
const char *prefix,
|
|
|
|
const char *separator,
|
|
|
|
const char *suffix)
|
2007-04-17 07:05:10 +08:00
|
|
|
{
|
2014-08-26 18:23:54 +08:00
|
|
|
const struct name_decoration *decoration;
|
2015-03-10 21:53:21 +08:00
|
|
|
const struct name_decoration *current_and_HEAD;
|
2010-06-19 09:37:35 +08:00
|
|
|
const char *color_commit =
|
2013-04-19 07:08:43 +08:00
|
|
|
diff_get_color(use_color, DIFF_COMMIT);
|
2010-06-19 09:37:35 +08:00
|
|
|
const char *color_reset =
|
2013-04-19 07:08:43 +08:00
|
|
|
decorate_get_color(use_color, DECORATION_NONE);
|
2007-04-17 07:05:10 +08:00
|
|
|
|
2014-08-26 18:23:54 +08:00
|
|
|
decoration = get_name_decoration(&commit->object);
|
2007-04-17 07:05:10 +08:00
|
|
|
if (!decoration)
|
|
|
|
return;
|
2015-03-10 21:53:21 +08:00
|
|
|
|
|
|
|
current_and_HEAD = current_pointed_by_HEAD(decoration);
|
2007-04-17 07:05:10 +08:00
|
|
|
while (decoration) {
|
2015-03-10 21:53:21 +08:00
|
|
|
/*
|
|
|
|
* When both current and HEAD are there, only
|
|
|
|
* show HEAD->current where HEAD would have
|
|
|
|
* appeared, skipping the entry for current.
|
|
|
|
*/
|
|
|
|
if (decoration != current_and_HEAD) {
|
|
|
|
strbuf_addstr(sb, color_commit);
|
|
|
|
strbuf_addstr(sb, prefix);
|
|
|
|
strbuf_addstr(sb, color_reset);
|
|
|
|
strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
|
|
|
|
if (decoration->type == DECORATION_REF_TAG)
|
|
|
|
strbuf_addstr(sb, "tag: ");
|
|
|
|
|
2015-05-14 03:40:35 +08:00
|
|
|
show_name(sb, decoration);
|
2015-03-10 21:53:21 +08:00
|
|
|
|
|
|
|
if (current_and_HEAD &&
|
|
|
|
decoration->type == DECORATION_REF_HEAD) {
|
|
|
|
strbuf_addstr(sb, " -> ");
|
|
|
|
strbuf_addstr(sb, color_reset);
|
|
|
|
strbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));
|
2015-05-14 03:40:35 +08:00
|
|
|
show_name(sb, current_and_HEAD);
|
2015-03-10 21:53:21 +08:00
|
|
|
}
|
|
|
|
strbuf_addstr(sb, color_reset);
|
|
|
|
|
|
|
|
prefix = separator;
|
|
|
|
}
|
2007-04-17 07:05:10 +08:00
|
|
|
decoration = decoration->next;
|
|
|
|
}
|
2013-04-19 07:08:43 +08:00
|
|
|
strbuf_addstr(sb, color_commit);
|
2014-09-19 04:53:53 +08:00
|
|
|
strbuf_addstr(sb, suffix);
|
2013-04-19 07:08:43 +08:00
|
|
|
strbuf_addstr(sb, color_reset);
|
|
|
|
}
|
|
|
|
|
|
|
|
void show_decorations(struct rev_info *opt, struct commit *commit)
|
|
|
|
{
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
2018-05-19 13:28:24 +08:00
|
|
|
if (opt->sources) {
|
|
|
|
char **slot = revision_sources_peek(opt->sources, commit);
|
|
|
|
|
|
|
|
if (slot && *slot)
|
|
|
|
fprintf(opt->diffopt.file, "\t%s", *slot);
|
|
|
|
}
|
2013-04-19 07:08:43 +08:00
|
|
|
if (!opt->show_decorations)
|
|
|
|
return;
|
|
|
|
format_decorations(&sb, commit, opt->diffopt.use_color);
|
2016-06-22 23:01:32 +08:00
|
|
|
fputs(sb.buf, opt->diffopt.file);
|
2013-04-19 07:08:43 +08:00
|
|
|
strbuf_release(&sb);
|
2007-04-17 07:05:10 +08:00
|
|
|
}
|
|
|
|
|
2007-02-09 08:43:54 +08:00
|
|
|
static unsigned int digits_in_number(unsigned int number)
|
|
|
|
{
|
|
|
|
unsigned int i = 10, result = 1;
|
|
|
|
while (i <= number) {
|
|
|
|
i *= 10;
|
|
|
|
result++;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-12-22 14:06:01 +08:00
|
|
|
void fmt_output_subject(struct strbuf *filename,
|
|
|
|
const char *subject,
|
2012-12-22 15:26:16 +08:00
|
|
|
struct rev_info *info)
|
2009-03-23 10:14:04 +08:00
|
|
|
{
|
2012-12-22 15:26:16 +08:00
|
|
|
const char *suffix = info->patch_suffix;
|
|
|
|
int nr = info->nr;
|
2012-12-22 14:06:01 +08:00
|
|
|
int start_len = filename->len;
|
format-patch: make output filename configurable
For the past 15 years, we've used the hardcoded 64 as the length
limit of the filename of the output from the "git format-patch"
command. Since the value is shorter than the 80-column terminal, it
could grow without line wrapping a bit. At the same time, since the
value is longer than half of the 80-column terminal, we could fit
two or more of them in "ls" output on such a terminal if we allowed
to lower it.
Introduce a new command line option --filename-max-length=<n> and a
new configuration variable format.filenameMaxLength to override the
hardcoded default.
While we are at it, remove a check that the name of output directory
does not exceed PATH_MAX---this check is pointless in that by the
time control reaches the function, the caller would already have
done an equivalent of "mkdir -p", so if the system does not like an
overly long directory name, the control wouldn't have reached here,
and otherwise, we know that the system allowed the output directory
to exist. In the worst case, we will get an error when we try to
open the output file and handle the error correctly anyway.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-07 05:56:24 +08:00
|
|
|
int max_len = start_len + info->patch_name_max - (strlen(suffix) + 1);
|
2012-12-22 14:06:01 +08:00
|
|
|
|
2021-03-23 19:12:25 +08:00
|
|
|
if (info->reroll_count) {
|
|
|
|
struct strbuf temp = STRBUF_INIT;
|
|
|
|
|
|
|
|
strbuf_addf(&temp, "v%s", info->reroll_count);
|
|
|
|
format_sanitized_subject(filename, temp.buf, temp.len);
|
|
|
|
strbuf_addstr(filename, "-");
|
|
|
|
strbuf_release(&temp);
|
|
|
|
}
|
2012-12-22 14:06:01 +08:00
|
|
|
strbuf_addf(filename, "%04d-%s", nr, subject);
|
|
|
|
|
|
|
|
if (max_len < filename->len)
|
|
|
|
strbuf_setlen(filename, max_len);
|
|
|
|
strbuf_addstr(filename, suffix);
|
|
|
|
}
|
|
|
|
|
|
|
|
void fmt_output_commit(struct strbuf *filename,
|
|
|
|
struct commit *commit,
|
|
|
|
struct rev_info *info)
|
|
|
|
{
|
|
|
|
struct pretty_print_context ctx = {0};
|
|
|
|
struct strbuf subject = STRBUF_INIT;
|
|
|
|
|
|
|
|
format_commit_message(commit, "%f", &subject, &ctx);
|
|
|
|
fmt_output_subject(filename, subject.buf, info);
|
|
|
|
strbuf_release(&subject);
|
2009-03-23 10:14:04 +08:00
|
|
|
}
|
|
|
|
|
2017-03-01 19:36:38 +08:00
|
|
|
void fmt_output_email_subject(struct strbuf *sb, struct rev_info *opt)
|
|
|
|
{
|
|
|
|
if (opt->total > 0) {
|
|
|
|
strbuf_addf(sb, "Subject: [%s%s%0*d/%d] ",
|
|
|
|
opt->subject_prefix,
|
|
|
|
*opt->subject_prefix ? " " : "",
|
|
|
|
digits_in_number(opt->total),
|
|
|
|
opt->nr, opt->total);
|
|
|
|
} else if (opt->total == 0 && opt->subject_prefix && *opt->subject_prefix) {
|
|
|
|
strbuf_addf(sb, "Subject: [%s] ",
|
|
|
|
opt->subject_prefix);
|
|
|
|
} else {
|
|
|
|
strbuf_addstr(sb, "Subject: ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-23 10:14:05 +08:00
|
|
|
void log_write_email_headers(struct rev_info *opt, struct commit *commit,
|
2008-03-15 15:09:20 +08:00
|
|
|
const char **extra_headers_p,
|
2018-05-02 10:20:52 +08:00
|
|
|
int *need_8bit_cte_p,
|
|
|
|
int maybe_multipart)
|
2008-02-19 11:56:08 +08:00
|
|
|
{
|
|
|
|
const char *extra_headers = opt->extra_headers;
|
2015-12-15 09:52:04 +08:00
|
|
|
const char *name = oid_to_hex(opt->zero_commit ?
|
2021-04-26 09:02:56 +08:00
|
|
|
null_oid() : &commit->object.oid);
|
2008-03-15 15:09:20 +08:00
|
|
|
|
|
|
|
*need_8bit_cte_p = 0; /* unknown */
|
2008-02-19 11:56:08 +08:00
|
|
|
|
2016-06-22 23:01:32 +08:00
|
|
|
fprintf(opt->diffopt.file, "From %s Mon Sep 17 00:00:00 2001\n", name);
|
2008-05-04 18:36:54 +08:00
|
|
|
graph_show_oneline(opt->graph);
|
|
|
|
if (opt->message_id) {
|
2016-06-22 23:01:32 +08:00
|
|
|
fprintf(opt->diffopt.file, "Message-Id: <%s>\n", opt->message_id);
|
2008-05-04 18:36:54 +08:00
|
|
|
graph_show_oneline(opt->graph);
|
|
|
|
}
|
2009-02-20 05:26:31 +08:00
|
|
|
if (opt->ref_message_ids && opt->ref_message_ids->nr > 0) {
|
|
|
|
int i, n;
|
|
|
|
n = opt->ref_message_ids->nr;
|
2016-06-22 23:01:32 +08:00
|
|
|
fprintf(opt->diffopt.file, "In-Reply-To: <%s>\n", opt->ref_message_ids->items[n-1].string);
|
2009-02-20 05:26:31 +08:00
|
|
|
for (i = 0; i < n; i++)
|
2016-06-22 23:01:32 +08:00
|
|
|
fprintf(opt->diffopt.file, "%s<%s>\n", (i > 0 ? "\t" : "References: "),
|
2009-02-20 05:26:31 +08:00
|
|
|
opt->ref_message_ids->items[i].string);
|
2008-05-04 18:36:54 +08:00
|
|
|
graph_show_oneline(opt->graph);
|
|
|
|
}
|
2018-05-02 10:20:52 +08:00
|
|
|
if (opt->mime_boundary && maybe_multipart) {
|
log_write_email_headers: use strbufs
When we write a MIME attachment, we write the mime headers
into fixed-size buffers. These are likely to be big enough
in practice, but technically the input could be arbitrarily
large (e.g., if the caller provided a lot of content in the
extra_headers string), in which case we'd quietly truncate
it and generate bogus output. Let's convert these buffers to
strbufs.
The memory ownership here is a bit funny. The original fixed
buffers were static, and we merely pass out pointers to them
to be used by the caller (and in one case, we even just
stuff our value into the opt->diffopt.stat_sep value).
Ideally we'd actually pass back heap buffers, and the caller
would be responsible for freeing them.
This patch punts on that cleanup for now, and instead just
marks the strbufs as static. That means we keep ownership in
this function, making it not a complete leak. This also
takes us one step closer to fixing it in the long term
(since we can eventually use strbuf_detach() to hand
ownership to the caller, once it's ready).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-19 09:57:44 +08:00
|
|
|
static struct strbuf subject_buffer = STRBUF_INIT;
|
|
|
|
static struct strbuf buffer = STRBUF_INIT;
|
2009-03-23 10:14:05 +08:00
|
|
|
struct strbuf filename = STRBUF_INIT;
|
2008-03-15 15:09:20 +08:00
|
|
|
*need_8bit_cte_p = -1; /* NEVER */
|
log_write_email_headers: use strbufs
When we write a MIME attachment, we write the mime headers
into fixed-size buffers. These are likely to be big enough
in practice, but technically the input could be arbitrarily
large (e.g., if the caller provided a lot of content in the
extra_headers string), in which case we'd quietly truncate
it and generate bogus output. Let's convert these buffers to
strbufs.
The memory ownership here is a bit funny. The original fixed
buffers were static, and we merely pass out pointers to them
to be used by the caller (and in one case, we even just
stuff our value into the opt->diffopt.stat_sep value).
Ideally we'd actually pass back heap buffers, and the caller
would be responsible for freeing them.
This patch punts on that cleanup for now, and instead just
marks the strbufs as static. That means we keep ownership in
this function, making it not a complete leak. This also
takes us one step closer to fixing it in the long term
(since we can eventually use strbuf_detach() to hand
ownership to the caller, once it's ready).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-19 09:57:44 +08:00
|
|
|
|
|
|
|
strbuf_reset(&subject_buffer);
|
|
|
|
strbuf_reset(&buffer);
|
|
|
|
|
|
|
|
strbuf_addf(&subject_buffer,
|
2008-02-19 11:56:08 +08:00
|
|
|
"%s"
|
|
|
|
"MIME-Version: 1.0\n"
|
|
|
|
"Content-Type: multipart/mixed;"
|
|
|
|
" boundary=\"%s%s\"\n"
|
|
|
|
"\n"
|
|
|
|
"This is a multi-part message in MIME "
|
|
|
|
"format.\n"
|
|
|
|
"--%s%s\n"
|
|
|
|
"Content-Type: text/plain; "
|
|
|
|
"charset=UTF-8; format=fixed\n"
|
|
|
|
"Content-Transfer-Encoding: 8bit\n\n",
|
|
|
|
extra_headers ? extra_headers : "",
|
|
|
|
mime_boundary_leader, opt->mime_boundary,
|
|
|
|
mime_boundary_leader, opt->mime_boundary);
|
log_write_email_headers: use strbufs
When we write a MIME attachment, we write the mime headers
into fixed-size buffers. These are likely to be big enough
in practice, but technically the input could be arbitrarily
large (e.g., if the caller provided a lot of content in the
extra_headers string), in which case we'd quietly truncate
it and generate bogus output. Let's convert these buffers to
strbufs.
The memory ownership here is a bit funny. The original fixed
buffers were static, and we merely pass out pointers to them
to be used by the caller (and in one case, we even just
stuff our value into the opt->diffopt.stat_sep value).
Ideally we'd actually pass back heap buffers, and the caller
would be responsible for freeing them.
This patch punts on that cleanup for now, and instead just
marks the strbufs as static. That means we keep ownership in
this function, making it not a complete leak. This also
takes us one step closer to fixing it in the long term
(since we can eventually use strbuf_detach() to hand
ownership to the caller, once it's ready).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-19 09:57:44 +08:00
|
|
|
extra_headers = subject_buffer.buf;
|
2008-02-19 11:56:08 +08:00
|
|
|
|
2012-12-22 13:39:37 +08:00
|
|
|
if (opt->numbered_files)
|
|
|
|
strbuf_addf(&filename, "%d", opt->nr);
|
|
|
|
else
|
2012-12-22 14:06:01 +08:00
|
|
|
fmt_output_commit(&filename, commit, opt);
|
log_write_email_headers: use strbufs
When we write a MIME attachment, we write the mime headers
into fixed-size buffers. These are likely to be big enough
in practice, but technically the input could be arbitrarily
large (e.g., if the caller provided a lot of content in the
extra_headers string), in which case we'd quietly truncate
it and generate bogus output. Let's convert these buffers to
strbufs.
The memory ownership here is a bit funny. The original fixed
buffers were static, and we merely pass out pointers to them
to be used by the caller (and in one case, we even just
stuff our value into the opt->diffopt.stat_sep value).
Ideally we'd actually pass back heap buffers, and the caller
would be responsible for freeing them.
This patch punts on that cleanup for now, and instead just
marks the strbufs as static. That means we keep ownership in
this function, making it not a complete leak. This also
takes us one step closer to fixing it in the long term
(since we can eventually use strbuf_detach() to hand
ownership to the caller, once it's ready).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-19 09:57:44 +08:00
|
|
|
strbuf_addf(&buffer,
|
2008-07-30 13:49:33 +08:00
|
|
|
"\n--%s%s\n"
|
2008-02-19 11:56:08 +08:00
|
|
|
"Content-Type: text/x-patch;"
|
2009-03-23 10:14:05 +08:00
|
|
|
" name=\"%s\"\n"
|
2008-02-19 11:56:08 +08:00
|
|
|
"Content-Transfer-Encoding: 8bit\n"
|
|
|
|
"Content-Disposition: %s;"
|
2009-03-23 10:14:05 +08:00
|
|
|
" filename=\"%s\"\n\n",
|
2008-02-19 11:56:08 +08:00
|
|
|
mime_boundary_leader, opt->mime_boundary,
|
2009-03-23 10:14:05 +08:00
|
|
|
filename.buf,
|
2008-02-19 11:56:08 +08:00
|
|
|
opt->no_inline ? "attachment" : "inline",
|
2009-03-23 10:14:05 +08:00
|
|
|
filename.buf);
|
log_write_email_headers: use strbufs
When we write a MIME attachment, we write the mime headers
into fixed-size buffers. These are likely to be big enough
in practice, but technically the input could be arbitrarily
large (e.g., if the caller provided a lot of content in the
extra_headers string), in which case we'd quietly truncate
it and generate bogus output. Let's convert these buffers to
strbufs.
The memory ownership here is a bit funny. The original fixed
buffers were static, and we merely pass out pointers to them
to be used by the caller (and in one case, we even just
stuff our value into the opt->diffopt.stat_sep value).
Ideally we'd actually pass back heap buffers, and the caller
would be responsible for freeing them.
This patch punts on that cleanup for now, and instead just
marks the strbufs as static. That means we keep ownership in
this function, making it not a complete leak. This also
takes us one step closer to fixing it in the long term
(since we can eventually use strbuf_detach() to hand
ownership to the caller, once it's ready).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-19 09:57:44 +08:00
|
|
|
opt->diffopt.stat_sep = buffer.buf;
|
2009-03-23 10:14:05 +08:00
|
|
|
strbuf_release(&filename);
|
2008-02-19 11:56:08 +08:00
|
|
|
}
|
|
|
|
*extra_headers_p = extra_headers;
|
|
|
|
}
|
|
|
|
|
2012-01-05 05:48:45 +08:00
|
|
|
static void show_sig_lines(struct rev_info *opt, int status, const char *bol)
|
|
|
|
{
|
|
|
|
const char *color, *reset, *eol;
|
|
|
|
|
|
|
|
color = diff_get_color_opt(&opt->diffopt,
|
|
|
|
status ? DIFF_WHITESPACE : DIFF_FRAGINFO);
|
|
|
|
reset = diff_get_color_opt(&opt->diffopt, DIFF_RESET);
|
|
|
|
while (*bol) {
|
|
|
|
eol = strchrnul(bol, '\n');
|
2016-06-22 23:01:32 +08:00
|
|
|
fprintf(opt->diffopt.file, "%s%.*s%s%s", color, (int)(eol - bol), bol, reset,
|
2012-01-05 05:48:45 +08:00
|
|
|
*eol ? "\n" : "");
|
2014-07-09 10:10:21 +08:00
|
|
|
graph_show_oneline(opt->graph);
|
2012-01-05 05:48:45 +08:00
|
|
|
bol = (*eol) ? (eol + 1) : eol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-19 06:53:23 +08:00
|
|
|
static void show_signature(struct rev_info *opt, struct commit *commit)
|
|
|
|
{
|
|
|
|
struct strbuf payload = STRBUF_INIT;
|
|
|
|
struct strbuf signature = STRBUF_INIT;
|
2020-03-04 19:48:04 +08:00
|
|
|
struct signature_check sigc = { 0 };
|
2011-10-19 06:53:23 +08:00
|
|
|
int status;
|
|
|
|
|
2021-01-19 07:49:11 +08:00
|
|
|
if (parse_signed_commit(commit, &payload, &signature, the_hash_algo) <= 0)
|
2011-10-19 06:53:23 +08:00
|
|
|
goto out;
|
|
|
|
|
2021-12-09 16:52:46 +08:00
|
|
|
sigc.payload_type = SIGNATURE_PAYLOAD_COMMIT;
|
2021-12-09 16:52:43 +08:00
|
|
|
sigc.payload = strbuf_detach(&payload, &sigc.payload_len);
|
|
|
|
status = check_signature(&sigc, signature.buf, signature.len);
|
2021-09-11 04:07:34 +08:00
|
|
|
if (status && !sigc.output)
|
2020-03-04 19:48:04 +08:00
|
|
|
show_sig_lines(opt, status, "No signature\n");
|
|
|
|
else
|
2021-09-11 04:07:34 +08:00
|
|
|
show_sig_lines(opt, status, sigc.output);
|
2020-03-04 19:48:04 +08:00
|
|
|
signature_check_clear(&sigc);
|
2011-10-19 06:53:23 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
strbuf_release(&payload);
|
|
|
|
strbuf_release(&signature);
|
|
|
|
}
|
|
|
|
|
2017-05-07 06:10:18 +08:00
|
|
|
static int which_parent(const struct object_id *oid, const struct commit *commit)
|
2012-01-05 05:51:28 +08:00
|
|
|
{
|
|
|
|
int nth;
|
|
|
|
const struct commit_list *parent;
|
|
|
|
|
|
|
|
for (nth = 0, parent = commit->parents; parent; parent = parent->next) {
|
convert "oidcmp() == 0" to oideq()
Using the more restrictive oideq() should, in the long run,
give the compiler more opportunities to optimize these
callsites. For now, this conversion should be a complete
noop with respect to the generated code.
The result is also perhaps a little more readable, as it
avoids the "zero is equal" idiom. Since it's so prevalent in
C, I think seasoned programmers tend not to even notice it
anymore, but it can sometimes make for awkward double
negations (e.g., we can drop a few !!oidcmp() instances
here).
This patch was generated almost entirely by the included
coccinelle patch. This mechanical conversion should be
completely safe, because we check explicitly for cases where
oidcmp() is compared to 0, which is what oideq() is doing
under the hood. Note that we don't have to catch "!oidcmp()"
separately; coccinelle's standard isomorphisms make sure the
two are treated equivalently.
I say "almost" because I did hand-edit the coccinelle output
to fix up a few style violations (it mostly keeps the
original formatting, but sometimes unwraps long lines).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-29 05:22:40 +08:00
|
|
|
if (oideq(&parent->item->object.oid, oid))
|
2012-01-05 05:51:28 +08:00
|
|
|
return nth;
|
|
|
|
nth++;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-01-05 08:23:12 +08:00
|
|
|
static int is_common_merge(const struct commit *commit)
|
|
|
|
{
|
|
|
|
return (commit->parents
|
|
|
|
&& commit->parents->next
|
|
|
|
&& !commit->parents->next->next);
|
|
|
|
}
|
|
|
|
|
2018-04-25 17:54:04 +08:00
|
|
|
static int show_one_mergetag(struct commit *commit,
|
|
|
|
struct commit_extra_header *extra,
|
|
|
|
void *data)
|
2012-01-05 05:51:28 +08:00
|
|
|
{
|
2014-07-07 14:35:37 +08:00
|
|
|
struct rev_info *opt = (struct rev_info *)data;
|
2017-05-07 06:10:18 +08:00
|
|
|
struct object_id oid;
|
2012-01-05 05:51:28 +08:00
|
|
|
struct tag *tag;
|
|
|
|
struct strbuf verify_message;
|
2020-03-04 19:48:04 +08:00
|
|
|
struct signature_check sigc = { 0 };
|
2012-01-05 05:51:28 +08:00
|
|
|
int status, nth;
|
2021-02-11 10:08:03 +08:00
|
|
|
struct strbuf payload = STRBUF_INIT;
|
|
|
|
struct strbuf signature = STRBUF_INIT;
|
2012-01-05 05:51:28 +08:00
|
|
|
|
2020-01-31 04:32:22 +08:00
|
|
|
hash_object_file(the_hash_algo, extra->value, extra->len,
|
2022-02-05 07:48:32 +08:00
|
|
|
OBJ_TAG, &oid);
|
2018-06-29 09:22:03 +08:00
|
|
|
tag = lookup_tag(the_repository, &oid);
|
2012-01-05 05:51:28 +08:00
|
|
|
if (!tag)
|
2018-04-25 17:54:04 +08:00
|
|
|
return -1; /* error message already given */
|
2012-01-05 05:51:28 +08:00
|
|
|
|
|
|
|
strbuf_init(&verify_message, 256);
|
2018-06-29 09:22:04 +08:00
|
|
|
if (parse_tag_buffer(the_repository, tag, extra->value, extra->len))
|
2012-01-05 05:51:28 +08:00
|
|
|
strbuf_addstr(&verify_message, "malformed mergetag\n");
|
2012-01-05 08:23:12 +08:00
|
|
|
else if (is_common_merge(commit) &&
|
convert "oidcmp() == 0" to oideq()
Using the more restrictive oideq() should, in the long run,
give the compiler more opportunities to optimize these
callsites. For now, this conversion should be a complete
noop with respect to the generated code.
The result is also perhaps a little more readable, as it
avoids the "zero is equal" idiom. Since it's so prevalent in
C, I think seasoned programmers tend not to even notice it
anymore, but it can sometimes make for awkward double
negations (e.g., we can drop a few !!oidcmp() instances
here).
This patch was generated almost entirely by the included
coccinelle patch. This mechanical conversion should be
completely safe, because we check explicitly for cases where
oidcmp() is compared to 0, which is what oideq() is doing
under the hood. Note that we don't have to catch "!oidcmp()"
separately; coccinelle's standard isomorphisms make sure the
two are treated equivalently.
I say "almost" because I did hand-edit the coccinelle output
to fix up a few style violations (it mostly keeps the
original formatting, but sometimes unwraps long lines).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-29 05:22:40 +08:00
|
|
|
oideq(&tag->tagged->oid,
|
|
|
|
&commit->parents->next->item->object.oid))
|
2012-01-05 08:23:12 +08:00
|
|
|
strbuf_addf(&verify_message,
|
|
|
|
"merged tag '%s'\n", tag->tag);
|
2017-05-07 06:10:18 +08:00
|
|
|
else if ((nth = which_parent(&tag->tagged->oid, commit)) < 0)
|
2012-01-05 05:51:28 +08:00
|
|
|
strbuf_addf(&verify_message, "tag %s names a non-parent %s\n",
|
2020-02-29 21:07:57 +08:00
|
|
|
tag->tag, oid_to_hex(&tag->tagged->oid));
|
2012-01-05 05:51:28 +08:00
|
|
|
else
|
|
|
|
strbuf_addf(&verify_message,
|
|
|
|
"parent #%d, tagged '%s'\n", nth + 1, tag->tag);
|
|
|
|
|
2013-02-15 00:04:43 +08:00
|
|
|
status = -1;
|
2021-02-11 10:08:03 +08:00
|
|
|
if (parse_signature(extra->value, extra->len, &payload, &signature)) {
|
2014-06-27 21:18:36 +08:00
|
|
|
/* could have a good signature */
|
2021-12-09 16:52:46 +08:00
|
|
|
sigc.payload_type = SIGNATURE_PAYLOAD_TAG;
|
2021-12-09 16:52:43 +08:00
|
|
|
sigc.payload = strbuf_detach(&payload, &sigc.payload_len);
|
|
|
|
status = check_signature(&sigc, signature.buf, signature.len);
|
2021-09-11 04:07:34 +08:00
|
|
|
if (sigc.output)
|
|
|
|
strbuf_addstr(&verify_message, sigc.output);
|
2020-03-04 19:48:04 +08:00
|
|
|
else
|
2014-06-27 21:18:36 +08:00
|
|
|
strbuf_addstr(&verify_message, "No signature\n");
|
2020-03-04 19:48:04 +08:00
|
|
|
signature_check_clear(&sigc);
|
2014-06-27 21:18:36 +08:00
|
|
|
/* otherwise we couldn't verify, which is shown as bad */
|
|
|
|
}
|
2012-01-05 05:51:28 +08:00
|
|
|
|
|
|
|
show_sig_lines(opt, status, verify_message.buf);
|
|
|
|
strbuf_release(&verify_message);
|
2021-02-11 10:08:03 +08:00
|
|
|
strbuf_release(&payload);
|
|
|
|
strbuf_release(&signature);
|
2018-04-25 17:54:04 +08:00
|
|
|
return 0;
|
2012-01-05 05:51:28 +08:00
|
|
|
}
|
|
|
|
|
2018-04-25 17:54:04 +08:00
|
|
|
static int show_mergetag(struct rev_info *opt, struct commit *commit)
|
2012-01-05 05:51:28 +08:00
|
|
|
{
|
2018-04-25 17:54:04 +08:00
|
|
|
return for_each_mergetag(show_one_mergetag, commit, opt);
|
2012-01-05 05:51:28 +08:00
|
|
|
}
|
|
|
|
|
2018-07-22 17:57:08 +08:00
|
|
|
static void next_commentary_block(struct rev_info *opt, struct strbuf *sb)
|
|
|
|
{
|
|
|
|
const char *x = opt->shown_dashes ? "\n" : "---\n";
|
|
|
|
if (sb)
|
|
|
|
strbuf_addstr(sb, x);
|
|
|
|
else
|
|
|
|
fputs(x, opt->diffopt.file);
|
|
|
|
opt->shown_dashes = 1;
|
|
|
|
}
|
|
|
|
|
2008-04-29 16:32:59 +08:00
|
|
|
void show_log(struct rev_info *opt)
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
{
|
2008-10-10 03:12:12 +08:00
|
|
|
struct strbuf msgbuf = STRBUF_INIT;
|
2006-06-25 18:54:14 +08:00
|
|
|
struct log_info *log = opt->loginfo;
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
struct commit *commit = log->commit, *parent = log->parent;
|
2018-07-16 09:28:06 +08:00
|
|
|
int abbrev_commit = opt->abbrev_commit ? opt->abbrev : the_hash_algo->hexsz;
|
2009-10-19 23:48:08 +08:00
|
|
|
const char *extra_headers = opt->extra_headers;
|
|
|
|
struct pretty_print_context ctx = {0};
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
|
|
|
|
opt->loginfo = NULL;
|
|
|
|
if (!opt->verbose_header) {
|
2008-05-04 18:36:54 +08:00
|
|
|
graph_show_commit(opt->graph);
|
|
|
|
|
2011-03-07 20:31:39 +08:00
|
|
|
if (!opt->graph)
|
2011-03-10 22:45:03 +08:00
|
|
|
put_revision_mark(opt, commit);
|
2018-03-12 10:27:30 +08:00
|
|
|
fputs(find_unique_abbrev(&commit->object.oid, abbrev_commit), opt->diffopt.file);
|
2008-05-04 18:36:52 +08:00
|
|
|
if (opt->print_parents)
|
2016-06-22 23:01:32 +08:00
|
|
|
show_parents(commit, abbrev_commit, opt->diffopt.file);
|
2011-10-04 22:02:03 +08:00
|
|
|
if (opt->children.name)
|
|
|
|
show_children(opt, commit, abbrev_commit);
|
2008-10-28 03:51:59 +08:00
|
|
|
show_decorations(opt, commit);
|
2008-05-04 18:36:54 +08:00
|
|
|
if (opt->graph && !graph_is_commit_finished(opt->graph)) {
|
2016-06-22 23:01:32 +08:00
|
|
|
putc('\n', opt->diffopt.file);
|
2008-05-04 18:36:54 +08:00
|
|
|
graph_show_remainder(opt->graph);
|
|
|
|
}
|
2016-06-22 23:01:32 +08:00
|
|
|
putc(opt->diffopt.line_termination, opt->diffopt.file);
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2009-07-01 15:26:28 +08:00
|
|
|
* If use_terminator is set, we already handled any record termination
|
|
|
|
* at the end of the last record.
|
2008-04-29 16:32:59 +08:00
|
|
|
* Otherwise, add a diffopt.line_termination character before all
|
|
|
|
* entries but the first. (IOW, as a separator between entries)
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
*/
|
2008-05-04 18:36:54 +08:00
|
|
|
if (opt->shown_one && !opt->use_terminator) {
|
|
|
|
/*
|
|
|
|
* If entries are separated by a newline, the output
|
|
|
|
* should look human-readable. If the last entry ended
|
|
|
|
* with a newline, print the graph output before this
|
|
|
|
* newline. Otherwise it will end up as a completely blank
|
|
|
|
* line and will look like a gap in the graph.
|
|
|
|
*
|
|
|
|
* If the entry separator is not a newline, the output is
|
|
|
|
* primarily intended for programmatic consumption, and we
|
|
|
|
* never want the extra graph output before the entry
|
|
|
|
* separator.
|
|
|
|
*/
|
|
|
|
if (opt->diffopt.line_termination == '\n' &&
|
|
|
|
!opt->missing_newline)
|
|
|
|
graph_show_padding(opt->graph);
|
2016-06-22 23:01:32 +08:00
|
|
|
putc(opt->diffopt.line_termination, opt->diffopt.file);
|
2008-05-04 18:36:54 +08:00
|
|
|
}
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
opt->shown_one = 1;
|
|
|
|
|
2008-05-04 18:36:54 +08:00
|
|
|
/*
|
|
|
|
* If the history graph was requested,
|
|
|
|
* print the graph, up to this commit's line
|
|
|
|
*/
|
|
|
|
graph_show_commit(opt->graph);
|
|
|
|
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
/*
|
|
|
|
* Print header line of header..
|
|
|
|
*/
|
2006-04-19 07:45:27 +08:00
|
|
|
|
2016-06-05 12:46:39 +08:00
|
|
|
if (cmit_fmt_is_mail(opt->commit_format)) {
|
2017-03-01 19:37:07 +08:00
|
|
|
log_write_email_headers(opt, commit, &extra_headers,
|
2018-05-02 10:20:52 +08:00
|
|
|
&ctx.need_8bit_cte, 1);
|
2017-03-01 19:37:07 +08:00
|
|
|
ctx.rev = opt;
|
|
|
|
ctx.print_email_subject = 1;
|
2007-02-23 08:35:03 +08:00
|
|
|
} else if (opt->commit_format != CMIT_FMT_USERFORMAT) {
|
2016-06-22 23:01:32 +08:00
|
|
|
fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), opt->diffopt.file);
|
2006-12-17 07:31:25 +08:00
|
|
|
if (opt->commit_format != CMIT_FMT_ONELINE)
|
2016-06-22 23:01:32 +08:00
|
|
|
fputs("commit ", opt->diffopt.file);
|
2008-05-25 15:07:21 +08:00
|
|
|
|
2011-03-07 20:31:39 +08:00
|
|
|
if (!opt->graph)
|
2011-03-10 22:45:03 +08:00
|
|
|
put_revision_mark(opt, commit);
|
2018-03-12 10:27:30 +08:00
|
|
|
fputs(find_unique_abbrev(&commit->object.oid,
|
|
|
|
abbrev_commit),
|
2016-06-22 23:01:32 +08:00
|
|
|
opt->diffopt.file);
|
2008-05-04 18:36:52 +08:00
|
|
|
if (opt->print_parents)
|
2016-06-22 23:01:32 +08:00
|
|
|
show_parents(commit, abbrev_commit, opt->diffopt.file);
|
2011-10-04 22:02:03 +08:00
|
|
|
if (opt->children.name)
|
|
|
|
show_children(opt, commit, abbrev_commit);
|
2006-05-25 03:19:47 +08:00
|
|
|
if (parent)
|
2016-06-22 23:01:32 +08:00
|
|
|
fprintf(opt->diffopt.file, " (from %s)",
|
2018-03-12 10:27:30 +08:00
|
|
|
find_unique_abbrev(&parent->object.oid, abbrev_commit));
|
2016-06-22 23:01:32 +08:00
|
|
|
fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), opt->diffopt.file);
|
2008-10-28 03:51:59 +08:00
|
|
|
show_decorations(opt, commit);
|
2008-05-04 18:36:54 +08:00
|
|
|
if (opt->commit_format == CMIT_FMT_ONELINE) {
|
2016-06-22 23:01:32 +08:00
|
|
|
putc(' ', opt->diffopt.file);
|
2008-05-04 18:36:54 +08:00
|
|
|
} else {
|
2016-06-22 23:01:32 +08:00
|
|
|
putc('\n', opt->diffopt.file);
|
2008-05-04 18:36:54 +08:00
|
|
|
graph_show_oneline(opt->graph);
|
|
|
|
}
|
2007-01-28 11:40:36 +08:00
|
|
|
if (opt->reflog_info) {
|
2008-05-04 18:36:54 +08:00
|
|
|
/*
|
|
|
|
* setup_revisions() ensures that opt->reflog_info
|
|
|
|
* and opt->graph cannot both be set,
|
|
|
|
* so we don't need to worry about printing the
|
|
|
|
* graph info here.
|
|
|
|
*/
|
2007-01-20 16:51:41 +08:00
|
|
|
show_reflog_message(opt->reflog_info,
|
2012-05-08 05:11:32 +08:00
|
|
|
opt->commit_format == CMIT_FMT_ONELINE,
|
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-26 00:55:02 +08:00
|
|
|
&opt->date_mode,
|
2012-05-08 05:11:32 +08:00
|
|
|
opt->date_mode_explicit);
|
2008-04-29 16:32:59 +08:00
|
|
|
if (opt->commit_format == CMIT_FMT_ONELINE)
|
2007-01-28 11:40:36 +08:00
|
|
|
return;
|
|
|
|
}
|
2006-04-19 07:45:27 +08:00
|
|
|
}
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
|
2012-01-05 05:51:28 +08:00
|
|
|
if (opt->show_signature) {
|
2011-10-19 06:53:23 +08:00
|
|
|
show_signature(opt, commit);
|
2012-01-05 05:51:28 +08:00
|
|
|
show_mergetag(opt, commit);
|
|
|
|
}
|
2011-10-19 06:53:23 +08:00
|
|
|
|
2012-10-18 09:51:47 +08:00
|
|
|
if (opt->show_notes) {
|
|
|
|
int raw;
|
|
|
|
struct strbuf notebuf = STRBUF_INIT;
|
|
|
|
|
|
|
|
raw = (opt->commit_format == CMIT_FMT_USERFORMAT);
|
2017-05-31 01:30:41 +08:00
|
|
|
format_display_notes(&commit->object.oid, ¬ebuf,
|
2012-10-18 09:51:47 +08:00
|
|
|
get_log_output_encoding(), raw);
|
2019-08-25 20:53:26 +08:00
|
|
|
ctx.notes_message = strbuf_detach(¬ebuf, NULL);
|
2012-10-18 09:51:47 +08:00
|
|
|
}
|
|
|
|
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
/*
|
|
|
|
* And then the pretty-printed message itself
|
|
|
|
*/
|
2013-02-12 18:17:38 +08:00
|
|
|
if (ctx.need_8bit_cte >= 0 && opt->add_signoff)
|
|
|
|
ctx.need_8bit_cte =
|
2019-02-05 02:48:50 +08:00
|
|
|
has_non_ascii(fmt_name(WANT_COMMITTER_IDENT));
|
2009-10-19 23:48:08 +08:00
|
|
|
ctx.date_mode = opt->date_mode;
|
log: respect date_mode_explicit with --format:%gd
When we show a reflog selector (e.g., via "git log -g"), we
perform some DWIM magic: while we normally show the entry's
index (e.g., HEAD@{1}), if the user has given us a date
with "--date", then we show a date-based select (e.g.,
HEAD@{yesterday}).
However, we don't want to trigger this magic if the
alternate date format we got was from the "log.date"
configuration; that is not sufficiently strong context for
us to invoke this particular magic. To fix this, commit
f4ea32f (improve reflog date/number heuristic, 2009-09-24)
introduced a "date_mode_explicit" flag in rev_info. This
flag is set only when we see a "--date" option on the
command line, and we a vanilla date to the reflog code if
the date was not explicit.
Later, commit 8f8f547 (Introduce new pretty formats %g[sdD]
for reflog information, 2009-10-19) added another way to
show selectors, and it did not respect the date_mode_explicit
flag from f4ea32f.
This patch propagates the date_mode_explicit flag to the
pretty-print code, which can then use it to pass the
appropriate date field to the reflog code. This brings the
behavior of "%gd" in line with the other formats, and means
that its output is independent of any user configuration.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-05-04 13:25:18 +08:00
|
|
|
ctx.date_mode_explicit = opt->date_mode_explicit;
|
2009-10-19 23:48:08 +08:00
|
|
|
ctx.abbrev = opt->diffopt.abbrev;
|
|
|
|
ctx.after_subject = extra_headers;
|
2011-05-27 06:28:17 +08:00
|
|
|
ctx.preserve_subject = opt->preserve_subject;
|
2020-04-08 12:31:38 +08:00
|
|
|
ctx.encode_email_headers = opt->encode_email_headers;
|
2009-10-19 23:48:10 +08:00
|
|
|
ctx.reflog_info = opt->reflog_info;
|
2011-05-27 06:27:49 +08:00
|
|
|
ctx.fmt = opt->commit_format;
|
2013-01-06 05:26:41 +08:00
|
|
|
ctx.mailmap = opt->mailmap;
|
2012-12-18 06:56:49 +08:00
|
|
|
ctx.color = opt->diffopt.use_color;
|
2016-03-17 00:15:53 +08:00
|
|
|
ctx.expand_tabs_in_log = opt->expand_tabs_in_log;
|
2013-06-26 18:19:50 +08:00
|
|
|
ctx.output_encoding = get_log_output_encoding();
|
2019-01-11 14:30:46 +08:00
|
|
|
ctx.rev = opt;
|
teach format-patch to place other authors into in-body "From"
Format-patch generates emails with the "From" address set to the
author of each patch. If you are going to send the emails, however,
you would want to replace the author identity with yours (if they
are not the same), and bump the author identity to an in-body
header.
Normally this is handled by git-send-email, which does the
transformation before sending out the emails. However, some
workflows may not use send-email (e.g., imap-send, or a custom
script which feeds the mbox to a non-git MUA). They could each
implement this feature themselves, but getting it right is
non-trivial (one must canonicalize the identities by reversing any
RFC2047 encoding or RFC822 quoting of the headers, which has caused
many bugs in send-email over the years).
This patch takes a different approach: it teaches format-patch a
"--from" option which handles the ident check and in-body header
while it is writing out the email. It's much simpler to do at this
level (because we haven't done any quoting yet), and any workflow
based on format-patch can easily turn it on.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-07-03 15:08:22 +08:00
|
|
|
if (opt->from_ident.mail_begin && opt->from_ident.name_begin)
|
|
|
|
ctx.from_ident = &opt->from_ident;
|
2016-06-16 21:18:37 +08:00
|
|
|
if (opt->graph)
|
|
|
|
ctx.graph_width = graph_width(opt->graph);
|
2011-05-27 06:27:49 +08:00
|
|
|
pretty_print_commit(&ctx, commit, &msgbuf);
|
2012-10-18 11:48:25 +08:00
|
|
|
|
|
|
|
if (opt->add_signoff)
|
2013-02-12 18:17:38 +08:00
|
|
|
append_signoff(&msgbuf, 0, APPEND_SIGNOFF_DEDUP);
|
2012-10-18 11:48:25 +08:00
|
|
|
|
2012-10-18 10:02:46 +08:00
|
|
|
if ((ctx.fmt != CMIT_FMT_USERFORMAT) &&
|
2012-10-18 12:27:22 +08:00
|
|
|
ctx.notes_message && *ctx.notes_message) {
|
2018-07-22 17:57:08 +08:00
|
|
|
if (cmit_fmt_is_mail(ctx.fmt))
|
|
|
|
next_commentary_block(opt, &msgbuf);
|
2012-10-18 10:02:46 +08:00
|
|
|
strbuf_addstr(&msgbuf, ctx.notes_message);
|
2012-10-18 12:27:22 +08:00
|
|
|
}
|
2006-06-01 06:11:49 +08:00
|
|
|
|
2008-05-04 18:36:54 +08:00
|
|
|
if (opt->show_log_size) {
|
2016-06-22 23:01:32 +08:00
|
|
|
fprintf(opt->diffopt.file, "log size %i\n", (int)msgbuf.len);
|
2008-05-04 18:36:54 +08:00
|
|
|
graph_show_oneline(opt->graph);
|
|
|
|
}
|
2007-07-21 02:15:13 +08:00
|
|
|
|
2008-05-04 18:36:54 +08:00
|
|
|
/*
|
|
|
|
* Set opt->missing_newline if msgbuf doesn't
|
|
|
|
* end in a newline (including if it is empty)
|
|
|
|
*/
|
|
|
|
if (!msgbuf.len || msgbuf.buf[msgbuf.len - 1] != '\n')
|
|
|
|
opt->missing_newline = 1;
|
|
|
|
else
|
|
|
|
opt->missing_newline = 0;
|
|
|
|
|
2016-09-01 07:27:20 +08:00
|
|
|
graph_show_commit_msg(opt->graph, opt->diffopt.file, &msgbuf);
|
2014-07-30 01:56:48 +08:00
|
|
|
if (opt->use_terminator && !commit_format_is_empty(opt->commit_format)) {
|
2008-05-04 18:36:54 +08:00
|
|
|
if (!opt->missing_newline)
|
|
|
|
graph_show_padding(opt->graph);
|
2016-06-22 23:01:32 +08:00
|
|
|
putc(opt->diffopt.line_termination, opt->diffopt.file);
|
2008-05-04 18:36:54 +08:00
|
|
|
}
|
|
|
|
|
2007-09-10 18:35:06 +08:00
|
|
|
strbuf_release(&msgbuf);
|
2012-10-18 09:51:47 +08:00
|
|
|
free(ctx.notes_message);
|
2018-07-22 17:57:09 +08:00
|
|
|
|
|
|
|
if (cmit_fmt_is_mail(ctx.fmt) && opt->idiff_oid1) {
|
|
|
|
struct diff_queue_struct dq;
|
|
|
|
|
|
|
|
memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
|
|
|
|
DIFF_QUEUE_CLEAR(&diff_queued_diff);
|
|
|
|
|
|
|
|
next_commentary_block(opt, NULL);
|
|
|
|
fprintf_ln(opt->diffopt.file, "%s", opt->idiff_title);
|
2020-09-08 15:16:09 +08:00
|
|
|
show_interdiff(opt->idiff_oid1, opt->idiff_oid2, 2,
|
|
|
|
&opt->diffopt);
|
2018-07-22 17:57:09 +08:00
|
|
|
|
|
|
|
memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
|
|
|
|
}
|
2018-07-22 17:57:17 +08:00
|
|
|
|
|
|
|
if (cmit_fmt_is_mail(ctx.fmt) && opt->rdiff1) {
|
|
|
|
struct diff_queue_struct dq;
|
range-diff: always pass at least minimal diff options
Commit d8981c3f88 ("format-patch: do not let its diff-options affect
--range-diff", 2018-11-30) taught `show_range_diff()` to accept a
NULL-pointer as an indication that it should use its own "reasonable
default". That fixed a regression from a5170794 ("Merge branch
'ab/range-diff-no-patch'", 2018-11-18), but unfortunately it introduced
a regression of its own.
In particular, it means we forget the `file` member of the diff options,
so rather than placing a range-diff in the cover-letter, we write it to
stdout. In order to fix this, rewrite the two callers adjusted by
d8981c3f88 to instead create a "dummy" set of diff options where they
only fill in the fields we absolutely require, such as output file and
color.
Modify and extend the existing tests to try and verify that the right
contents end up in the right place.
Don't revert `show_range_diff()`, i.e., let it keep accepting NULL.
Rather than removing what is dead code and figuring out it isn't
actually dead and we've broken 2.20, just leave it for now.
[es: retain diff coloring when going to stdout]
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-12-04 05:21:31 +08:00
|
|
|
struct diff_options opts;
|
2021-02-05 22:46:11 +08:00
|
|
|
struct range_diff_options range_diff_opts = {
|
|
|
|
.creation_factor = opt->creation_factor,
|
|
|
|
.dual_color = 1,
|
|
|
|
.diffopt = &opts
|
|
|
|
};
|
2018-07-22 17:57:17 +08:00
|
|
|
|
|
|
|
memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
|
|
|
|
DIFF_QUEUE_CLEAR(&diff_queued_diff);
|
|
|
|
|
|
|
|
next_commentary_block(opt, NULL);
|
|
|
|
fprintf_ln(opt->diffopt.file, "%s", opt->rdiff_title);
|
range-diff: always pass at least minimal diff options
Commit d8981c3f88 ("format-patch: do not let its diff-options affect
--range-diff", 2018-11-30) taught `show_range_diff()` to accept a
NULL-pointer as an indication that it should use its own "reasonable
default". That fixed a regression from a5170794 ("Merge branch
'ab/range-diff-no-patch'", 2018-11-18), but unfortunately it introduced
a regression of its own.
In particular, it means we forget the `file` member of the diff options,
so rather than placing a range-diff in the cover-letter, we write it to
stdout. In order to fix this, rewrite the two callers adjusted by
d8981c3f88 to instead create a "dummy" set of diff options where they
only fill in the fields we absolutely require, such as output file and
color.
Modify and extend the existing tests to try and verify that the right
contents end up in the right place.
Don't revert `show_range_diff()`, i.e., let it keep accepting NULL.
Rather than removing what is dead code and figuring out it isn't
actually dead and we've broken 2.20, just leave it for now.
[es: retain diff coloring when going to stdout]
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-12-04 05:21:31 +08:00
|
|
|
/*
|
|
|
|
* Pass minimum required diff-options to range-diff; others
|
|
|
|
* can be added later if deemed desirable.
|
|
|
|
*/
|
|
|
|
diff_setup(&opts);
|
|
|
|
opts.file = opt->diffopt.file;
|
|
|
|
opts.use_color = opt->diffopt.use_color;
|
|
|
|
diff_setup_done(&opts);
|
2021-02-05 22:46:11 +08:00
|
|
|
show_range_diff(opt->rdiff1, opt->rdiff2, &range_diff_opts);
|
2018-07-22 17:57:17 +08:00
|
|
|
|
|
|
|
memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
|
|
|
|
}
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
}
|
|
|
|
|
Common option parsing for "git log --diff" and friends
This basically does a few things that are sadly somewhat interdependent,
and nontrivial to split out
- get rid of "struct log_tree_opt"
The fields in "log_tree_opt" are moved into "struct rev_info", and all
users of log_tree_opt are changed to use the rev_info struct instead.
- add the parsing for the log_tree_opt arguments to "setup_revision()"
- make setup_revision set a flag (revs->diff) if the diff-related
arguments were used. This allows "git log" to decide whether it wants
to show diffs or not.
- make setup_revision() also initialize the diffopt part of rev_info
(which we had from before, but we just didn't initialize it)
- make setup_revision() do all the "finishing touches" on it all (it will
do the proper flag combination logic, and call "diff_setup_done()")
Now, that was the easy and straightforward part.
The slightly more involved part is that some of the programs that want to
use the new-and-improved rev_info parsing don't actually want _commits_,
they may want tree'ish arguments instead. That meant that I had to change
setup_revision() to parse the arguments not into the "revs->commits" list,
but into the "revs->pending_objects" list.
Then, when we do "prepare_revision_walk()", we walk that list, and create
the sorted commit list from there.
This actually cleaned some stuff up, but it's the less obvious part of the
patch, and re-organized the "revision.c" logic somewhat. It actually paves
the way for splitting argument parsing _entirely_ out of "revision.c",
since now the argument parsing really is totally independent of the commit
walking: that didn't use to be true, since there was lots of overlap with
get_commit_reference() handling etc, now the _only_ overlap is the shared
(and trivial) "add_pending_object()" thing.
However, I didn't do that file split, just because I wanted the diff
itself to be smaller, and show the actual changes more clearly. If this
gets accepted, I'll do further cleanups then - that includes the file
split, but also using the new infrastructure to do a nicer "git diff" etc.
Even in this form, it actually ends up removing more lines than it adds.
It's nice to note how simple and straightforward this makes the built-in
"git log" command, even though it continues to support all the diff flags
too. It doesn't get much simpler that this.
I think this is worth merging soonish, because it does allow for future
cleanup and even more sharing of code. However, it obviously touches
"revision.c", which is subtle. I've tested that it passes all the tests we
have, and it passes my "looks sane" detector, but somebody else should
also give it a good look-over.
[jc: squashed the original and three "oops this too" updates, with
another fix-up.]
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-15 07:52:13 +08:00
|
|
|
int log_tree_diff_flush(struct rev_info *opt)
|
2006-04-09 16:11:11 +08:00
|
|
|
{
|
2012-10-18 12:27:22 +08:00
|
|
|
opt->shown_dashes = 0;
|
2006-04-09 16:11:11 +08:00
|
|
|
diffcore_std(&opt->diffopt);
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
|
2022-02-02 10:37:34 +08:00
|
|
|
if (diff_queue_is_empty(&opt->diffopt)) {
|
2006-04-09 16:11:11 +08:00
|
|
|
int saved_fmt = opt->diffopt.output_format;
|
|
|
|
opt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT;
|
|
|
|
diff_flush(&opt->diffopt);
|
|
|
|
opt->diffopt.output_format = saved_fmt;
|
|
|
|
return 0;
|
|
|
|
}
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
|
2006-06-28 06:08:19 +08:00
|
|
|
if (opt->loginfo && !opt->no_commit_id) {
|
2008-04-29 16:32:59 +08:00
|
|
|
show_log(opt);
|
2007-10-10 00:35:22 +08:00
|
|
|
if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) &&
|
|
|
|
opt->verbose_header &&
|
2014-07-30 01:56:48 +08:00
|
|
|
opt->commit_format != CMIT_FMT_ONELINE &&
|
|
|
|
!commit_format_is_empty(opt->commit_format)) {
|
2012-11-14 02:09:07 +08:00
|
|
|
/*
|
|
|
|
* When showing a verbose header (i.e. log message),
|
|
|
|
* and not in --pretty=oneline format, we would want
|
|
|
|
* an extra newline between the end of log and the
|
|
|
|
* diff/diffstat output for readability.
|
|
|
|
*/
|
2006-06-28 06:08:19 +08:00
|
|
|
int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;
|
2010-05-26 15:08:03 +08:00
|
|
|
if (opt->diffopt.output_prefix) {
|
|
|
|
struct strbuf *msg = NULL;
|
|
|
|
msg = opt->diffopt.output_prefix(&opt->diffopt,
|
|
|
|
opt->diffopt.output_prefix_data);
|
2016-06-22 23:01:32 +08:00
|
|
|
fwrite(msg->buf, msg->len, 1, opt->diffopt.file);
|
2010-05-26 15:08:03 +08:00
|
|
|
}
|
2012-11-14 02:09:07 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We may have shown three-dashes line early
|
2018-07-22 17:57:08 +08:00
|
|
|
* between generated commentary (notes, etc.)
|
|
|
|
* and the log message, in which case we only
|
|
|
|
* want a blank line after the commentary
|
|
|
|
* without (an extra) three-dashes line.
|
2012-11-14 02:09:07 +08:00
|
|
|
* Otherwise, we show the three-dashes line if
|
|
|
|
* we are showing the patch with diffstat, but
|
|
|
|
* in that case, there is no extra blank line
|
|
|
|
* after the three-dashes line.
|
|
|
|
*/
|
|
|
|
if (!opt->shown_dashes &&
|
|
|
|
(pch & opt->diffopt.output_format) == pch)
|
2016-06-22 23:01:32 +08:00
|
|
|
fprintf(opt->diffopt.file, "---");
|
|
|
|
putc('\n', opt->diffopt.file);
|
2006-06-28 06:08:19 +08:00
|
|
|
}
|
|
|
|
}
|
2006-04-09 16:11:11 +08:00
|
|
|
diff_flush(&opt->diffopt);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
Common option parsing for "git log --diff" and friends
This basically does a few things that are sadly somewhat interdependent,
and nontrivial to split out
- get rid of "struct log_tree_opt"
The fields in "log_tree_opt" are moved into "struct rev_info", and all
users of log_tree_opt are changed to use the rev_info struct instead.
- add the parsing for the log_tree_opt arguments to "setup_revision()"
- make setup_revision set a flag (revs->diff) if the diff-related
arguments were used. This allows "git log" to decide whether it wants
to show diffs or not.
- make setup_revision() also initialize the diffopt part of rev_info
(which we had from before, but we just didn't initialize it)
- make setup_revision() do all the "finishing touches" on it all (it will
do the proper flag combination logic, and call "diff_setup_done()")
Now, that was the easy and straightforward part.
The slightly more involved part is that some of the programs that want to
use the new-and-improved rev_info parsing don't actually want _commits_,
they may want tree'ish arguments instead. That meant that I had to change
setup_revision() to parse the arguments not into the "revs->commits" list,
but into the "revs->pending_objects" list.
Then, when we do "prepare_revision_walk()", we walk that list, and create
the sorted commit list from there.
This actually cleaned some stuff up, but it's the less obvious part of the
patch, and re-organized the "revision.c" logic somewhat. It actually paves
the way for splitting argument parsing _entirely_ out of "revision.c",
since now the argument parsing really is totally independent of the commit
walking: that didn't use to be true, since there was lots of overlap with
get_commit_reference() handling etc, now the _only_ overlap is the shared
(and trivial) "add_pending_object()" thing.
However, I didn't do that file split, just because I wanted the diff
itself to be smaller, and show the actual changes more clearly. If this
gets accepted, I'll do further cleanups then - that includes the file
split, but also using the new infrastructure to do a nicer "git diff" etc.
Even in this form, it actually ends up removing more lines than it adds.
It's nice to note how simple and straightforward this makes the built-in
"git log" command, even though it continues to support all the diff flags
too. It doesn't get much simpler that this.
I think this is worth merging soonish, because it does allow for future
cleanup and even more sharing of code. However, it obviously touches
"revision.c", which is subtle. I've tested that it passes all the tests we
have, and it passes my "looks sane" detector, but somebody else should
also give it a good look-over.
[jc: squashed the original and three "oops this too" updates, with
another fix-up.]
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-15 07:52:13 +08:00
|
|
|
static int do_diff_combined(struct rev_info *opt, struct commit *commit)
|
2006-04-09 16:11:11 +08:00
|
|
|
{
|
2020-09-29 19:31:22 +08:00
|
|
|
diff_tree_combined_merge(commit, opt);
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
return !opt->loginfo;
|
2006-04-09 16:11:11 +08:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:37:35 +08:00
|
|
|
static void setup_additional_headers(struct diff_options *o,
|
|
|
|
struct strmap *all_headers)
|
|
|
|
{
|
|
|
|
struct hashmap_iter iter;
|
|
|
|
struct strmap_entry *entry;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make o->additional_path_headers contain the subset of all_headers
|
|
|
|
* that match o->pathspec. If there aren't any that match o->pathspec,
|
|
|
|
* then make o->additional_path_headers be NULL.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!o->pathspec.nr) {
|
|
|
|
o->additional_path_headers = all_headers;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
o->additional_path_headers = xmalloc(sizeof(struct strmap));
|
|
|
|
strmap_init_with_options(o->additional_path_headers, NULL, 0);
|
|
|
|
strmap_for_each_entry(all_headers, &iter, entry) {
|
|
|
|
if (match_pathspec(the_repository->index, &o->pathspec,
|
|
|
|
entry->key, strlen(entry->key),
|
|
|
|
0 /* prefix */, NULL /* seen */,
|
|
|
|
0 /* is_dir */))
|
|
|
|
strmap_put(o->additional_path_headers,
|
|
|
|
entry->key, entry->value);
|
|
|
|
}
|
|
|
|
if (!strmap_get_size(o->additional_path_headers)) {
|
|
|
|
strmap_clear(o->additional_path_headers, 0);
|
|
|
|
FREE_AND_NULL(o->additional_path_headers);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cleanup_additional_headers(struct diff_options *o)
|
|
|
|
{
|
|
|
|
if (!o->pathspec.nr) {
|
|
|
|
o->additional_path_headers = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!o->additional_path_headers)
|
|
|
|
return;
|
|
|
|
|
|
|
|
strmap_clear(o->additional_path_headers, 0);
|
|
|
|
FREE_AND_NULL(o->additional_path_headers);
|
|
|
|
}
|
|
|
|
|
show, log: provide a --remerge-diff capability
When this option is specified, we remerge all (two parent) merge commits
and diff the actual merge commit to the automatically created version,
in order to show how users removed conflict markers, resolved the
different conflict versions, and potentially added new changes outside
of conflict regions in order to resolve semantic merge problems (or,
possibly, just to hide other random changes).
This capability works by creating a temporary object directory and
marking it as the primary object store. This makes it so that any blobs
or trees created during the automatic merge are easily removable
afterwards by just deleting all objects from the temporary object
directory.
There are a few ways that this implementation is suboptimal:
* `log --remerge-diff` becomes slow, because the temporary object
directory can fill with many loose objects while running
* the log output can be muddied with misplaced "warning: cannot merge
binary files" messages, since ll-merge.c unconditionally writes those
messages to stderr while running instead of allowing callers to
manage them.
* important conflict and warning messages are simply dropped; thus for
conflicts like modify/delete or rename/rename or file/directory which
are not representable with content conflict markers, there may be no
way for a user of --remerge-diff to know that there had been a
conflict which was resolved (and which possibly motivated other
changes in the merge commit).
* when fixing the previous issue, note that some unimportant conflict
and warning messages might start being included. We should instead
make sure these remain dropped.
Subsequent commits will address these issues.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-02 10:37:28 +08:00
|
|
|
static int do_remerge_diff(struct rev_info *opt,
|
|
|
|
struct commit_list *parents,
|
|
|
|
struct object_id *oid,
|
|
|
|
struct commit *commit)
|
|
|
|
{
|
|
|
|
struct merge_options o;
|
|
|
|
struct commit_list *bases;
|
|
|
|
struct merge_result res = {0};
|
|
|
|
struct pretty_print_context ctx = {0};
|
|
|
|
struct commit *parent1 = parents->item;
|
|
|
|
struct commit *parent2 = parents->next->item;
|
|
|
|
struct strbuf parent1_desc = STRBUF_INIT;
|
|
|
|
struct strbuf parent2_desc = STRBUF_INIT;
|
|
|
|
|
|
|
|
/* Setup merge options */
|
|
|
|
init_merge_options(&o, the_repository);
|
|
|
|
o.show_rename_progress = 0;
|
2022-02-02 10:37:35 +08:00
|
|
|
o.record_conflict_msgs_as_headers = 1;
|
|
|
|
o.msg_header_prefix = "remerge";
|
show, log: provide a --remerge-diff capability
When this option is specified, we remerge all (two parent) merge commits
and diff the actual merge commit to the automatically created version,
in order to show how users removed conflict markers, resolved the
different conflict versions, and potentially added new changes outside
of conflict regions in order to resolve semantic merge problems (or,
possibly, just to hide other random changes).
This capability works by creating a temporary object directory and
marking it as the primary object store. This makes it so that any blobs
or trees created during the automatic merge are easily removable
afterwards by just deleting all objects from the temporary object
directory.
There are a few ways that this implementation is suboptimal:
* `log --remerge-diff` becomes slow, because the temporary object
directory can fill with many loose objects while running
* the log output can be muddied with misplaced "warning: cannot merge
binary files" messages, since ll-merge.c unconditionally writes those
messages to stderr while running instead of allowing callers to
manage them.
* important conflict and warning messages are simply dropped; thus for
conflicts like modify/delete or rename/rename or file/directory which
are not representable with content conflict markers, there may be no
way for a user of --remerge-diff to know that there had been a
conflict which was resolved (and which possibly motivated other
changes in the merge commit).
* when fixing the previous issue, note that some unimportant conflict
and warning messages might start being included. We should instead
make sure these remain dropped.
Subsequent commits will address these issues.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-02 10:37:28 +08:00
|
|
|
|
|
|
|
ctx.abbrev = DEFAULT_ABBREV;
|
|
|
|
format_commit_message(parent1, "%h (%s)", &parent1_desc, &ctx);
|
|
|
|
format_commit_message(parent2, "%h (%s)", &parent2_desc, &ctx);
|
|
|
|
o.branch1 = parent1_desc.buf;
|
|
|
|
o.branch2 = parent2_desc.buf;
|
|
|
|
|
|
|
|
/* Parse the relevant commits and get the merge bases */
|
|
|
|
parse_commit_or_die(parent1);
|
|
|
|
parse_commit_or_die(parent2);
|
|
|
|
bases = get_merge_bases(parent1, parent2);
|
|
|
|
|
|
|
|
/* Re-merge the parents */
|
|
|
|
merge_incore_recursive(&o, bases, parent1, parent2, &res);
|
|
|
|
|
|
|
|
/* Show the diff */
|
2022-02-02 10:37:35 +08:00
|
|
|
setup_additional_headers(&opt->diffopt, res.path_messages);
|
show, log: provide a --remerge-diff capability
When this option is specified, we remerge all (two parent) merge commits
and diff the actual merge commit to the automatically created version,
in order to show how users removed conflict markers, resolved the
different conflict versions, and potentially added new changes outside
of conflict regions in order to resolve semantic merge problems (or,
possibly, just to hide other random changes).
This capability works by creating a temporary object directory and
marking it as the primary object store. This makes it so that any blobs
or trees created during the automatic merge are easily removable
afterwards by just deleting all objects from the temporary object
directory.
There are a few ways that this implementation is suboptimal:
* `log --remerge-diff` becomes slow, because the temporary object
directory can fill with many loose objects while running
* the log output can be muddied with misplaced "warning: cannot merge
binary files" messages, since ll-merge.c unconditionally writes those
messages to stderr while running instead of allowing callers to
manage them.
* important conflict and warning messages are simply dropped; thus for
conflicts like modify/delete or rename/rename or file/directory which
are not representable with content conflict markers, there may be no
way for a user of --remerge-diff to know that there had been a
conflict which was resolved (and which possibly motivated other
changes in the merge commit).
* when fixing the previous issue, note that some unimportant conflict
and warning messages might start being included. We should instead
make sure these remain dropped.
Subsequent commits will address these issues.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-02 10:37:28 +08:00
|
|
|
diff_tree_oid(&res.tree->object.oid, oid, "", &opt->diffopt);
|
|
|
|
log_tree_diff_flush(opt);
|
|
|
|
|
|
|
|
/* Cleanup */
|
2022-02-02 10:37:35 +08:00
|
|
|
cleanup_additional_headers(&opt->diffopt);
|
show, log: provide a --remerge-diff capability
When this option is specified, we remerge all (two parent) merge commits
and diff the actual merge commit to the automatically created version,
in order to show how users removed conflict markers, resolved the
different conflict versions, and potentially added new changes outside
of conflict regions in order to resolve semantic merge problems (or,
possibly, just to hide other random changes).
This capability works by creating a temporary object directory and
marking it as the primary object store. This makes it so that any blobs
or trees created during the automatic merge are easily removable
afterwards by just deleting all objects from the temporary object
directory.
There are a few ways that this implementation is suboptimal:
* `log --remerge-diff` becomes slow, because the temporary object
directory can fill with many loose objects while running
* the log output can be muddied with misplaced "warning: cannot merge
binary files" messages, since ll-merge.c unconditionally writes those
messages to stderr while running instead of allowing callers to
manage them.
* important conflict and warning messages are simply dropped; thus for
conflicts like modify/delete or rename/rename or file/directory which
are not representable with content conflict markers, there may be no
way for a user of --remerge-diff to know that there had been a
conflict which was resolved (and which possibly motivated other
changes in the merge commit).
* when fixing the previous issue, note that some unimportant conflict
and warning messages might start being included. We should instead
make sure these remain dropped.
Subsequent commits will address these issues.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-02 10:37:28 +08:00
|
|
|
strbuf_release(&parent1_desc);
|
|
|
|
strbuf_release(&parent2_desc);
|
|
|
|
merge_finalize(&o, &res);
|
2022-02-02 10:37:29 +08:00
|
|
|
|
|
|
|
/* Clean up the contents of the temporary object directory */
|
|
|
|
if (opt->remerge_objdir)
|
|
|
|
tmp_objdir_discard_objects(opt->remerge_objdir);
|
|
|
|
else
|
|
|
|
BUG("did a remerge diff without remerge_objdir?!?");
|
show, log: provide a --remerge-diff capability
When this option is specified, we remerge all (two parent) merge commits
and diff the actual merge commit to the automatically created version,
in order to show how users removed conflict markers, resolved the
different conflict versions, and potentially added new changes outside
of conflict regions in order to resolve semantic merge problems (or,
possibly, just to hide other random changes).
This capability works by creating a temporary object directory and
marking it as the primary object store. This makes it so that any blobs
or trees created during the automatic merge are easily removable
afterwards by just deleting all objects from the temporary object
directory.
There are a few ways that this implementation is suboptimal:
* `log --remerge-diff` becomes slow, because the temporary object
directory can fill with many loose objects while running
* the log output can be muddied with misplaced "warning: cannot merge
binary files" messages, since ll-merge.c unconditionally writes those
messages to stderr while running instead of allowing callers to
manage them.
* important conflict and warning messages are simply dropped; thus for
conflicts like modify/delete or rename/rename or file/directory which
are not representable with content conflict markers, there may be no
way for a user of --remerge-diff to know that there had been a
conflict which was resolved (and which possibly motivated other
changes in the merge commit).
* when fixing the previous issue, note that some unimportant conflict
and warning messages might start being included. We should instead
make sure these remain dropped.
Subsequent commits will address these issues.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-02 10:37:28 +08:00
|
|
|
|
|
|
|
return !opt->loginfo;
|
|
|
|
}
|
|
|
|
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
/*
|
|
|
|
* Show the diff of a commit.
|
|
|
|
*
|
|
|
|
* Return true if we printed any log info messages
|
|
|
|
*/
|
|
|
|
static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log_info *log)
|
2006-04-09 16:11:11 +08:00
|
|
|
{
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
int showed_log;
|
2006-04-09 16:11:11 +08:00
|
|
|
struct commit_list *parents;
|
2015-11-10 10:22:28 +08:00
|
|
|
struct object_id *oid;
|
2020-12-21 23:19:53 +08:00
|
|
|
int is_merge;
|
|
|
|
int all_need_diff = opt->diff || opt->diffopt.flags.exit_with_status;
|
2006-04-09 16:11:11 +08:00
|
|
|
|
2020-12-21 23:19:53 +08:00
|
|
|
if (!all_need_diff && !opt->merges_need_diff)
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
return 0;
|
|
|
|
|
2013-10-24 16:52:36 +08:00
|
|
|
parse_commit_or_die(commit);
|
2018-04-07 03:09:38 +08:00
|
|
|
oid = get_commit_tree_oid(commit);
|
2013-03-28 16:19:34 +08:00
|
|
|
|
log: use true parents for diff even when rewriting
When using pathspec filtering in combination with diff-based log
output, parent simplification happens before the diff is computed.
The diff is therefore against the *simplified* parents.
This works okay, arguably by accident, in the normal case:
simplification reduces to one parent as long as the commit is TREESAME
to it. So the simplified parent of any given commit must have the
same tree contents on the filtered paths as its true (unfiltered)
parent.
However, --full-diff breaks this guarantee, and indeed gives pretty
spectacular results when comparing the output of
git log --graph --stat ...
git log --graph --full-diff --stat ...
(--graph internally kicks in parent simplification, much like
--parents).
To fix it, store a copy of the parent list before simplification (in a
slab) whenever --full-diff is in effect. Then use the stored parents
instead of the simplified ones in the commit display code paths. The
latter do not actually check for --full-diff to avoid duplicated code;
they just grab the original parents if save_parents() has not been
called for this revision walk.
For ordinary commits it should be obvious that this is the right thing
to do.
Merge commits are a bit subtle. Observe that with default
simplification, merge simplification is an all-or-nothing decision:
either the merge is TREESAME to one parent and disappears, or it is
different from all parents and the parent list remains intact.
Redundant parents are not pruned, so the existing code also shows them
as a merge.
So if we do show a merge commit, the parent list just consists of the
rewrite result on each parent. Running, e.g., --cc on this in
--full-diff mode is not very useful: if any commits were skipped, some
hunks will disagree with all sides of the merge (with one side,
because commits were skipped; with the others, because they didn't
have those changes in the first place). This triggers --cc showing
these hunks spuriously.
Therefore I believe that even for merge commits it is better to show
the diffs wrt. the original parents.
Reported-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Thomas Rast <trast@inf.ethz.ch>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-08-01 04:13:20 +08:00
|
|
|
parents = get_saved_parents(opt, commit);
|
2020-12-21 23:19:53 +08:00
|
|
|
is_merge = parents && parents->next;
|
|
|
|
if (!is_merge && !all_need_diff)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Root commit? */
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
if (!parents) {
|
2006-10-27 00:52:39 +08:00
|
|
|
if (opt->show_root_diff) {
|
2017-05-31 01:30:57 +08:00
|
|
|
diff_root_tree_oid(oid, "", &opt->diffopt);
|
2006-10-27 00:52:39 +08:00
|
|
|
log_tree_diff_flush(opt);
|
|
|
|
}
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
return !opt->loginfo;
|
2006-04-09 16:11:11 +08:00
|
|
|
}
|
|
|
|
|
2020-12-21 23:19:53 +08:00
|
|
|
if (is_merge) {
|
show, log: provide a --remerge-diff capability
When this option is specified, we remerge all (two parent) merge commits
and diff the actual merge commit to the automatically created version,
in order to show how users removed conflict markers, resolved the
different conflict versions, and potentially added new changes outside
of conflict regions in order to resolve semantic merge problems (or,
possibly, just to hide other random changes).
This capability works by creating a temporary object directory and
marking it as the primary object store. This makes it so that any blobs
or trees created during the automatic merge are easily removable
afterwards by just deleting all objects from the temporary object
directory.
There are a few ways that this implementation is suboptimal:
* `log --remerge-diff` becomes slow, because the temporary object
directory can fill with many loose objects while running
* the log output can be muddied with misplaced "warning: cannot merge
binary files" messages, since ll-merge.c unconditionally writes those
messages to stderr while running instead of allowing callers to
manage them.
* important conflict and warning messages are simply dropped; thus for
conflicts like modify/delete or rename/rename or file/directory which
are not representable with content conflict markers, there may be no
way for a user of --remerge-diff to know that there had been a
conflict which was resolved (and which possibly motivated other
changes in the merge commit).
* when fixing the previous issue, note that some unimportant conflict
and warning messages might start being included. We should instead
make sure these remain dropped.
Subsequent commits will address these issues.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-02 10:37:28 +08:00
|
|
|
int octopus = (parents->next->next != NULL);
|
|
|
|
|
|
|
|
if (opt->remerge_diff) {
|
|
|
|
if (octopus) {
|
|
|
|
show_log(opt);
|
|
|
|
fprintf(opt->diffopt.file,
|
|
|
|
"diff: warning: Skipping remerge-diff "
|
|
|
|
"for octopus merges.\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return do_remerge_diff(opt, parents, oid, commit);
|
|
|
|
}
|
2020-12-21 23:19:46 +08:00
|
|
|
if (opt->combine_merges)
|
2006-04-09 16:11:11 +08:00
|
|
|
return do_diff_combined(opt, commit);
|
2020-12-21 23:19:46 +08:00
|
|
|
if (opt->separate_merges) {
|
|
|
|
if (!opt->first_parent_merges) {
|
|
|
|
/* Show parent info for multiple diffs */
|
|
|
|
log->parent = parents->item;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
return 0;
|
2006-04-09 16:11:11 +08:00
|
|
|
}
|
|
|
|
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
showed_log = 0;
|
|
|
|
for (;;) {
|
2006-04-09 16:11:11 +08:00
|
|
|
struct commit *parent = parents->item;
|
|
|
|
|
2013-10-24 16:52:36 +08:00
|
|
|
parse_commit_or_die(parent);
|
2018-04-07 03:09:38 +08:00
|
|
|
diff_tree_oid(get_commit_tree_oid(parent),
|
2017-05-31 01:31:03 +08:00
|
|
|
oid, "", &opt->diffopt);
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
log_tree_diff_flush(opt);
|
|
|
|
|
|
|
|
showed_log |= !opt->loginfo;
|
|
|
|
|
|
|
|
/* Set up the log info for the next parent, if any.. */
|
|
|
|
parents = parents->next;
|
2020-12-21 23:19:40 +08:00
|
|
|
if (!parents || opt->first_parent_merges)
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
break;
|
|
|
|
log->parent = parents->item;
|
|
|
|
opt->loginfo = log;
|
|
|
|
}
|
|
|
|
return showed_log;
|
|
|
|
}
|
|
|
|
|
|
|
|
int log_tree_commit(struct rev_info *opt, struct commit *commit)
|
|
|
|
{
|
|
|
|
struct log_info log;
|
diff: add an API for deferred freeing
Add a diff_free() function to free anything we may have allocated in
the "diff_options" struct, and the ability to make calling it a noop
by setting "no_free" in "diff_options".
This is required because when e.g. "git diff" is run we'll allocate
things in that struct, use the diff machinery once, and then exit.
But if we run e.g. "git log -p" we're going to re-use what we
allocated across multiple diff_flush() calls, and only want to free
things at the end.
We've thus ended up with features like the recently added "diff -I"[1]
where we'll leak memory. As it turns out it could have simply used the
pattern established in 6ea57703f6 (log: prepare log/log-tree to reuse
the diffopt.close_file attribute, 2016-06-22).
Manually adding more such flags to things log_tree_commit() every time
we need to allocate something would be tedious. Let's instead move
that fclose() code it to a new diff_free(), in anticipation of freeing
more things in that function in follow-up commits.
Some functions such as log_tree_commit() need an idiom of optionally
retaining a previous "no_free", as they may either free the memory
themselves, or their caller may do so. I'm keeping that idiom in
log_show_early() for good measure, even though I don't think it's
currently called in this manner. It also gets passed an existing
"struct rev_info", so future callers may want to set the "no_free"
flag.
This change is a bit hard to read because while the freeing pattern
we're introducing isn't unusual, the "file" member is a special
snowflake. We usually don't want to fclose() it. This is because
"file" is usually stdout, in which case we don't want to fclose()
it. We only want to opt-in to closing it when we e.g. open a file on
the filesystem. Thus the opt-in "close_file" flag.
So the API in general just needs a "no_free" flag to defer freeing,
but the "file" member still needs its "close_file" flag. This is made
more confusing because while refactoring this code we could replace
some "close_file=0" with "no_free=1", whereas others need to set both
flags.
This is because there were some cases where an existing "close_file=0"
meant "let's defer deallocation", and others where it meant "we don't
want to close this file handle at all".
1. 296d4a94e7 (diff: add -I<regex> that ignores matching changes,
2020-10-20)
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-02-11 18:45:34 +08:00
|
|
|
int shown;
|
|
|
|
/* maybe called by e.g. cmd_log_walk(), maybe stand-alone */
|
|
|
|
int no_free = opt->diffopt.no_free;
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
|
|
|
|
log.commit = commit;
|
|
|
|
log.parent = NULL;
|
|
|
|
opt->loginfo = &log;
|
diff: add an API for deferred freeing
Add a diff_free() function to free anything we may have allocated in
the "diff_options" struct, and the ability to make calling it a noop
by setting "no_free" in "diff_options".
This is required because when e.g. "git diff" is run we'll allocate
things in that struct, use the diff machinery once, and then exit.
But if we run e.g. "git log -p" we're going to re-use what we
allocated across multiple diff_flush() calls, and only want to free
things at the end.
We've thus ended up with features like the recently added "diff -I"[1]
where we'll leak memory. As it turns out it could have simply used the
pattern established in 6ea57703f6 (log: prepare log/log-tree to reuse
the diffopt.close_file attribute, 2016-06-22).
Manually adding more such flags to things log_tree_commit() every time
we need to allocate something would be tedious. Let's instead move
that fclose() code it to a new diff_free(), in anticipation of freeing
more things in that function in follow-up commits.
Some functions such as log_tree_commit() need an idiom of optionally
retaining a previous "no_free", as they may either free the memory
themselves, or their caller may do so. I'm keeping that idiom in
log_show_early() for good measure, even though I don't think it's
currently called in this manner. It also gets passed an existing
"struct rev_info", so future callers may want to set the "no_free"
flag.
This change is a bit hard to read because while the freeing pattern
we're introducing isn't unusual, the "file" member is a special
snowflake. We usually don't want to fclose() it. This is because
"file" is usually stdout, in which case we don't want to fclose()
it. We only want to opt-in to closing it when we e.g. open a file on
the filesystem. Thus the opt-in "close_file" flag.
So the API in general just needs a "no_free" flag to defer freeing,
but the "file" member still needs its "close_file" flag. This is made
more confusing because while refactoring this code we could replace
some "close_file=0" with "no_free=1", whereas others need to set both
flags.
This is because there were some cases where an existing "close_file=0"
meant "let's defer deallocation", and others where it meant "we don't
want to close this file handle at all".
1. 296d4a94e7 (diff: add -I<regex> that ignores matching changes,
2020-10-20)
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-02-11 18:45:34 +08:00
|
|
|
opt->diffopt.no_free = 1;
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
|
2.36 gitk/diff-tree --stdin regression fix
This only surfaced as a regression after 2.36 release, but the
breakage was already there with us for at least a year.
The diff_free() call is to be used after we completely finished with
a diffopt structure. After "git diff A B" finishes producing
output, calling it before process exit is fine. But there are
commands that prepares diff_options struct once, compares two sets
of paths, releases resources that were used to do the comparison,
then reuses the same diff_option struct to go on to compare the next
two sets of paths, like "git log -p".
After "git log -p" finishes showing a single commit, calling it
before it goes on to the next commit is NOT fine. There is a
mechanism, the .no_free member in diff_options struct, to help "git
log" to avoid calling diff_free() after showing each commit and
instead call it just one. When the mechanism was introduced in
e900d494 (diff: add an API for deferred freeing, 2021-02-11),
however, we forgot to do the same to "diff-tree --stdin", which *is*
a moral equivalent to "git log".
During 2.36 release cycle, we started clearing the pathspec in
diff_free(), so programs like gitk that runs
git diff-tree --stdin -- <pathspec>
downstream of a pipe, processing one commit after another, started
showing irrelevant comparison outside the given <pathspec> from the
second commit. The same commit, by forgetting to teach the .no_free
mechanism, broke "diff-tree --stdin -I<regexp>" and nobody noticed
it for over a year, presumably because it is so seldom used an
option.
But <pathspec> is a different story. The breakage was very
prominently visible and was reported immediately after 2.36 was
released.
Fix this breakage by mimicking how "git log" utilizes the .no_free
member so that "diff-tree --stdin" behaves more similarly to "log".
Protect the fix with a few new tests.
Reported-by: Matthias Aßhauer <mha1993@live.de>
Helped-by: René Scharfe <l.s.r@web.de>
Helped-by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-04-27 00:11:44 +08:00
|
|
|
/* NEEDSWORK: no restoring of no_free? Why? */
|
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-29 00:47:32 +08:00
|
|
|
if (opt->line_level_traverse)
|
|
|
|
return line_log_print(opt, commit);
|
|
|
|
|
2014-03-25 21:23:27 +08:00
|
|
|
if (opt->track_linear && !opt->linear && !opt->reverse_output_stage)
|
2016-06-22 23:01:32 +08:00
|
|
|
fprintf(opt->diffopt.file, "\n%s\n", opt->break_bar);
|
2006-04-19 07:45:27 +08:00
|
|
|
shown = log_tree_diff(opt, commit, &log);
|
|
|
|
if (!shown && opt->loginfo && opt->always_show_header) {
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
log.parent = NULL;
|
2008-04-29 16:32:59 +08:00
|
|
|
show_log(opt);
|
2006-04-19 07:45:27 +08:00
|
|
|
shown = 1;
|
2006-04-09 16:11:11 +08:00
|
|
|
}
|
2014-03-25 21:23:27 +08:00
|
|
|
if (opt->track_linear && !opt->linear && opt->reverse_output_stage)
|
2016-06-22 23:01:32 +08:00
|
|
|
fprintf(opt->diffopt.file, "\n%s\n", opt->break_bar);
|
Log message printout cleanups
On Sun, 16 Apr 2006, Junio C Hamano wrote:
>
> In the mid-term, I am hoping we can drop the generate_header()
> callchain _and_ the custom code that formats commit log in-core,
> found in cmd_log_wc().
Ok, this was nastier than expected, just because the dependencies between
the different log-printing stuff were absolutely _everywhere_, but here's
a patch that does exactly that.
The patch is not very easy to read, and the "--patch-with-stat" thing is
still broken (it does not call the "show_log()" thing properly for
merges). That's not a new bug. In the new world order it _should_ do
something like
if (rev->logopt)
show_log(rev, rev->logopt, "---\n");
but it doesn't. I haven't looked at the --with-stat logic, so I left it
alone.
That said, this patch removes more lines than it adds, and in particular,
the "cmd_log_wc()" loop is now a very clean:
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
free(commit->buffer);
commit->buffer = NULL;
}
so it doesn't get much prettier than this. All the complexity is entirely
hidden in log-tree.c, and any code that needs to flush the log literally
just needs to do the "if (rev->logopt) show_log(...)" incantation.
I had to make the combined_diff() logic take a "struct rev_info" instead
of just a "struct diff_options", but that part is pretty clean.
This does change "git whatchanged" from using "diff-tree" as the commit
descriptor to "commit", and I changed one of the tests to reflect that new
reality. Otherwise everything still passes, and my other tests look fine
too.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-04-18 02:59:32 +08:00
|
|
|
opt->loginfo = NULL;
|
2016-06-22 23:01:32 +08:00
|
|
|
maybe_flush_or_die(opt->diffopt.file, "stdout");
|
diff: add an API for deferred freeing
Add a diff_free() function to free anything we may have allocated in
the "diff_options" struct, and the ability to make calling it a noop
by setting "no_free" in "diff_options".
This is required because when e.g. "git diff" is run we'll allocate
things in that struct, use the diff machinery once, and then exit.
But if we run e.g. "git log -p" we're going to re-use what we
allocated across multiple diff_flush() calls, and only want to free
things at the end.
We've thus ended up with features like the recently added "diff -I"[1]
where we'll leak memory. As it turns out it could have simply used the
pattern established in 6ea57703f6 (log: prepare log/log-tree to reuse
the diffopt.close_file attribute, 2016-06-22).
Manually adding more such flags to things log_tree_commit() every time
we need to allocate something would be tedious. Let's instead move
that fclose() code it to a new diff_free(), in anticipation of freeing
more things in that function in follow-up commits.
Some functions such as log_tree_commit() need an idiom of optionally
retaining a previous "no_free", as they may either free the memory
themselves, or their caller may do so. I'm keeping that idiom in
log_show_early() for good measure, even though I don't think it's
currently called in this manner. It also gets passed an existing
"struct rev_info", so future callers may want to set the "no_free"
flag.
This change is a bit hard to read because while the freeing pattern
we're introducing isn't unusual, the "file" member is a special
snowflake. We usually don't want to fclose() it. This is because
"file" is usually stdout, in which case we don't want to fclose()
it. We only want to opt-in to closing it when we e.g. open a file on
the filesystem. Thus the opt-in "close_file" flag.
So the API in general just needs a "no_free" flag to defer freeing,
but the "file" member still needs its "close_file" flag. This is made
more confusing because while refactoring this code we could replace
some "close_file=0" with "no_free=1", whereas others need to set both
flags.
This is because there were some cases where an existing "close_file=0"
meant "let's defer deallocation", and others where it meant "we don't
want to close this file handle at all".
1. 296d4a94e7 (diff: add -I<regex> that ignores matching changes,
2020-10-20)
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-02-11 18:45:34 +08:00
|
|
|
opt->diffopt.no_free = no_free;
|
|
|
|
diff_free(&opt->diffopt);
|
2006-04-19 07:45:27 +08:00
|
|
|
return shown;
|
2006-04-09 16:11:11 +08:00
|
|
|
}
|