2007-07-14 23:14:45 +00:00
|
|
|
#include "builtin.h"
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
#include "cache.h"
|
Honor core.precomposeUnicode in more places
On Mac's HFS where git sets core.precomposeUnicode to true automatically
by git init/clone, when a user creates a simple unicode refname (in NFC
format) such as españa:
$ git branch españa
different commands would display the branch name differently. For
example, git branch, git log --decorate, and git fast-export all used
65 73 70 61 c3 b1 61 (or "espa\xc3\xb1a")
(NFC form) while show-ref would use
65 73 70 61 6e cc 83 61 (or "espan\xcc\x83a")
(NFD form). A stress test for git filter-repo was tripped up by this
inconsistency, though digging in I found that the problems could
compound; for example, if the user ran
$ git pack-refs --all
and then tried to check out the branch, they would be met with:
$ git checkout españa
error: pathspec 'españa' did not match any file(s) known to git
$ git checkout españa --
fatal: invalid reference: españa
$ git branch
españa
* master
Note that the user could run the `git branch` command first and copy and
paste the `españa` portion of the output and still see the same two
errors. Also, if the user added --no-prune to the pack-refs command,
then they would see three branches: master, españa, and españa (those
last two are NFC vs. NFD forms, even if they render the same).
Further, if the user had the `españa` branch checked out before
running `git pack-refs --all`, the user would be greeted with (note
that I'm trimming trailing output with an ellipsis):
$ git rev-parse HEAD
fatal: ambiguous argument 'HEAD': unknown revision or path...
$ git status
On branch españa
No commits yet...
Or worse, if the user didn't check this stuff first, running `git
commit` will create a new commit with all changes of all of history
being squashed into it.
In addition to pack-refs, one could also get into this state with
upload-pack or anything that calls either pack-refs or upload-pack (e.g.
gc or clone).
Add code in a few places (pack-refs, show-ref, upload-pack) to check and
honor the setting of core.precomposeUnicode to avoid these bugs.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-25 14:58:54 +00:00
|
|
|
#include "config.h"
|
2023-03-21 06:25:54 +00:00
|
|
|
#include "gettext.h"
|
2023-02-24 00:09:27 +00:00
|
|
|
#include "hex.h"
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
#include "refs.h"
|
2018-05-15 23:42:15 +00:00
|
|
|
#include "object-store.h"
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
#include "object.h"
|
|
|
|
#include "tag.h"
|
2008-07-21 18:03:49 +00:00
|
|
|
#include "string-list.h"
|
2009-06-21 04:40:46 +00:00
|
|
|
#include "parse-options.h"
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
|
2009-06-21 04:40:46 +00:00
|
|
|
static const char * const show_ref_usage[] = {
|
2022-10-13 15:39:02 +00:00
|
|
|
N_("git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
|
|
|
|
" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
|
|
|
|
" [--heads] [--] [<pattern>...]"),
|
usage: do not insist that standard input must come from a file
The synopsys text and the usage string of subcommands that read list
of things from the standard input are often shown like this:
git gostak [--distim] < <list-of-doshes>
This is problematic in a number of ways:
* The way to use these commands is more often to feed them the
output from another command, not feed them from a file.
* Manual pages outside Git, commands that operate on the data read
from the standard input, e.g "sort", "grep", "sed", etc., are not
described with such a "< redirection-from-file" in their synopsys
text. Our doing so introduces inconsistency.
* We do not insist on where the output should go, by saying
git gostak [--distim] < <list-of-doshes> > <output>
* As it is our convention to enclose placeholders inside <braket>,
the redirection operator followed by a placeholder filename
becomes very hard to read, both in the documentation and in the
help text.
Let's clean them all up, after making sure that the documentation
clearly describes the modes that take information from the standard
input and what kind of things are expected on the input.
[jc: stole example for fmt-merge-msg from Jonathan]
Helped-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-10-16 18:27:42 +00:00
|
|
|
N_("git show-ref --exclude-existing[=<pattern>]"),
|
2009-06-21 04:40:46 +00:00
|
|
|
NULL
|
|
|
|
};
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
|
2009-06-21 04:40:46 +00:00
|
|
|
static int deref_tags, show_head, tags_only, heads_only, found_match, verify,
|
|
|
|
quiet, hash_only, abbrev, exclude_arg;
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
static const char **pattern;
|
2009-06-21 04:40:46 +00:00
|
|
|
static const char *exclude_existing_arg;
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
|
2015-05-25 18:38:51 +00:00
|
|
|
static void show_one(const char *refname, const struct object_id *oid)
|
2006-12-18 03:27:49 +00:00
|
|
|
{
|
2017-01-23 18:00:56 +00:00
|
|
|
const char *hex;
|
|
|
|
struct object_id peeled;
|
|
|
|
|
2019-01-07 08:37:54 +00:00
|
|
|
if (!has_object_file(oid))
|
2017-01-23 18:00:58 +00:00
|
|
|
die("git show-ref: bad ref %s (%s)", refname,
|
|
|
|
oid_to_hex(oid));
|
|
|
|
|
2017-01-23 18:00:57 +00:00
|
|
|
if (quiet)
|
|
|
|
return;
|
|
|
|
|
2018-03-12 02:27:30 +00:00
|
|
|
hex = find_unique_abbrev(oid, abbrev);
|
2006-12-18 03:27:49 +00:00
|
|
|
if (hash_only)
|
|
|
|
printf("%s\n", hex);
|
|
|
|
else
|
|
|
|
printf("%s %s\n", hex, refname);
|
2017-01-23 18:00:56 +00:00
|
|
|
|
|
|
|
if (!deref_tags)
|
|
|
|
return;
|
|
|
|
|
refs: switch peel_ref() to peel_iterated_oid()
The peel_ref() interface is confusing and error-prone:
- it's typically used by ref iteration callbacks that have both a
refname and oid. But since they pass only the refname, we may load
the ref value from the filesystem again. This is inefficient, but
also means we are open to a race if somebody simultaneously updates
the ref. E.g., this:
int some_ref_cb(const char *refname, const struct object_id *oid, ...)
{
if (!peel_ref(refname, &peeled))
printf("%s peels to %s",
oid_to_hex(oid), oid_to_hex(&peeled);
}
could print nonsense. It is correct to say "refname peels to..."
(you may see the "before" value or the "after" value, either of
which is consistent), but mentioning both oids may be mixing
before/after values.
Worse, whether this is possible depends on whether the optimization
to read from the current iterator value kicks in. So it is actually
not possible with:
for_each_ref(some_ref_cb);
but it _is_ possible with:
head_ref(some_ref_cb);
which does not use the iterator mechanism (though in practice, HEAD
should never peel to anything, so this may not be triggerable).
- it must take a fully-qualified refname for the read_ref_full() code
path to work. Yet we routinely pass it partial refnames from
callbacks to for_each_tag_ref(), etc. This happens to work when
iterating because there we do not call read_ref_full() at all, and
only use the passed refname to check if it is the same as the
iterator. But the requirements for the function parameters are quite
unclear.
Instead of taking a refname, let's instead take an oid. That fixes both
problems. It's a little funny for a "ref" function not to involve refs
at all. The key thing is that it's optimizing under the hood based on
having access to the ref iterator. So let's change the name to make it
clear why you'd want this function versus just peel_object().
There are two other directions I considered but rejected:
- we could pass the peel information into the each_ref_fn callback.
However, we don't know if the caller actually wants it or not. For
packed-refs, providing it is essentially free. But for loose refs,
we actually have to peel the object, which would be wasteful in most
cases. We could likewise pass in a flag to the callback indicating
whether the peeled information is known, but that complicates those
callbacks, as they then have to decide whether to manually peel
themselves. Plus it requires changing the interface of every
callback, whether they care about peeling or not, and there are many
of them.
- we could make a function to return the peeled value of the current
iterated ref (computing it if necessary), and BUG() otherwise. I.e.:
int peel_current_iterated_ref(struct object_id *out);
Each of the current callers is an each_ref_fn callback, so they'd
mostly be happy. But:
- we use those callbacks with functions like head_ref(), which do
not use the iteration code. So we'd need to handle the fallback
case there, anyway.
- it's possible that a caller would want to call into generic code
that sometimes is used during iteration and sometimes not. This
encapsulates the logic to do the fast thing when possible, and
fallback when necessary.
The implementation is mostly obvious, but I want to call out a few
things in the patch:
- the test-tool coverage for peel_ref() is now meaningless, as it all
collapses to a single peel_object() call (arguably they were pretty
uninteresting before; the tricky part of that function is the
fast-path we see during iteration, but these calls didn't trigger
that). I've just dropped it entirely, though note that some other
tests relied on the tags we created; I've moved that creation to the
tests where it matters.
- we no longer need to take a ref_store parameter, since we'd never
look up a ref now. We do still rely on a global "current iterator"
variable which _could_ be kept per-ref-store. But in practice this
is only useful if there are multiple recursive iterations, at which
point the more appropriate solution is probably a stack of
iterators. No caller used the actual ref-store parameter anyway
(they all call the wrapper that passes the_repository).
- the original only kicked in the optimization when the "refname"
pointer matched (i.e., not string comparison). We do likewise with
the "oid" parameter here, but fall back to doing an actual oideq()
call. This in theory lets us kick in the optimization more often,
though in practice no current caller cares. It should never be
wrong, though (peeling is a property of an object, so two refs
pointing to the same object would peel identically).
- the original took care not to touch the peeled out-parameter unless
we found something to put in it. But no caller cares about this, and
anyway, it is enforced by peel_object() itself (and even in the
optimized iterator case, that's where we eventually end up). We can
shorten the code and avoid an extra copy by just passing the
out-parameter through the stack.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-01-20 19:44:43 +00:00
|
|
|
if (!peel_iterated_oid(oid, &peeled)) {
|
2018-03-12 02:27:30 +00:00
|
|
|
hex = find_unique_abbrev(&peeled, abbrev);
|
2017-01-23 18:00:56 +00:00
|
|
|
printf("%s %s^{}\n", hex, refname);
|
|
|
|
}
|
2006-12-18 03:27:49 +00:00
|
|
|
}
|
|
|
|
|
2015-05-25 18:38:51 +00:00
|
|
|
static int show_ref(const char *refname, const struct object_id *oid,
|
2022-08-25 17:09:48 +00:00
|
|
|
int flag UNUSED, void *cbdata UNUSED)
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
{
|
2013-07-17 00:05:14 +00:00
|
|
|
if (show_head && !strcmp(refname, "HEAD"))
|
|
|
|
goto match;
|
|
|
|
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
if (pattern) {
|
|
|
|
int reflen = strlen(refname);
|
|
|
|
const char **p = pattern, *m;
|
|
|
|
while ((m = *p++) != NULL) {
|
|
|
|
int len = strlen(m);
|
|
|
|
if (len > reflen)
|
|
|
|
continue;
|
|
|
|
if (memcmp(m, refname + reflen - len, len))
|
|
|
|
continue;
|
|
|
|
if (len == reflen)
|
|
|
|
goto match;
|
|
|
|
if (refname[reflen - len - 1] == '/')
|
|
|
|
goto match;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
match:
|
|
|
|
found_match++;
|
2006-11-19 21:22:44 +00:00
|
|
|
|
2015-05-25 18:38:51 +00:00
|
|
|
show_one(refname, oid);
|
2006-11-19 21:22:44 +00:00
|
|
|
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-19 10:08:32 +00:00
|
|
|
static int add_existing(const char *refname,
|
2022-08-25 17:09:48 +00:00
|
|
|
const struct object_id *oid UNUSED,
|
|
|
|
int flag UNUSED, void *cbdata)
|
2006-12-18 01:57:19 +00:00
|
|
|
{
|
2008-07-21 18:03:49 +00:00
|
|
|
struct string_list *list = (struct string_list *)cbdata;
|
2010-06-25 23:41:35 +00:00
|
|
|
string_list_insert(list, refname);
|
2006-12-18 01:57:19 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* read "^(?:<anything>\s)?<refname>(?:\^\{\})?$" from the standard input,
|
|
|
|
* and
|
|
|
|
* (1) strip "^{}" at the end of line if any;
|
|
|
|
* (2) ignore if match is provided and does not head-match refname;
|
|
|
|
* (3) warn if refname is not a well-formed refname and skip;
|
|
|
|
* (4) ignore if refname is a ref that exists in the local repository;
|
|
|
|
* (5) otherwise output the line.
|
|
|
|
*/
|
|
|
|
static int exclude_existing(const char *match)
|
|
|
|
{
|
2013-05-25 09:08:22 +00:00
|
|
|
static struct string_list existing_refs = STRING_LIST_INIT_DUP;
|
2006-12-18 01:57:19 +00:00
|
|
|
char buf[1024];
|
|
|
|
int matchlen = match ? strlen(match) : 0;
|
|
|
|
|
2015-05-25 18:38:51 +00:00
|
|
|
for_each_ref(add_existing, &existing_refs);
|
2006-12-18 01:57:19 +00:00
|
|
|
while (fgets(buf, sizeof(buf), stdin)) {
|
|
|
|
char *ref;
|
2006-12-18 21:33:47 +00:00
|
|
|
int len = strlen(buf);
|
|
|
|
|
2006-12-18 01:57:19 +00:00
|
|
|
if (len > 0 && buf[len - 1] == '\n')
|
|
|
|
buf[--len] = '\0';
|
2006-12-18 21:33:47 +00:00
|
|
|
if (3 <= len && !strcmp(buf + len - 3, "^{}")) {
|
2006-12-18 01:57:19 +00:00
|
|
|
len -= 3;
|
|
|
|
buf[len] = '\0';
|
|
|
|
}
|
|
|
|
for (ref = buf + len; buf < ref; ref--)
|
|
|
|
if (isspace(ref[-1]))
|
|
|
|
break;
|
|
|
|
if (match) {
|
|
|
|
int reflen = buf + len - ref;
|
|
|
|
if (reflen < matchlen)
|
|
|
|
continue;
|
|
|
|
if (strncmp(ref, match, matchlen))
|
|
|
|
continue;
|
|
|
|
}
|
2011-09-15 21:10:25 +00:00
|
|
|
if (check_refname_format(ref, 0)) {
|
2009-03-24 01:09:16 +00:00
|
|
|
warning("ref '%s' ignored", ref);
|
2006-12-18 01:57:19 +00:00
|
|
|
continue;
|
|
|
|
}
|
2008-07-21 18:03:49 +00:00
|
|
|
if (!string_list_has_string(&existing_refs, ref)) {
|
2006-12-18 01:57:19 +00:00
|
|
|
printf("%s\n", buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-06-21 04:40:46 +00:00
|
|
|
static int hash_callback(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
hash_only = 1;
|
|
|
|
/* Use full length SHA1 if no argument */
|
|
|
|
if (!arg)
|
|
|
|
return 0;
|
|
|
|
return parse_opt_abbrev_cb(opt, arg, unset);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int exclude_existing_callback(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
|
|
|
{
|
assert NOARG/NONEG behavior of parse-options callbacks
When we define a parse-options callback, the flags we put in the option
struct must match what the callback expects. For example, a callback
which does not handle the "unset" parameter should only be used with
PARSE_OPT_NONEG. But since the callback and the option struct are not
defined next to each other, it's easy to get this wrong (as earlier
patches in this series show).
Fortunately, the compiler can help us here: compiling with
-Wunused-parameters can show us which callbacks ignore their "unset"
parameters (and likewise, ones that ignore "arg" expect to be triggered
with PARSE_OPT_NOARG).
But after we've inspected a callback and determined that all of its
callers use the right flags, what do we do next? We'd like to silence
the compiler warning, but do so in a way that will catch any wrong calls
in the future.
We can do that by actually checking those variables and asserting that
they match our expectations. Because this is such a common pattern,
we'll introduce some helper macros. The resulting messages aren't
as descriptive as we could make them, but the file/line information from
BUG() is enough to identify the problem (and anyway, the point is that
these should never be seen).
Each of the annotated callbacks in this patch triggers
-Wunused-parameters, and was manually inspected to make sure all callers
use the correct options (so none of these BUGs should be triggerable).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 06:45:42 +00:00
|
|
|
BUG_ON_OPT_NEG(unset);
|
2009-06-21 04:40:46 +00:00
|
|
|
exclude_arg = 1;
|
|
|
|
*(const char **)opt->value = arg;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct option show_ref_options[] = {
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "tags", &tags_only, N_("only show tags (can be combined with heads)")),
|
|
|
|
OPT_BOOL(0, "heads", &heads_only, N_("only show heads (can be combined with tags)")),
|
|
|
|
OPT_BOOL(0, "verify", &verify, N_("stricter reference checking, "
|
2012-08-20 12:32:45 +00:00
|
|
|
"requires exact ref path")),
|
2013-08-03 11:51:18 +00:00
|
|
|
OPT_HIDDEN_BOOL('h', NULL, &show_head,
|
|
|
|
N_("show the HEAD reference, even if it would be filtered out")),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "head", &show_head,
|
2013-07-17 00:05:14 +00:00
|
|
|
N_("show the HEAD reference, even if it would be filtered out")),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL('d', "dereference", &deref_tags,
|
2012-08-20 12:32:45 +00:00
|
|
|
N_("dereference tags into object IDs")),
|
Use OPT_CALLBACK and OPT_CALLBACK_F
In the codebase, there are many options which use OPTION_CALLBACK in a
plain ol' struct definition. However, we have the OPT_CALLBACK and
OPT_CALLBACK_F macros which are meant to abstract these plain struct
definitions away. These macros are useful as they semantically signal to
developers that these are just normal callback option with nothing fancy
happening.
Replace plain struct definitions of OPTION_CALLBACK with OPT_CALLBACK or
OPT_CALLBACK_F where applicable. The heavy lifting was done using the
following (disgusting) shell script:
#!/bin/sh
do_replacement () {
tr '\n' '\r' |
sed -e 's/{\s*OPTION_CALLBACK,\s*\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\s*0,\(\s*[^[:space:]}]*\)\s*}/OPT_CALLBACK(\1,\2,\3,\4,\5,\6)/g' |
sed -e 's/{\s*OPTION_CALLBACK,\s*\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\(\s*[^[:space:]}]*\)\s*}/OPT_CALLBACK_F(\1,\2,\3,\4,\5,\6,\7)/g' |
tr '\r' '\n'
}
for f in $(git ls-files \*.c)
do
do_replacement <"$f" >"$f.tmp"
mv "$f.tmp" "$f"
done
The result was manually inspected and then reformatted to match the
style of the surrounding code. Finally, using
`git grep OPTION_CALLBACK \*.c`, leftover results which were not handled
by the script were manually transformed.
Signed-off-by: Denton Liu <liu.denton@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-28 08:36:28 +00:00
|
|
|
OPT_CALLBACK_F('s', "hash", &abbrev, N_("n"),
|
|
|
|
N_("only show SHA1 hash using <n> digits"),
|
|
|
|
PARSE_OPT_OPTARG, &hash_callback),
|
2009-06-21 04:40:46 +00:00
|
|
|
OPT__ABBREV(&abbrev),
|
2010-11-08 19:54:48 +00:00
|
|
|
OPT__QUIET(&quiet,
|
2012-08-20 12:32:45 +00:00
|
|
|
N_("do not print results to stdout (useful with --verify)")),
|
Use OPT_CALLBACK and OPT_CALLBACK_F
In the codebase, there are many options which use OPTION_CALLBACK in a
plain ol' struct definition. However, we have the OPT_CALLBACK and
OPT_CALLBACK_F macros which are meant to abstract these plain struct
definitions away. These macros are useful as they semantically signal to
developers that these are just normal callback option with nothing fancy
happening.
Replace plain struct definitions of OPTION_CALLBACK with OPT_CALLBACK or
OPT_CALLBACK_F where applicable. The heavy lifting was done using the
following (disgusting) shell script:
#!/bin/sh
do_replacement () {
tr '\n' '\r' |
sed -e 's/{\s*OPTION_CALLBACK,\s*\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\s*0,\(\s*[^[:space:]}]*\)\s*}/OPT_CALLBACK(\1,\2,\3,\4,\5,\6)/g' |
sed -e 's/{\s*OPTION_CALLBACK,\s*\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\(\s*[^[:space:]}]*\)\s*}/OPT_CALLBACK_F(\1,\2,\3,\4,\5,\6,\7)/g' |
tr '\r' '\n'
}
for f in $(git ls-files \*.c)
do
do_replacement <"$f" >"$f.tmp"
mv "$f.tmp" "$f"
done
The result was manually inspected and then reformatted to match the
style of the surrounding code. Finally, using
`git grep OPTION_CALLBACK \*.c`, leftover results which were not handled
by the script were manually transformed.
Signed-off-by: Denton Liu <liu.denton@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-28 08:36:28 +00:00
|
|
|
OPT_CALLBACK_F(0, "exclude-existing", &exclude_existing_arg,
|
|
|
|
N_("pattern"), N_("show refs from stdin that aren't in local repository"),
|
|
|
|
PARSE_OPT_OPTARG | PARSE_OPT_NONEG, exclude_existing_callback),
|
2009-06-21 04:40:46 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
int cmd_show_ref(int argc, const char **argv, const char *prefix)
|
|
|
|
{
|
Honor core.precomposeUnicode in more places
On Mac's HFS where git sets core.precomposeUnicode to true automatically
by git init/clone, when a user creates a simple unicode refname (in NFC
format) such as españa:
$ git branch españa
different commands would display the branch name differently. For
example, git branch, git log --decorate, and git fast-export all used
65 73 70 61 c3 b1 61 (or "espa\xc3\xb1a")
(NFC form) while show-ref would use
65 73 70 61 6e cc 83 61 (or "espan\xcc\x83a")
(NFD form). A stress test for git filter-repo was tripped up by this
inconsistency, though digging in I found that the problems could
compound; for example, if the user ran
$ git pack-refs --all
and then tried to check out the branch, they would be met with:
$ git checkout españa
error: pathspec 'españa' did not match any file(s) known to git
$ git checkout españa --
fatal: invalid reference: españa
$ git branch
españa
* master
Note that the user could run the `git branch` command first and copy and
paste the `españa` portion of the output and still see the same two
errors. Also, if the user added --no-prune to the pack-refs command,
then they would see three branches: master, españa, and españa (those
last two are NFC vs. NFD forms, even if they render the same).
Further, if the user had the `españa` branch checked out before
running `git pack-refs --all`, the user would be greeted with (note
that I'm trimming trailing output with an ellipsis):
$ git rev-parse HEAD
fatal: ambiguous argument 'HEAD': unknown revision or path...
$ git status
On branch españa
No commits yet...
Or worse, if the user didn't check this stuff first, running `git
commit` will create a new commit with all changes of all of history
being squashed into it.
In addition to pack-refs, one could also get into this state with
upload-pack or anything that calls either pack-refs or upload-pack (e.g.
gc or clone).
Add code in a few places (pack-refs, show-ref, upload-pack) to check and
honor the setting of core.precomposeUnicode to avoid these bugs.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-25 14:58:54 +00:00
|
|
|
git_config(git_default_config, NULL);
|
|
|
|
|
2009-06-21 04:40:46 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, show_ref_options,
|
2015-11-17 10:26:05 +00:00
|
|
|
show_ref_usage, 0);
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
|
2009-06-21 04:40:46 +00:00
|
|
|
if (exclude_arg)
|
|
|
|
return exclude_existing(exclude_existing_arg);
|
|
|
|
|
|
|
|
pattern = argv;
|
|
|
|
if (!*pattern)
|
|
|
|
pattern = NULL;
|
2006-12-18 02:08:52 +00:00
|
|
|
|
|
|
|
if (verify) {
|
2007-02-23 17:12:33 +00:00
|
|
|
if (!pattern)
|
|
|
|
die("--verify requires a reference");
|
2006-12-18 02:08:52 +00:00
|
|
|
while (*pattern) {
|
2015-05-25 18:38:51 +00:00
|
|
|
struct object_id oid;
|
2007-02-23 17:12:33 +00:00
|
|
|
|
2017-01-23 18:00:55 +00:00
|
|
|
if ((starts_with(*pattern, "refs/") || !strcmp(*pattern, "HEAD")) &&
|
2017-10-15 22:06:56 +00:00
|
|
|
!read_ref(*pattern, &oid)) {
|
2017-01-23 18:00:57 +00:00
|
|
|
show_one(*pattern, &oid);
|
2006-12-18 02:53:24 +00:00
|
|
|
}
|
2006-12-18 02:08:52 +00:00
|
|
|
else if (!quiet)
|
|
|
|
die("'%s' - not a valid ref", *pattern);
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
pattern++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
if (show_head)
|
2015-05-25 18:38:51 +00:00
|
|
|
head_ref(show_ref, NULL);
|
builtin/show-ref.c: avoid over-iterating with --heads, --tags
When `show-ref` is combined with the `--heads` or `--tags` options, it
can avoid iterating parts of a repository's references that it doesn't
care about.
But it doesn't take advantage of this potential optimization. When this
command was introduced back in 358ddb62cf (Add "git show-ref" builtin
command, 2006-09-15), `for_each_ref_in()` did exist. But since most
repositories don't have many (any?) references that aren't branches or
tags already, this makes little difference in practice.
Though for repositories with a large imbalance of branches and tags (or,
more likely in the case of server operators, many hidden references),
this can make quite a difference. Take, for example, a repository with
500,000 "hidden" references (all of the form "refs/__hidden__/N"), and
a single branch:
git commit --allow-empty -m "base" &&
seq 1 500000 | sed 's,\(.*\),create refs/__hidden__/\1 HEAD,' |
git update-ref --stdin &&
git pack-refs --all
Outputting the existence of that single branch currently takes on the
order of ~50ms on my machine. The vast majority of this time is wasted
iterating through references that we know we're going to discard.
Instead, teach `show-ref` that it can iterate just "refs/heads" and/or
"refs/tags" when given `--heads` and/or `--tags`, respectively. A few
small interesting things to note:
- When given either option, we can avoid the general-purpose
for_each_ref() call altogether, since we know that it won't give us
any references that we wouldn't filter out already.
- We can make two separate calls to `for_each_fullref_in()` (and
avoid, say, the more specialized `for_each_fullref_in_prefixes()`,
since we know that the set of references enumerated by each is
disjoint, so we'll never see the same reference appear in both
calls.
- We have to use the "fullref" variant (instead of just
`for_each_branch_ref()` and `for_each_tag_ref()`), since we expect
fully-qualified reference names to appear in `show-ref`'s output.
When either of `heads_only` or `tags_only` is set, we can eliminate the
strcmp() calls in `builtin/show-ref.c::show_ref()` altogether, since we
know that `show_ref()` will never see a non-branch or tag reference.
Unfortunately, we can't use `for_each_fullref_in_prefixes()` to enhance
`show-ref`'s pattern matching, since `show-ref` patterns match on the
_suffix_ (e.g., the pattern "foo" shows "refs/heads/foo",
"refs/tags/foo", and etc, not "foo/*").
Nonetheless, in our synthetic example above, this provides a significant
speed-up ("git" is roughly v2.36, "git.compile" is this patch):
$ hyperfine -N 'git show-ref --heads' 'git.compile show-ref --heads'
Benchmark 1: git show-ref --heads
Time (mean ± σ): 49.9 ms ± 6.2 ms [User: 45.6 ms, System: 4.1 ms]
Range (min … max): 46.1 ms … 73.6 ms 43 runs
Benchmark 2: git.compile show-ref --heads
Time (mean ± σ): 2.8 ms ± 0.4 ms [User: 1.4 ms, System: 1.2 ms]
Range (min … max): 1.3 ms … 5.6 ms 957 runs
Summary
'git.compile show-ref --heads' ran
18.03 ± 3.38 times faster than 'git show-ref --heads'
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-06-03 21:55:36 +00:00
|
|
|
if (heads_only || tags_only) {
|
|
|
|
if (heads_only)
|
|
|
|
for_each_fullref_in("refs/heads/", show_ref, NULL);
|
|
|
|
if (tags_only)
|
|
|
|
for_each_fullref_in("refs/tags/", show_ref, NULL);
|
|
|
|
} else {
|
|
|
|
for_each_ref(show_ref, NULL);
|
|
|
|
}
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 18:19:32 +00:00
|
|
|
if (!found_match) {
|
|
|
|
if (verify && !quiet)
|
|
|
|
die("No match");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|