2023-04-11 09:41:56 +02:00
|
|
|
#include "git-compat-util.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 03:37:28 +01:00
|
|
|
#include "commit-reach.h"
|
2017-06-14 20:07:36 +02:00
|
|
|
#include "config.h"
|
2006-04-09 10:11:11 +02:00
|
|
|
#include "diff.h"
|
2023-03-21 07:26:03 +01:00
|
|
|
#include "environment.h"
|
2023-02-24 01:09:27 +01:00
|
|
|
#include "hex.h"
|
2023-04-11 09:41:49 +02:00
|
|
|
#include "object-name.h"
|
2023-05-16 08:34:06 +02:00
|
|
|
#include "object-store-ll.h"
|
2018-06-29 03:21:51 +02:00
|
|
|
#include "repository.h"
|
2022-02-02 03:37:29 +01:00
|
|
|
#include "tmp-objdir.h"
|
2006-04-09 10:11:11 +02:00
|
|
|
#include "commit.h"
|
2008-09-04 23:39:21 +02:00
|
|
|
#include "tag.h"
|
2008-05-04 12:36:54 +02:00
|
|
|
#include "graph.h"
|
2006-04-09 10:11:11 +02: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 03:37:28 +01:00
|
|
|
#include "merge-ort.h"
|
2007-01-11 11:47:48 +01:00
|
|
|
#include "reflog-walk.h"
|
2008-09-04 23:39:21 +02:00
|
|
|
#include "refs.h"
|
2023-02-24 01:09:33 +01:00
|
|
|
#include "replace-object.h"
|
2023-05-16 08:33:58 +02:00
|
|
|
#include "revision.h"
|
2009-02-19 22:26:31 +01:00
|
|
|
#include "string-list.h"
|
2010-06-19 03:37:35 +02:00
|
|
|
#include "color.h"
|
2011-10-19 00:53:23 +02:00
|
|
|
#include "gpg-interface.h"
|
2013-02-12 11:17:39 +01: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-28 17:47:32 +01:00
|
|
|
#include "line-log.h"
|
2018-05-26 15:55:24 +02:00
|
|
|
#include "help.h"
|
2018-07-22 11:57:17 +02:00
|
|
|
#include "range-diff.h"
|
2022-02-02 03:37:35 +01:00
|
|
|
#include "strmap.h"
|
2023-04-22 22:17:26 +02:00
|
|
|
#include "tree.h"
|
2023-05-16 08:34:03 +02:00
|
|
|
#include "wildmatch.h"
|
2023-03-21 07:26:07 +01:00
|
|
|
#include "write-or-die.h"
|
2006-04-09 10:11:11 +02:00
|
|
|
|
2014-08-26 12:23:54 +02: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-13 19:25:18 +02:00
|
|
|
static int decoration_loaded;
|
|
|
|
static int decoration_flags;
|
2010-06-19 03:37:34 +02:00
|
|
|
|
2010-06-19 03:37:35 +02: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 14:29:37 +02:00
|
|
|
GIT_COLOR_BOLD_BLUE, /* GRAFTED */
|
2010-06-19 03:37:35 +02:00
|
|
|
};
|
|
|
|
|
2018-05-26 15:55:21 +02: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 15:55:31 +02:00
|
|
|
[DECORATION_GRAFTED] = "grafted",
|
2018-05-26 15:55:21 +02:00
|
|
|
};
|
|
|
|
|
2010-06-19 03:37:35 +02: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 07:04:23 +02:00
|
|
|
if (want_color(decorate_use_color))
|
2010-06-19 03:37:35 +02:00
|
|
|
return decoration_colors[ix];
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2018-05-26 15:55:24 +02:00
|
|
|
define_list_config_array(color_decorate_slots);
|
2010-06-24 02:21:16 +02:00
|
|
|
|
2014-10-07 21:16:57 +02:00
|
|
|
int parse_decorate_color_config(const char *var, const char *slot_name, const char *value)
|
2010-06-24 02:21:16 +02:00
|
|
|
{
|
2018-05-26 15:55:21 +02:00
|
|
|
int slot = LOOKUP_CONFIG(color_decorate_slots, slot_name);
|
2010-06-24 02:21:16 +02:00
|
|
|
if (slot < 0)
|
|
|
|
return 0;
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
2014-10-07 21:33:09 +02:00
|
|
|
return color_parse(value, decoration_colors[slot]);
|
2010-06-24 02:21:16 +02:00
|
|
|
}
|
|
|
|
|
2010-06-19 03:37:35 +02: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 07:03:12 +02:00
|
|
|
decorate_get_color((o)->use_color, ix)
|
2010-06-19 03:37:35 +02:00
|
|
|
|
2014-08-26 12:23:36 +02:00
|
|
|
void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
|
2008-09-04 23:39:21 +02:00
|
|
|
{
|
2016-02-22 23:44:32 +01:00
|
|
|
struct name_decoration *res;
|
|
|
|
FLEX_ALLOC_STR(res, name, name);
|
2010-06-19 03:37:34 +02:00
|
|
|
res->type = type;
|
2008-09-04 23:39:21 +02:00
|
|
|
res->next = add_decoration(&name_decoration, obj, res);
|
|
|
|
}
|
|
|
|
|
2014-08-26 12:23:54 +02:00
|
|
|
const struct name_decoration *get_name_decoration(const struct object *obj)
|
|
|
|
{
|
2019-09-08 19:58:51 +02:00
|
|
|
load_ref_decorations(NULL, DECORATE_SHORT_REFS);
|
2014-08-26 12:23:54 +02:00
|
|
|
return lookup_decoration(&name_decoration, obj);
|
|
|
|
}
|
|
|
|
|
2020-04-16 16:15:48 +02:00
|
|
|
static int match_ref_pattern(const char *refname,
|
|
|
|
const struct string_list_item *item)
|
|
|
|
{
|
|
|
|
int matched = 0;
|
2022-05-02 18:50:37 +02:00
|
|
|
if (!item->util) {
|
2020-04-16 16:15:48 +02: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 16:15:49 +02:00
|
|
|
const struct string_list *exclude_patterns_config =
|
|
|
|
filter->exclude_ref_config_pattern;
|
2020-04-16 16:15:48 +02: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 16:15:49 +02:00
|
|
|
if (match_ref_pattern(refname, item))
|
|
|
|
return 1;
|
2020-04-16 16:15:48 +02:00
|
|
|
}
|
2020-04-16 16:15:49 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2020-04-16 16:15:48 +02:00
|
|
|
|
2020-04-16 16:15:49 +02: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 16:15:48 +02:00
|
|
|
}
|
2020-04-16 16:15:49 +02:00
|
|
|
|
2020-04-16 16:15:48 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-05-25 20:38:57 +02:00
|
|
|
static int add_ref_decoration(const char *refname, const struct object_id *oid,
|
2022-08-25 19:09:48 +02:00
|
|
|
int flags UNUSED,
|
2022-08-19 12:08:32 +02:00
|
|
|
void *cb_data)
|
2008-09-04 23:39:21 +02:00
|
|
|
{
|
2022-08-05 19:58:38 +02:00
|
|
|
int i;
|
2011-08-19 14:43:50 +02: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-22 19:06:48 +02:00
|
|
|
enum object_type objtype;
|
2021-06-22 19:09:26 +02: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-21 22:33:41 +01:00
|
|
|
struct decoration_filter *filter = (struct decoration_filter *)cb_data;
|
2022-08-05 19:58:37 +02:00
|
|
|
const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
|
2011-08-19 14:43:50 +02:00
|
|
|
|
2020-04-16 16:15:48 +02: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-21 22:33:41 +01:00
|
|
|
return 0;
|
2015-05-13 21:40:35 +02:00
|
|
|
|
2015-06-11 23:34:59 +02:00
|
|
|
if (starts_with(refname, git_replace_ref_base)) {
|
2015-05-25 20:38:58 +02:00
|
|
|
struct object_id original_oid;
|
2023-06-06 15:24:36 +02:00
|
|
|
if (!replace_refs_enabled(the_repository))
|
2011-08-25 17:09:30 +02:00
|
|
|
return 0;
|
2015-08-03 20:01:10 +02:00
|
|
|
if (get_oid_hex(refname + strlen(git_replace_ref_base),
|
|
|
|
&original_oid)) {
|
2011-08-19 14:43:50 +02:00
|
|
|
warning("invalid replace ref %s", refname);
|
|
|
|
return 0;
|
|
|
|
}
|
2018-06-29 03:21:51 +02:00
|
|
|
obj = parse_object(the_repository, &original_oid);
|
2011-08-19 14:43:50 +02: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-22 19:06:48 +02:00
|
|
|
objtype = oid_object_info(the_repository, oid, NULL);
|
|
|
|
if (objtype < 0)
|
2008-09-04 23:39:21 +02: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-22 19:06:48 +02:00
|
|
|
obj = lookup_object_by_type(the_repository, oid, objtype);
|
2010-06-19 03:37:34 +02:00
|
|
|
|
2022-08-05 19:58:38 +02:00
|
|
|
for (i = 0; i < ARRAY_SIZE(ref_namespace); i++) {
|
|
|
|
struct ref_namespace_info *info = &ref_namespace[i];
|
|
|
|
|
|
|
|
if (!info->decoration)
|
|
|
|
continue;
|
|
|
|
if (info->exact) {
|
|
|
|
if (!strcmp(refname, info->ref)) {
|
|
|
|
deco_type = info->decoration;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (starts_with(refname, info->ref)) {
|
|
|
|
deco_type = info->decoration;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-06-19 03:37:34 +02:00
|
|
|
|
2021-06-22 19:09:26 +02:00
|
|
|
add_name_decoration(deco_type, refname, obj);
|
2008-09-04 23:39:21 +02: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-14 18:31:36 +02:00
|
|
|
if (!obj->parsed)
|
|
|
|
parse_object(the_repository, &obj->oid);
|
2008-09-04 23:39:21 +02:00
|
|
|
obj = ((struct tag *)obj)->tagged;
|
|
|
|
if (!obj)
|
|
|
|
break;
|
2010-06-19 03:37:34 +02:00
|
|
|
add_name_decoration(DECORATION_REF_TAG, refname, obj);
|
2008-09-04 23:39:21 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-02-24 07:39:40 +01:00
|
|
|
static int add_graft_decoration(const struct commit_graft *graft,
|
|
|
|
void *cb_data UNUSED)
|
2011-08-18 14:29:37 +02:00
|
|
|
{
|
2018-06-29 03:21:59 +02:00
|
|
|
struct commit *commit = lookup_commit(the_repository, &graft->oid);
|
2011-08-18 14:29:37 +02: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-21 22:33:41 +01:00
|
|
|
void load_ref_decorations(struct decoration_filter *filter, int flags)
|
2008-09-04 23:39:21 +02: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-13 19:25:18 +02: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-21 22:33:41 +01: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 16:15:49 +02: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-21 22:33:41 +01: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-13 19:25:18 +02: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-21 22:33:41 +01:00
|
|
|
for_each_ref(add_ref_decoration, filter);
|
|
|
|
head_ref(add_ref_decoration, filter);
|
|
|
|
for_each_commit_graft(add_graft_decoration, filter);
|
2008-09-04 23:39:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-22 17:01:32 +02:00
|
|
|
static void show_parents(struct commit *commit, int abbrev, FILE *file)
|
2006-05-03 16:59:00 +02:00
|
|
|
{
|
|
|
|
struct commit_list *p;
|
|
|
|
for (p = commit->parents; p ; p = p->next) {
|
|
|
|
struct commit *parent = p->item;
|
2023-03-28 15:58:46 +02:00
|
|
|
fprintf(file, " %s",
|
|
|
|
repo_find_unique_abbrev(the_repository, &parent->object.oid, abbrev));
|
2006-05-03 16:59:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-04 16:02:03 +02: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) {
|
2023-03-28 15:58:46 +02:00
|
|
|
fprintf(opt->diffopt.file, " %s",
|
|
|
|
repo_find_unique_abbrev(the_repository, &p->item->object.oid, abbrev));
|
2011-10-04 16:02:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-10 14:53:21 +01: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 11:45:04 +02:00
|
|
|
branch_name = resolve_ref_unsafe("HEAD", 0, NULL, &rru_flags);
|
2017-10-19 19:49:01 +02:00
|
|
|
if (!branch_name || !(rru_flags & REF_ISSYMREF))
|
2015-03-10 14:53:21 +01: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-13 19:25:18 +02:00
|
|
|
|
2015-05-13 21:40:35 +02:00
|
|
|
if (!starts_with(branch_name, "refs/"))
|
2015-03-10 14:53:21 +01: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-13 21:40:35 +02: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 01:08:43 +02:00
|
|
|
/*
|
2014-09-18 22:53:53 +02:00
|
|
|
* The caller makes sure there is no funny color before calling.
|
|
|
|
* format_decorations_extended makes sure the same after return.
|
2013-04-19 01:08:43 +02:00
|
|
|
*/
|
2014-09-18 22:53:53 +02:00
|
|
|
void format_decorations_extended(struct strbuf *sb,
|
2013-04-19 01:08:43 +02:00
|
|
|
const struct commit *commit,
|
2014-09-18 22:53:53 +02:00
|
|
|
int use_color,
|
|
|
|
const char *prefix,
|
|
|
|
const char *separator,
|
|
|
|
const char *suffix)
|
2007-04-17 01:05:10 +02:00
|
|
|
{
|
2014-08-26 12:23:54 +02:00
|
|
|
const struct name_decoration *decoration;
|
2015-03-10 14:53:21 +01:00
|
|
|
const struct name_decoration *current_and_HEAD;
|
2010-06-19 03:37:35 +02:00
|
|
|
const char *color_commit =
|
2013-04-19 01:08:43 +02:00
|
|
|
diff_get_color(use_color, DIFF_COMMIT);
|
2010-06-19 03:37:35 +02:00
|
|
|
const char *color_reset =
|
2013-04-19 01:08:43 +02:00
|
|
|
decorate_get_color(use_color, DECORATION_NONE);
|
2007-04-17 01:05:10 +02:00
|
|
|
|
2014-08-26 12:23:54 +02:00
|
|
|
decoration = get_name_decoration(&commit->object);
|
2007-04-17 01:05:10 +02:00
|
|
|
if (!decoration)
|
|
|
|
return;
|
2015-03-10 14:53:21 +01:00
|
|
|
|
|
|
|
current_and_HEAD = current_pointed_by_HEAD(decoration);
|
2007-04-17 01:05:10 +02:00
|
|
|
while (decoration) {
|
2015-03-10 14:53:21 +01: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-13 21:40:35 +02:00
|
|
|
show_name(sb, decoration);
|
2015-03-10 14:53:21 +01: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-13 21:40:35 +02:00
|
|
|
show_name(sb, current_and_HEAD);
|
2015-03-10 14:53:21 +01:00
|
|
|
}
|
|
|
|
strbuf_addstr(sb, color_reset);
|
|
|
|
|
|
|
|
prefix = separator;
|
|
|
|
}
|
2007-04-17 01:05:10 +02:00
|
|
|
decoration = decoration->next;
|
|
|
|
}
|
2013-04-19 01:08:43 +02:00
|
|
|
strbuf_addstr(sb, color_commit);
|
2014-09-18 22:53:53 +02:00
|
|
|
strbuf_addstr(sb, suffix);
|
2013-04-19 01:08:43 +02:00
|
|
|
strbuf_addstr(sb, color_reset);
|
|
|
|
}
|
|
|
|
|
|
|
|
void show_decorations(struct rev_info *opt, struct commit *commit)
|
|
|
|
{
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
2018-05-19 07:28:24 +02: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 01:08:43 +02:00
|
|
|
if (!opt->show_decorations)
|
|
|
|
return;
|
|
|
|
format_decorations(&sb, commit, opt->diffopt.use_color);
|
2016-06-22 17:01:32 +02:00
|
|
|
fputs(sb.buf, opt->diffopt.file);
|
2013-04-19 01:08:43 +02:00
|
|
|
strbuf_release(&sb);
|
2007-04-17 01:05:10 +02:00
|
|
|
}
|
|
|
|
|
2007-02-09 01:43:54 +01: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 07:06:01 +01:00
|
|
|
void fmt_output_subject(struct strbuf *filename,
|
|
|
|
const char *subject,
|
2012-12-22 08:26:16 +01:00
|
|
|
struct rev_info *info)
|
2009-03-23 03:14:04 +01:00
|
|
|
{
|
2012-12-22 08:26:16 +01:00
|
|
|
const char *suffix = info->patch_suffix;
|
|
|
|
int nr = info->nr;
|
2012-12-22 07:06:01 +01: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-06 22:56:24 +01:00
|
|
|
int max_len = start_len + info->patch_name_max - (strlen(suffix) + 1);
|
2012-12-22 07:06:01 +01:00
|
|
|
|
2021-03-23 12:12:25 +01: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 07:06:01 +01: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;
|
|
|
|
|
2023-03-28 15:58:51 +02:00
|
|
|
repo_format_commit_message(the_repository, commit, "%f", &subject,
|
|
|
|
&ctx);
|
2012-12-22 07:06:01 +01:00
|
|
|
fmt_output_subject(filename, subject.buf, info);
|
|
|
|
strbuf_release(&subject);
|
2009-03-23 03:14:04 +01:00
|
|
|
}
|
|
|
|
|
2017-03-01 12:36:38 +01: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 03:14:05 +01:00
|
|
|
void log_write_email_headers(struct rev_info *opt, struct commit *commit,
|
2008-03-15 08:09:20 +01:00
|
|
|
const char **extra_headers_p,
|
2018-05-02 04:20:52 +02:00
|
|
|
int *need_8bit_cte_p,
|
|
|
|
int maybe_multipart)
|
2008-02-19 04:56:08 +01:00
|
|
|
{
|
|
|
|
const char *extra_headers = opt->extra_headers;
|
2015-12-15 02:52:04 +01:00
|
|
|
const char *name = oid_to_hex(opt->zero_commit ?
|
2021-04-26 03:02:56 +02:00
|
|
|
null_oid() : &commit->object.oid);
|
2008-03-15 08:09:20 +01:00
|
|
|
|
|
|
|
*need_8bit_cte_p = 0; /* unknown */
|
2008-02-19 04:56:08 +01:00
|
|
|
|
2016-06-22 17:01:32 +02:00
|
|
|
fprintf(opt->diffopt.file, "From %s Mon Sep 17 00:00:00 2001\n", name);
|
2008-05-04 12:36:54 +02:00
|
|
|
graph_show_oneline(opt->graph);
|
|
|
|
if (opt->message_id) {
|
2022-12-16 02:47:19 +01:00
|
|
|
fprintf(opt->diffopt.file, "Message-ID: <%s>\n", opt->message_id);
|
2008-05-04 12:36:54 +02:00
|
|
|
graph_show_oneline(opt->graph);
|
|
|
|
}
|
2009-02-19 22:26:31 +01:00
|
|
|
if (opt->ref_message_ids && opt->ref_message_ids->nr > 0) {
|
|
|
|
int i, n;
|
|
|
|
n = opt->ref_message_ids->nr;
|
2016-06-22 17:01:32 +02:00
|
|
|
fprintf(opt->diffopt.file, "In-Reply-To: <%s>\n", opt->ref_message_ids->items[n-1].string);
|
2009-02-19 22:26:31 +01:00
|
|
|
for (i = 0; i < n; i++)
|
2016-06-22 17:01:32 +02:00
|
|
|
fprintf(opt->diffopt.file, "%s<%s>\n", (i > 0 ? "\t" : "References: "),
|
2009-02-19 22:26:31 +01:00
|
|
|
opt->ref_message_ids->items[i].string);
|
2008-05-04 12:36:54 +02:00
|
|
|
graph_show_oneline(opt->graph);
|
|
|
|
}
|
2018-05-02 04:20:52 +02: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 03:57:44 +02:00
|
|
|
static struct strbuf subject_buffer = STRBUF_INIT;
|
|
|
|
static struct strbuf buffer = STRBUF_INIT;
|
2009-03-23 03:14:05 +01:00
|
|
|
struct strbuf filename = STRBUF_INIT;
|
2008-03-15 08:09:20 +01: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 03:57:44 +02:00
|
|
|
|
|
|
|
strbuf_reset(&subject_buffer);
|
|
|
|
strbuf_reset(&buffer);
|
|
|
|
|
|
|
|
strbuf_addf(&subject_buffer,
|
2008-02-19 04:56:08 +01: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 03:57:44 +02:00
|
|
|
extra_headers = subject_buffer.buf;
|
2008-02-19 04:56:08 +01:00
|
|
|
|
2012-12-22 06:39:37 +01:00
|
|
|
if (opt->numbered_files)
|
|
|
|
strbuf_addf(&filename, "%d", opt->nr);
|
|
|
|
else
|
2012-12-22 07:06:01 +01: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 03:57:44 +02:00
|
|
|
strbuf_addf(&buffer,
|
2008-07-30 07:49:33 +02:00
|
|
|
"\n--%s%s\n"
|
2008-02-19 04:56:08 +01:00
|
|
|
"Content-Type: text/x-patch;"
|
2009-03-23 03:14:05 +01:00
|
|
|
" name=\"%s\"\n"
|
2008-02-19 04:56:08 +01:00
|
|
|
"Content-Transfer-Encoding: 8bit\n"
|
|
|
|
"Content-Disposition: %s;"
|
2009-03-23 03:14:05 +01:00
|
|
|
" filename=\"%s\"\n\n",
|
2008-02-19 04:56:08 +01:00
|
|
|
mime_boundary_leader, opt->mime_boundary,
|
2009-03-23 03:14:05 +01:00
|
|
|
filename.buf,
|
2008-02-19 04:56:08 +01:00
|
|
|
opt->no_inline ? "attachment" : "inline",
|
2009-03-23 03:14:05 +01: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 03:57:44 +02:00
|
|
|
opt->diffopt.stat_sep = buffer.buf;
|
2009-03-23 03:14:05 +01:00
|
|
|
strbuf_release(&filename);
|
2008-02-19 04:56:08 +01:00
|
|
|
}
|
|
|
|
*extra_headers_p = extra_headers;
|
|
|
|
}
|
|
|
|
|
2012-01-04 22:48:45 +01:00
|
|
|
static void show_sig_lines(struct rev_info *opt, int status, const char *bol)
|
|
|
|
{
|
|
|
|