2015-11-09 14:34:01 +01:00
|
|
|
/*
|
|
|
|
* The backend-independent part of the reference module.
|
|
|
|
*/
|
|
|
|
|
2005-06-06 22:31:29 +02:00
|
|
|
#include "cache.h"
|
2017-06-14 20:07:36 +02:00
|
|
|
#include "config.h"
|
2017-02-10 12:16:15 +01:00
|
|
|
#include "hashmap.h"
|
2014-10-01 12:28:42 +02:00
|
|
|
#include "lockfile.h"
|
2017-04-16 08:41:26 +02:00
|
|
|
#include "iterator.h"
|
2006-12-19 23:34:12 +01:00
|
|
|
#include "refs.h"
|
2015-11-10 12:42:36 +01:00
|
|
|
#include "refs/refs-internal.h"
|
refs: implement reference transaction hook
The low-level reference transactions used to update references are
currently completely opaque to the user. While certainly desirable in
most usecases, there are some which might want to hook into the
transaction to observe all queued reference updates as well as observing
the abortion or commit of a prepared transaction.
One such usecase would be to have a set of replicas of a given Git
repository, where we perform Git operations on all of the repositories
at once and expect the outcome to be the same in all of them. While
there exist hooks already for a certain subset of Git commands that
could be used to implement a voting mechanism for this, many others
currently don't have any mechanism for this.
The above scenario is the motivation for the new "reference-transaction"
hook that reaches directly into Git's reference transaction mechanism.
The hook receives as parameter the current state the transaction was
moved to ("prepared", "committed" or "aborted") and gets via its
standard input all queued reference updates. While the exit code gets
ignored in the "committed" and "aborted" states, a non-zero exit code in
the "prepared" state will cause the transaction to be aborted
prematurely.
Given the usecase described above, a voting mechanism can now be
implemented via this hook: as soon as it gets called, it will take all
of stdin and use it to cast a vote to a central service. When all
replicas of the repository agree, the hook will exit with zero,
otherwise it will abort the transaction by returning non-zero. The most
important upside is that this will catch _all_ commands writing
references at once, allowing to implement strong consistency for
reference updates via a single mechanism.
In order to test the impact on the case where we don't have any
"reference-transaction" hook installed in the repository, this commit
introduce two new performance tests for git-update-refs(1). Run against
an empty repository, it produces the following results:
Test origin/master HEAD
--------------------------------------------------------------------
1400.2: update-ref 2.70(2.10+0.71) 2.71(2.10+0.73) +0.4%
1400.3: update-ref --stdin 0.21(0.09+0.11) 0.21(0.07+0.14) +0.0%
The performance test p1400.2 creates, updates and deletes a branch a
thousand times, thus averaging runtime of git-update-refs over 3000
invocations. p1400.3 instead calls `git-update-refs --stdin` three times
and queues a thousand creations, updates and deletes respectively.
As expected, p1400.3 consistently shows no noticeable impact, as for
each batch of updates there's a single call to access(3P) for the
negative hook lookup. On the other hand, for p1400.2, one can see an
impact caused by this patchset. But doing five runs of the performance
tests where each one was run with GIT_PERF_REPEAT_COUNT=10, the overhead
ranged from -1.5% to +1.1%. These inconsistent performance numbers can
be explained by the overhead of spawning 3000 processes. This shows that
the overhead of assembling the hook path and executing access(3P) once
to check if it's there is mostly outweighed by the operating system's
overhead.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-06-19 08:56:14 +02:00
|
|
|
#include "run-command.h"
|
2018-05-16 01:42:15 +02:00
|
|
|
#include "object-store.h"
|
2006-11-19 22:22:44 +01:00
|
|
|
#include "object.h"
|
|
|
|
#include "tag.h"
|
2017-03-26 04:42:31 +02:00
|
|
|
#include "submodule.h"
|
2017-04-24 12:01:22 +02:00
|
|
|
#include "worktree.h"
|
2020-07-28 22:23:39 +02:00
|
|
|
#include "strvec.h"
|
2018-04-12 02:21:09 +02:00
|
|
|
#include "repository.h"
|
refs: implement reference transaction hook
The low-level reference transactions used to update references are
currently completely opaque to the user. While certainly desirable in
most usecases, there are some which might want to hook into the
transaction to observe all queued reference updates as well as observing
the abortion or commit of a prepared transaction.
One such usecase would be to have a set of replicas of a given Git
repository, where we perform Git operations on all of the repositories
at once and expect the outcome to be the same in all of them. While
there exist hooks already for a certain subset of Git commands that
could be used to implement a voting mechanism for this, many others
currently don't have any mechanism for this.
The above scenario is the motivation for the new "reference-transaction"
hook that reaches directly into Git's reference transaction mechanism.
The hook receives as parameter the current state the transaction was
moved to ("prepared", "committed" or "aborted") and gets via its
standard input all queued reference updates. While the exit code gets
ignored in the "committed" and "aborted" states, a non-zero exit code in
the "prepared" state will cause the transaction to be aborted
prematurely.
Given the usecase described above, a voting mechanism can now be
implemented via this hook: as soon as it gets called, it will take all
of stdin and use it to cast a vote to a central service. When all
replicas of the repository agree, the hook will exit with zero,
otherwise it will abort the transaction by returning non-zero. The most
important upside is that this will catch _all_ commands writing
references at once, allowing to implement strong consistency for
reference updates via a single mechanism.
In order to test the impact on the case where we don't have any
"reference-transaction" hook installed in the repository, this commit
introduce two new performance tests for git-update-refs(1). Run against
an empty repository, it produces the following results:
Test origin/master HEAD
--------------------------------------------------------------------
1400.2: update-ref 2.70(2.10+0.71) 2.71(2.10+0.73) +0.4%
1400.3: update-ref --stdin 0.21(0.09+0.11) 0.21(0.07+0.14) +0.0%
The performance test p1400.2 creates, updates and deletes a branch a
thousand times, thus averaging runtime of git-update-refs over 3000
invocations. p1400.3 instead calls `git-update-refs --stdin` three times
and queues a thousand creations, updates and deletes respectively.
As expected, p1400.3 consistently shows no noticeable impact, as for
each batch of updates there's a single call to access(3P) for the
negative hook lookup. On the other hand, for p1400.2, one can see an
impact caused by this patchset. But doing five runs of the performance
tests where each one was run with GIT_PERF_REPEAT_COUNT=10, the overhead
ranged from -1.5% to +1.1%. These inconsistent performance numbers can
be explained by the overhead of spawning 3000 processes. This shows that
the overhead of assembling the hook path and executing access(3P) once
to check if it's there is mostly outweighed by the operating system's
overhead.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-06-19 08:56:14 +02:00
|
|
|
#include "sigchain.h"
|
2014-12-12 09:57:02 +01:00
|
|
|
|
2016-09-04 18:08:10 +02:00
|
|
|
/*
|
|
|
|
* List of all available backends
|
|
|
|
*/
|
|
|
|
static struct ref_storage_be *refs_backends = &refs_be_files;
|
|
|
|
|
|
|
|
static struct ref_storage_be *find_ref_storage_backend(const char *name)
|
|
|
|
{
|
|
|
|
struct ref_storage_be *be;
|
|
|
|
for (be = refs_backends; be; be = be->next)
|
|
|
|
if (!strcmp(be->name, name))
|
|
|
|
return be;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ref_storage_backend_exists(const char *name)
|
|
|
|
{
|
|
|
|
return find_ref_storage_backend(name) != NULL;
|
|
|
|
}
|
|
|
|
|
2012-04-10 07:30:13 +02:00
|
|
|
/*
|
2014-06-04 05:38:10 +02:00
|
|
|
* How to handle various characters in refnames:
|
|
|
|
* 0: An acceptable character for refs
|
2014-07-28 19:41:53 +02:00
|
|
|
* 1: End-of-component
|
|
|
|
* 2: ., look for a preceding . to reject .. in refs
|
|
|
|
* 3: {, look for a preceding @ to reject @{ in refs
|
2015-07-22 23:05:32 +02:00
|
|
|
* 4: A bad character: ASCII control characters, and
|
2015-07-22 23:05:33 +02:00
|
|
|
* ":", "?", "[", "\", "^", "~", SP, or TAB
|
|
|
|
* 5: *, reject unless REFNAME_REFSPEC_PATTERN is set
|
2014-06-04 05:38:10 +02:00
|
|
|
*/
|
|
|
|
static unsigned char refname_disposition[256] = {
|
2014-07-28 19:41:53 +02:00
|
|
|
1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
2015-07-22 23:05:33 +02:00
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 2, 1,
|
2014-07-28 19:41:53 +02:00
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4,
|
2014-06-04 05:38:10 +02:00
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
2014-07-28 19:41:53 +02:00
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 4, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4
|
2014-06-04 05:38:10 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Try to read one refname component from the front of refname.
|
|
|
|
* Return the length of the component found, or -1 if the component is
|
|
|
|
* not legal. It is legal if it is something reasonable to have under
|
|
|
|
* ".git/refs/"; We do not like it if:
|
2012-04-10 07:30:13 +02:00
|
|
|
*
|
2019-03-08 10:28:34 +01:00
|
|
|
* - it begins with ".", or
|
2012-04-10 07:30:13 +02:00
|
|
|
* - it has double dots "..", or
|
2015-07-22 23:05:32 +02:00
|
|
|
* - it has ASCII control characters, or
|
2015-07-22 23:05:33 +02:00
|
|
|
* - it has ":", "?", "[", "\", "^", "~", SP, or TAB anywhere, or
|
|
|
|
* - it has "*" anywhere unless REFNAME_REFSPEC_PATTERN is set, or
|
2015-07-22 23:05:32 +02:00
|
|
|
* - it ends with a "/", or
|
|
|
|
* - it ends with ".lock", or
|
|
|
|
* - it contains a "@{" portion
|
2019-03-08 10:28:34 +01:00
|
|
|
*
|
|
|
|
* When sanitized is not NULL, instead of rejecting the input refname
|
|
|
|
* as an error, try to come up with a usable replacement for the input
|
|
|
|
* refname in it.
|
2012-04-10 07:30:13 +02:00
|
|
|
*/
|
2019-03-08 10:28:34 +01:00
|
|
|
static int check_refname_component(const char *refname, int *flags,
|
|
|
|
struct strbuf *sanitized)
|
2012-04-10 07:30:13 +02:00
|
|
|
{
|
|
|
|
const char *cp;
|
|
|
|
char last = '\0';
|
2019-03-08 10:28:34 +01:00
|
|
|
size_t component_start = 0; /* garbage - not a reasonable initial value */
|
|
|
|
|
|
|
|
if (sanitized)
|
|
|
|
component_start = sanitized->len;
|
2012-04-10 07:30:13 +02:00
|
|
|
|
|
|
|
for (cp = refname; ; cp++) {
|
2014-06-04 05:38:10 +02:00
|
|
|
int ch = *cp & 255;
|
|
|
|
unsigned char disp = refname_disposition[ch];
|
2019-03-08 10:28:34 +01:00
|
|
|
|
|
|
|
if (sanitized && disp != 1)
|
|
|
|
strbuf_addch(sanitized, ch);
|
|
|
|
|
2014-06-04 05:38:10 +02:00
|
|
|
switch (disp) {
|
2014-07-28 19:41:53 +02:00
|
|
|
case 1:
|
2014-06-04 05:38:10 +02:00
|
|
|
goto out;
|
2014-07-28 19:41:53 +02:00
|
|
|
case 2:
|
2019-03-08 10:28:34 +01:00
|
|
|
if (last == '.') { /* Refname contains "..". */
|
|
|
|
if (sanitized)
|
|
|
|
/* collapse ".." to single "." */
|
|
|
|
strbuf_setlen(sanitized, sanitized->len - 1);
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
2014-06-04 05:38:10 +02:00
|
|
|
break;
|
2014-07-28 19:41:53 +02:00
|
|
|
case 3:
|
2019-03-08 10:28:34 +01:00
|
|
|
if (last == '@') { /* Refname contains "@{". */
|
|
|
|
if (sanitized)
|
|
|
|
sanitized->buf[sanitized->len-1] = '-';
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
2012-04-10 07:30:13 +02:00
|
|
|
break;
|
2014-07-28 19:41:53 +02:00
|
|
|
case 4:
|
2019-03-08 10:28:34 +01:00
|
|
|
/* forbidden char */
|
|
|
|
if (sanitized)
|
|
|
|
sanitized->buf[sanitized->len-1] = '-';
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
break;
|
2015-07-22 23:05:33 +02:00
|
|
|
case 5:
|
2019-03-08 10:28:34 +01:00
|
|
|
if (!(*flags & REFNAME_REFSPEC_PATTERN)) {
|
|
|
|
/* refspec can't be a pattern */
|
|
|
|
if (sanitized)
|
|
|
|
sanitized->buf[sanitized->len-1] = '-';
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
2015-07-22 23:05:33 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Unset the pattern flag so that we only accept
|
|
|
|
* a single asterisk for one side of refspec.
|
|
|
|
*/
|
|
|
|
*flags &= ~ REFNAME_REFSPEC_PATTERN;
|
|
|
|
break;
|
2014-06-04 05:38:10 +02:00
|
|
|
}
|
2012-04-10 07:30:13 +02:00
|
|
|
last = ch;
|
|
|
|
}
|
2014-06-04 05:38:10 +02:00
|
|
|
out:
|
2012-04-10 07:30:13 +02:00
|
|
|
if (cp == refname)
|
2012-04-10 07:30:22 +02:00
|
|
|
return 0; /* Component has zero length. */
|
2019-03-08 10:28:34 +01:00
|
|
|
|
|
|
|
if (refname[0] == '.') { /* Component starts with '.'. */
|
|
|
|
if (sanitized)
|
|
|
|
sanitized->buf[component_start] = '-';
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
2014-10-01 12:28:15 +02:00
|
|
|
if (cp - refname >= LOCK_SUFFIX_LEN &&
|
2019-03-08 10:28:34 +01:00
|
|
|
!memcmp(cp - LOCK_SUFFIX_LEN, LOCK_SUFFIX, LOCK_SUFFIX_LEN)) {
|
|
|
|
if (!sanitized)
|
|
|
|
return -1;
|
|
|
|
/* Refname ends with ".lock". */
|
|
|
|
while (strbuf_strip_suffix(sanitized, LOCK_SUFFIX)) {
|
|
|
|
/* try again in case we have .lock.lock */
|
|
|
|
}
|
|
|
|
}
|
2012-04-10 07:30:13 +02:00
|
|
|
return cp - refname;
|
|
|
|
}
|
|
|
|
|
2019-03-08 10:28:34 +01:00
|
|
|
static int check_or_sanitize_refname(const char *refname, int flags,
|
|
|
|
struct strbuf *sanitized)
|
2012-04-10 07:30:13 +02:00
|
|
|
{
|
|
|
|
int component_len, component_count = 0;
|
|
|
|
|
2019-03-08 10:28:34 +01:00
|
|
|
if (!strcmp(refname, "@")) {
|
Add new @ shortcut for HEAD
Typing 'HEAD' is tedious, especially when we can use '@' instead.
The reason for choosing '@' is that it follows naturally from the
ref@op syntax (e.g. HEAD@{u}), except we have no ref, and no
operation, and when we don't have those, it makes sens to assume
'HEAD'.
So now we can use 'git show @~1', and all that goody goodness.
Until now '@' was a valid name, but it conflicts with this idea, so
let's make it invalid. Probably very few people, if any, used this name.
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-02 08:34:30 +02:00
|
|
|
/* Refname is a single character '@'. */
|
2019-03-08 10:28:34 +01:00
|
|
|
if (sanitized)
|
|
|
|
strbuf_addch(sanitized, '-');
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
Add new @ shortcut for HEAD
Typing 'HEAD' is tedious, especially when we can use '@' instead.
The reason for choosing '@' is that it follows naturally from the
ref@op syntax (e.g. HEAD@{u}), except we have no ref, and no
operation, and when we don't have those, it makes sens to assume
'HEAD'.
So now we can use 'git show @~1', and all that goody goodness.
Until now '@' was a valid name, but it conflicts with this idea, so
let's make it invalid. Probably very few people, if any, used this name.
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-02 08:34:30 +02:00
|
|
|
|
2012-04-10 07:30:13 +02:00
|
|
|
while (1) {
|
2019-03-08 10:28:34 +01:00
|
|
|
if (sanitized && sanitized->len)
|
|
|
|
strbuf_complete(sanitized, '/');
|
|
|
|
|
2012-04-10 07:30:13 +02:00
|
|
|
/* We are at the start of a path component. */
|
2019-03-08 10:28:34 +01:00
|
|
|
component_len = check_refname_component(refname, &flags,
|
|
|
|
sanitized);
|
|
|
|
if (sanitized && component_len == 0)
|
|
|
|
; /* OK, omit empty component */
|
|
|
|
else if (component_len <= 0)
|
2015-07-22 23:05:33 +02:00
|
|
|
return -1;
|
|
|
|
|
2012-04-10 07:30:13 +02:00
|
|
|
component_count++;
|
|
|
|
if (refname[component_len] == '\0')
|
|
|
|
break;
|
|
|
|
/* Skip to next component. */
|
|
|
|
refname += component_len + 1;
|
|
|
|
}
|
|
|
|
|
2019-03-08 10:28:34 +01:00
|
|
|
if (refname[component_len - 1] == '.') {
|
|
|
|
/* Refname ends with '.'. */
|
|
|
|
if (sanitized)
|
|
|
|
; /* omit ending dot */
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
2012-04-10 07:30:13 +02:00
|
|
|
if (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2)
|
|
|
|
return -1; /* Refname has only one component. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-08 10:28:34 +01:00
|
|
|
int check_refname_format(const char *refname, int flags)
|
|
|
|
{
|
|
|
|
return check_or_sanitize_refname(refname, flags, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void sanitize_refname_component(const char *refname, struct strbuf *out)
|
|
|
|
{
|
|
|
|
if (check_or_sanitize_refname(refname, REFNAME_ALLOW_ONELEVEL, out))
|
|
|
|
BUG("sanitizing refname '%s' check returned error", refname);
|
|
|
|
}
|
|
|
|
|
2015-11-10 12:42:36 +01:00
|
|
|
int refname_is_safe(const char *refname)
|
refs.c: allow listing and deleting badly named refs
We currently do not handle badly named refs well:
$ cp .git/refs/heads/master .git/refs/heads/master.....@\*@\\.
$ git branch
fatal: Reference has invalid format: 'refs/heads/master.....@*@\.'
$ git branch -D master.....@\*@\\.
error: branch 'master.....@*@\.' not found.
Users cannot recover from a badly named ref without manually finding
and deleting the loose ref file or appropriate line in packed-refs.
Making that easier will make it easier to tweak the ref naming rules
in the future, for example to forbid shell metacharacters like '`'
and '"', without putting people in a state that is hard to get out of.
So allow "branch --list" to show these refs and allow "branch -d/-D"
and "update-ref -d" to delete them. Other commands (for example to
rename refs) will continue to not handle these refs but can be changed
in later patches.
Details:
In resolving functions, refuse to resolve refs that don't pass the
git-check-ref-format(1) check unless the new RESOLVE_REF_ALLOW_BAD_NAME
flag is passed. Even with RESOLVE_REF_ALLOW_BAD_NAME, refuse to
resolve refs that escape the refs/ directory and do not match the
pattern [A-Z_]* (think "HEAD" and "MERGE_HEAD").
In locking functions, refuse to act on badly named refs unless they
are being deleted and either are in the refs/ directory or match [A-Z_]*.
Just like other invalid refs, flag resolved, badly named refs with the
REF_ISBROKEN flag, treat them as resolving to null_sha1, and skip them
in all iteration functions except for for_each_rawref.
Flag badly named refs (but not symrefs pointing to badly named refs)
with a REF_BAD_NAME flag to make it easier for future callers to
notice and handle them specially. For example, in a later patch
for-each-ref will use this flag to detect refs whose names can confuse
callers parsing for-each-ref output.
In the transaction API, refuse to create or update badly named refs,
but allow deleting them (unless they try to escape refs/ and don't match
[A-Z_]*).
Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-03 20:45:43 +02:00
|
|
|
{
|
2016-04-27 12:39:11 +02:00
|
|
|
const char *rest;
|
|
|
|
|
|
|
|
if (skip_prefix(refname, "refs/", &rest)) {
|
refs.c: allow listing and deleting badly named refs
We currently do not handle badly named refs well:
$ cp .git/refs/heads/master .git/refs/heads/master.....@\*@\\.
$ git branch
fatal: Reference has invalid format: 'refs/heads/master.....@*@\.'
$ git branch -D master.....@\*@\\.
error: branch 'master.....@*@\.' not found.
Users cannot recover from a badly named ref without manually finding
and deleting the loose ref file or appropriate line in packed-refs.
Making that easier will make it easier to tweak the ref naming rules
in the future, for example to forbid shell metacharacters like '`'
and '"', without putting people in a state that is hard to get out of.
So allow "branch --list" to show these refs and allow "branch -d/-D"
and "update-ref -d" to delete them. Other commands (for example to
rename refs) will continue to not handle these refs but can be changed
in later patches.
Details:
In resolving functions, refuse to resolve refs that don't pass the
git-check-ref-format(1) check unless the new RESOLVE_REF_ALLOW_BAD_NAME
flag is passed. Even with RESOLVE_REF_ALLOW_BAD_NAME, refuse to
resolve refs that escape the refs/ directory and do not match the
pattern [A-Z_]* (think "HEAD" and "MERGE_HEAD").
In locking functions, refuse to act on badly named refs unless they
are being deleted and either are in the refs/ directory or match [A-Z_]*.
Just like other invalid refs, flag resolved, badly named refs with the
REF_ISBROKEN flag, treat them as resolving to null_sha1, and skip them
in all iteration functions except for for_each_rawref.
Flag badly named refs (but not symrefs pointing to badly named refs)
with a REF_BAD_NAME flag to make it easier for future callers to
notice and handle them specially. For example, in a later patch
for-each-ref will use this flag to detect refs whose names can confuse
callers parsing for-each-ref output.
In the transaction API, refuse to create or update badly named refs,
but allow deleting them (unless they try to escape refs/ and don't match
[A-Z_]*).
Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-03 20:45:43 +02:00
|
|
|
char *buf;
|
|
|
|
int result;
|
2016-04-27 12:40:39 +02:00
|
|
|
size_t restlen = strlen(rest);
|
|
|
|
|
|
|
|
/* rest must not be empty, or start or end with "/" */
|
|
|
|
if (!restlen || *rest == '/' || rest[restlen - 1] == '/')
|
|
|
|
return 0;
|
refs.c: allow listing and deleting badly named refs
We currently do not handle badly named refs well:
$ cp .git/refs/heads/master .git/refs/heads/master.....@\*@\\.
$ git branch
fatal: Reference has invalid format: 'refs/heads/master.....@*@\.'
$ git branch -D master.....@\*@\\.
error: branch 'master.....@*@\.' not found.
Users cannot recover from a badly named ref without manually finding
and deleting the loose ref file or appropriate line in packed-refs.
Making that easier will make it easier to tweak the ref naming rules
in the future, for example to forbid shell metacharacters like '`'
and '"', without putting people in a state that is hard to get out of.
So allow "branch --list" to show these refs and allow "branch -d/-D"
and "update-ref -d" to delete them. Other commands (for example to
rename refs) will continue to not handle these refs but can be changed
in later patches.
Details:
In resolving functions, refuse to resolve refs that don't pass the
git-check-ref-format(1) check unless the new RESOLVE_REF_ALLOW_BAD_NAME
flag is passed. Even with RESOLVE_REF_ALLOW_BAD_NAME, refuse to
resolve refs that escape the refs/ directory and do not match the
pattern [A-Z_]* (think "HEAD" and "MERGE_HEAD").
In locking functions, refuse to act on badly named refs unless they
are being deleted and either are in the refs/ directory or match [A-Z_]*.
Just like other invalid refs, flag resolved, badly named refs with the
REF_ISBROKEN flag, treat them as resolving to null_sha1, and skip them
in all iteration functions except for for_each_rawref.
Flag badly named refs (but not symrefs pointing to badly named refs)
with a REF_BAD_NAME flag to make it easier for future callers to
notice and handle them specially. For example, in a later patch
for-each-ref will use this flag to detect refs whose names can confuse
callers parsing for-each-ref output.
In the transaction API, refuse to create or update badly named refs,
but allow deleting them (unless they try to escape refs/ and don't match
[A-Z_]*).
Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-03 20:45:43 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Does the refname try to escape refs/?
|
|
|
|
* For example: refs/foo/../bar is safe but refs/foo/../../bar
|
|
|
|
* is not.
|
|
|
|
*/
|
2016-04-27 12:40:39 +02:00
|
|
|
buf = xmallocz(restlen);
|
|
|
|
result = !normalize_path_copy(buf, rest) && !strcmp(buf, rest);
|
refs.c: allow listing and deleting badly named refs
We currently do not handle badly named refs well:
$ cp .git/refs/heads/master .git/refs/heads/master.....@\*@\\.
$ git branch
fatal: Reference has invalid format: 'refs/heads/master.....@*@\.'
$ git branch -D master.....@\*@\\.
error: branch 'master.....@*@\.' not found.
Users cannot recover from a badly named ref without manually finding
and deleting the loose ref file or appropriate line in packed-refs.
Making that easier will make it easier to tweak the ref naming rules
in the future, for example to forbid shell metacharacters like '`'
and '"', without putting people in a state that is hard to get out of.
So allow "branch --list" to show these refs and allow "branch -d/-D"
and "update-ref -d" to delete them. Other commands (for example to
rename refs) will continue to not handle these refs but can be changed
in later patches.
Details:
In resolving functions, refuse to resolve refs that don't pass the
git-check-ref-format(1) check unless the new RESOLVE_REF_ALLOW_BAD_NAME
flag is passed. Even with RESOLVE_REF_ALLOW_BAD_NAME, refuse to
resolve refs that escape the refs/ directory and do not match the
pattern [A-Z_]* (think "HEAD" and "MERGE_HEAD").
In locking functions, refuse to act on badly named refs unless they
are being deleted and either are in the refs/ directory or match [A-Z_]*.
Just like other invalid refs, flag resolved, badly named refs with the
REF_ISBROKEN flag, treat them as resolving to null_sha1, and skip them
in all iteration functions except for for_each_rawref.
Flag badly named refs (but not symrefs pointing to badly named refs)
with a REF_BAD_NAME flag to make it easier for future callers to
notice and handle them specially. For example, in a later patch
for-each-ref will use this flag to detect refs whose names can confuse
callers parsing for-each-ref output.
In the transaction API, refuse to create or update badly named refs,
but allow deleting them (unless they try to escape refs/ and don't match
[A-Z_]*).
Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-03 20:45:43 +02:00
|
|
|
free(buf);
|
|
|
|
return result;
|
|
|
|
}
|
2016-04-27 12:42:27 +02:00
|
|
|
|
|
|
|
do {
|
refs.c: allow listing and deleting badly named refs
We currently do not handle badly named refs well:
$ cp .git/refs/heads/master .git/refs/heads/master.....@\*@\\.
$ git branch
fatal: Reference has invalid format: 'refs/heads/master.....@*@\.'
$ git branch -D master.....@\*@\\.
error: branch 'master.....@*@\.' not found.
Users cannot recover from a badly named ref without manually finding
and deleting the loose ref file or appropriate line in packed-refs.
Making that easier will make it easier to tweak the ref naming rules
in the future, for example to forbid shell metacharacters like '`'
and '"', without putting people in a state that is hard to get out of.
So allow "branch --list" to show these refs and allow "branch -d/-D"
and "update-ref -d" to delete them. Other commands (for example to
rename refs) will continue to not handle these refs but can be changed
in later patches.
Details:
In resolving functions, refuse to resolve refs that don't pass the
git-check-ref-format(1) check unless the new RESOLVE_REF_ALLOW_BAD_NAME
flag is passed. Even with RESOLVE_REF_ALLOW_BAD_NAME, refuse to
resolve refs that escape the refs/ directory and do not match the
pattern [A-Z_]* (think "HEAD" and "MERGE_HEAD").
In locking functions, refuse to act on badly named refs unless they
are being deleted and either are in the refs/ directory or match [A-Z_]*.
Just like other invalid refs, flag resolved, badly named refs with the
REF_ISBROKEN flag, treat them as resolving to null_sha1, and skip them
in all iteration functions except for for_each_rawref.
Flag badly named refs (but not symrefs pointing to badly named refs)
with a REF_BAD_NAME flag to make it easier for future callers to
notice and handle them specially. For example, in a later patch
for-each-ref will use this flag to detect refs whose names can confuse
callers parsing for-each-ref output.
In the transaction API, refuse to create or update badly named refs,
but allow deleting them (unless they try to escape refs/ and don't match
[A-Z_]*).
Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-03 20:45:43 +02:00
|
|
|
if (!isupper(*refname) && *refname != '_')
|
|
|
|
return 0;
|
|
|
|
refname++;
|
2016-04-27 12:42:27 +02:00
|
|
|
} while (*refname);
|
refs.c: allow listing and deleting badly named refs
We currently do not handle badly named refs well:
$ cp .git/refs/heads/master .git/refs/heads/master.....@\*@\\.
$ git branch
fatal: Reference has invalid format: 'refs/heads/master.....@*@\.'
$ git branch -D master.....@\*@\\.
error: branch 'master.....@*@\.' not found.
Users cannot recover from a badly named ref without manually finding
and deleting the loose ref file or appropriate line in packed-refs.
Making that easier will make it easier to tweak the ref naming rules
in the future, for example to forbid shell metacharacters like '`'
and '"', without putting people in a state that is hard to get out of.
So allow "branch --list" to show these refs and allow "branch -d/-D"
and "update-ref -d" to delete them. Other commands (for example to
rename refs) will continue to not handle these refs but can be changed
in later patches.
Details:
In resolving functions, refuse to resolve refs that don't pass the
git-check-ref-format(1) check unless the new RESOLVE_REF_ALLOW_BAD_NAME
flag is passed. Even with RESOLVE_REF_ALLOW_BAD_NAME, refuse to
resolve refs that escape the refs/ directory and do not match the
pattern [A-Z_]* (think "HEAD" and "MERGE_HEAD").
In locking functions, refuse to act on badly named refs unless they
are being deleted and either are in the refs/ directory or match [A-Z_]*.
Just like other invalid refs, flag resolved, badly named refs with the
REF_ISBROKEN flag, treat them as resolving to null_sha1, and skip them
in all iteration functions except for for_each_rawref.
Flag badly named refs (but not symrefs pointing to badly named refs)
with a REF_BAD_NAME flag to make it easier for future callers to
notice and handle them specially. For example, in a later patch
for-each-ref will use this flag to detect refs whose names can confuse
callers parsing for-each-ref output.
In the transaction API, refuse to create or update badly named refs,
but allow deleting them (unless they try to escape refs/ and don't match
[A-Z_]*).
Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-03 20:45:43 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-06-23 09:01:37 +02:00
|
|
|
/*
|
|
|
|
* Return true if refname, which has the specified oid and flags, can
|
|
|
|
* be resolved to an object in the database. If the referred-to object
|
|
|
|
* does not exist, emit a warning and return false.
|
|
|
|
*/
|
|
|
|
int ref_resolves_to_object(const char *refname,
|
|
|
|
const struct object_id *oid,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
if (flags & REF_ISBROKEN)
|
|
|
|
return 0;
|
2019-01-07 09:37:54 +01:00
|
|
|
if (!has_object_file(oid)) {
|
2018-07-21 09:49:35 +02:00
|
|
|
error(_("%s does not point to a valid object!"), refname);
|
2017-06-23 09:01:37 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-03-26 04:42:34 +02:00
|
|
|
char *refs_resolve_refdup(struct ref_store *refs,
|
|
|
|
const char *refname, int resolve_flags,
|
refs: convert resolve_refdup and refs_resolve_refdup to struct object_id
All of the callers already pass the hash member of struct object_id, so
update them to pass a pointer to the struct directly,
This transformation was done with an update to declaration and
definition and the following semantic patch:
@@
expression E1, E2, E3, E4;
@@
- resolve_refdup(E1, E2, E3.hash, E4)
+ resolve_refdup(E1, E2, &E3, E4)
@@
expression E1, E2, E3, E4;
@@
- resolve_refdup(E1, E2, E3->hash, E4)
+ resolve_refdup(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-16 00:06:55 +02:00
|
|
|
struct object_id *oid, int *flags)
|
2017-03-26 04:42:34 +02:00
|
|
|
{
|
|
|
|
const char *result;
|
|
|
|
|
|
|
|
result = refs_resolve_ref_unsafe(refs, refname, resolve_flags,
|
refs: convert resolve_ref_unsafe to struct object_id
Convert resolve_ref_unsafe to take a pointer to struct object_id by
converting one remaining caller to use struct object_id, removing the
temporary NULL pointer check in expand_ref, converting the declaration
and definition, and applying the following semantic patch:
@@
expression E1, E2, E3, E4;
@@
- resolve_ref_unsafe(E1, E2, E3.hash, E4)
+ resolve_ref_unsafe(E1, E2, &E3, E4)
@@
expression E1, E2, E3, E4;
@@
- resolve_ref_unsafe(E1, E2, E3->hash, E4)
+ resolve_ref_unsafe(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-16 00:07:09 +02:00
|
|
|
oid, flags);
|
2017-03-26 04:42:34 +02:00
|
|
|
return xstrdup_or_null(result);
|
|
|
|
}
|
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
char *resolve_refdup(const char *refname, int resolve_flags,
|
refs: convert resolve_refdup and refs_resolve_refdup to struct object_id
All of the callers already pass the hash member of struct object_id, so
update them to pass a pointer to the struct directly,
This transformation was done with an update to declaration and
definition and the following semantic patch:
@@
expression E1, E2, E3, E4;
@@
- resolve_refdup(E1, E2, E3.hash, E4)
+ resolve_refdup(E1, E2, &E3, E4)
@@
expression E1, E2, E3, E4;
@@
- resolve_refdup(E1, E2, E3->hash, E4)
+ resolve_refdup(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-16 00:06:55 +02:00
|
|
|
struct object_id *oid, int *flags)
|
Start handling references internally as a sorted in-memory list
This also adds some very rudimentary support for the notion of packed
refs. HOWEVER! At this point it isn't used to actually look up a ref
yet, only for listing them (ie "for_each_ref()" and friends see the
packed refs, but none of the other single-ref lookup routines).
Note how we keep two separate lists: one for the loose refs, and one for
the packed refs we read. That's so that we can easily keep the two apart,
and read only one set or the other (and still always make sure that the
loose refs take precedence).
[ From this, it's not actually obvious why we'd keep the two separate
lists, but it's important to have the packed refs on their own list
later on, when I add support for looking up a single loose one.
For that case, we will want to read _just_ the packed refs in case the
single-ref lookup fails, yet we may end up needing the other list at
some point in the future, so keeping them separated is important ]
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-12 01:37:32 +02:00
|
|
|
{
|
2018-04-12 02:21:09 +02:00
|
|
|
return refs_resolve_refdup(get_main_ref_store(the_repository),
|
2017-03-26 04:42:34 +02:00
|
|
|
refname, resolve_flags,
|
refs: convert resolve_refdup and refs_resolve_refdup to struct object_id
All of the callers already pass the hash member of struct object_id, so
update them to pass a pointer to the struct directly,
This transformation was done with an update to declaration and
definition and the following semantic patch:
@@
expression E1, E2, E3, E4;
@@
- resolve_refdup(E1, E2, E3.hash, E4)
+ resolve_refdup(E1, E2, &E3, E4)
@@
expression E1, E2, E3, E4;
@@
- resolve_refdup(E1, E2, E3->hash, E4)
+ resolve_refdup(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-16 00:06:55 +02:00
|
|
|
oid, flags);
|
2011-12-12 06:38:22 +01:00
|
|
|
}
|
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
/* The argument to filter_refs */
|
|
|
|
struct ref_filter {
|
|
|
|
const char *pattern;
|
2018-11-12 14:25:44 +01:00
|
|
|
const char *prefix;
|
2015-11-09 14:34:01 +01:00
|
|
|
each_ref_fn *fn;
|
|
|
|
void *cb_data;
|
|
|
|
};
|
2012-04-10 07:30:26 +02:00
|
|
|
|
2017-03-26 04:42:34 +02:00
|
|
|
int refs_read_ref_full(struct ref_store *refs, const char *refname,
|
2017-10-16 00:06:56 +02:00
|
|
|
int resolve_flags, struct object_id *oid, int *flags)
|
2012-04-10 07:30:21 +02:00
|
|
|
{
|
refs: convert resolve_ref_unsafe to struct object_id
Convert resolve_ref_unsafe to take a pointer to struct object_id by
converting one remaining caller to use struct object_id, removing the
temporary NULL pointer check in expand_ref, converting the declaration
and definition, and applying the following semantic patch:
@@
expression E1, E2, E3, E4;
@@
- resolve_ref_unsafe(E1, E2, E3.hash, E4)
+ resolve_ref_unsafe(E1, E2, &E3, E4)
@@
expression E1, E2, E3, E4;
@@
- resolve_ref_unsafe(E1, E2, E3->hash, E4)
+ resolve_ref_unsafe(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-16 00:07:09 +02:00
|
|
|
if (refs_resolve_ref_unsafe(refs, refname, resolve_flags, oid, flags))
|
2015-11-09 14:34:01 +01:00
|
|
|
return 0;
|
|
|
|
return -1;
|
2012-04-10 07:30:21 +02:00
|
|
|
}
|
|
|
|
|
2017-10-16 00:06:56 +02:00
|
|
|
int read_ref_full(const char *refname, int resolve_flags, struct object_id *oid, int *flags)
|
2017-03-26 04:42:34 +02:00
|
|
|
{
|
2018-04-12 02:21:09 +02:00
|
|
|
return refs_read_ref_full(get_main_ref_store(the_repository), refname,
|
2017-10-16 00:06:56 +02:00
|
|
|
resolve_flags, oid, flags);
|
2017-03-26 04:42:34 +02:00
|
|
|
}
|
|
|
|
|
2017-10-16 00:06:56 +02:00
|
|
|
int read_ref(const char *refname, struct object_id *oid)
|
2011-12-12 06:38:22 +01:00
|
|
|
{
|
2017-10-16 00:06:56 +02:00
|
|
|
return read_ref_full(refname, RESOLVE_REF_READING, oid, NULL);
|
2007-04-17 03:42:50 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 18:59:34 +02:00
|
|
|
int refs_ref_exists(struct ref_store *refs, const char *refname)
|
2019-04-06 13:34:24 +02:00
|
|
|
{
|
|
|
|
return !!refs_resolve_ref_unsafe(refs, refname, RESOLVE_REF_READING, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
int ref_exists(const char *refname)
|
2012-04-10 07:30:13 +02:00
|
|
|
{
|
2019-04-06 13:34:24 +02:00
|
|
|
return refs_ref_exists(get_main_ref_store(the_repository), refname);
|
2012-04-10 07:30:13 +02:00
|
|
|
}
|
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
static int filter_refs(const char *refname, const struct object_id *oid,
|
|
|
|
int flags, void *data)
|
2012-04-10 07:30:26 +02:00
|
|
|
{
|
2015-11-09 14:34:01 +01:00
|
|
|
struct ref_filter *filter = (struct ref_filter *)data;
|
|
|
|
|
2017-06-22 23:38:08 +02:00
|
|
|
if (wildmatch(filter->pattern, refname, 0))
|
2015-11-09 14:34:01 +01:00
|
|
|
return 0;
|
2018-11-12 14:25:44 +01:00
|
|
|
if (filter->prefix)
|
|
|
|
skip_prefix(refname, filter->prefix, &refname);
|
2015-11-09 14:34:01 +01:00
|
|
|
return filter->fn(refname, oid, flags, filter->cb_data);
|
2012-04-10 07:30:26 +02:00
|
|
|
}
|
|
|
|
|
2017-10-16 00:07:10 +02:00
|
|
|
enum peel_status peel_object(const struct object_id *name, struct object_id *oid)
|
2007-04-17 03:42:50 +02:00
|
|
|
{
|
2021-04-13 09:16:36 +02:00
|
|
|
struct object *o = lookup_unknown_object(the_repository, name);
|
2007-04-17 03:42:50 +02:00
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
if (o->type == OBJ_NONE) {
|
2018-04-25 20:20:59 +02:00
|
|
|
int type = oid_object_info(the_repository, name, NULL);
|
2020-06-17 11:14:08 +02:00
|
|
|
if (type < 0 || !object_as_type(o, type, 0))
|
2015-11-09 14:34:01 +01:00
|
|
|
return PEEL_INVALID;
|
|
|
|
}
|
2012-04-10 07:30:13 +02:00
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
if (o->type != OBJ_TAG)
|
|
|
|
return PEEL_NON_TAG;
|
2012-05-22 23:03:29 +02:00
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
o = deref_tag_noverify(o);
|
|
|
|
if (!o)
|
|
|
|
return PEEL_INVALID;
|
|
|
|
|
2017-10-16 00:07:10 +02:00
|
|
|
oidcpy(oid, &o->oid);
|
2015-11-09 14:34:01 +01:00
|
|
|
return PEEL_PEELED;
|
2012-05-22 23:03:29 +02:00
|
|
|
}
|
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
struct warn_if_dangling_data {
|
|
|
|
FILE *fp;
|
|
|
|
const char *refname;
|
|
|
|
const struct string_list *refnames;
|
|
|
|
const char *msg_fmt;
|
|
|
|
};
|
2012-04-10 07:30:13 +02:00
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
static int warn_if_dangling_symref(const char *refname, const struct object_id *oid,
|
|
|
|
int flags, void *cb_data)
|
|
|
|
{
|
|
|
|
struct warn_if_dangling_data *d = cb_data;
|
|
|
|
const char *resolves_to;
|
2012-04-10 07:30:13 +02:00
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
if (!(flags & REF_ISSYMREF))
|
|
|
|
return 0;
|
2012-04-10 07:30:13 +02:00
|
|
|
|
2017-09-23 11:45:04 +02:00
|
|
|
resolves_to = resolve_ref_unsafe(refname, 0, NULL, NULL);
|
2015-11-09 14:34:01 +01:00
|
|
|
if (!resolves_to
|
|
|
|
|| (d->refname
|
|
|
|
? strcmp(resolves_to, d->refname)
|
|
|
|
: !string_list_has_string(d->refnames, resolves_to))) {
|
|
|
|
return 0;
|
|
|
|
}
|
2012-04-10 07:30:13 +02:00
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
fprintf(d->fp, d->msg_fmt, refname);
|
|
|
|
fputc('\n', d->fp);
|
|
|
|
return 0;
|
2012-04-10 07:30:13 +02:00
|
|
|
}
|
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
|
2012-04-25 00:45:11 +02:00
|
|
|
{
|
2015-11-09 14:34:01 +01:00
|
|
|
struct warn_if_dangling_data data;
|
|
|
|
|
|
|
|
data.fp = fp;
|
|
|
|
data.refname = refname;
|
|
|
|
data.refnames = NULL;
|
|
|
|
data.msg_fmt = msg_fmt;
|
|
|
|
for_each_rawref(warn_if_dangling_symref, &data);
|
2012-04-25 00:45:11 +02:00
|
|
|
}
|
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames)
|
2012-04-10 07:30:26 +02:00
|
|
|
{
|
2015-11-09 14:34:01 +01:00
|
|
|
struct warn_if_dangling_data data;
|
2012-04-10 07:30:26 +02:00
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
data.fp = fp;
|
|
|
|
data.refname = NULL;
|
|
|
|
data.refnames = refnames;
|
|
|
|
data.msg_fmt = msg_fmt;
|
|
|
|
for_each_rawref(warn_if_dangling_symref, &data);
|
2012-04-10 07:30:26 +02:00
|
|
|
}
|
|
|
|
|
2017-03-26 04:42:34 +02:00
|
|
|
int refs_for_each_tag_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
|
|
|
{
|
|
|
|
return refs_for_each_ref_in(refs, "refs/tags/", fn, cb_data);
|
|
|
|
}
|
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
int for_each_tag_ref(each_ref_fn fn, void *cb_data)
|
2012-04-10 07:30:26 +02:00
|
|
|
{
|
2018-04-12 02:21:09 +02:00
|
|
|
return refs_for_each_tag_ref(get_main_ref_store(the_repository), fn, cb_data);
|
2012-04-10 07:30:26 +02:00
|
|
|
}
|
|
|
|
|
2017-03-26 04:42:34 +02:00
|
|
|
int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
|
|
|
{
|
|
|
|
return refs_for_each_ref_in(refs, "refs/heads/", fn, cb_data);
|
2012-04-10 07:30:26 +02:00
|
|
|
}
|
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
int for_each_branch_ref(each_ref_fn fn, void *cb_data)
|
2012-04-10 07:30:26 +02:00
|
|
|
{
|
2018-04-12 02:21:09 +02:00
|
|
|
return refs_for_each_branch_ref(get_main_ref_store(the_repository), fn, cb_data);
|
2012-04-10 07:30:26 +02:00
|
|
|
}
|
|
|
|
|
2017-03-26 04:42:34 +02:00
|
|
|
int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
|
|
|
{
|
|
|
|
return refs_for_each_ref_in(refs, "refs/remotes/", fn, cb_data);
|
2011-12-12 06:38:15 +01:00
|
|
|
}
|
2012-04-10 07:30:26 +02:00
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
int for_each_remote_ref(each_ref_fn fn, void *cb_data)
|
2011-09-30 00:11:42 +02:00
|
|
|
{
|
2018-04-12 02:21:09 +02:00
|
|
|
return refs_for_each_remote_ref(get_main_ref_store(the_repository), fn, cb_data);
|
2011-12-12 06:38:15 +01:00
|
|
|
}
|
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
int head_ref_namespaced(each_ref_fn fn, void *cb_data)
|
|
|
|
{
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
int ret = 0;
|
|
|
|
struct object_id oid;
|
|
|
|
int flag;
|
2007-04-17 03:42:50 +02:00
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
strbuf_addf(&buf, "%sHEAD", get_git_namespace());
|
2017-10-16 00:06:56 +02:00
|
|
|
if (!read_ref_full(buf.buf, RESOLVE_REF_READING, &oid, &flag))
|
2015-11-09 14:34:01 +01:00
|
|
|
ret = fn(buf.buf, &oid, flag, cb_data);
|
|
|
|
strbuf_release(&buf);
|
2007-04-17 03:42:50 +02:00
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
return ret;
|
2011-09-30 00:11:42 +02:00
|
|
|
}
|
2007-04-17 03:42:50 +02:00
|
|
|
|
log: add option to choose which refs to decorate
When `log --decorate` is used, git will decorate commits with all
available refs. While in most cases this may give the desired effect,
under some conditions it can lead to excessively verbose output.
Introduce two command line options, `--decorate-refs=<pattern>` and
`--decorate-refs-exclude=<pattern>` to allow the user to select which
refs are used in decoration.
When "--decorate-refs=<pattern>" is given, only the refs that match the
pattern are used in decoration. The refs that match the pattern when
"--decorate-refs-exclude=<pattern>" is given, are never used in
decoration.
These options follow the same convention for mixing negative and
positive patterns across the system, assuming that the inclusive default
is to match all refs available.
(1) if there is no positive pattern given, pretend as if an
inclusive default positive pattern was given;
(2) for each candidate, reject it if it matches no positive
pattern, or if it matches any one of the negative patterns.
The rules for what is considered a match are slightly different from the
rules used elsewhere.
Commands like `log --glob` assume a trailing '/*' when glob chars are
not present in the pattern. This makes it difficult to specify a single
ref. On the other hand, commands like `describe --match --all` allow
specifying exact refs, but do not have the convenience of allowing
"shorthand refs" like 'refs/heads' or 'heads' to refer to
'refs/heads/*'.
The commands introduced in this patch consider a match if:
(a) the pattern contains globs chars,
and regular pattern matching returns a match.
(b) the pattern does not contain glob chars,
and ref '<pattern>' exists, or if ref exists under '<pattern>/'
This allows both behaviours (allowing single refs and shorthand refs)
yet remaining compatible with existent commands.
Helped-by: Kevin Daudt <me@ikke.info>
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Rafael Ascensão <rafa.almas@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-21 22:33:41 +01:00
|
|
|
void normalize_glob_ref(struct string_list_item *item, const char *prefix,
|
|
|
|
const char *pattern)
|
|
|
|
{
|
|
|
|
struct strbuf normalized_pattern = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (*pattern == '/')
|
|
|
|
BUG("pattern must not start with '/'");
|
|
|
|
|
|
|
|
if (prefix) {
|
|
|
|
strbuf_addstr(&normalized_pattern, prefix);
|
|
|
|
}
|
|
|
|
else if (!starts_with(pattern, "refs/"))
|
|
|
|
strbuf_addstr(&normalized_pattern, "refs/");
|
|
|
|
strbuf_addstr(&normalized_pattern, pattern);
|
|
|
|
strbuf_strip_suffix(&normalized_pattern, "/");
|
|
|
|
|
|
|
|
item->string = strbuf_detach(&normalized_pattern, NULL);
|
|
|
|
item->util = has_glob_specials(pattern) ? NULL : item->string;
|
|
|
|
strbuf_release(&normalized_pattern);
|
|
|
|
}
|
|
|
|
|
2015-11-09 14:34:01 +01:00
|
|
|
int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
|
|
|
|
const char *prefix, void *cb_data)
|
2013-04-22 21:52:18 +02:00
|
|
|
{
|
2015-11-09 14:34:01 +01:00
|
|
|
struct strbuf real_pattern = STRBUF_INIT;
|
|
|
|
struct ref_filter filter;
|
|
|
|
int ret;
|
2010-01-20 10:48:25 +01:00
|
|
|
|
2013-11-30 21:55:40 +01:00
|
|
|
if (!prefix && !starts_with(pattern, "refs/"))
|
2010-01-20 10:48:25 +01:00
|
|
|
strbuf_addstr(&real_pattern, "refs/");
|
2010-01-20 10:48:26 +01:00
|
|
|
else if (prefix)
|
|
|
|
strbuf_addstr(&real_pattern, prefix);
|
2010-01-20 10:48:25 +01:00
|
|
|
strbuf_addstr(&real_pattern, pattern);
|
|
|
|
|
2010-03-12 18:04:26 +01:00
|
|
|
if (!has_glob_specials(pattern)) {
|
2010-02-04 06:23:18 +01:00
|
|
|
/* Append implied '/' '*' if not present. */
|
use strbuf_complete to conditionally append slash
When working with paths in strbufs, we frequently want to
ensure that a directory contains a trailing slash before
appending to it. We can shorten this code (and make the
intent more obvious) by calling strbuf_complete.
Most of these cases are trivially identical conversions, but
there are two things to note:
- in a few cases we did not check that the strbuf is
non-empty (which would lead to an out-of-bounds memory
access). These were generally not triggerable in
practice, either from earlier assertions, or typically
because we would have just fed the strbuf to opendir(),
which would choke on an empty path.
- in a few cases we indexed the buffer with "original_len"
or similar, rather than the current sb->len, and it is
not immediately obvious from the diff that they are the
same. In all of these cases, I manually verified that
the strbuf does not change between the assignment and
the strbuf_complete call.
This does not convert cases which look like:
if (sb->len && !is_dir_sep(sb->buf[sb->len - 1]))
strbuf_addch(sb, '/');
as those are obviously semantically different. Some of these
cases arguably should be doing that, but that is out of
scope for this change, which aims purely for cleanup with no
behavior change (and at least it will make such sites easier
to find and examine in the future, as we can grep for
strbuf_complete).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-24 23:08:35 +02:00
|
|
|
strbuf_complete(&real_pattern, '/');
|
2010-01-20 10:48:25 +01:00
|
|
|
/* No need to check for '*', there is none. */
|
|
|
|
strbuf_addch(&real_pattern, '*');
|
|
|
|
}
|
|
|
|
|
|
|
|
filter.pattern = real_pattern.buf;
|
2018-11-12 14:25:44 +01:00
|
|
|
filter.prefix = prefix;
|
2010-01-20 10:48:25 +01:00
|
|
|
filter.fn = fn;
|
|
|
|
filter.cb_data = cb_data;
|
|
|
|
ret = for_each_ref(filter_refs, &filter);
|
|
|
|
|
|
|
|
strbuf_release(&real_pattern);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-01-20 10:48:26 +01:00
|
|
|
int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)
|
|
|
|
{
|
|
|
|
return for_each_glob_ref_in(fn, pattern, NULL, cb_data);
|
|
|
|
}
|
|
|
|
|
2009-05-13 23:22:04 +02:00
|
|
|
const char *prettify_refname(const char *name)
|
|