refactoring refspecs
cover refactoring refspecs
When working on protocol v2 I noticed that working with refspecs was a little difficult because of the various api's that existed. Some functions expected an array of "const char *" while others expected an array of "struct refspec". In all cases a length parameter needed to be passed as a parameter as well. This makes working with refspecs a little challenging because of the different expectations different parts of the code base have.
This series refactors how refspecs are handled through out the code base by renaming the existing struct refspec to refspec_item and introducing a new 'struct refspec' which is a container of refspec_items, much like how a pathspec contains pathspec_items. This simplifies many callers and makes handling pathspecs a bit easier.
I have some follow on work which I'll build on top of this series, but since this was already getting a bit lengthy at 35 patches I'll save that for another time.
Brandon Williams (35):
refspec: move refspec parsing logic into its own file
refspec: factor out parsing a single refspec
refspec: rename struct refspec to struct refspec_item
refspec: introduce struct refspec
refspec: convert valid_fetch_refspec to use parse_refspec
submodule--helper: convert push_check to use struct refspec
pull: convert get_tracking_branch to use refspec_item_init
transport: convert transport_push to use struct refspec
remote: convert check_push_refs to use struct refspec
remote: convert match_push_refs to use struct refspec
clone: convert cmd_clone to use refspec_item_init
fast-export: convert to use struct refspec
remote: convert push refspecs to struct refspec
remote: convert fetch refspecs to struct refspec
transport-helper: convert to use struct refspec
fetch: convert fetch_one to use struct refspec
fetch: convert refmap to use struct refspec
refspec: remove the deprecated functions
fetch: convert do_fetch to take a struct refspec
fetch: convert get_ref_map to take a struct refspec
fetch: convert prune_refs to take a struct refspec
remote: convert get_stale_heads to take a struct refspec
remote: convert apply_refspecs to take a struct refspec
remote: convert query_refspecs to take a struct refspec
remote: convert get_ref_match to take a struct refspec
remote: convert match_explicit_refs to take a struct refspec
push: check for errors earlier
push: convert to use struct refspec
transport: convert transport_push to take a struct refspec
send-pack: store refspecs in a struct refspec
transport: remove transport_verify_remote_names
http-push: store refspecs in a struct refspec
remote: convert match_push_refs to take a struct refspec
remote: convert check_push_refs to take a struct refspec
submodule: convert push_unpushed_submodules to take a struct refspec
Makefile | 1 + branch.c | 7 +- builtin/clone.c | 13 +- builtin/fast-export.c | 22 +-- builtin/fetch.c | 128 +++++++------- builtin/merge.c | 1 + builtin/pull.c | 9 +- builtin/push.c | 80 ++++----- builtin/remote.c | 37 ++-- builtin/send-pack.c | 24 +-- builtin/submodule--helper.c | 14 +- checkout.c | 5 +- http-push.c | 18 +- refspec.c | 194 +++++++++++++++++++++ refspec.h | 44 +++++ remote.c | 324 ++++++++---------------------------- remote.h | 48 ++---- submodule.c | 19 +-- submodule.h | 3 +- transport-helper.c | 39 ++--- transport.c | 51 ++---- transport.h | 4 +- 22 files changed, 514 insertions(+), 571 deletions(-) create mode 100644 refspec.c create mode 100644 refspec.h
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 1/35 refspec: move refspec parsing logic into its own file
In preperation for performing a refactor on refspec related code, move the refspec parsing logic into its own file.
--- Makefile | 1 + branch.c | 1 + builtin/clone.c | 1 + builtin/fast-export.c | 1 + builtin/fetch.c | 1 + builtin/merge.c | 1 + builtin/pull.c | 1 + builtin/push.c | 1 + builtin/remote.c | 1 + builtin/submodule--helper.c | 1 + checkout.c | 1 + refspec.c | 168 ++++++++++++++++++++++++++++++++++++ refspec.h | 23 +++++ remote.c | 165 +---------------------------------- remote.h | 20 ----- transport-helper.c | 1 + transport.c | 1 + 17 files changed, 205 insertions(+), 184 deletions(-) create mode 100644 refspec.c create mode 100644 refspec.h
Makefile +1 -0
@@ -928,6 +928,7 @@ LIB_OBJS += refs/files-backend.o LIB_OBJS += refs/iterator.o LIB_OBJS += refs/packed-backend.o LIB_OBJS += refs/ref-cache.o +LIB_OBJS += refspec.o LIB_OBJS += ref-filter.o LIB_OBJS += remote.o LIB_OBJS += replace-object.o
branch.c +1 -0
@@ -3,6 +3,7 @@#include "config.h" #include "branch.h" #include "refs.h" +#include "refspec.h" #include "remote.h" #include "commit.h" #include "worktree.h"
builtin/clone.c +1 -0
@@ -14,6 +14,7 @@#include "parse-options.h" #include "fetch-pack.h" #include "refs.h" +#include "refspec.h" #include "tree.h" #include "tree-walk.h" #include "unpack-trees.h"
builtin/fast-export.c +1 -0
@@ -7,6 +7,7 @@#include "cache.h" #include "config.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "object.h" #include "tag.h"
builtin/fetch.c +1 -0
@@ -5,6 +5,7 @@#include "config.h" #include "repository.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "builtin.h" #include "string-list.h"
builtin/merge.c +1 -0
@@ -14,6 +14,7 @@#include "run-command.h" #include "diff.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "diffcore.h" #include "revision.h"
builtin/pull.c +1 -0
@@ -15,6 +15,7 @@#include "remote.h" #include "dir.h" #include "refs.h" +#include "refspec.h" #include "revision.h" #include "submodule.h" #include "submodule-config.h"
builtin/push.c +1 -0
@@ -4,6 +4,7 @@#include "cache.h" #include "config.h" #include "refs.h" +#include "refspec.h" #include "run-command.h" #include "builtin.h" #include "remote.h"
builtin/remote.c +1 -0
@@ -7,6 +7,7 @@#include "strbuf.h" #include "run-command.h" #include "refs.h" +#include "refspec.h" #include "argv-array.h" static const char *const builtin_remote_usage[] = {
builtin/submodule--helper.c +1 -0
@@ -12,6 +12,7 @@#include "run-command.h" #include "remote.h" #include "refs.h" +#include "refspec.h" #include "connect.h" #include "revision.h" #include "diffcore.h"
checkout.c +1 -0
@@ -1,5 +1,6 @@#include "cache.h" #include "remote.h" +#include "refspec.h" #include "checkout.h" struct tracking_name_data {
refspec.c new file +168 -0
168 lines not on this page · raw message
refspec.h new file +23 -0
@@ -0,0 +1,23 @@ +#ifndef REFSPEC_H +#define REFSPEC_H + +#define TAG_REFSPEC "refs/tags/*:refs/tags/*" +const struct refspec *tag_refspec; + +struct refspec { +unsigned force : 1; +unsigned pattern : 1; +unsigned matching : 1; +unsigned exact_sha1 : 1; + +char *src; +char *dst; +}; + +int valid_fetch_refspec(const char *refspec); +struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec); +struct refspec *parse_push_refspec(int nr_refspec, const char **refspec); + +void free_refspec(int nr_refspec, struct refspec *refspec); + +#endif /* REFSPEC_H */
remote.c +1 -164
183 lines not on this page · raw message
remote.h +0 -20
@@ -68,18 +68,6 @@ int for_each_remote(each_remote_fn fn, void *priv);int remote_has_url (struct remote *remote,const char *url); -struct refspec { -unsigned force :1 ; -unsigned pattern :1 ; -unsigned matching :1 ; -unsigned exact_sha1 :1 ; - -char *src; -char *dst; -}; - -extern const struct refspec *tag_refspec; -struct ref {struct ref *next;struct object_id old_oid;
@@ -175,12 +163,6 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);*/ struct ref *ref_remove_duplicates (struct ref *ref_map); -int valid_fetch_refspec (const char *refspec); -struct refspec *parse_fetch_refspec (int nr_refspec,const char **refspec); -extern struct refspec *parse_push_refspec (int nr_refspec,const char **refspec); - -void free_refspec (int nr_refspec,struct refspec *refspec); -extern int query_refspecs (struct refspec *specs,int nr,struct refspec *query);char *apply_refspecs (struct refspec *refspecs,int nr_refspec,const char *name);
@@ -313,8 +295,6 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, intextern int is_empty_cas (const struct push_cas_option *);void apply_push_cas (struct push_cas_option *,struct remote *,struct ref *); -#define TAG_REFSPEC "refs/tags/*:refs/tags/*" -void add_prune_tags_to_fetch_refspec (struct remote *remote);#endif
transport-helper.c +1 -0
@@ -11,6 +11,7 @@#include "sigchain.h" #include "argv-array.h" #include "refs.h" +#include "refspec.h" #include "transport-internal.h" #include "protocol.h"
transport.c +1 -0
@@ -11,6 +11,7 @@#include "bundle.h" #include "dir.h" #include "refs.h" +#include "refspec.h" #include "branch.h" #include "url.h" #include "submodule.h"
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Re: [PATCH 01/35] refspec: move refspec parsing logic into its own file
Quoted 1 line · Brandon Williams
In preperation for performing a refactor on refspec related code, move
Preparation?
Quoted 618 lines
the refspec parsing logic into its own file.
Signed-off-by Brandon Williams <[email protected]>--- Makefile | 1 + branch.c | 1 + builtin/clone.c | 1 + builtin/fast-export.c | 1 + builtin/fetch.c | 1 + builtin/merge.c | 1 + builtin/pull.c | 1 + builtin/push.c | 1 + builtin/remote.c | 1 + builtin/submodule--helper.c | 1 + checkout.c | 1 + refspec.c | 168 ++++++++++++++++++++++++++++++++++++ refspec.h | 23 +++++ remote.c | 165 +---------------------------------- remote.h | 20 ----- transport-helper.c | 1 + transport.c | 1 + 17 files changed, 205 insertions(+), 184 deletions(-) create mode 100644 refspec.c create mode 100644 refspec.hMakefile +1
-0@@ -928,6 +928,7 @@ LIB_OBJS += refs/files-backend.o LIB_OBJS += refs/iterator.o LIB_OBJS += refs/packed-backend.o LIB_OBJS += refs/ref-cache.o +LIB_OBJS += refspec.o LIB_OBJS += ref-filter.o LIB_OBJS += remote.o LIB_OBJS += replace-object.obranch.c +1
-0@@ -3,6 +3,7 @@#include "config.h" #include "branch.h" #include "refs.h" +#include "refspec.h" #include "remote.h" #include "commit.h" #include "worktree.h" builtin/clone.c +1
-0@@ -14,6 +14,7 @@#include "parse-options.h" #include "fetch-pack.h" #include "refs.h" +#include "refspec.h" #include "tree.h" #include "tree-walk.h" #include "unpack-trees.h" builtin/fast-export.c +1
-0@@ -7,6 +7,7 @@#include "cache.h" #include "config.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "object.h" #include "tag.h" builtin/fetch.c +1
-0@@ -5,6 +5,7 @@#include "config.h" #include "repository.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "builtin.h" #include "string-list.h" builtin/merge.c +1
-0@@ -14,6 +14,7 @@#include "run-command.h" #include "diff.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "diffcore.h" #include "revision.h" builtin/pull.c +1
-0@@ -15,6 +15,7 @@#include "remote.h" #include "dir.h" #include "refs.h" +#include "refspec.h" #include "revision.h" #include "submodule.h" #include "submodule-config.h" builtin/push.c +1
-0@@ -4,6 +4,7 @@#include "cache.h" #include "config.h" #include "refs.h" +#include "refspec.h" #include "run-command.h" #include "builtin.h" #include "remote.h" builtin/remote.c +1
-0@@ -7,6 +7,7 @@#include "strbuf.h" #include "run-command.h" #include "refs.h" +#include "refspec.h" #include "argv-array.h" static const char *const builtin_remote_usage[] = {builtin/submodule--helper.c +1
-0@@ -12,6 +12,7 @@#include "run-command.h" #include "remote.h" #include "refs.h" +#include "refspec.h" #include "connect.h" #include "revision.h" #include "diffcore.h" checkout.c +1
-0@@ -1,5 +1,6 @@#include "cache.h" #include "remote.h" +#include "refspec.h" #include "checkout.h" struct tracking_name_data {refspec.c new file +168
-0@@ -0,0 +1,168 @@ +#include "cache.h" +#include "refs.h" +#include "refspec.h" + +static struct refspec s_tag_refspec = { +0 , +1 , +0 , +0 , +"refs/tags/*" , +"refs/tags/*" +}; + +/* See TAG_REFSPEC for the string version */ +const struct refspec *tag_refspec = &s_tag_refspec; + +static struct refspec *parse_refspec_internal (int nr_refspec,const char **refspec,int fetch,int verify) +{ +int i; +struct refspec *rs =xcalloc (nr_refspec,sizeof (*rs)); + +for (i =0 ; i < nr_refspec; i++) { +size_t llen; +int is_glob; +const char *lhs, *rhs; +int flags; + + is_glob =0 ; + + lhs = refspec[i]; +if (*lhs =='+' ) { + rs[i].force =1 ; + lhs++; + } + + rhs =strrchr (lhs,':' ); + +/* +* Before going on, special case ":" (or "+:") as a refspec +* for pushing matching refs. +*/ +if (!fetch && rhs == lhs && rhs[1 ] =='\0' ) { + rs[i].matching =1 ; +continue ; + } + +if (rhs) { +size_t rlen =strlen (++rhs); + is_glob = (1 <= rlen &&strchr (rhs,'*' )); + rs[i].dst =xstrndup (rhs, rlen); + } + + llen = (rhs ? (rhs - lhs -1 ) :strlen (lhs)); +if (1 <= llen &&memchr (lhs,'*' , llen)) { +if ((rhs && !is_glob) || (!rhs && fetch)) + goto invalid; + is_glob =1 ; + }else if (rhs && is_glob) { + goto invalid; + } + + rs[i].pattern = is_glob; + rs[i].src =xstrndup (lhs, llen); + flags =REFNAME_ALLOW_ONELEVEL | (is_glob ?REFNAME_REFSPEC_PATTERN :0 ); + +if (fetch) { +struct object_id unused; + +/* LHS */ +if (!*rs[i].src) + ;/* empty is ok; it means "HEAD" */ +else if (llen ==GIT_SHA1_HEXSZ && !get_oid_hex (rs[i].src, &unused)) + rs[i].exact_sha1 =1 ;/* ok */ +else if (!check_refname_format (rs[i].src, flags)) + ;/* valid looking ref is ok */ +else + goto invalid; +/* RHS */ +if (!rs[i].dst) + ;/* missing is ok; it is the same as empty */ +else if (!*rs[i].dst) + ;/* empty is ok; it means "do not store" */ +else if (!check_refname_format (rs[i].dst, flags)) + ;/* valid looking ref is ok */ +else + goto invalid; + }else { +/* +* LHS +* - empty is allowed; it means delete. +* - when wildcarded, it must be a valid looking ref. +* - otherwise, it must be an extended SHA-1, but +* there is no existing way to validate this. +*/ +if (!*rs[i].src) + ;/* empty is ok */ +else if (is_glob) { +if (check_refname_format (rs[i].src, flags)) + goto invalid; + } +else + ;/* anything goes, for now */ +/* +* RHS +* - missing is allowed, but LHS then must be a +* valid looking ref. +* - empty is not allowed. +* - otherwise it must be a valid looking ref. +*/ +if (!rs[i].dst) { +if (check_refname_format (rs[i].src, flags)) + goto invalid; + }else if (!*rs[i].dst) { + goto invalid; + }else { +if (check_refname_format (rs[i].dst, flags)) + goto invalid; + } + } + } +return rs; + + invalid: +if (verify) { +/* +* nr_refspec must be greater than zero and i must be valid +* since it is only possible to reach this point from within +* the for loop above. +*/ +free_refspec (i+1 , rs); +return NULL ; + } +die ("Invalid refspec '%s'" , refspec[i]); +} + +int valid_fetch_refspec (const char *fetch_refspec_str) +{ +struct refspec *refspec; + + refspec =parse_refspec_internal (1 , &fetch_refspec_str,1 ,1 ); +free_refspec (1 , refspec); +return !!refspec; +} + +struct refspec *parse_fetch_refspec (int nr_refspec,const char **refspec) +{ +return parse_refspec_internal (nr_refspec, refspec,1 ,0 ); +} + +struct refspec *parse_push_refspec (int nr_refspec,const char **refspec) +{ +return parse_refspec_internal (nr_refspec, refspec,0 ,0 ); +} + +void free_refspec (int nr_refspec,struct refspec *refspec) +{ +int i; + +if (!refspec) +return ; + +for (i =0 ; i < nr_refspec; i++) { +free (refspec[i].src); +free (refspec[i].dst); + } +free (refspec); +} +refspec.h new file +23
-0@@ -0,0 +1,23 @@ +#ifndef REFSPEC_H +#define REFSPEC_H + +#define TAG_REFSPEC "refs/tags/*:refs/tags/*" +const struct refspec *tag_refspec; + +struct refspec { +unsigned force : 1; +unsigned pattern : 1; +unsigned matching : 1; +unsigned exact_sha1 : 1; + +char *src; +char *dst; +}; + +int valid_fetch_refspec(const char *refspec); +struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec); +struct refspec *parse_push_refspec(int nr_refspec, const char **refspec); + +void free_refspec(int nr_refspec, struct refspec *refspec); + +#endif /* REFSPEC_H */ remote.c +1
-164@@ -2,6 +2,7 @@#include "config.h" #include "remote.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "diff.h" #include "revision.h" @@ -13,18 +14,6 @@enum map_direction {FROM_SRC ,FROM_DST }; -static struct refspec s_tag_refspec = { -0 , -1 , -0 , -0 , -"refs/tags/*" , -"refs/tags/*" -}; - -/* See TAG_REFSPEC for the string version */ -const struct refspec *tag_refspec = &s_tag_refspec; -struct counted_string {size_t len;const char *s;@@ -499,158 +488,6 @@ static void read_config(void)alias_all_urls (); } -static struct refspec *parse_refspec_internal (int nr_refspec,const char **refspec,int fetch,int verify) -{ -int i; -struct refspec *rs =xcalloc (nr_refspec,sizeof (*rs)); - -for (i =0 ; i < nr_refspec; i++) { -size_t llen; -int is_glob; -const char *lhs, *rhs; -int flags; - - is_glob =0 ; - - lhs = refspec[i]; -if (*lhs =='+' ) { - rs[i].force =1 ; - lhs++; - } - - rhs =strrchr (lhs,':' ); - -/* -* Before going on, special case ":" (or "+:") as a refspec -* for pushing matching refs. -*/ -if (!fetch && rhs == lhs && rhs[1 ] =='\0' ) { - rs[i].matching =1 ; -continue ; - } - -if (rhs) { -size_t rlen =strlen (++rhs); - is_glob = (1 <= rlen &&strchr (rhs,'*' )); - rs[i].dst =xstrndup (rhs, rlen); - } - - llen = (rhs ? (rhs - lhs -1 ) :strlen (lhs)); -if (1 <= llen &&memchr (lhs,'*' , llen)) { -if ((rhs && !is_glob) || (!rhs && fetch)) - goto invalid; - is_glob =1 ; - }else if (rhs && is_glob) { - goto invalid; - } - - rs[i].pattern = is_glob; - rs[i].src =xstrndup (lhs, llen); - flags =REFNAME_ALLOW_ONELEVEL | (is_glob ?REFNAME_REFSPEC_PATTERN :0 ); - -if (fetch) { -struct object_id unused; - -/* LHS */ -if (!*rs[i].src) - ;/* empty is ok; it means "HEAD" */ -else if (llen ==GIT_SHA1_HEXSZ && !get_oid_hex (rs[i].src, &unused)) - rs[i].exact_sha1 =1 ;/* ok */ -else if (!check_refname_format (rs[i].src, flags)) - ;/* valid looking ref is ok */ -else - goto invalid; -/* RHS */ -if (!rs[i].dst) - ;/* missing is ok; it is the same as empty */ -else if (!*rs[i].dst) - ;/* empty is ok; it means "do not store" */ -else if (!check_refname_format (rs[i].dst, flags)) - ;/* valid looking ref is ok */ -else - goto invalid; - }else { -/* -* LHS -* - empty is allowed; it means delete. -* - when wildcarded, it must be a valid looking ref. -* - otherwise, it must be an extended SHA-1, but -* there is no existing way to validate this. -*/ -if (!*rs[i].src) - ;/* empty is ok */ -else if (is_glob) { -if (check_refname_format (rs[i].src, flags)) - goto invalid; - } -else - ;/* anything goes, for now */ -/* -* RHS -* - missing is allowed, but LHS then must be a -* valid looking ref. -* - empty is not allowed. -* - otherwise it must be a valid looking ref. -*/ -if (!rs[i].dst) { -if (check_refname_format (rs[i].src, flags)) - goto invalid; - }else if (!*rs[i].dst) { - goto invalid; - }else { -if (check_refname_format (rs[i].dst, flags)) - goto invalid; - } - } - } -return rs; - - invalid: -if (verify) { -/* -* nr_refspec must be greater than zero and i must be valid -* since it is only possible to reach this point from within -* the for loop above. -*/ -free_refspec (i+1 , rs); -return NULL ; - } -die ("Invalid refspec '%s'" , refspec[i]); -} - -int valid_fetch_refspec (const char *fetch_refspec_str) -{ -struct refspec *refspec; - - refspec =parse_refspec_internal (1 , &fetch_refspec_str,1 ,1 ); -free_refspec (1 , refspec); -return !!refspec; -} - -struct refspec *parse_fetch_refspec (int nr_refspec,const char **refspec) -{ -return parse_refspec_internal (nr_refspec, refspec,1 ,0 ); -} - -struct refspec *parse_push_refspec (int nr_refspec,const char **refspec) -{ -return parse_refspec_internal (nr_refspec, refspec,0 ,0 ); -} - -void free_refspec (int nr_refspec,struct refspec *refspec) -{ -int i; - -if (!refspec) -return ; - -for (i =0 ; i < nr_refspec; i++) { -free (refspec[i].src); -free (refspec[i].dst); - } -free (refspec); -} -static int valid_remote_nick (const char *name) {if (!name[0 ] ||is_dot_or_dotdot (name))remote.h +0
-20@@ -68,18 +68,6 @@ int for_each_remote(each_remote_fn fn, void *priv);int remote_has_url (struct remote *remote,const char *url); -struct refspec { -unsigned force :1 ; -unsigned pattern :1 ; -unsigned matching :1 ; -unsigned exact_sha1 :1 ; - -char *src; -char *dst; -}; - -extern const struct refspec *tag_refspec; -struct ref {struct ref *next;struct object_id old_oid;@@ -175,12 +163,6 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);*/ struct ref *ref_remove_duplicates (struct ref *ref_map); -int valid_fetch_refspec (const char *refspec); -struct refspec *parse_fetch_refspec (int nr_refspec,const char **refspec); -extern struct refspec *parse_push_refspec (int nr_refspec,const char **refspec); - -void free_refspec (int nr_refspec,struct refspec *refspec); -extern int query_refspecs (struct refspec *specs,int nr,struct refspec *query);char *apply_refspecs (struct refspec *refspecs,int nr_refspec,const char *name);@@ -313,8 +295,6 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, intextern int is_empty_cas (const struct push_cas_option *);void apply_push_cas (struct push_cas_option *,struct remote *,struct ref *); -#define TAG_REFSPEC "refs/tags/*:refs/tags/*" -void add_prune_tags_to_fetch_refspec (struct remote *remote);#endif transport-helper.c +1
-0@@ -11,6 +11,7 @@#include "sigchain.h" #include "argv-array.h" #include "refs.h" +#include "refspec.h" #include "transport-internal.h" #include "protocol.h" transport.c +1
-0@@ -11,6 +11,7 @@#include "bundle.h" #include "dir.h" #include "refs.h" +#include "refspec.h" #include "branch.h" #include "url.h" #include "submodule.h"
Re: [PATCH 01/35] refspec: move refspec parsing logic into its own file
Quoted 5 lines · Junio C Hamano
Quoted 1 line · Brandon Williams
In preperation for performing a refactor on refspec related code, move
Preparation?
Oops, I'll fix that.
Signature · 1 line
Brandon Williams
Re: [PATCH 01/35] refspec: move refspec parsing logic into its own file
Quoted 8 lines · Brandon Williams
Quoted 5 lines · Junio C Hamano
Quoted 1 line · Brandon Williams
In preperation for performing a refactor on refspec related code, move
Preparation?
Oops, I'll fix that.
Thanks. And sorry for forcing you to page thru 600+ lines only to find that I commented on only that line. I'll try harder to make sure I trim quotes from my responses.
PATCH 2/35 refspec: factor out parsing a single refspec
In reply to Brandon WilliamsFactor out the logic which parses a single refspec into its own function. This makes it easier to reuse this logic in a future patch.
--- refspec.c | 195 +++++++++++++++++++++++++++++------------------------- 1 file changed, 104 insertions(+), 91 deletions(-)
refspec.c +104 -91
@@ -14,110 +14,123 @@ static struct refspec s_tag_refspec = {/* See TAG_REFSPEC for the string version */ const struct refspec *tag_refspec = &s_tag_refspec; -static struct refspec *parse_refspec_internal (int nr_refspec,const char **refspec,int fetch,int verify) +/* +* Parses 'refspec' and populates 'rs'. returns 1 if successful and 0 if the +* refspec is invalid. +*/ +static int parse_refspec (struct refspec *rs,const char *refspec,int fetch) { -int i; -struct refspec *rs =xcalloc (nr_refspec,sizeof (*rs)); +size_t llen; +int is_glob; +const char *lhs, *rhs; +int flags; -for (i =0 ; i < nr_refspec; i++) { -size_t llen; -int is_glob; -const char *lhs, *rhs; -int flags; + is_glob =0 ; - is_glob =0 ; + lhs = refspec; +if (*lhs =='+' ) { + rs->force =1 ; + lhs++; + } - lhs = refspec[i]; -if (*lhs =='+' ) { - rs[i].force =1 ; - lhs++; - } + rhs =strrchr (lhs,':' ); - rhs =strrchr (lhs,':' ); +/* +* Before going on, special case ":" (or "+:") as a refspec +* for pushing matching refs. +*/ +if (!fetch && rhs == lhs && rhs[1 ] =='\0' ) { + rs->matching =1 ; +return 1 ; + } +if (rhs) { +size_t rlen =strlen (++rhs); + is_glob = (1 <= rlen &&strchr (rhs,'*' )); + rs->dst =xstrndup (rhs, rlen); + } + + llen = (rhs ? (rhs - lhs -1 ) :strlen (lhs)); +if (1 <= llen &&memchr (lhs,'*' , llen)) { +if ((rhs && !is_glob) || (!rhs && fetch)) +return 0 ; + is_glob =1 ; + }else if (rhs && is_glob) { +return 0 ; + } + + rs->pattern = is_glob; + rs->src =xstrndup (lhs, llen); + flags =REFNAME_ALLOW_ONELEVEL | (is_glob ?REFNAME_REFSPEC_PATTERN :0 ); + +if (fetch) { +struct object_id unused; + +/* LHS */ +if (!*rs->src) + ;/* empty is ok; it means "HEAD" */ +else if (llen ==GIT_SHA1_HEXSZ && !get_oid_hex (rs->src, &unused)) + rs->exact_sha1 =1 ;/* ok */ +else if (!check_refname_format (rs->src, flags)) + ;/* valid looking ref is ok */ +else +return 0 ; +/* RHS */ +if (!rs->dst) + ;/* missing is ok; it is the same as empty */ +else if (!*rs->dst) + ;/* empty is ok; it means "do not store" */ +else if (!check_refname_format (rs->dst, flags)) + ;/* valid looking ref is ok */ +else +return 0 ; + }else {/* -* Before going on, special case ":" (or "+:") as a refspec -* for pushing matching refs. +* LHS +* - empty is allowed; it means delete. +* - when wildcarded, it must be a valid looking ref. +* - otherwise, it must be an extended SHA-1, but +* there is no existing way to validate this. */ -if (!fetch && rhs == lhs && rhs[1 ] =='\0' ) { - rs[i].matching =1 ; -continue ; +if (!*rs->src) + ;/* empty is ok */ +else if (is_glob) { +if (check_refname_format (rs->src, flags)) +return 0 ; } - -if (rhs) { -size_t rlen =strlen (++rhs); - is_glob = (1 <= rlen &&strchr (rhs,'*' )); - rs[i].dst =xstrndup (rhs, rlen); +else + ;/* anything goes, for now */ +/* +* RHS +* - missing is allowed, but LHS then must be a +* valid looking ref. +* - empty is not allowed. +* - otherwise it must be a valid looking ref. +*/ +if (!rs->dst) { +if (check_refname_format (rs->src, flags)) +return 0 ; + }else if (!*rs->dst) { +return 0 ; + }else { +if (check_refname_format (rs->dst, flags)) +return 0 ; } + } - llen = (rhs ? (rhs - lhs -1 ) :strlen (lhs)); -if (1 <= llen &&memchr (lhs,'*' , llen)) { -if ((rhs && !is_glob) || (!rhs && fetch)) - goto invalid; - is_glob =1 ; - }else if (rhs && is_glob) { - goto invalid; - } +return 1 ; +} - rs[i].pattern = is_glob; - rs[i].src =xstrndup (lhs, llen); - flags =REFNAME_ALLOW_ONELEVEL | (is_glob ?REFNAME_REFSPEC_PATTERN :0 ); - -if (fetch) { -struct object_id unused; - -/* LHS */ -if (!*rs[i].src) - ;/* empty is ok; it means "HEAD" */ -else if (llen ==GIT_SHA1_HEXSZ && !get_oid_hex (rs[i].src, &unused)) - rs[i].exact_sha1 =1 ;/* ok */ -else if (!check_refname_format (rs[i].src, flags)) - ;/* valid looking ref is ok */ -else - goto invalid; -/* RHS */ -if (!rs[i].dst) - ;/* missing is ok; it is the same as empty */ -else if (!*rs[i].dst) - ;/* empty is ok; it means "do not store" */ -else if (!check_refname_format (rs[i].dst, flags)) - ;/* valid looking ref is ok */ -else - goto invalid; - }else { -/* -* LHS -* - empty is allowed; it means delete. -* - when wildcarded, it must be a valid looking ref. -* - otherwise, it must be an extended SHA-1, but -* there is no existing way to validate this. -*/ -if (!*rs[i].src) - ;/* empty is ok */ -else if (is_glob) { -if (check_refname_format (rs[i].src, flags)) - goto invalid; - } -else - ;/* anything goes, for now */ -/* -* RHS -* - missing is allowed, but LHS then must be a -* valid looking ref. -* - empty is not allowed. -* - otherwise it must be a valid looking ref. -*/ -if (!rs[i].dst) { -if (check_refname_format (rs[i].src, flags)) - goto invalid; - }else if (!*rs[i].dst) { - goto invalid; - }else { -if (check_refname_format (rs[i].dst, flags)) - goto invalid; - } - } +static struct refspec *parse_refspec_internal (int nr_refspec,const char **refspec,int fetch,int verify) +{ +int i; +struct refspec *rs =xcalloc (nr_refspec,sizeof (*rs)); + +for (i =0 ; i < nr_refspec; i++) { +if (!parse_refspec (&rs[i], refspec[i], fetch)) + goto invalid; } +return rs; invalid:
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 3/35 refspec: rename struct refspec to struct refspec_item
In reply to Brandon WilliamsIn preperation for introducing an abstraction around a collection of refspecs (much like how a 'struct pathspec' is a collection of 'struct pathspec_item's) rename the existing 'struct refspec' to 'struct refspec_item'.
--- branch.c | 6 ++--- builtin/clone.c | 4 +-- builtin/fast-export.c | 4 +-- builtin/fetch.c | 12 ++++----- builtin/pull.c | 2 +- builtin/push.c | 4 +-- builtin/remote.c | 8 +++--- builtin/submodule--helper.c | 4 +-- checkout.c | 4 +-- refspec.c | 19 +++++++------- refspec.h | 10 ++++---- remote.c | 50 ++++++++++++++++++------------------- remote.h | 16 ++++++------ transport-helper.c | 2 +- transport.c | 4 +-- 15 files changed, 74 insertions(+), 75 deletions(-)
branch.c +3 -3
@@ -9,7 +9,7 @@#include "worktree.h" struct tracking { -struct refspec spec; +struct refspec_item spec;char *src;const char *remote;int matches;
@@ -219,8 +219,8 @@ int validate_new_branchname(const char *name, struct strbuf *ref, int force)static int check_tracking_branch (struct remote *remote,void *cb_data) {char *tracking_branch = cb_data; -struct refspec query; -memset (&query,0 ,sizeof (struct refspec )); +struct refspec_item query; +memset (&query,0 ,sizeof (struct refspec_item )); query.dst = tracking_branch;return !remote_find_tracking (remote, &query); }
builtin/clone.c +2 -2
@@ -547,7 +547,7 @@ static struct ref *find_remote_branch(const struct ref *refs, const char *branch }static struct ref *wanted_peer_refs (const struct ref *refs, -struct refspec *refspec) +struct refspec_item *refspec) {struct ref *head =copy_ref (find_ref_by_name (refs,"HEAD" ));struct ref *local_refs = head;
@@ -895,7 +895,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)int err =0 , complete_refs_before_fetch =1 ;int submodule_progress; -struct refspec *refspec; +struct refspec_item *refspec;const char *fetch_pattern; fetch_if_missing =0 ;
builtin/fast-export.c +2 -2
@@ -36,7 +36,7 @@ static int use_done_feature;static int no_data;static int full_tree;static struct string_list extra_refs =STRING_LIST_INIT_NODUP ; -static struct refspec *refspecs; +static struct refspec_item *refspecs;static int refspecs_nr;static int anonymize;
@@ -979,7 +979,7 @@ static void handle_deletes(void) {int i;for (i =0 ; i < refspecs_nr; i++) { -struct refspec *refspec = &refspecs[i]; +struct refspec_item *refspec = &refspecs[i];if (*refspec->src)continue ;
builtin/fetch.c +6 -6
@@ -203,7 +203,7 @@ static void add_merge_config(struct ref **head,for (i =0 ; i < branch->merge_nr; i++) {struct ref *rm, **old_tail = *tail; -struct refspec refspec; +struct refspec_item refspec;for (rm = *head; rm; rm = rm->next) {if (branch_merge_matches (branch, i, rm->name)) {
@@ -340,7 +340,7 @@ static void find_non_local_tags(struct transport *transport, }static struct ref *get_ref_map (struct transport *transport, -struct refspec *refspecs,int refspec_count, +struct refspec_item *refspecs,int refspec_count,int tags,int *autotags) {int i;
@@ -371,7 +371,7 @@ static struct ref *get_ref_map(struct transport *transport,argv_array_clear (&ref_prefixes);if (refspec_count) { -struct refspec *fetch_refspec; +struct refspec_item *fetch_refspec;int fetch_refspec_nr;for (i =0 ; i < refspec_count; i++) {
@@ -965,7 +965,7 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)return ret; } -static int prune_refs (struct refspec *refs,int ref_count,struct ref *ref_map, +static int prune_refs (struct refspec_item *refs,int ref_count,struct ref *ref_map,const char *raw_url) {int url_len, i, result =0 ;
@@ -1115,7 +1115,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map) }static int do_fetch (struct transport *transport, -struct refspec *refs,int ref_count) +struct refspec_item *refs,int ref_count) {struct string_list existing_refs =STRING_LIST_INIT_DUP ;struct ref *ref_map;
@@ -1357,7 +1357,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)static int fetch_one (struct remote *remote,int argc,const char **argv,int prune_tags_ok) {static const char **refs =NULL ; -struct refspec *refspec; +struct refspec_item *refspec;int ref_nr =0 ;int j =0 ;int exit_code;
builtin/pull.c +1 -1
@@ -676,7 +676,7 @@ static const char *get_upstream_branch(const char *remote)*/ static const char *get_tracking_branch (const char *remote,const char *refspec) { -struct refspec *spec; +struct refspec_item *spec;const char *spec_src;const char *merge_branch;
builtin/push.c +2 -2
@@ -80,8 +80,8 @@ static const char *map_refspec(const char *ref,return ref;if (remote->push) { -struct refspec query; -memset (&query,0 ,sizeof (struct refspec )); +struct refspec_item query; +memset (&query,0 ,sizeof (struct refspec_item )); query.src = matched->name;if (!query_refspecs (remote->push, remote->push_refspec_nr, &query) && query.dst) {
builtin/remote.c +4 -4
@@ -442,7 +442,7 @@ static int get_push_ref_states_noquery(struct ref_states *states) info->dest =xstrdup (item->string); }for (i =0 ; i < remote->push_refspec_nr; i++) { -struct refspec *spec = remote->push + i; +struct refspec_item *spec = remote->push + i;if (spec->matching) item =string_list_append (&states->push,_ ("(matching)" ));else if (strlen (spec->src))
@@ -462,7 +462,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat {struct ref *ref, *matches;struct ref *fetch_map =NULL , **fetch_map_tail = &fetch_map; -struct refspec refspec; +struct refspec_item refspec; refspec.force =0 ; refspec.pattern =1 ;
@@ -515,7 +515,7 @@ static int add_branch_for_removal(const char *refname, const struct object_id *oid, int flags, void *cb_data) { struct branches_for_remote *branches = cb_data; -struct refspec refspec; +struct refspec_item refspec;struct known_remote *kr;memset (&refspec,0 ,sizeof (refspec));
@@ -834,7 +834,7 @@ static int append_ref_to_tracked_list(const char *refname, const struct object_id *oid, int flags, void *cb_data) { struct ref_states *states = cb_data; -struct refspec refspec; +struct refspec_item refspec;if (flags &REF_ISSYMREF )return 0 ;
builtin/submodule--helper.c +2 -2
@@ -1746,11 +1746,11 @@ static int push_check(int argc, const char **argv, const char *prefix)if (argc >2 ) {int i, refspec_nr = argc -2 ;struct ref *local_refs =get_local_heads (); -struct refspec *refspec =parse_push_refspec (refspec_nr, +struct refspec_item *refspec =parse_push_refspec (refspec_nr, argv +2 );for (i =0 ; i < refspec_nr; i++) { -struct refspec *rs = refspec + i; +struct refspec_item *rs = refspec + i;if (rs->pattern || rs->matching)continue ;
checkout.c +2 -2
@@ -13,8 +13,8 @@ struct tracking_name_data {static int check_tracking_name (struct remote *remote,void *cb_data) {struct tracking_name_data *cb = cb_data; -struct refspec query; -memset (&query,0 ,sizeof (struct refspec )); +struct refspec_item query; +memset (&query,0 ,sizeof (struct refspec_item )); query.src = cb->src_ref;if (remote_find_tracking (remote, &query) ||get_oid (query.dst, cb->dst_oid)) {
refspec.c +9 -10
@@ -2,7 +2,7 @@#include "refs.h" #include "refspec.h" -static struct refspec s_tag_refspec = { +static struct refspec_item s_tag_refspec = {0 ,1 ,0 ,
@@ -12,13 +12,13 @@ static struct refspec s_tag_refspec = { };/* See TAG_REFSPEC for the string version */ -const struct refspec *tag_refspec = &s_tag_refspec; +const struct refspec_item *tag_refspec = &s_tag_refspec;/* * Parses 'refspec' and populates 'rs'. returns 1 if successful and 0 if the * refspec is invalid. */ -static int parse_refspec (struct refspec *rs,const char *refspec,int fetch) +static int parse_refspec (struct refspec_item *rs,const char *refspec,int fetch) {size_t llen;int is_glob;
@@ -121,10 +121,10 @@ static int parse_refspec(struct refspec *rs, const char *refspec, int fetch)return 1 ; } -static struct refspec *parse_refspec_internal (int nr_refspec,const char **refspec,int fetch,int verify) +static struct refspec_item *parse_refspec_internal (int nr_refspec,const char **refspec,int fetch,int verify) {int i; -struct refspec *rs =xcalloc (nr_refspec,sizeof (*rs)); +struct refspec_item *rs =xcalloc (nr_refspec,sizeof (*rs));for (i =0 ; i < nr_refspec; i++) {if (!parse_refspec (&rs[i], refspec[i], fetch))
@@ -148,24 +148,24 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspint valid_fetch_refspec (const char *fetch_refspec_str) { -struct refspec *refspec; +struct refspec_item *refspec; refspec =parse_refspec_internal (1 , &fetch_refspec_str,1 ,1 );free_refspec (1 , refspec);return !!refspec; } -struct refspec *parse_fetch_refspec (int nr_refspec,const char **refspec) +struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec) {return parse_refspec_internal (nr_refspec, refspec,1 ,0 ); } -struct refspec *parse_push_refspec (int nr_refspec,const char **refspec) +struct refspec_item *parse_push_refspec (int nr_refspec,const char **refspec) {return parse_refspec_internal (nr_refspec, refspec,0 ,0 ); } -void free_refspec (int nr_refspec,struct refspec *refspec) +void free_refspec (int nr_refspec,struct refspec_item *refspec) {int i;
@@ -178,4 +178,3 @@ void free_refspec(int nr_refspec, struct refspec *refspec) }free (refspec); } -
refspec.h +5 -5
@@ -2,9 +2,9 @@#define REFSPEC_H #define TAG_REFSPEC "refs/tags/*:refs/tags/*" -const struct refspec *tag_refspec; +const struct refspec_item *tag_refspec; -struct refspec { +struct refspec_item {unsigned force :1 ;unsigned pattern :1 ;unsigned matching :1 ;
@@ -15,9 +15,9 @@ struct refspec { };int valid_fetch_refspec (const char *refspec); -struct refspec *parse_fetch_refspec (int nr_refspec,const char **refspec); -struct refspec *parse_push_refspec (int nr_refspec,const char **refspec); +struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec); +struct refspec_item *parse_push_refspec (int nr_refspec,const char **refspec); -void free_refspec (int nr_refspec,struct refspec *refspec); +void free_refspec (int nr_refspec,struct refspec_item *refspec);#endif /* REFSPEC_H */
remote.c +25 -25
173 lines not on this page · raw message
remote.h +8 -8
@@ -28,12 +28,12 @@ struct remote {int pushurl_alloc;const char **push_refspec; -struct refspec *push; +struct refspec_item *push;int push_refspec_nr;int push_refspec_alloc;const char **fetch_refspec; -struct refspec *fetch; +struct refspec_item *fetch;int fetch_refspec_nr;int fetch_refspec_alloc;
@@ -163,8 +163,8 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);*/ struct ref *ref_remove_duplicates (struct ref *ref_map); -extern int query_refspecs (struct refspec *specs,int nr,struct refspec *query); -char *apply_refspecs (struct refspec *refspecs,int nr_refspec, +extern int query_refspecs (struct refspec_item *specs,int nr,struct refspec_item *query); +char *apply_refspecs (struct refspec_item *refspecs,int nr_refspec,const char *name);int check_push_refs (struct ref *src,int nr_refspec,const char **refspec);
@@ -185,7 +185,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,* missing_ok is usually false, but when we are adding branch.$name.merge * it is Ok if the branch is not at the remote anymore. */ -int get_fetch_map (const struct ref *remote_refs,const struct refspec *refspec, +int get_fetch_map (const struct ref *remote_refs,const struct refspec_item *refspec,struct ref ***tail,int missing_ok);struct ref *get_remote_ref (const struct ref *remote_refs,const char *name);
@@ -193,7 +193,7 @@ struct ref *get_remote_ref(const struct ref *remote_refs, const char *name);/* * For the given remote, reads the refspec's src and sets the other fields. */ -int remote_find_tracking (struct remote *remote,struct refspec *refspec); +int remote_find_tracking (struct remote *remote,struct refspec_item *refspec);struct branch {const char *name;
@@ -203,7 +203,7 @@ struct branch {const char *pushremote_name;const char **merge_name; -struct refspec **merge; +struct refspec_item **merge;int merge_nr;int merge_alloc;
@@ -272,7 +272,7 @@ struct ref *guess_remote_head(const struct ref *head, int all);/* Return refs which no longer exist on remote */ -struct ref *get_stale_heads (struct refspec *refs,int ref_count,struct ref *fetch_map); +struct ref *get_stale_heads (struct refspec_item *refs,int ref_count,struct ref *fetch_map);/* * Compare-and-swap
transport-helper.c +1 -1
@@ -36,7 +36,7 @@ struct helper_data {char *export_marks;char *import_marks;/* These go from remote name (as in "list") to private name */ -struct refspec *refspecs; +struct refspec_item *refspecs;int refspec_nr;/* Transport options for fetch-pack/send-pack (should one of * those be invoked).
transport.c +2 -2
@@ -390,7 +390,7 @@ int transport_refs_pushed(struct ref *ref)void transport_update_tracking_ref (struct remote *remote,struct ref *ref,int verbose) { -struct refspec rs; +struct refspec_item rs;if (ref->status !=REF_STATUS_OK && ref->status !=REF_STATUS_UPTODATE )return ;
@@ -1111,7 +1111,7 @@ int transport_push(struct transport *transport,int porcelain = flags &TRANSPORT_PUSH_PORCELAIN ;int pretend = flags &TRANSPORT_PUSH_DRY_RUN ;int push_ret, ret, err; -struct refspec *tmp_rs; +struct refspec_item *tmp_rs;struct argv_array ref_prefixes =ARGV_ARRAY_INIT ;int i;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Re: [PATCH 03/35] refspec: rename struct refspec to struct refspec_item
Quoted 4 lines · Brandon Williams
In preperation for introducing an abstraction around a collection of refspecs (much like how a 'struct pathspec' is a collection of 'struct pathspec_item's) rename the existing 'struct refspec' to 'struct
refspec_item'.
Makes sense.
refspec.c static struct refspec s_tag_refspec = { · line 21
Quoted 10 lines
/* See
TAG_REFSPECfor the string version */refspec.c +2
-2-const struct refspec *tag_refspec = &s_tag_refspec; +const struct refspec_item *tag_refspec = &s_tag_refspec;/* * Parses 'refspec' and populates 'rs'. returns 1 if successful and 0 if the * refspec is invalid. */ -static int parse_refspec (struct refspec *rs,const char *refspec,int fetch) +static int parse_refspec (struct refspec_item *rs,const char *refspec,int fetch)
The new comment given to the function in the previous step talks in terms of the variable name and not type, so technically it is still valid after this change without updating.
I however wonder if it makes more sense to go one step further and rename the "const char *" variable that is a string form of a single refspec item to something other than "refspec". Which would invalidate the commit you gave to the function and make it necessary to be updated in this step.
I wonder if the early part of the series becomes easier to read if patches 2 and 3 are swapped. That may result in less code/comment churn.
Re: [PATCH 03/35] refspec: rename struct refspec to struct refspec_item
Quoted 30 lines · Junio C Hamano
Quoted 4 lines · Brandon Williams
In preperation for introducing an abstraction around a collection of refspecs (much like how a 'struct pathspec' is a collection of 'struct pathspec_item's) rename the existing 'struct refspec' to 'struct
refspec_item'.Makes sense.
refspec.c static struct refspec s_tag_refspec = { · line 21
Quoted 10 lines
/* See
TAG_REFSPECfor the string version */refspec.c +2
-2-const struct refspec *tag_refspec = &s_tag_refspec; +const struct refspec_item *tag_refspec = &s_tag_refspec;/* * Parses 'refspec' and populates 'rs'. returns 1 if successful and 0 if the * refspec is invalid. */ -static int parse_refspec (struct refspec *rs,const char *refspec,int fetch) +static int parse_refspec (struct refspec_item *rs,const char *refspec,int fetch)The new comment given to the function in the previous step talks in terms of the variable name and not type, so technically it is still valid after this change without updating.
I however wonder if it makes more sense to go one step further and rename the "const char *" variable that is a string form of a single refspec item to something other than "refspec". Which would invalidate the commit you gave to the function and make it necessary to be updated in this step.
Quoted 3 lines
I wonder if the early part of the series becomes easier to read if patches 2 and 3 are swapped. That may result in less code/comment churn.
I'll go ahead and switch these two patches and fixup the comment and function name.
Signature · 1 line
Brandon Williams
PATCH 4/35 refspec: introduce struct refspec
In reply to Brandon WilliamsIntroduce 'struct refspec', an abstraction around a collection of 'struct refspec_item's much like how 'struct pathspec' holds a collection of 'struct pathspec_item's.
A refspec struct also contains an array of the original refspec strings which will be used to facilitate the migration to using this new abstraction throughout the code base.
--- refspec.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ refspec.h | 25 ++++++++++++++++++++++ 2 files changed, 89 insertions(+)
refspec.c +64 -0
@@ -178,3 +178,67 @@ void free_refspec(int nr_refspec, struct refspec_item *refspec) }free (refspec); } + +void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch) +{ +memset (item,0 ,sizeof (*item)); + +if (!parse_refspec (item, refspec, fetch)) +die ("Invalid refspec '%s'" , refspec); +} + +void refspec_item_clear (struct refspec_item *item) +{ +FREE_AND_NULL (item->src); +FREE_AND_NULL (item->dst); + item->force =0 ; + item->pattern =0 ; + item->matching =0 ; + item->exact_sha1 =0 ; +} + +void refspec_init (struct refspec *rs,int fetch) +{ +memset (rs,0 ,sizeof (*rs)); + rs->fetch = fetch; +} + +void refspec_append (struct refspec *rs,const char *refspec) +{ +struct refspec_item item; + +refspec_item_init (&item, refspec, rs->fetch); + +ALLOC_GROW (rs->items, rs->nr +1 , rs->alloc); + rs->items[rs->nr++] = item; + +ALLOC_GROW (rs->raw, rs->raw_nr +1 , rs->raw_alloc); + rs->raw[rs->raw_nr++] =xstrdup (refspec); +} + +void refspec_appendn (struct refspec *rs,const char **refspecs,int nr) +{ +int i; +for (i =0 ; i < nr; i++) +refspec_append (rs, refspecs[i]); +} + +void refspec_clear (struct refspec *rs) +{ +int i; + +for (i =0 ; i < rs->nr; i++) +refspec_item_clear (&rs->items[i]); + +FREE_AND_NULL (rs->items); + rs->alloc =0 ; + rs->nr =0 ; + +for (i =0 ; i < rs->raw_nr; i++) +free ((char *)rs->raw[i]); +FREE_AND_NULL (rs->raw); + rs->raw_alloc =0 ; + rs->raw_nr =0 ; + + rs->fetch =0 ; +}
refspec.h +25 -0
@@ -20,4 +20,29 @@ struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);void free_refspec (int nr_refspec,struct refspec_item *refspec); +#define REFSPEC_FETCH 1 +#define REFSPEC_PUSH 0 + +#define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH } +#define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH } + +struct refspec { +struct refspec_item *items; +int alloc; +int nr; + +const char **raw; +int raw_alloc; +int raw_nr; + +int fetch; +}; + +void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch); +void refspec_item_clear (struct refspec_item *item); +void refspec_init (struct refspec *rs,int fetch); +void refspec_append (struct refspec *rs,const char *refspec); +void refspec_appendn (struct refspec *rs,const char **refspecs,int nr); +void refspec_clear (struct refspec *rs); +#endif /* REFSPEC_H */
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Re: [PATCH 04/35] refspec: introduce struct refspec
refspec.h struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec); · line 24
Quoted 10 lines · Brandon Williams
refspec.h +2
-0@@ -20,4 +20,29 @@ struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);void free_refspec (int nr_refspec,struct refspec_item *refspec); +#define REFSPEC_FETCH 1 +#define REFSPEC_PUSH 0
The reversed order of these two definitions looks somewhat unusual. I guess the reason why you made FETCH true and PUSH false is probably because quite a lot of places in the existing code we do
if (fetch) do the fetch thing; else do the push thing;
i.e. "fetch" variable is used as "is this a fetch: yes/no?" boolean, and a caller that mysteriously passes "1" (or "0") is harder to read than necessary. Being able to pass REFSPEC_PUSH instead of "0" would certainly make the caller easier to read. But as long as the variable is understood as "is_fetch? Yes/no", the caller can pass Yes or No and be still descriptive enough.
I think the way to make such a code more readable would not be to rewrite the above to
if (fetch_or_push) do the fetch thing; else do the push thing;
Rather it would be
if (fetch_or_push == REFSPEC_FETCH) do the fetch thing; else do the push thing;
And once you have gone that far, the actual "enum" value assignment no longer makes difference.
Quoted 23 lines
refspec.h +22
-0+#define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH } +#define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH } + +struct refspec { +struct refspec_item *items; +int alloc; +int nr; + +const char **raw; +int raw_alloc; +int raw_nr; + +int fetch; +}; + +void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch); +void refspec_item_clear (struct refspec_item *item); +void refspec_init (struct refspec *rs,int fetch); +void refspec_append (struct refspec *rs,const char *refspec); +void refspec_appendn (struct refspec *rs,const char **refspecs,int nr); +void refspec_clear (struct refspec *rs); +#endif /* REFSPEC_H */
Re: [PATCH 04/35] refspec: introduce struct refspec
Quoted 8 lines · Junio C Hamano
Quoted 6 lines · Brandon Williams
refspec.h +0
-0@@ -20,4 +20,29 @@ struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);
Quoted 8 lines
refspec.h struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec); · line 24
Quoted 4 lines
refspec.h +2
-0void free_refspec (int nr_refspec,struct refspec_item *refspec); +#define REFSPEC_FETCH 1 +#define REFSPEC_PUSH 0The reversed order of these two definitions looks somewhat unusual. I guess the reason why you made FETCH true and PUSH false is probably because quite a lot of places in the existing code we do
Yeah I really just made the choice based on what the existing logic did (parse_refspec takes in a parameter 'fetch' which is 1 if we are parsing the refspec for a fetch and 0 for push). So it wouldn't be too difficult to go and make this change here since all future callers use the #defines themselves, because it is significantly easier to read 'REFSPEC_PUSH' than to read a 0 like you point out below :)
Quoted 54 lines
if (fetch) do the fetch thing; else do the push thing;i.e. "fetch" variable is used as "is this a fetch: yes/no?" boolean, and a caller that mysteriously passes "1" (or "0") is harder to read than necessary. Being able to pass
REFSPEC_PUSHinstead of "0" would certainly make the caller easier to read. But as long as the variable is understood as "is_fetch? Yes/no", the caller can pass Yes or No and be still descriptive enough.I think the way to make such a code more readable would not be to rewrite the above to
if (fetch_or_push) do the fetch thing; else do the push thing;Rather it would be
if (fetch_or_push == REFSPEC_FETCH) do the fetch thing; else do the push thing;And once you have gone that far, the actual "enum" value assignment no longer makes difference.
Quoted 23 lines
refspec.h +22
-0+#define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH } +#define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH } + +struct refspec { +struct refspec_item *items; +int alloc; +int nr; + +const char **raw; +int raw_alloc; +int raw_nr; + +int fetch; +}; + +void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch); +void refspec_item_clear (struct refspec_item *item); +void refspec_init (struct refspec *rs,int fetch); +void refspec_append (struct refspec *rs,const char *refspec); +void refspec_appendn (struct refspec *rs,const char **refspecs,int nr); +void refspec_clear (struct refspec *rs); +#endif /* REFSPEC_H */
Signature · 1 line
Brandon Williams
PATCH 5/35 refspec: convert valid_fetch_refspec to use parse_refspec
In reply to Brandon WilliamsConvert 'valid_fetch_refspec()' to use the new 'parse_refspec()' function to only parse a single refspec an eliminate an allocation.
--- refspec.c | 17 ++++++++--------- refspec.h | 3 ++- 2 files changed, 10 insertions(+), 10 deletions(-)
refspec.c +8 -9
@@ -146,15 +146,6 @@ static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **die ("Invalid refspec '%s'" , refspec[i]); } -int valid_fetch_refspec (const char *fetch_refspec_str) -{ -struct refspec_item *refspec; - - refspec =parse_refspec_internal (1 , &fetch_refspec_str,1 ,1 ); -free_refspec (1 , refspec); -return !!refspec; -} -struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec) {return parse_refspec_internal (nr_refspec, refspec,1 ,0 );
@@ -242,3 +233,11 @@ void refspec_clear(struct refspec *rs) rs->fetch =0 ; } + +int valid_fetch_refspec (const char *fetch_refspec_str) +{ +struct refspec_item refspec; +int ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH ); +refspec_item_clear (&refspec); +return ret; +}
refspec.h +2 -1
@@ -14,7 +14,6 @@ struct refspec_item {char *dst; }; -int valid_fetch_refspec (const char *refspec);struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec);struct refspec_item *parse_push_refspec (int nr_refspec,const char **refspec);
@@ -45,4 +44,6 @@ void refspec_append(struct refspec *rs, const char *refspec);void refspec_appendn (struct refspec *rs,const char **refspecs,int nr);void refspec_clear (struct refspec *rs); +int valid_fetch_refspec (const char *refspec); +#endif /* REFSPEC_H */
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Re: [PATCH 05/35] refspec: convert valid_fetch_refspec to use parse_refspec
Quoted 2 lines · Brandon Williams
Convert '
valid_fetch_refspec()' to use the new 'parse_refspec()' function to only parse a single refspec an eliminate an allocation.
s/an/and/, perhaps?
Quoted 14 lines
refspec.c +0
-9-int valid_fetch_refspec (const char *fetch_refspec_str) -{ -struct refspec_item *refspec; - - refspec =parse_refspec_internal (1 , &fetch_refspec_str,1 ,1 ); -free_refspec (1 , refspec); -return !!refspec; -} -struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec) {return parse_refspec_internal (nr_refspec, refspec,1 ,0 );@@ -242,3 +233,11 @@ void refspec_clear(struct refspec *rs)
refspec.c void refspec_clear(struct refspec *rs) · line 243
Quoted 10 lines
refspec.c +8
-0rs->fetch =0 ; } + +int valid_fetch_refspec (const char *fetch_refspec_str) +{ +struct refspec_item refspec; +int ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH ); +refspec_item_clear (&refspec); +return ret; +}
Makes quite a lot of sense. The function name may eventually want to become parse_refspec_item(), though?
PATCH 6/35 submodule--helper: convert push_check to use struct refspec
In reply to Brandon WilliamsConvert 'push_check()' to use 'struct refspec'.
--- builtin/submodule--helper.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
builtin/submodule--helper.c +7 -6
@@ -1744,13 +1744,14 @@ static int push_check(int argc, const char **argv, const char *prefix)/* Check the refspec */ if (argc >2 ) { -int i, refspec_nr = argc -2 ; +int i;struct ref *local_refs =get_local_heads (); -struct refspec_item *refspec =parse_push_refspec (refspec_nr, - argv +2 ); +struct refspec refspec =REFSPEC_INIT_PUSH ; -for (i =0 ; i < refspec_nr; i++) { -struct refspec_item *rs = refspec + i; +refspec_appendn (&refspec, argv +2 , argc -2 ); + +for (i =0 ; i < refspec.nr; i++) { +const struct refspec_item *rs = &refspec.items[i];if (rs->pattern || rs->matching)continue ;
@@ -1777,7 +1778,7 @@ static int push_check(int argc, const char **argv, const char *prefix) rs->src); } } -free_refspec (refspec_nr, refspec); +refspec_clear (&refspec); }free (head);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 7/35 pull: convert get_tracking_branch to use refspec_item_init
In reply to Brandon WilliamsConvert 'get_tracking_branch()' to use 'refspec_item_init()' instead of the old 'parse_fetch_refspec()' function.
--- builtin/pull.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
builtin/pull.c +4 -4
@@ -676,12 +676,12 @@ static const char *get_upstream_branch(const char *remote)*/ static const char *get_tracking_branch (const char *remote,const char *refspec) { -struct refspec_item *spec; +struct refspec_item spec;const char *spec_src;const char *merge_branch; - spec =parse_fetch_refspec (1 , &refspec); - spec_src = spec->src; +refspec_item_init (&spec, refspec,REFSPEC_FETCH ); + spec_src = spec.src;if (!*spec_src || !strcmp (spec_src,"HEAD" )) spec_src ="HEAD" ;else if (skip_prefix (spec_src,"heads/" , &spec_src))
@@ -701,7 +701,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec) }else merge_branch =NULL ; -free_refspec (1 , spec); +refspec_item_clear (&spec);return merge_branch; }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 8/35 transport: convert transport_push to use struct refspec
In reply to Brandon WilliamsConvert the logic in 'transport_push()' which calculates a list of ref-prefixes to use 'struct refspec'.
--- transport.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
transport.c +9 -8
@@ -1111,21 +1111,22 @@ int transport_push(struct transport *transport,int porcelain = flags &TRANSPORT_PUSH_PORCELAIN ;int pretend = flags &TRANSPORT_PUSH_DRY_RUN ;int push_ret, ret, err; -struct refspec_item *tmp_rs; +struct refspec tmp_rs =REFSPEC_INIT_PUSH ;struct argv_array ref_prefixes =ARGV_ARRAY_INIT ;int i;if (check_push_refs (local_refs, refspec_nr, refspec) <0 )return -1 ; - tmp_rs =parse_push_refspec (refspec_nr, refspec); -for (i =0 ; i < refspec_nr; i++) { +refspec_appendn (&tmp_rs, refspec, refspec_nr); +for (i =0 ; i < tmp_rs.nr; i++) { +const struct refspec_item *item = &tmp_rs.items[i];const char *prefix =NULL ; -if (tmp_rs[i].dst) - prefix = tmp_rs[i].dst; -else if (tmp_rs[i].src && !tmp_rs[i].exact_sha1) - prefix = tmp_rs[i].src; +if (item->dst) + prefix = item->dst; +else if (item->src && !item->exact_sha1) + prefix = item->src;if (prefix) {const char *glob =strchr (prefix,'*' );
@@ -1142,7 +1143,7 @@ int transport_push(struct transport *transport, &ref_prefixes);argv_array_clear (&ref_prefixes); -free_refspec (refspec_nr, tmp_rs); +refspec_clear (&tmp_rs);if (flags &TRANSPORT_PUSH_ALL ) match_flags |=MATCH_REFS_ALL ;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 9/35 remote: convert check_push_refs to use struct refspec
In reply to Brandon WilliamsConvert 'check_push_refs()' to use 'struct refspec'.
--- remote.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
remote.c +6 -4
@@ -1282,12 +1282,14 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)*/ int check_push_refs (struct ref *src,int nr_refspec,const char **refspec_names) { -struct refspec_item *refspec =parse_push_refspec (nr_refspec, refspec_names); +struct refspec refspec =REFSPEC_INIT_PUSH ;int ret =0 ;int i; -for (i =0 ; i < nr_refspec; i++) { -struct refspec_item *rs = refspec + i; +refspec_appendn (&refspec, refspec_names, nr_refspec); + +for (i =0 ; i < refspec.nr; i++) { +struct refspec_item *rs = &refspec.items[i];if (rs->pattern || rs->matching)continue ;
@@ -1295,7 +1297,7 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names) ret |=match_explicit_lhs (src, rs,NULL ,NULL ); } -free_refspec (nr_refspec, refspec); +refspec_clear (&refspec);return ret; }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 10/35 remote: convert match_push_refs to use struct refspec
In reply to Brandon WilliamsConvert 'match_push_refs()' to use struct refspec.
--- remote.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
remote.c +8 -5
@@ -1312,7 +1312,7 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)int match_push_refs (struct ref *src,struct ref **dst,int nr_refspec,const char **refspec,int flags) { -struct refspec_item *rs; +struct refspec rs =REFSPEC_INIT_PUSH ;int send_all = flags &MATCH_REFS_ALL ;int send_mirror = flags &MATCH_REFS_MIRROR ;int send_prune = flags &MATCH_REFS_PRUNE ;
@@ -1325,8 +1325,8 @@ int match_push_refs(struct ref *src, struct ref **dst, nr_refspec =1 ; refspec = default_refspec; } - rs =parse_push_refspec (nr_refspec, (const char **) refspec); - errs =match_explicit_refs (src, *dst, &dst_tail, rs, nr_refspec); +refspec_appendn (&rs, refspec, nr_refspec); + errs =match_explicit_refs (src, *dst, &dst_tail, rs.items, rs.nr);/* pick the remainder */ for (ref = src; ref; ref = ref->next) {
@@ -1335,7 +1335,7 @@ int match_push_refs(struct ref *src, struct ref **dst,const struct refspec_item *pat =NULL ;char *dst_name; - dst_name =get_ref_match (rs, nr_refspec, ref, send_mirror,FROM_SRC , &pat); + dst_name =get_ref_match (rs.items, rs.nr, ref, send_mirror,FROM_SRC , &pat);if (!dst_name)continue ;
@@ -1384,7 +1384,7 @@ int match_push_refs(struct ref *src, struct ref **dst,/* We're already sending something to this ref. */ continue ; - src_name =get_ref_match (rs, nr_refspec, ref, send_mirror,FROM_DST ,NULL ); + src_name =get_ref_match (rs.items, rs.nr, ref, send_mirror,FROM_DST ,NULL );if (src_name) {if (!src_ref_index.nr)prepare_ref_index (&src_ref_index, src);
@@ -1396,6 +1396,9 @@ int match_push_refs(struct ref *src, struct ref **dst, }string_list_clear (&src_ref_index,0 ); } + +refspec_clear (&rs); +if (errs)return -1 ;return 0 ;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 11/35 clone: convert cmd_clone to use refspec_item_init
In reply to Brandon WilliamsConvert 'cmd_clone()' to use 'refspec_item_init()' instead of relying on the old 'parse_fetch_refspec()' to initialize a single refspec item.
--- builtin/clone.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
builtin/clone.c +4 -6
@@ -895,8 +895,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)int err =0 , complete_refs_before_fetch =1 ;int submodule_progress; -struct refspec_item *refspec; -const char *fetch_pattern; +struct refspec_item refspec; fetch_if_missing =0 ;
@@ -1078,8 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (option_required_reference.nr || option_optional_reference.nr)setup_reference (); - fetch_pattern = value.buf; - refspec =parse_fetch_refspec (1 , &fetch_pattern); +refspec_item_init (&refspec, value.buf,REFSPEC_FETCH );strbuf_reset (&value);
@@ -1139,7 +1137,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) refs =transport_get_remote_refs (transport,NULL );if (refs) { - mapped_refs =wanted_peer_refs (refs, refspec); + mapped_refs =wanted_peer_refs (refs, &refspec);/* * transport_get_remote_refs() may return refs with null sha-1 * in mapped_refs (see struct transport->get_refs_list
@@ -1233,6 +1231,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)strbuf_release (&value); junk_mode =JUNK_LEAVE_ALL ; -free (refspec); +refspec_item_clear (&refspec);return err; }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 12/35 fast-export: convert to use struct refspec
In reply to Brandon WilliamsConvert fast-export to use 'struct refspec' instead of using a list of refspec_item's.
--- builtin/fast-export.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-)
builtin/fast-export.c +7 -14
@@ -36,8 +36,7 @@ static int use_done_feature;static int no_data;static int full_tree;static struct string_list extra_refs =STRING_LIST_INIT_NODUP ; -static struct refspec_item *refspecs; -static int refspecs_nr; +static struct refspec refspecs =REFSPEC_INIT_FETCH ;static int anonymize; static int parse_opt_signed_tag_mode(const struct option *opt,
@@ -830,9 +829,9 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)if (dwim_ref (e->name,strlen (e->name), &oid, &full_name) !=1 )continue ; -if (refspecs) { +if (refspecs.nr) {char *private; - private =apply_refspecs (refspecs, refspecs_nr, full_name); + private =apply_refspecs (refspecs.items, refspecs.nr, full_name);if (private) {free (full_name); full_name = private;
@@ -978,8 +977,8 @@ static void import_marks(char *input_file)static void handle_deletes (void ) {int i; -for (i =0 ; i < refspecs_nr; i++) { -struct refspec_item *refspec = &refspecs[i]; +for (i =0 ; i < refspecs.nr; i++) { +struct refspec_item *refspec = &refspecs.items[i];if (*refspec->src)continue ;
@@ -1040,18 +1039,12 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)usage_with_options (fast_export_usage, options);if (refspecs_list.nr) { -const char **refspecs_str;int i; -ALLOC_ARRAY (refspecs_str, refspecs_list.nr);for (i =0 ; i < refspecs_list.nr; i++) - refspecs_str[i] = refspecs_list.items[i].string; - - refspecs_nr = refspecs_list.nr; - refspecs =parse_fetch_refspec (refspecs_nr, refspecs_str); +refspec_append (&refspecs, refspecs_list.items[i].string);string_list_clear (&refspecs_list,1 ); -free (refspecs_str); }if (use_done_feature)
@@ -1090,7 +1083,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)if (use_done_feature)printf ("done\n" ); -free_refspec (refspecs_nr, refspecs); +refspec_clear (&refspecs);return 0 ; }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 13/35 remote: convert push refspecs to struct refspec
In reply to Brandon WilliamsConvert the set of push refspecs stored in 'struct remote' to use 'struct refspec'.
--- builtin/push.c | 10 +++++----- builtin/remote.c | 14 +++++++------- remote.c | 23 +++++++++-------------- remote.h | 6 ++---- 4 files changed, 23 insertions(+), 30 deletions(-)
builtin/push.c +5 -5
@@ -79,11 +79,11 @@ static const char *map_refspec(const char *ref,if (count_refspec_match (ref, local_refs, &matched) !=1 )return ref; -if (remote->push) { +if (remote->push.nr) {struct refspec_item query;memset (&query,0 ,sizeof (struct refspec_item )); query.src = matched->name; -if (!query_refspecs (remote->push, remote->push_refspec_nr, &query) && +if (!query_refspecs (remote->push.items, remote->push.nr, &query) && query.dst) {struct strbuf buf =STRBUF_INIT ; strbuf_addf(&buf, "%s%s:%s",
@@ -436,9 +436,9 @@ static int do_push(const char *repo, int flags, }if (!refspec && !(flags &TRANSPORT_PUSH_ALL )) { -if (remote->push_refspec_nr) { - refspec = remote->push_refspec; - refspec_nr = remote->push_refspec_nr; +if (remote->push.raw_nr) { + refspec = remote->push.raw; + refspec_nr = remote->push.raw_nr; }else if (!(flags &TRANSPORT_PUSH_MIRROR ))setup_default_push_refspecs (remote); }
builtin/remote.c +7 -7
@@ -388,8 +388,8 @@ static int get_push_ref_states(const struct ref *remote_refs, local_refs =get_local_heads (); push_map =copy_ref_list (remote_refs); -match_push_refs (local_refs, &push_map, remote->push_refspec_nr, - remote->push_refspec,MATCH_REFS_NONE ); +match_push_refs (local_refs, &push_map, remote->push.raw_nr, + remote->push.raw,MATCH_REFS_NONE ); states->push.strdup_strings =1 ;for (ref = push_map; ref; ref = ref->next) {
@@ -435,14 +435,14 @@ static int get_push_ref_states_noquery(struct ref_states *states)return 0 ; states->push.strdup_strings =1 ; -if (!remote->push_refspec_nr) { +if (!remote->push.nr) { item =string_list_append (&states->push,_ ("(matching)" )); info = item->util =xcalloc (1 ,sizeof (struct push_info )); info->status =PUSH_STATUS_NOTQUERIED ; info->dest =xstrdup (item->string); } -for (i =0 ; i < remote->push_refspec_nr; i++) { -struct refspec_item *spec = remote->push + i; +for (i =0 ; i < remote->push.nr; i++) { +const struct refspec_item *spec = &remote->push.items[i];if (spec->matching) item =string_list_append (&states->push,_ ("(matching)" ));else if (strlen (spec->src))
@@ -586,8 +586,8 @@ static int migrate_file(struct remote *remote)git_config_set_multivar (buf.buf, remote->url[i],"^$" ,0 );strbuf_reset (&buf);strbuf_addf (&buf,"remote.%s.push" , remote->name); -for (i =0 ; i < remote->push_refspec_nr; i++) -git_config_set_multivar (buf.buf, remote->push_refspec[i],"^$" ,0 ); +for (i =0 ; i < remote->push.raw_nr; i++) +git_config_set_multivar (buf.buf, remote->push.raw[i],"^$" ,0 );strbuf_reset (&buf);strbuf_addf (&buf,"remote.%s.fetch" , remote->name);for (i =0 ; i < remote->fetch_refspec_nr; i++)
remote.c +9 -14
@@ -79,10 +79,7 @@ static const char *alias_url(const char *url, struct rewrites *r)static void add_push_refspec (struct remote *remote,const char *ref) { -ALLOC_GROW (remote->push_refspec, - remote->push_refspec_nr +1 , - remote->push_refspec_alloc); - remote->push_refspec[remote->push_refspec_nr++] = ref; +refspec_append (&remote->push, ref); }static void add_fetch_refspec (struct remote *remote,const char *ref)
@@ -175,9 +172,11 @@ static struct remote *make_remote(const char *name, int len) ret =xcalloc (1 ,sizeof (struct remote )); ret->prune =-1 ;/* unspecified */ ret->prune_tags =-1 ;/* unspecified */ + ret->name =xstrndup (name, len); +refspec_init (&ret->push,REFSPEC_PUSH ); +ALLOC_GROW (remotes, remotes_nr +1 , remotes_alloc); remotes[remotes_nr++] = ret; - ret->name =xstrndup (name, len);hashmap_entry_init (ret, lookup_entry.hash); replaced =hashmap_put (&remotes_hash, ret);
@@ -542,9 +541,9 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push,pushremote_for_branch (branch,NULL );struct remote *remote =remote_get (remote_name); -if (remote && remote->push_refspec_nr && - (dst =apply_refspecs (remote->push, - remote->push_refspec_nr, +if (remote && remote->push.nr && + (dst =apply_refspecs (remote->push.items, + remote->push.nr, branch->refname))) {if (explicit) *explicit =1 ;
@@ -582,7 +581,6 @@ static struct remote *remote_get_1(const char *name,if (!valid_remote (ret))return NULL ; ret->fetch =parse_fetch_refspec (ret->fetch_refspec_nr, ret->fetch_refspec); - ret->push =parse_push_refspec (ret->push_refspec_nr, ret->push_refspec);return ret; }
@@ -616,9 +614,6 @@ int for_each_remote(each_remote_fn fn, void *priv)if (!r->fetch) r->fetch =parse_fetch_refspec (r->fetch_refspec_nr, r->fetch_refspec); -if (!r->push) - r->push =parse_push_refspec (r->push_refspec_nr, - r->push_refspec); result =fn (r, priv); }return result;
@@ -1613,11 +1608,11 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err)_ ("branch '%s' has no remote for pushing" ), branch->name); -if (remote->push_refspec_nr) { +if (remote->push.nr) {char *dst;const char *ret; - dst =apply_refspecs (remote->push, remote->push_refspec_nr, + dst =apply_refspecs (remote->push.items, remote->push.nr, branch->refname);if (!dst) return error_buf(err,
remote.h +2 -4
@@ -3,6 +3,7 @@#include "parse-options.h" #include "hashmap.h" +#include "refspec.h" enum {REMOTE_UNCONFIGURED =0 ,
@@ -27,10 +28,7 @@ struct remote {int pushurl_nr;int pushurl_alloc; -const char **push_refspec; -struct refspec_item *push; -int push_refspec_nr; -int push_refspec_alloc; +struct refspec push;const char **fetch_refspec;struct refspec_item *fetch;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 14/35 remote: convert fetch refspecs to struct refspec
In reply to Brandon WilliamsConvert the set of fetch refspecs stored in 'struct remote' to use 'struct refspec'.
--- builtin/fetch.c | 20 ++++++++++---------- builtin/remote.c | 18 +++++++++--------- remote.c | 24 ++++++------------------ remote.h | 5 +---- 4 files changed, 26 insertions(+), 41 deletions(-)
builtin/fetch.c +10 -10
@@ -407,8 +407,8 @@ static struct ref *get_ref_map(struct transport *transport, fetch_refspec =parse_fetch_refspec (refmap_nr, refmap_array); fetch_refspec_nr = refmap_nr; }else { - fetch_refspec = transport->remote->fetch; - fetch_refspec_nr = transport->remote->fetch_refspec_nr; + fetch_refspec = transport->remote->fetch.items; + fetch_refspec_nr = transport->remote->fetch.nr; }for (i =0 ; i < fetch_refspec_nr; i++)
@@ -421,16 +421,16 @@ static struct ref *get_ref_map(struct transport *transport,struct branch *branch =branch_get (NULL );int has_merge =branch_has_merge_config (branch);if (remote && - (remote->fetch_refspec_nr || + (remote->fetch.nr ||/* Note: has_merge implies non-NULL branch->remote_name */ (has_merge && !strcmp (branch->remote_name, remote->name)))) { -for (i =0 ; i < remote->fetch_refspec_nr; i++) { -get_fetch_map (remote_refs, &remote->fetch[i], &tail,0 ); -if (remote->fetch[i].dst && - remote->fetch[i].dst[0 ]) +for (i =0 ; i < remote->fetch.nr; i++) { +get_fetch_map (remote_refs, &remote->fetch.items[i], &tail,0 ); +if (remote->fetch.items[i].dst && + remote->fetch.items[i].dst[0 ]) *autotags =1 ;if (!i && !has_merge && ref_map && - !remote->fetch[0 ].pattern) + !remote->fetch.items[0 ].pattern) ref_map->fetch_head_status =FETCH_HEAD_MERGE ; }/*
@@ -1166,8 +1166,8 @@ static int do_fetch(struct transport *transport,if (ref_count) {prune_refs (refs, ref_count, ref_map, transport->url); }else { -prune_refs (transport->remote->fetch, - transport->remote->fetch_refspec_nr, +prune_refs (transport->remote->fetch.items, + transport->remote->fetch.nr, ref_map, transport->url); }
builtin/remote.c +9 -9
@@ -333,10 +333,10 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *statstruct ref *ref, *stale_refs;int i; -for (i =0 ; i < states->remote->fetch_refspec_nr; i++) -if (get_fetch_map (remote_refs, states->remote->fetch + i, &tail,1 )) +for (i =0 ; i < states->remote->fetch.nr; i++) +if (get_fetch_map (remote_refs, &states->remote->fetch.items[i], &tail,1 ))die (_ ("Could not get fetch map for refspec %s" ), - states->remote->fetch_refspec[i]); + states->remote->fetch.raw[i]); states->new_refs.strdup_strings =1 ; states->tracked.strdup_strings =1 ;
@@ -347,8 +347,8 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *statelse string_list_append (&states->tracked,abbrev_branch (ref->name)); } - stale_refs =get_stale_heads (states->remote->fetch, - states->remote->fetch_refspec_nr, fetch_map); + stale_refs =get_stale_heads (states->remote->fetch.items, + states->remote->fetch.nr, fetch_map);for (ref = stale_refs; ref; ref = ref->next) {struct string_list_item *item =string_list_append (&states->stale,abbrev_branch (ref->name));
@@ -590,8 +590,8 @@ static int migrate_file(struct remote *remote)git_config_set_multivar (buf.buf, remote->push.raw[i],"^$" ,0 );strbuf_reset (&buf);strbuf_addf (&buf,"remote.%s.fetch" , remote->name); -for (i =0 ; i < remote->fetch_refspec_nr; i++) -git_config_set_multivar (buf.buf, remote->fetch_refspec[i],"^$" ,0 ); +for (i =0 ; i < remote->fetch.raw_nr; i++) +git_config_set_multivar (buf.buf, remote->fetch.raw[i],"^$" ,0 );if (remote->origin ==REMOTE_REMOTES )unlink_or_warn (git_path ("remotes/%s" , remote->name));else if (remote->origin ==REMOTE_BRANCHES )
@@ -646,11 +646,11 @@ static int mv(int argc, const char **argv)strbuf_addf (&buf,"remote.%s.fetch" , rename.new_name);git_config_set_multivar (buf.buf,NULL ,NULL ,1 );strbuf_addf (&old_remote_context,":refs/remotes/%s/" , rename.old_name); -for (i =0 ; i < oldremote->fetch_refspec_nr; i++) { +for (i =0 ; i < oldremote->fetch.raw_nr; i++) {char *ptr;strbuf_reset (&buf2); -strbuf_addstr (&buf2, oldremote->fetch_refspec[i]); +strbuf_addstr (&buf2, oldremote->fetch.raw[i]); ptr =strstr (buf2.buf, old_remote_context.buf);if (ptr) { refspec_updated =1 ;
remote.c +6 -18
@@ -84,21 +84,12 @@ static void add_push_refspec(struct remote *remote, const char *ref)static void add_fetch_refspec (struct remote *remote,const char *ref) { -ALLOC_GROW (remote->fetch_refspec, - remote->fetch_refspec_nr +1 , - remote->fetch_refspec_alloc); - remote->fetch_refspec[remote->fetch_refspec_nr++] = ref; +refspec_append (&remote->fetch, ref); }void add_prune_tags_to_fetch_refspec (struct remote *remote) { -int nr = remote->fetch_refspec_nr; -int bufsize = nr +1 ; -int size =sizeof (struct refspec_item ); - - remote->fetch =xrealloc (remote->fetch, size * bufsize); -memcpy (&remote->fetch[nr], tag_refspec, size); -add_fetch_refspec (remote,xstrdup (TAG_REFSPEC )); +refspec_append (&remote->fetch,TAG_REFSPEC ); }static void add_url (struct remote *remote,const char *url)
@@ -174,6 +165,7 @@ static struct remote *make_remote(const char *name, int len) ret->prune_tags =-1 ;/* unspecified */ ret->name =xstrndup (name, len);refspec_init (&ret->push,REFSPEC_PUSH ); +refspec_init (&ret->fetch,REFSPEC_FETCH );ALLOC_GROW (remotes, remotes_nr +1 , remotes_alloc); remotes[remotes_nr++] = ret;
@@ -580,7 +572,6 @@ static struct remote *remote_get_1(const char *name,add_url_alias (ret, name);if (!valid_remote (ret))return NULL ; - ret->fetch =parse_fetch_refspec (ret->fetch_refspec_nr, ret->fetch_refspec);return ret; }
@@ -611,9 +602,6 @@ int for_each_remote(each_remote_fn fn, void *priv)struct remote *r = remotes[i];if (!r)continue ; -if (!r->fetch) - r->fetch =parse_fetch_refspec (r->fetch_refspec_nr, - r->fetch_refspec); result =fn (r, priv); }return result;
@@ -792,7 +780,7 @@ char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec,int remote_find_tracking (struct remote *remote,struct refspec_item *refspec) { -return query_refspecs (remote->fetch, remote->fetch_refspec_nr, refspec); +return query_refspecs (remote->fetch.items, remote->fetch.nr, refspec); } static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
@@ -1590,7 +1578,7 @@ static const char *tracking_for_push_dest(struct remote *remote, {char *ret; - ret =apply_refspecs (remote->fetch, remote->fetch_refspec_nr, refname); + ret =apply_refspecs (remote->fetch.items, remote->fetch.nr, refname);if (!ret) return error_buf(err, _("push destination '%s' on remote '%s' has no local tracking branch"),
@@ -2224,7 +2212,7 @@ static int remote_tracking(struct remote *remote, const char *refname, {char *dst; - dst =apply_refspecs (remote->fetch, remote->fetch_refspec_nr, refname); + dst =apply_refspecs (remote->fetch.items, remote->fetch.nr, refname);if (!dst)return -1 ;/* no tracking ref for refname at remote */ if (read_ref (dst, oid))
remote.h +1 -4
@@ -30,10 +30,7 @@ struct remote {struct refspec push; -const char **fetch_refspec; -struct refspec_item *fetch; -int fetch_refspec_nr; -int fetch_refspec_alloc; +struct refspec fetch;/* * -1 to never fetch tags
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Re: [PATCH 14/35] remote: convert fetch refspecs to struct refspec
remote.c static void add_push_refspec(struct remote *remote, const char *ref) · line 93
Quoted 11 lines · Brandon Williams
void
add_prune_tags_to_fetch_refspec(struct remote *remote){remote.c +1
-7-int nr = remote->fetch_refspec_nr; -int bufsize = nr +1 ; -int size =sizeof (struct refspec_item ); - - remote->fetch =xrealloc (remote->fetch, size * bufsize); -memcpy (&remote->fetch[nr], tag_refspec, size); -add_fetch_refspec (remote,xstrdup (TAG_REFSPEC )); +refspec_append (&remote->fetch,TAG_REFSPEC ); }
Thanks for fixing the hack I needed to put in place in 97716d217c ("fetch: add a --prune-tags option and fetch.pruneTags config", 2018-02-09).
I'm not sure where it belongs in this series, but I think this makes sense on top of the whole thing:
diff --git a/builtin/fetch.c b/builtin/fetch.c
index af7064dce3..9a523249f5 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1383,7 +1383,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
maybe_prune_tags = prune_tags_ok && prune_tags;
if (maybe_prune_tags && remote_via_config)
- add_prune_tags_to_fetch_refspec(remote);
+ refspec_append(&remote->fetch, TAG_REFSPEC);
+
if (maybe_prune_tags && (argc || !remote_via_config))
refspec_append(&rs, TAG_REFSPEC);
diff --git a/remote.c b/remote.c
index 8e6522f4d0..946b95d18d 100644
--- a/remote.c
+++ b/remote.c
@@ -87,11 +87,6 @@ static void add_fetch_refspec(struct remote *remote, const char *ref)
refspec_append(&remote->fetch, ref);
}
-void add_prune_tags_to_fetch_refspec(struct remote *remote)
-{
- refspec_append(&remote->fetch, TAG_REFSPEC);
-}
-
static void add_url(struct remote *remote, const char *url)
{
ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
diff --git a/remote.h b/remote.h
index 9014f707f0..62a6566594 100644
--- a/remote.h
+++ b/remote.h
@@ -289,6 +289,4 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int
extern int is_empty_cas(const struct push_cas_option *);
void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
-void add_prune_tags_to_fetch_refspec(struct remote *remote);
-
#endifI.e. the whole reason we have this function is because of my above commit where I had to very carefully hack around the fact that we didn't have something which could ALLOW_GROW() the structure after it had been created.
So I added the add_prune_tags_to_fetch_refspec() function to very carefully do *only* that so others wouldn't be tempted to use this hack more generally.
But now we have a nice API for it, so we can just throw away the wrapper, and use the same API everywhere. You already did the other half of that in your e69b54f53a ("fetch: convert fetch_one to use struct refspec", 2018-05-11).
Re: [PATCH 14/35] remote: convert fetch refspecs to struct refspec
Quoted 19 lines · Ævar Arnfjörð Bjarmason
remote.c static void add_push_refspec(struct remote *remote, const char *ref) · line 93
Quoted 11 lines · Brandon Williams
void
add_prune_tags_to_fetch_refspec(struct remote *remote){remote.c +1
-7-int nr = remote->fetch_refspec_nr; -int bufsize = nr +1 ; -int size =sizeof (struct refspec_item ); - - remote->fetch =xrealloc (remote->fetch, size * bufsize); -memcpy (&remote->fetch[nr], tag_refspec, size); -add_fetch_refspec (remote,xstrdup (TAG_REFSPEC )); +refspec_append (&remote->fetch,TAG_REFSPEC ); }Thanks for fixing the hack I needed to put in place in
97716d217c("fetch: add a --prune-tags option and fetch.pruneTags config", 2018-02-09).
Quoted 2 lines
I'm not sure where it belongs in this series, but I think this makes sense on top of the whole thing:
This actually would work well immediately after this patch, so I'll add it here :)
Thanks!
Quoted 56 lines
diff --git a/builtin/fetch.c b/builtin/fetch.c index af7064dce3..9a523249f5 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1383,7 +1383,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru maybe_prune_tags = prune_tags_ok && prune_tags; if (maybe_prune_tags && remote_via_config) - add_prune_tags_to_fetch_refspec(remote); + refspec_append(&remote->fetch, TAG_REFSPEC); + if (maybe_prune_tags && (argc || !remote_via_config)) refspec_append(&rs, TAG_REFSPEC); diff --git a/remote.c b/remote.c index 8e6522f4d0..946b95d18d 100644 --- a/remote.c +++ b/remote.c @@ -87,11 +87,6 @@ static void add_fetch_refspec(struct remote *remote, const char *ref) refspec_append(&remote->fetch, ref); } -void add_prune_tags_to_fetch_refspec(struct remote *remote) -{ - refspec_append(&remote->fetch, TAG_REFSPEC); -} - static void add_url(struct remote *remote, const char *url) { ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc); diff --git a/remote.h b/remote.h index 9014f707f0..62a6566594 100644 --- a/remote.h +++ b/remote.h @@ -289,6 +289,4 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int extern int is_empty_cas(const struct push_cas_option *); void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *); -void add_prune_tags_to_fetch_refspec(struct remote *remote); - #endifI.e. the whole reason we have this function is because of my above commit where I had to very carefully hack around the fact that we didn't have something which could
ALLOW_GROW()the structure after it had been created.So I added the
add_prune_tags_to_fetch_refspec()function to very carefully do *only* that so others wouldn't be tempted to use this hack more generally.But now we have a nice API for it, so we can just throw away the wrapper, and use the same API everywhere. You already did the other half of that in your
e69b54f53a("fetch: convertfetch_oneto use struct refspec", 2018-05-11).
Signature · 1 line
Brandon Williams
PATCH 15/35 transport-helper: convert to use struct refspec
In reply to Brandon WilliamsConvert the refspecs in transport-helper.c to be stored in a 'struct refspec'.
--- transport-helper.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-)
transport-helper.c +12 -26
@@ -36,8 +36,7 @@ struct helper_data {char *export_marks;char *import_marks;/* These go from remote name (as in "list") to private name */ -struct refspec_item *refspecs; -int refspec_nr; +struct refspec rs;/* Transport options for fetch-pack/send-pack (should one of * those be invoked). */
@@ -107,9 +106,6 @@ static struct child_process *get_helper(struct transport *transport)struct helper_data *data = transport->data;struct strbuf buf =STRBUF_INIT ;struct child_process *helper; -const char **refspecs =NULL ; -int refspec_nr =0 ; -int refspec_alloc =0 ;int duped;int code;
@@ -139,6 +135,7 @@ static struct child_process *get_helper(struct transport *transport) data->helper = helper; data->no_disconnect_req =0 ; +refspec_init (&data->rs,REFSPEC_FETCH );/* * Open the output as FILE* so strbuf_getline_*() family of
@@ -184,11 +181,8 @@ static struct child_process *get_helper(struct transport *transport) data->export =1 ; else if (!strcmp(capname, "check-connectivity")) data->check_connectivity =1 ; - else if (!data->refspecs && skip_prefix(capname, "refspec ", &arg)) { -ALLOC_GROW (refspecs, - refspec_nr +1 , - refspec_alloc); - refspecs[refspec_nr++] =xstrdup (arg); + else if (skip_prefix(capname, "refspec ", &arg)) { +refspec_append (&data->rs, arg); } else if (!strcmp(capname, "connect")) { data->connect =1 ; } else if (!strcmp(capname, "stateless-connect")) {
@@ -207,14 +201,7 @@ static struct child_process *get_helper(struct transport *transport) capname); } } -if (refspecs) { -int i; - data->refspec_nr = refspec_nr; - data->refspecs =parse_fetch_refspec (refspec_nr, refspecs); -for (i =0 ; i < refspec_nr; i++) -free ((char *)refspecs[i]); -free (refspecs); - }else if (data->import || data->bidi_import || data->export) { +if (!data->rs.nr && (data->import || data->bidi_import || data->export)) {warning ("This remote helper should implement refspec capability." ); }strbuf_release (&buf);
@@ -378,8 +365,7 @@ static int release_helper(struct transport *transport) {int res =0 ;struct helper_data *data = transport->data; -free_refspec (data->refspec_nr, data->refspecs); - data->refspecs =NULL ; +refspec_clear (&data->rs); res =disconnect_helper (transport);free (transport->data);return res;
@@ -536,8 +522,8 @@ static int fetch_with_import(struct transport *transport,if (posn->status &REF_STATUS_UPTODATE )continue ; name = posn->symref ? posn->symref : posn->name; -if (data->refspecs) - private =apply_refspecs (data->refspecs, data->refspec_nr, name); +if (data->rs.nr) + private =apply_refspecs (data->rs.items, data->rs.nr, name);else private =xstrdup (name);if (private) {
@@ -815,11 +801,11 @@ static int push_update_refs_status(struct helper_data *data,if (push_update_ref_status (&buf, &ref, remote_refs))continue ; -if (flags &TRANSPORT_PUSH_DRY_RUN || !data->refspecs || data->no_private_update) +if (flags &TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update)continue ;/* propagate back the update to the remote namespace */ - private =apply_refspecs (data->refspecs, data->refspec_nr, ref->name); + private =apply_refspecs (data->rs.items, data->rs.nr, ref->name);if (!private)continue ; update_ref("update by helper", private, &ref->new_oid, NULL,
@@ -939,7 +925,7 @@ static int push_refs_with_export(struct transport *transport,struct string_list revlist_args =STRING_LIST_INIT_DUP ;struct strbuf buf =STRBUF_INIT ; -if (!data->refspecs) +if (!data->rs.nr)die ("remote-helper doesn't support push; refspec needed" );set_common_push_options (transport, data->name, flags);
@@ -956,7 +942,7 @@ static int push_refs_with_export(struct transport *transport,char *private;struct object_id oid; - private =apply_refspecs (data->refspecs, data->refspec_nr, ref->name); + private =apply_refspecs (data->rs.items, data->rs.nr, ref->name);if (private && !get_oid (private, &oid)) {strbuf_addf (&buf,"^%s" , private); string_list_append_nodup(&revlist_args,
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 16/35 fetch: convert fetch_one to use struct refspec
In reply to Brandon WilliamsConvert 'fetch_one()' to use 'struct refspec'.
--- builtin/fetch.c | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-)
builtin/fetch.c +19 -27
@@ -1356,10 +1356,8 @@ static inline void fetch_one_setup_partial(struct remote *remote)static int fetch_one (struct remote *remote,int argc,const char **argv,int prune_tags_ok) { -static const char **refs =NULL ; -struct refspec_item *refspec; -int ref_nr =0 ; -int j =0 ; +struct refspec rs =REFSPEC_INIT_FETCH ; +int i;int exit_code;int maybe_prune_tags;int remote_via_config =remote_is_configured (remote,0 );
@@ -1394,35 +1392,29 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pruif (maybe_prune_tags && remote_via_config)add_prune_tags_to_fetch_refspec (remote); -if (argc >0 || (maybe_prune_tags && !remote_via_config)) { -size_t nr_alloc =st_add3 (argc, maybe_prune_tags,1 ); - refs =xcalloc (nr_alloc,sizeof (const char *)); -if (maybe_prune_tags) { - refs[j++] =xstrdup ("refs/tags/*:refs/tags/*" ); - ref_nr++; - } - } +if (maybe_prune_tags && (argc || !remote_via_config)) +refspec_append (&rs,TAG_REFSPEC ); -if (argc >0 ) { -int i; -for (i =0 ; i < argc; i++) { -if (!strcmp (argv[i],"tag" )) { - i++; -if (i >= argc) -die (_ ("You need to specify a tag name." )); - refs[j++] =xstrfmt ("refs/tags/%s:refs/tags/%s" , - argv[i], argv[i]); - }else - refs[j++] = argv[i]; - ref_nr++; +for (i =0 ; i < argc; i++) { +if (!strcmp (argv[i],"tag" )) { +char *tag; + i++; +if (i >= argc) +die (_ ("You need to specify a tag name." )); + + tag =xstrfmt ("refs/tags/%s:refs/tags/%s" , + argv[i], argv[i]); +refspec_append (&rs, tag); +free (tag); + }else { +refspec_append (&rs, argv[i]); } }sigchain_push_common (unlock_pack_on_signal);atexit (unlock_pack); - refspec =parse_fetch_refspec (ref_nr, refs); - exit_code =do_fetch (gtransport, refspec, ref_nr); -free_refspec (ref_nr, refspec); + exit_code =do_fetch (gtransport, rs.items, rs.nr); +refspec_clear (&rs);transport_disconnect (gtransport); gtransport =NULL ;return exit_code;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 17/35 fetch: convert refmap to use struct refspec
In reply to Brandon WilliamsConvert the refmap in builtin/fetch.c to be stored in a 'struct refspec'.
--- builtin/fetch.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)
builtin/fetch.c +7 -10
@@ -60,8 +60,7 @@ static const char *submodule_prefix = "";static int recurse_submodules =RECURSE_SUBMODULES_DEFAULT ;static int recurse_submodules_default =RECURSE_SUBMODULES_ON_DEMAND ;static int shown_url =0 ; -static int refmap_alloc, refmap_nr; -static const char **refmap_array; +static struct refspec refmap =REFSPEC_INIT_FETCH ;static struct list_objects_filter_options filter_options;static int git_fetch_config (const char *k,const char *v,void *cb)
@@ -108,14 +107,12 @@ static int gitmodules_fetch_config(const char *var, const char *value, void *cb)static int parse_refmap_arg (const struct option *opt,const char *arg,int unset) { -ALLOC_GROW (refmap_array, refmap_nr +1 , refmap_alloc); -/* * "git fetch --refmap='' origin foo" * can be used to tell the command not to store anywhere */ -if (*arg) - refmap_array[refmap_nr++] = arg; +refspec_append (&refmap, arg); +return 0 ; }
@@ -403,9 +400,9 @@ static struct ref *get_ref_map(struct transport *transport,* by ref_remove_duplicates() in favor of one of these * opportunistic entries with FETCH_HEAD_IGNORE. */ -if (refmap_array) { - fetch_refspec =parse_fetch_refspec (refmap_nr, refmap_array); - fetch_refspec_nr = refmap_nr; +if (refmap.nr) { + fetch_refspec = refmap.items; + fetch_refspec_nr = refmap.nr; }else { fetch_refspec = transport->remote->fetch.items; fetch_refspec_nr = transport->remote->fetch.nr;
@@ -413,7 +410,7 @@ static struct ref *get_ref_map(struct transport *transport,for (i =0 ; i < fetch_refspec_nr; i++)get_fetch_map (ref_map, &fetch_refspec[i], &oref_tail,1 ); - }else if (refmap_array) { + }else if (refmap.nr) {die ("--refmap option is only meaningful with command-line refspec(s)." ); }else {/* Use the defaults */
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 18/35 refspec: remove the deprecated functions
In reply to Brandon WilliamsNow that there are no callers of 'parse_push_refspec()', 'parse_fetch_refspec()', and 'free_refspec()', remove these functions.
--- refspec.c | 49 ------------------------------------------------- refspec.h | 5 ----- 2 files changed, 54 deletions(-)
refspec.c +0 -49
@@ -121,55 +121,6 @@ static int parse_refspec(struct refspec_item *rs, const char *refspec, int fetchreturn 1 ; } -static struct refspec_item *parse_refspec_internal (int nr_refspec,const char **refspec,int fetch,int verify) -{ -int i; -struct refspec_item *rs =xcalloc (nr_refspec,sizeof (*rs)); - -for (i =0 ; i < nr_refspec; i++) { -if (!parse_refspec (&rs[i], refspec[i], fetch)) - goto invalid; - } - -return rs; - - invalid: -if (verify) { -/* -* nr_refspec must be greater than zero and i must be valid -* since it is only possible to reach this point from within -* the for loop above. -*/ -free_refspec (i+1 , rs); -return NULL ; - } -die ("Invalid refspec '%s'" , refspec[i]); -} - -struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec) -{ -return parse_refspec_internal (nr_refspec, refspec,1 ,0 ); -} - -struct refspec_item *parse_push_refspec (int nr_refspec,const char **refspec) -{ -return parse_refspec_internal (nr_refspec, refspec,0 ,0 ); -} - -void free_refspec (int nr_refspec,struct refspec_item *refspec) -{ -int i; - -if (!refspec) -return ; - -for (i =0 ; i < nr_refspec; i++) { -free (refspec[i].src); -free (refspec[i].dst); - } -free (refspec); -} -void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch) {memset (item,0 ,sizeof (*item));
refspec.h +0 -5
@@ -14,11 +14,6 @@ struct refspec_item {char *dst; }; -struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec); -struct refspec_item *parse_push_refspec (int nr_refspec,const char **refspec); - -void free_refspec (int nr_refspec,struct refspec_item *refspec); -#define REFSPEC_FETCH 1#define REFSPEC_PUSH 0
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 19/35 fetch: convert do_fetch to take a struct refspec
In reply to Brandon WilliamsConvert 'do_fetch()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- builtin/fetch.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
builtin/fetch.c +5 -5
@@ -1112,7 +1112,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map) }static int do_fetch (struct transport *transport, -struct refspec_item *refs,int ref_count) +struct refspec *rs) {struct string_list existing_refs =STRING_LIST_INIT_DUP ;struct ref *ref_map;
@@ -1136,7 +1136,7 @@ static int do_fetch(struct transport *transport, goto cleanup; } - ref_map =get_ref_map (transport, refs, ref_count, tags, &autotags); + ref_map =get_ref_map (transport, rs->items, rs->nr, tags, &autotags);if (!update_head_ok)check_not_current_branch (ref_map);
@@ -1160,8 +1160,8 @@ static int do_fetch(struct transport *transport,* explicitly (via command line or configuration); we * don't care whether --tags was specified. */ -if (ref_count) { -prune_refs (refs, ref_count, ref_map, transport->url); +if (rs->nr) { +prune_refs (rs->items, rs->nr, ref_map, transport->url); }else { prune_refs(transport->remote->fetch.items, transport->remote->fetch.nr,
@@ -1410,7 +1410,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int prusigchain_push_common (unlock_pack_on_signal);atexit (unlock_pack); - exit_code =do_fetch (gtransport, rs.items, rs.nr); + exit_code =do_fetch (gtransport, &rs);refspec_clear (&rs);transport_disconnect (gtransport); gtransport =NULL ;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 20/35 fetch: convert get_ref_map to take a struct refspec
In reply to Brandon WilliamsConvert 'get_ref_map()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- builtin/fetch.c | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-)
builtin/fetch.c +20 -23
@@ -337,7 +337,7 @@ static void find_non_local_tags(struct transport *transport, }static struct ref *get_ref_map (struct transport *transport, -struct refspec_item *refspecs,int refspec_count, +struct refspec *rs,int tags,int *autotags) {int i;
@@ -351,15 +351,16 @@ static struct ref *get_ref_map(struct transport *transport,const struct ref *remote_refs; -for (i =0 ; i < refspec_count; i++) { -if (!refspecs[i].exact_sha1) { -const char *glob =strchr (refspecs[i].src,'*' ); +for (i =0 ; i < rs->nr; i++) { +const struct refspec_item *item = &rs->items[i]; +if (!item->exact_sha1) { +const char *glob =strchr (item->src,'*' );if (glob)argv_array_pushf (&ref_prefixes,"%.*s" , - (int )(glob - refspecs[i].src), - refspecs[i].src); + (int )(glob - item->src), + item->src);else -expand_ref_prefix (&ref_prefixes, refspecs[i].src); +expand_ref_prefix (&ref_prefixes, item->src); } }
@@ -367,13 +368,12 @@ static struct ref *get_ref_map(struct transport *transport,argv_array_clear (&ref_prefixes); -if (refspec_count) { -struct refspec_item *fetch_refspec; -int fetch_refspec_nr; +if (rs->nr) { +struct refspec *fetch_refspec; -for (i =0 ; i < refspec_count; i++) { -get_fetch_map (remote_refs, &refspecs[i], &tail,0 ); -if (refspecs[i].dst && refspecs[i].dst[0 ]) +for (i =0 ; i < rs->nr; i++) { +get_fetch_map (remote_refs, &rs->items[i], &tail,0 ); +if (rs->items[i].dst && rs->items[i].dst[0 ]) *autotags =1 ; }/* Merge everything on the command line (but not --tags) */
@@ -400,16 +400,13 @@ static struct ref *get_ref_map(struct transport *transport,* by ref_remove_duplicates() in favor of one of these * opportunistic entries with FETCH_HEAD_IGNORE. */ -if (refmap.nr) { - fetch_refspec = refmap.items; - fetch_refspec_nr = refmap.nr; - }else { - fetch_refspec = transport->remote->fetch.items; - fetch_refspec_nr = transport->remote->fetch.nr; - } +if (refmap.nr) + fetch_refspec = &refmap; +else + fetch_refspec = &transport->remote->fetch; -for (i =0 ; i < fetch_refspec_nr; i++) -get_fetch_map (ref_map, &fetch_refspec[i], &oref_tail,1 ); +for (i =0 ; i < fetch_refspec->nr; i++) +get_fetch_map (ref_map, &fetch_refspec->items[i], &oref_tail,1 ); }else if (refmap.nr) {die ("--refmap option is only meaningful with command-line refspec(s)." ); }else {
@@ -1136,7 +1133,7 @@ static int do_fetch(struct transport *transport, goto cleanup; } - ref_map =get_ref_map (transport, rs->items, rs->nr, tags, &autotags); + ref_map =get_ref_map (transport, rs, tags, &autotags);if (!update_head_ok)check_not_current_branch (ref_map);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 21/35 fetch: convert prune_refs to take a struct refspec
In reply to Brandon WilliamsConvert 'prune_refs()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- builtin/fetch.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
builtin/fetch.c +5 -6
@@ -959,11 +959,11 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)return ret; } -static int prune_refs (struct refspec_item *refs,int ref_count,struct ref *ref_map, -const char *raw_url) +static int prune_refs (struct refspec *rs,struct ref *ref_map, +const char *raw_url) {int url_len, i, result =0 ; -struct ref *ref, *stale_refs =get_stale_heads (refs, ref_count, ref_map); +struct ref *ref, *stale_refs =get_stale_heads (rs->items, rs->nr, ref_map);char *url;int summary_width =transport_summary_width (stale_refs);const char *dangling_msg = dry_run
@@ -1158,10 +1158,9 @@ static int do_fetch(struct transport *transport,* don't care whether --tags was specified. */ if (rs->nr) { -prune_refs (rs->items, rs->nr, ref_map, transport->url); +prune_refs (rs, ref_map, transport->url); }else { -prune_refs (transport->remote->fetch.items, - transport->remote->fetch.nr, +prune_refs (&transport->remote->fetch, ref_map, transport->url); }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 22/35 remote: convert get_stale_heads to take a struct refspec
In reply to Brandon WilliamsConvert 'get_stale_heads()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- builtin/fetch.c | 2 +- builtin/remote.c | 3 +-- remote.c | 18 +++++++++--------- remote.h | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-)
builtin/fetch.c +1 -1
@@ -963,7 +963,7 @@ static int prune_refs(struct refspec *rs, struct ref *ref_map, const char *raw_url) {int url_len, i, result =0 ; -struct ref *ref, *stale_refs =get_stale_heads (rs->items, rs->nr, ref_map); +struct ref *ref, *stale_refs =get_stale_heads (rs, ref_map);char *url;int summary_width =transport_summary_width (stale_refs);const char *dangling_msg = dry_run
builtin/remote.c +1 -2
@@ -347,8 +347,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *statelse string_list_append (&states->tracked,abbrev_branch (ref->name)); } - stale_refs =get_stale_heads (states->remote->fetch.items, - states->remote->fetch.nr, fetch_map); + stale_refs =get_stale_heads (&states->remote->fetch, fetch_map);for (ref = stale_refs; ref; ref = ref->next) {struct string_list_item *item =string_list_append (&states->stale,abbrev_branch (ref->name));
remote.c +9 -9
@@ -707,7 +707,9 @@ static int match_name_with_pattern(const char *key, const char *name,return ret; } -static void query_refspecs_multiple (struct refspec_item *refs,int ref_count,struct refspec_item *query,struct string_list *results) +static void query_refspecs_multiple (struct refspec *rs, +struct refspec_item *query, +struct string_list *results) {int i;int find_src = !query->src;
@@ -715,8 +717,8 @@ static void query_refspecs_multiple(struct refspec_item *refs, int ref_count, stif (find_src && !query->dst)error ("query_refspecs_multiple: need either src or dst" ); -for (i =0 ; i < ref_count; i++) { -struct refspec_item *refspec = &refs[i]; +for (i =0 ; i < rs->nr; i++) { +struct refspec_item *refspec = &rs->items[i];const char *key = find_src ? refspec->dst : refspec->src;const char *value = find_src ? refspec->src : refspec->dst;const char *needle = find_src ? query->dst : query->src;
@@ -2077,8 +2079,7 @@ struct ref *guess_remote_head(const struct ref *head,struct stale_heads_info {struct string_list *ref_names;struct ref **stale_refs_tail; -struct refspec_item *refs; -int ref_count; +struct refspec *rs; }; static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
@@ -2091,7 +2092,7 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,memset (&query,0 ,sizeof (struct refspec_item )); query.dst = (char *)refname; -query_refspecs_multiple (info->refs, info->ref_count, &query, &matches); +query_refspecs_multiple (info->rs, &query, &matches);if (matches.nr ==0 ) goto clean_exit;/* No matches */
@@ -2119,7 +2120,7 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,return 0 ; } -struct ref *get_stale_heads (struct refspec_item *refs,int ref_count,struct ref *fetch_map) +struct ref *get_stale_heads (struct refspec *rs,struct ref *fetch_map) {struct ref *ref, *stale_refs =NULL ;struct string_list ref_names =STRING_LIST_INIT_NODUP ;
@@ -2127,8 +2128,7 @@ struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref info.ref_names = &ref_names; info.stale_refs_tail = &stale_refs; - info.refs = refs; - info.ref_count = ref_count; + info.rs = rs;for (ref = fetch_map; ref; ref = ref->next)string_list_append (&ref_names, ref->name);string_list_sort (&ref_names);
remote.h +1 -1
@@ -267,7 +267,7 @@ struct ref *guess_remote_head(const struct ref *head, int all);/* Return refs which no longer exist on remote */ -struct ref *get_stale_heads (struct refspec_item *refs,int ref_count,struct ref *fetch_map); +struct ref *get_stale_heads (struct refspec *rs,struct ref *fetch_map);/* * Compare-and-swap
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 23/35 remote: convert apply_refspecs to take a struct refspec
In reply to Brandon WilliamsConvert 'apply_refspecs()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- builtin/fast-export.c | 2 +- remote.c | 15 ++++++--------- remote.h | 3 +-- transport-helper.c | 6 +++--- 4 files changed, 11 insertions(+), 15 deletions(-)
builtin/fast-export.c +1 -1
@@ -831,7 +831,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)if (refspecs.nr) {char *private; - private =apply_refspecs (refspecs.items, refspecs.nr, full_name); + private =apply_refspecs (&refspecs, full_name);if (private) {free (full_name); full_name = private;
remote.c +6 -9
@@ -534,8 +534,7 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push,struct remote *remote =remote_get (remote_name);if (remote && remote->push.nr && - (dst =apply_refspecs (remote->push.items, - remote->push.nr, + (dst =apply_refspecs (&remote->push, branch->refname))) {if (explicit) *explicit =1 ;
@@ -766,15 +765,14 @@ int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_itemreturn -1 ; } -char *apply_refspecs (struct refspec_item *refspecs,int nr_refspec, -const char *name) +char *apply_refspecs (struct refspec *rs,const char *name) {struct refspec_item query;memset (&query,0 ,sizeof (struct refspec_item )); query.src = (char *)name; -if (query_refspecs (refspecs, nr_refspec, &query)) +if (query_refspecs (rs->items, rs->nr, &query))return NULL ;return query.dst;
@@ -1580,7 +1578,7 @@ static const char *tracking_for_push_dest(struct remote *remote, {char *ret; - ret =apply_refspecs (remote->fetch.items, remote->fetch.nr, refname); + ret =apply_refspecs (&remote->fetch, refname);if (!ret) return error_buf(err, _("push destination '%s' on remote '%s' has no local tracking branch"),
@@ -1602,8 +1600,7 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err)char *dst;const char *ret; - dst =apply_refspecs (remote->push.items, remote->push.nr, - branch->refname); + dst =apply_refspecs (&remote->push, branch->refname);if (!dst) return error_buf(err, _("push refspecs for '%s' do not include '%s'"),
@@ -2212,7 +2209,7 @@ static int remote_tracking(struct remote *remote, const char *refname, {char *dst; - dst =apply_refspecs (remote->fetch.items, remote->fetch.nr, refname); + dst =apply_refspecs (&remote->fetch, refname);if (!dst)return -1 ;/* no tracking ref for refname at remote */ if (read_ref (dst, oid))
remote.h +1 -2
@@ -159,8 +159,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);struct ref *ref_remove_duplicates (struct ref *ref_map);extern int query_refspecs (struct refspec_item *specs,int nr,struct refspec_item *query); -char *apply_refspecs (struct refspec_item *refspecs,int nr_refspec, -const char *name); +char *apply_refspecs (struct refspec *rs,const char *name);int check_push_refs (struct ref *src,int nr_refspec,const char **refspec); int match_push_refs(struct ref *src, struct ref **dst,
transport-helper.c +3 -3
@@ -523,7 +523,7 @@ static int fetch_with_import(struct transport *transport,continue ; name = posn->symref ? posn->symref : posn->name;if (data->rs.nr) - private =apply_refspecs (data->rs.items, data->rs.nr, name); + private =apply_refspecs (&data->rs, name);else private =xstrdup (name);if (private) {
@@ -805,7 +805,7 @@ static int push_update_refs_status(struct helper_data *data,continue ;/* propagate back the update to the remote namespace */ - private =apply_refspecs (data->rs.items, data->rs.nr, ref->name); + private =apply_refspecs (&data->rs, ref->name);if (!private)continue ; update_ref("update by helper", private, &ref->new_oid, NULL,
@@ -942,7 +942,7 @@ static int push_refs_with_export(struct transport *transport,char *private;struct object_id oid; - private =apply_refspecs (data->rs.items, data->rs.nr, ref->name); + private =apply_refspecs (&data->rs, ref->name);if (private && !get_oid (private, &oid)) {strbuf_addf (&buf,"^%s" , private); string_list_append_nodup(&revlist_args,
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 24/35 remote: convert query_refspecs to take a struct refspec
In reply to Brandon WilliamsConvert 'query_refspecs()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- builtin/push.c | 3 +-- remote.c | 10 +++++----- remote.h | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-)
builtin/push.c +1 -2
@@ -83,8 +83,7 @@ static const char *map_refspec(const char *ref,struct refspec_item query;memset (&query,0 ,sizeof (struct refspec_item )); query.src = matched->name; -if (!query_refspecs (remote->push.items, remote->push.nr, &query) && - query.dst) { +if (!query_refspecs (&remote->push, &query) && query.dst) {struct strbuf buf =STRBUF_INIT ; strbuf_addf(&buf, "%s%s:%s", query.force ? "+" : "",
remote.c +5 -5
@@ -734,7 +734,7 @@ static void query_refspecs_multiple(struct refspec *rs, } } -int query_refspecs (struct refspec_item *refs,int ref_count,struct refspec_item *query) +int query_refspecs (struct refspec *rs,struct refspec_item *query) {int i;int find_src = !query->src;
@@ -744,8 +744,8 @@ int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_itemif (find_src && !query->dst)return error ("query_refspecs: need either src or dst" ); -for (i =0 ; i < ref_count; i++) { -struct refspec_item *refspec = &refs[i]; +for (i =0 ; i < rs->nr; i++) { +struct refspec_item *refspec = &rs->items[i];const char *key = find_src ? refspec->dst : refspec->src;const char *value = find_src ? refspec->src : refspec->dst;
@@ -772,7 +772,7 @@ char *apply_refspecs(struct refspec *rs, const char *name)memset (&query,0 ,sizeof (struct refspec_item )); query.src = (char *)name; -if (query_refspecs (rs->items, rs->nr, &query)) +if (query_refspecs (rs, &query))return NULL ;return query.dst;
@@ -780,7 +780,7 @@ char *apply_refspecs(struct refspec *rs, const char *name)int remote_find_tracking (struct remote *remote,struct refspec_item *refspec) { -return query_refspecs (remote->fetch.items, remote->fetch.nr, refspec); +return query_refspecs (&remote->fetch, refspec); } static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
remote.h +1 -1
@@ -158,7 +158,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);*/ struct ref *ref_remove_duplicates (struct ref *ref_map); -extern int query_refspecs (struct refspec_item *specs,int nr,struct refspec_item *query); +int query_refspecs (struct refspec *rs,struct refspec_item *query);char *apply_refspecs (struct refspec *rs,const char *name);int check_push_refs (struct ref *src,int nr_refspec,const char **refspec);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 25/35 remote: convert get_ref_match to take a struct refspec
In reply to Brandon WilliamsConvert 'get_ref_match()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- remote.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-)
remote.c +14 -12
@@ -1091,27 +1091,29 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,return errs; } -static char *get_ref_match (const struct refspec_item *rs,int rs_nr,const struct ref *ref, -int send_mirror,int direction,const struct refspec_item **ret_pat) +static char *get_ref_match (const struct refspec *rs,const struct ref *ref, +int send_mirror,int direction, +const struct refspec_item **ret_pat) {const struct refspec_item *pat;char *name;int i;int matching_refs =-1 ; -for (i =0 ; i < rs_nr; i++) { -if (rs[i].matching && - (matching_refs ==-1 || rs[i].force)) { +for (i =0 ; i < rs->nr; i++) { +const struct refspec_item *item = &rs->items[i]; +if (item->matching && + (matching_refs ==-1 || item->force)) { matching_refs = i;continue ; } -if (rs[i].pattern) { -const char *dst_side = rs[i].dst ? rs[i].dst : rs[i].src; +if (item->pattern) { +const char *dst_side = item->dst ? item->dst : item->src;int match;if (direction ==FROM_SRC ) - match =match_name_with_pattern (rs[i].src, ref->name, dst_side, &name); + match =match_name_with_pattern (item->src, ref->name, dst_side, &name);else - match =match_name_with_pattern (dst_side, ref->name, rs[i].src, &name); + match =match_name_with_pattern (dst_side, ref->name, item->src, &name);if (match) { matching_refs = i;break ;
@@ -1121,7 +1123,7 @@ static char *get_ref_match(const struct refspec_item *rs, int rs_nr, const strucif (matching_refs ==-1 )return NULL ; - pat = rs + matching_refs; + pat = &rs->items[matching_refs];if (pat->matching) {/* * "matching refs"; traditionally we pushed everything
@@ -1318,7 +1320,7 @@ int match_push_refs(struct ref *src, struct ref **dst,const struct refspec_item *pat =NULL ;char *dst_name; - dst_name =get_ref_match (rs.items, rs.nr, ref, send_mirror,FROM_SRC , &pat); + dst_name =get_ref_match (&rs, ref, send_mirror,FROM_SRC , &pat);if (!dst_name)continue ;
@@ -1367,7 +1369,7 @@ int match_push_refs(struct ref *src, struct ref **dst,/* We're already sending something to this ref. */ continue ; - src_name =get_ref_match (rs.items, rs.nr, ref, send_mirror,FROM_DST ,NULL ); + src_name =get_ref_match (&rs, ref, send_mirror,FROM_DST ,NULL );if (src_name) {if (!src_ref_index.nr)prepare_ref_index (&src_ref_index, src);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 26/35 remote: convert match_explicit_refs to take a struct refspec
In reply to Brandon WilliamsConvert 'match_explicit_refs()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- remote.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
remote.c +4 -5
@@ -1082,12 +1082,11 @@ static int match_explicit(struct ref *src, struct ref *dst, }static int match_explicit_refs (struct ref *src,struct ref *dst, -struct ref ***dst_tail,struct refspec_item *rs, -int rs_nr) +struct ref ***dst_tail,struct refspec *rs) {int i, errs; -for (i = errs =0 ; i < rs_nr; i++) - errs +=match_explicit (src, dst, dst_tail, &rs[i]); +for (i = errs =0 ; i < rs->nr; i++) + errs +=match_explicit (src, dst, dst_tail, &rs->items[i]);return errs; }
@@ -1311,7 +1310,7 @@ int match_push_refs(struct ref *src, struct ref **dst, refspec = default_refspec; }refspec_appendn (&rs, refspec, nr_refspec); - errs =match_explicit_refs (src, *dst, &dst_tail, rs.items, rs.nr); + errs =match_explicit_refs (src, *dst, &dst_tail, &rs);/* pick the remainder */ for (ref = src; ref; ref = ref->next) {
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 27/35 push: check for errors earlier
In reply to Brandon WilliamsMove the error checking for using the "--mirror", "--all", and "--tags" options earlier and explicitly check for the presence of the flags instead of checking for a side-effect of the flag.
--- builtin/push.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-)
builtin/push.c +14 -17
@@ -417,23 +417,6 @@ static int do_push(const char *repo, int flags,if (push_options->nr) flags |=TRANSPORT_PUSH_OPTIONS ; -if ((flags &TRANSPORT_PUSH_ALL ) && refspec) { -if (!strcmp (*refspec,"refs/tags/*" )) -return error (_ ("--all and --tags are incompatible" )); -return error (_ ("--all can't be combined with refspecs" )); - } - -if ((flags &TRANSPORT_PUSH_MIRROR ) && refspec) { -if (!strcmp (*refspec,"refs/tags/*" )) -return error (_ ("--mirror and --tags are incompatible" )); -return error (_ ("--mirror can't be combined with refspecs" )); - } - -if ((flags & (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) == - (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) { -return error (_ ("--all and --mirror are incompatible" )); - } -if (!refspec && !(flags &TRANSPORT_PUSH_ALL )) {if (remote->push.raw_nr) { refspec = remote->push.raw;
@@ -625,6 +608,20 @@ int cmd_push(int argc, const char **argv, const char *prefix)die (_ ("--delete is incompatible with --all, --mirror and --tags" ));if (deleterefs && argc <2 )die (_ ("--delete doesn't make sense without any refs" )); +if (flags &TRANSPORT_PUSH_ALL ) { +if (tags) +die (_ ("--all and --tags are incompatible" )); +if (argc >=2 ) +die (_ ("--all can't be combined with refspecs" )); + } +if (flags &TRANSPORT_PUSH_MIRROR ) { +if (tags) +die (_ ("--mirror and --tags are incompatible" )); +if (argc >=2 ) +die (_ ("--mirror can't be combined with refspecs" )); + } +if ((flags &TRANSPORT_PUSH_ALL ) && (flags &TRANSPORT_PUSH_MIRROR )) +die (_ ("--all and --mirror are incompatible" ));if (recurse_submodules ==RECURSE_SUBMODULES_CHECK ) flags |=TRANSPORT_RECURSE_SUBMODULES_CHECK ;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 28/35 push: convert to use struct refspec
In reply to Brandon WilliamsConvert the refspecs in builtin/push.c to be stored in a 'struct refspec' instead of being stored in a list of 'struct refspec_item's.
--- builtin/push.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-)
builtin/push.c +15 -23
@@ -57,19 +57,10 @@ static enum transport_family family;static struct push_cas_option cas; -static const char **refspec; -static int refspec_nr; -static int refspec_alloc; +static struct refspec rs =REFSPEC_INIT_PUSH ;static struct string_list push_options_config =STRING_LIST_INIT_DUP ; -static void add_refspec (const char *ref) -{ - refspec_nr++; -ALLOC_GROW (refspec, refspec_nr, refspec_alloc); - refspec[refspec_nr-1 ] = ref; -} -static const char *map_refspec (const char *ref,struct remote *remote,struct ref *local_refs) {
@@ -138,7 +129,7 @@ static void set_refspecs(const char **refs, int nr, const char *repo) } ref =map_refspec (ref, remote, local_refs); } -add_refspec (ref); +refspec_append (&rs, ref); } }
@@ -226,7 +217,7 @@ static void setup_push_upstream(struct remote *remote, struct branch *branch, }strbuf_addf (&refspec,"%s:%s" , branch->refname, branch->merge[0 ]->src); -add_refspec (refspec.buf); +refspec_append (&rs, refspec.buf); }static void setup_push_current (struct remote *remote,struct branch *branch)
@@ -236,7 +227,7 @@ static void setup_push_current(struct remote *remote, struct branch *branch)if (!branch)die (_ (message_detached_head_die), remote->name);strbuf_addf (&refspec,"%s:%s" , branch->refname, branch->refname); -add_refspec (refspec.buf); +refspec_append (&rs, refspec.buf); }static int is_workflow_triangular (struct remote *remote)
@@ -253,7 +244,7 @@ static void setup_default_push_refspecs(struct remote *remote)switch (push_default) {default :case PUSH_DEFAULT_MATCHING : -add_refspec (":" ); +refspec_append (&rs,":" );break ;case PUSH_DEFAULT_UNSPECIFIED :
@@ -341,7 +332,8 @@ static void advise_ref_needs_force(void)advise (_ (message_advice_ref_needs_force)); } -static int push_with_options (struct transport *transport,int flags) +static int push_with_options (struct transport *transport,struct refspec *rs, +int flags) {int err;unsigned int reject_reasons;
@@ -363,7 +355,7 @@ static int push_with_options(struct transport *transport, int flags)if (verbosity >0 )fprintf (stderr,_ ("Pushing to %s\n" ), transport->url); - err =transport_push (transport, refspec_nr, refspec, flags, + err =transport_push (transport, rs->raw_nr, rs->raw, flags, &reject_reasons);if (err !=0 ) {fprintf (stderr,"%s" ,push_get_color (PUSH_COLOR_ERROR ));
@@ -397,6 +389,7 @@ static int do_push(const char *repo, int flags,struct remote *remote =pushremote_get (repo);const char **url;int url_nr; +struct refspec *push_refspec = &rs;if (!remote) {if (repo)
@@ -417,10 +410,9 @@ static int do_push(const char *repo, int flags,if (push_options->nr) flags |=TRANSPORT_PUSH_OPTIONS ; -if (!refspec && !(flags &TRANSPORT_PUSH_ALL )) { -if (remote->push.raw_nr) { - refspec = remote->push.raw; - refspec_nr = remote->push.raw_nr; +if (!push_refspec->nr && !(flags &TRANSPORT_PUSH_ALL )) { +if (remote->push.nr) { + push_refspec = &remote->push; }else if (!(flags &TRANSPORT_PUSH_MIRROR ))setup_default_push_refspecs (remote); }
@@ -432,7 +424,7 @@ static int do_push(const char *repo, int flags,transport_get (remote, url[i]);if (flags &TRANSPORT_PUSH_OPTIONS ) transport->push_options = push_options; -if (push_with_options (transport, flags)) +if (push_with_options (transport, push_refspec, flags)) errs++; } }else {
@@ -440,7 +432,7 @@ static int do_push(const char *repo, int flags,transport_get (remote,NULL );if (flags &TRANSPORT_PUSH_OPTIONS ) transport->push_options = push_options; -if (push_with_options (transport, flags)) +if (push_with_options (transport, push_refspec, flags)) errs++; }return !!errs;
@@ -631,7 +623,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) flags |=TRANSPORT_RECURSE_SUBMODULES_ONLY ;if (tags) -add_refspec ("refs/tags/*" ); +refspec_append (&rs,"refs/tags/*" );if (argc >0 ) { repo = argv[0 ];
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 29/35 transport: convert transport_push to take a struct refspec
In reply to Brandon WilliamsConvert 'transport_push()' to take a 'struct refspec' as a parameter instead of an array of strings which represent refspecs.
--- builtin/push.c | 3 +-- transport.c | 17 +++++++---------- transport.h | 2 +- 3 files changed, 9 insertions(+), 13 deletions(-)
builtin/push.c +1 -2
@@ -355,8 +355,7 @@ static int push_with_options(struct transport *transport, struct refspec *rs,if (verbosity >0 )fprintf (stderr,_ ("Pushing to %s\n" ), transport->url); - err =transport_push (transport, rs->raw_nr, rs->raw, flags, - &reject_reasons); + err =transport_push (transport, rs, flags, &reject_reasons);if (err !=0 ) {fprintf (stderr,"%s" ,push_get_color (PUSH_COLOR_ERROR ));error (_ ("failed to push some refs to '%s'" ), transport->url);
transport.c +7 -10
@@ -1093,11 +1093,11 @@ static int run_pre_push_hook(struct transport *transport, }int transport_push (struct transport *transport, -int refspec_nr,const char **refspec,int flags, +struct refspec *rs,int flags,unsigned int *reject_reasons) { *reject_reasons =0 ; -transport_verify_remote_names (refspec_nr, refspec); +transport_verify_remote_names (rs->raw_nr, rs->raw);if (transport_color_config () <0 )return -1 ;
@@ -1111,16 +1111,14 @@ int transport_push(struct transport *transport,int porcelain = flags &TRANSPORT_PUSH_PORCELAIN ;int pretend = flags &TRANSPORT_PUSH_DRY_RUN ;int push_ret, ret, err; -struct refspec tmp_rs =REFSPEC_INIT_PUSH ;struct argv_array ref_prefixes =ARGV_ARRAY_INIT ;int i; -if (check_push_refs (local_refs, refspec_nr, refspec) <0 ) +if (check_push_refs (local_refs, rs->raw_nr, rs->raw) <0 )return -1 ; -refspec_appendn (&tmp_rs, refspec, refspec_nr); -for (i =0 ; i < tmp_rs.nr; i++) { -const struct refspec_item *item = &tmp_rs.items[i]; +for (i =0 ; i < rs->nr; i++) { +const struct refspec_item *item = &rs->items[i];const char *prefix =NULL ;if (item->dst)
@@ -1143,7 +1141,6 @@ int transport_push(struct transport *transport, &ref_prefixes);argv_array_clear (&ref_prefixes); -refspec_clear (&tmp_rs);if (flags &TRANSPORT_PUSH_ALL ) match_flags |=MATCH_REFS_ALL ;
@@ -1155,7 +1152,7 @@ int transport_push(struct transport *transport, match_flags |=MATCH_REFS_FOLLOW_TAGS ;if (match_push_refs (local_refs, &remote_refs, - refspec_nr, refspec, match_flags)) { + rs->raw_nr, rs->raw, match_flags)) {return -1 ; }
@@ -1186,7 +1183,7 @@ int transport_push(struct transport *transport,if (!push_unpushed_submodules (&commits, transport->remote, - refspec, refspec_nr, + rs->raw, rs->raw_nr, transport->push_options, pretend)) {oid_array_clear (&commits);
transport.h +1 -1
@@ -197,7 +197,7 @@ void transport_set_verbosity(struct transport *transport, int verbosity,#define REJECT_NEEDS_FORCE 0x10int transport_push (struct transport *connection, -int refspec_nr,const char **refspec,int flags, +struct refspec *rs,int flags,unsigned int * reject_reasons);/*
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 30/35 send-pack: store refspecs in a struct refspec
In reply to Brandon WilliamsConvert send-pack.c to store refspecs in a 'struct refspec' instead of as an array of 'const char *'.
--- builtin/send-pack.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-)
builtin/send-pack.c +7 -17
@@ -126,8 +126,7 @@ static int send_pack_config(const char *k, const char *v, void *cb)int cmd_send_pack (int argc,const char **argv,const char *prefix) { -int i, nr_refspecs =0 ; -const char **refspecs =NULL ; +struct refspec rs =REFSPEC_INIT_PUSH ;const char *remote_name =NULL ;struct remote *remote =NULL ;const char *dest =NULL ;
@@ -189,8 +188,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) argc =parse_options (argc, argv, prefix, options, send_pack_usage,0 );if (argc >0 ) { dest = argv[0 ]; - refspecs = (const char **)(argv +1 ); - nr_refspecs = argc -1 ; +refspec_appendn (&rs, argv +1 , argc -1 ); }if (!dest)
@@ -209,31 +207,23 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) args.push_options = push_options.nr ? &push_options :NULL ;if (from_stdin) { -struct argv_array all_refspecs =ARGV_ARRAY_INIT ; - -for (i =0 ; i < nr_refspecs; i++) -argv_array_push (&all_refspecs, refspecs[i]); -if (args.stateless_rpc) {const char *buf;while ((buf =packet_read_line (0 ,NULL ))) -argv_array_push (&all_refspecs, buf); +refspec_append (&rs, buf); }else {struct strbuf line =STRBUF_INIT ;while (strbuf_getline (&line, stdin) !=EOF ) -argv_array_push (&all_refspecs, line.buf); +refspec_append (&rs, line.buf);strbuf_release (&line); } - - refspecs = all_refspecs.argv; - nr_refspecs = all_refspecs.argc; }/* * --all and --mirror are incompatible; neither makes sense * with any refspecs. */ -if ((nr_refspecs >0 && (send_all || args.send_mirror)) || +if ((rs.nr >0 && (send_all || args.send_mirror)) || (send_all && args.send_mirror))usage_with_options (send_pack_usage, options);
@@ -275,7 +265,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)BUG ("unknown protocol version" ); } -transport_verify_remote_names (nr_refspecs, refspecs); +transport_verify_remote_names (rs.raw_nr, rs.raw); local_refs =get_local_heads ();
@@ -287,7 +277,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) flags |=MATCH_REFS_MIRROR ;/* match them up */ -if (match_push_refs (local_refs, &remote_refs, nr_refspecs, refspecs, flags)) +if (match_push_refs (local_refs, &remote_refs, rs.raw_nr, rs.raw, flags))return -1 ;if (!is_empty_cas (&cas))
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 31/35 transport: remove transport_verify_remote_names
In reply to Brandon WilliamsRemove 'transprot_verify_remote_names()' because all callers have migrated to using 'struct refspec' which performs the same checks in 'parse_refspec()'.
--- builtin/send-pack.c | 2 -- transport.c | 24 ------------------------ transport.h | 2 -- 3 files changed, 28 deletions(-)
builtin/send-pack.c +0 -2
@@ -265,8 +265,6 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)BUG ("unknown protocol version" ); } -transport_verify_remote_names (rs.raw_nr, rs.raw); - local_refs =get_local_heads (); flags =MATCH_REFS_NONE ;
transport.c +0 -24
@@ -619,29 +619,6 @@ void transport_print_push_status(const char *dest, struct ref *refs,free (head); } -void transport_verify_remote_names (int nr_heads,const char **heads) -{ -int i; - -for (i =0 ; i < nr_heads; i++) { -const char *local = heads[i]; -const char *remote =strrchr (heads[i],':' ); - -if (*local =='+' ) - local++; - -/* A matching refspec is okay. */ -if (remote == local && remote[1 ] =='\0' ) -continue ; - - remote = remote ? (remote +1 ) : local; -if (check_refname_format (remote, -REFNAME_ALLOW_ONELEVEL |REFNAME_REFSPEC_PATTERN )) -die ("remote part of refspec is not a valid name in %s" , - heads[i]); - } -} -static int git_transport_push (struct transport *transport,struct ref *remote_refs,int flags) {struct git_transport_data *data = transport->data;
@@ -1097,7 +1074,6 @@ int transport_push(struct transport *transport, unsigned int *reject_reasons) { *reject_reasons =0 ; -transport_verify_remote_names (rs->raw_nr, rs->raw);if (transport_color_config () <0 )return -1 ;
transport.h +0 -2
@@ -227,8 +227,6 @@ int transport_helper_init(struct transport *transport, const char *name);int bidirectional_transfer_loop (int input,int output);/* common methods used by transport.c and builtin/send-pack.c */ -void transport_verify_remote_names (int nr_heads,const char **heads); -void transport_update_tracking_ref (struct remote *remote,struct ref *ref,int verbose);int transport_refs_pushed (struct ref *ref);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 32/35 http-push: store refspecs in a struct refspec
In reply to Brandon WilliamsConvert http-push.c to store refspecs in a 'struct refspec' instead of in an array of 'const char *'.
--- http-push.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
http-push.c +8 -9
@@ -1692,8 +1692,7 @@ int cmd_main(int argc, const char **argv) {struct transfer_request *request;struct transfer_request *next_request; -int nr_refspec =0 ; -const char **refspec =NULL ; +struct refspec rs =REFSPEC_INIT_PUSH ;struct remote_lock *ref_lock =NULL ;struct remote_lock *info_ref_lock =NULL ;struct rev_info revs;
@@ -1756,8 +1755,7 @@ int cmd_main(int argc, const char **argv) }continue ; } - refspec = argv; - nr_refspec = argc - i; +refspec_appendn (&rs, argv, argc - i);break ; }
@@ -1768,7 +1766,7 @@ int cmd_main(int argc, const char **argv)if (!repo->url)usage (http_push_usage); -if (delete_branch && nr_refspec !=1 ) +if (delete_branch && rs.nr !=1 )die ("You must specify only one branch name when deleting a remote branch" );setup_git_directory ();
@@ -1814,18 +1812,19 @@ int cmd_main(int argc, const char **argv)/* Remove a remote branch if -d or -D was specified */ if (delete_branch) { -if (delete_remote_branch (refspec[0 ], force_delete) ==-1 ) { +const char *branch = rs.items[i].src; +if (delete_remote_branch (branch, force_delete) ==-1 ) {fprintf (stderr,"Unable to delete remote branch %s\n" , - refspec[0 ]); + branch);if (helper_status) -printf ("error %s cannot remove\n" , refspec[0 ]); +printf ("error %s cannot remove\n" , branch); } goto cleanup; }/* match them up */ if (match_push_refs (local_refs, &remote_refs, - nr_refspec, (const char **) refspec, push_all)) { + rs.raw_nr, rs.raw, push_all)) { rc =-1 ; goto cleanup; }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 33/35 remote: convert match_push_refs to take a struct refspec
In reply to Brandon WilliamsConvert 'match_push_refs()' to take a 'struct refspec' as a parameter instead of an array of 'const char *'.
--- builtin/remote.c | 3 +-- builtin/send-pack.c | 2 +- http-push.c | 3 +-- remote.c | 21 ++++++++------------- remote.h | 2 +- transport.c | 4 +--- 6 files changed, 13 insertions(+), 22 deletions(-)
builtin/remote.c +1 -2
@@ -387,8 +387,7 @@ static int get_push_ref_states(const struct ref *remote_refs, local_refs =get_local_heads (); push_map =copy_ref_list (remote_refs); -match_push_refs (local_refs, &push_map, remote->push.raw_nr, - remote->push.raw,MATCH_REFS_NONE ); +match_push_refs (local_refs, &push_map, &remote->push,MATCH_REFS_NONE ); states->push.strdup_strings =1 ;for (ref = push_map; ref; ref = ref->next) {
builtin/send-pack.c +1 -1
@@ -275,7 +275,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) flags |=MATCH_REFS_MIRROR ;/* match them up */ -if (match_push_refs (local_refs, &remote_refs, rs.raw_nr, rs.raw, flags)) +if (match_push_refs (local_refs, &remote_refs, &rs, flags))return -1 ;if (!is_empty_cas (&cas))
http-push.c +1 -2
@@ -1823,8 +1823,7 @@ int cmd_main(int argc, const char **argv) }/* match them up */ -if (match_push_refs (local_refs, &remote_refs, - rs.raw_nr, rs.raw, push_all)) { +if (match_push_refs (local_refs, &remote_refs, &rs, push_all)) { rc =-1 ; goto cleanup; }
remote.c +8 -13
@@ -1294,23 +1294,20 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)* dst (e.g. pushing to a new branch, done in match_explicit_refs). */ int match_push_refs (struct ref *src,struct ref **dst, -int nr_refspec,const char **refspec,int flags) +struct refspec *rs,int flags) { -struct refspec rs =REFSPEC_INIT_PUSH ;int send_all = flags &MATCH_REFS_ALL ;int send_mirror = flags &MATCH_REFS_MIRROR ;int send_prune = flags &MATCH_REFS_PRUNE ;int errs; -static const char *default_refspec[] = {":" ,NULL };struct ref *ref, **dst_tail =tail_ref (dst);struct string_list dst_ref_index =STRING_LIST_INIT_NODUP ; -if (!nr_refspec) { - nr_refspec =1 ; - refspec = default_refspec; - } -refspec_appendn (&rs, refspec, nr_refspec); - errs =match_explicit_refs (src, *dst, &dst_tail, &rs); +/* If no refspec is provided, use the default ":" */ +if (!rs->nr) +refspec_append (rs,":" ); + + errs =match_explicit_refs (src, *dst, &dst_tail, rs);/* pick the remainder */ for (ref = src; ref; ref = ref->next) {
@@ -1319,7 +1316,7 @@ int match_push_refs(struct ref *src, struct ref **dst,const struct refspec_item *pat =NULL ;char *dst_name; - dst_name =get_ref_match (&rs, ref, send_mirror,FROM_SRC , &pat); + dst_name =get_ref_match (rs, ref, send_mirror,FROM_SRC , &pat);if (!dst_name)continue ;
@@ -1368,7 +1365,7 @@ int match_push_refs(struct ref *src, struct ref **dst,/* We're already sending something to this ref. */ continue ; - src_name =get_ref_match (&rs, ref, send_mirror,FROM_DST ,NULL ); + src_name =get_ref_match (rs, ref, send_mirror,FROM_DST ,NULL );if (src_name) {if (!src_ref_index.nr)prepare_ref_index (&src_ref_index, src);
@@ -1381,8 +1378,6 @@ int match_push_refs(struct ref *src, struct ref **dst,string_list_clear (&src_ref_index,0 ); } -refspec_clear (&rs); -if (errs)return -1 ;return 0 ;
remote.h +1 -1
@@ -163,7 +163,7 @@ char *apply_refspecs(struct refspec *rs, const char *name);int check_push_refs (struct ref *src,int nr_refspec,const char **refspec);int match_push_refs (struct ref *src,struct ref **dst, -int nr_refspec,const char **refspec,int all); +struct refspec *rs,int flags);void set_ref_status_for_push (struct ref *remote_refs,int send_mirror,int force_update);
transport.c +1 -3
@@ -1127,10 +1127,8 @@ int transport_push(struct transport *transport,if (flags &TRANSPORT_PUSH_FOLLOW_TAGS ) match_flags |=MATCH_REFS_FOLLOW_TAGS ; -if (match_push_refs (local_refs, &remote_refs, - rs->raw_nr, rs->raw, match_flags)) { +if (match_push_refs (local_refs, &remote_refs, rs, match_flags))return -1 ; - } if (transport->smart_options && transport->smart_options->cas &&
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 34/35 remote: convert check_push_refs to take a struct refspec
In reply to Brandon WilliamsConvert 'check_push_refs()' to take a 'struct refspec' as a parameter instead of an array of 'const char *'.
--- remote.c | 14 +++++--------- remote.h | 2 +- transport.c | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-)
remote.c +5 -9
@@ -1264,24 +1264,20 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)* but we can catch some errors early before even talking to the * remote side. */ -int check_push_refs (struct ref *src,int nr_refspec,const char **refspec_names) +int check_push_refs (struct ref *src,struct refspec *rs) { -struct refspec refspec =REFSPEC_INIT_PUSH ;int ret =0 ;int i; -refspec_appendn (&refspec, refspec_names, nr_refspec); - -for (i =0 ; i < refspec.nr; i++) { -struct refspec_item *rs = &refspec.items[i]; +for (i =0 ; i < rs->nr; i++) { +struct refspec_item *item = &rs->items[i]; -if (rs->pattern || rs->matching) +if (item->pattern || item->matching)continue ; - ret |=match_explicit_lhs (src, rs,NULL ,NULL ); + ret |=match_explicit_lhs (src, item,NULL ,NULL ); } -refspec_clear (&refspec);return ret; }
remote.h +1 -1
@@ -161,7 +161,7 @@ struct ref *ref_remove_duplicates(struct ref *ref_map);int query_refspecs (struct refspec *rs,struct refspec_item *query);char *apply_refspecs (struct refspec *rs,const char *name); -int check_push_refs (struct ref *src,int nr_refspec,const char **refspec); +int check_push_refs (struct ref *src,struct refspec *rs);int match_push_refs (struct ref *src,struct ref **dst,struct refspec *rs,int flags); void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
transport.c +1 -1
@@ -1090,7 +1090,7 @@ int transport_push(struct transport *transport,struct argv_array ref_prefixes =ARGV_ARRAY_INIT ;int i; -if (check_push_refs (local_refs, rs->raw_nr, rs->raw) <0 ) +if (check_push_refs (local_refs, rs) <0 )return -1 ;for (i =0 ; i < rs->nr; i++) {
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 35/35 submodule: convert push_unpushed_submodules to take a struct refspec
In reply to Brandon WilliamsConvert 'push_unpushed_submodules()' to take a 'struct refspec' as a parameter instead of an array of 'const char *'.
--- submodule.c | 19 +++++++++---------- submodule.h | 3 ++- transport.c | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-)
submodule.c +9 -10
@@ -968,7 +968,7 @@ int find_unpushed_submodules(struct oid_array *commits,static int push_submodule (const char *path,const struct remote *remote, -const char **refspec,int refspec_nr, +const struct refspec *rs,const struct string_list *push_options,int dry_run) {
@@ -991,8 +991,8 @@ static int push_submodule(const char *path,if (remote->origin !=REMOTE_UNCONFIGURED ) {int i;argv_array_push (&cp.args, remote->name); -for (i =0 ; i < refspec_nr; i++) -argv_array_push (&cp.args, refspec[i]); +for (i =0 ; i < rs->raw_nr; i++) +argv_array_push (&cp.args, rs->raw[i]); }prepare_submodule_repo_env (&cp.env_array);
@@ -1013,7 +1013,7 @@ static int push_submodule(const char *path,*/ static void submodule_push_check (const char *path,const char *head,const struct remote *remote, -const char **refspec,int refspec_nr) +const struct refspec *rs) {struct child_process cp =CHILD_PROCESS_INIT ;int i;
@@ -1023,8 +1023,8 @@ static void submodule_push_check(const char *path, const char *head,argv_array_push (&cp.args, head);argv_array_push (&cp.args, remote->name); -for (i =0 ; i < refspec_nr; i++) -argv_array_push (&cp.args, refspec[i]); +for (i =0 ; i < rs->raw_nr; i++) +argv_array_push (&cp.args, rs->raw[i]);prepare_submodule_repo_env (&cp.env_array); cp.git_cmd =1 ;
@@ -1043,7 +1043,7 @@ static void submodule_push_check(const char *path, const char *head,int push_unpushed_submodules (struct oid_array *commits,const struct remote *remote, -const char **refspec,int refspec_nr, +const struct refspec *rs,const struct string_list *push_options,int dry_run) {
@@ -1069,8 +1069,7 @@ int push_unpushed_submodules(struct oid_array *commits,for (i =0 ; i < needs_pushing.nr; i++)submodule_push_check (needs_pushing.items[i].string, - head, remote, - refspec, refspec_nr); + head, remote, rs);free (head); }
@@ -1078,7 +1077,7 @@ int push_unpushed_submodules(struct oid_array *commits,for (i =0 ; i < needs_pushing.nr; i++) {const char *path = needs_pushing.items[i].string;fprintf (stderr,"Pushing submodule '%s'\n" , path); -if (!push_submodule (path, remote, refspec, refspec_nr, +if (!push_submodule (path, remote, rs, push_options, dry_run)) {fprintf (stderr,"Unable to push submodule '%s'\n" , path); ret =0 ;
submodule.h +2 -1
@@ -100,9 +100,10 @@ extern int submodule_touches_in_range(struct object_id *a,extern int find_unpushed_submodules (struct oid_array *commits,const char *remotes_name,struct string_list *needs_pushing); +struct refspec ;extern int push_unpushed_submodules (struct oid_array *commits,const struct remote *remote, -const char **refspec,int refspec_nr, +const struct refspec *rs,const struct string_list *push_options,int dry_run);/*
transport.c +1 -1
@@ -1157,7 +1157,7 @@ int transport_push(struct transport *transport,if (!push_unpushed_submodules (&commits, transport->remote, - rs->raw, rs->raw_nr, + rs, transport->push_options, pretend)) {oid_array_clear (&commits);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Re: [PATCH 35/35] submodule: convert push_unpushed_submodules to take a struct refspec
Quoted 9 lines · Brandon Williams
Convert '
push_unpushed_submodules()' to take a 'struct refspec' as a parameter instead of an array of 'const char *'.
[...]submodule.h +0
-0@@ -100,9 +100,10 @@ extern int submodule_touches_in_range(struct object_id *a, extern int find_unpushed_submodules(struct oid_array *commits,
submodule.h extern int submodule_touches_in_range(struct object_id *a, · line 109
Quoted 10 lines
submodule.h +2
-1const char *remotes_name, struct string_list *needs_pushing); +struct refspec ;extern int push_unpushed_submodules (struct oid_array *commits,const struct remote *remote, -const char **refspec,int refspec_nr, +const struct refspec *rs,const struct string_list *push_options,int dry_run);/*
Why do you prefer doing this to having this on top?:
diff --git a/submodule.h b/submodule.h
index aae0c9c8ff..c3f206ce17 100644
--- a/submodule.h
+++ b/submodule.h
@@ -1,5 +1,6 @@
#ifndef SUBMODULE_H
#define SUBMODULE_H
+#include "refspec.h"
struct repository;
struct diff_options;
@@ -100,7 +101,6 @@ extern int submodule_touches_in_range(struct object_id *a,
extern int find_unpushed_submodules(struct oid_array *commits,
const char *remotes_name,
struct string_list *needs_pushing);
-struct refspec;
extern int push_unpushed_submodules(struct oid_array *commits,
const struct remote *remote,
const struct refspec *rs,Re: [PATCH 35/35] submodule: convert push_unpushed_submodules to take a struct refspec
Quoted 16 lines · Ævar Arnfjörð Bjarmason
Quoted 13 lines · Brandon Williams
Convert '
push_unpushed_submodules()' to take a 'struct refspec' as a parameter instead of an array of 'const char *'.
[...]submodule.h +1
-0@@ -100,9 +100,10 @@ extern int submodule_touches_in_range(struct object_id *a,extern int find_unpushed_submodules (struct oid_array *commits,const char *remotes_name,struct string_list *needs_pushing); +struct refspec ; extern int push_unpushed_submodules(struct oid_array *commits,
Quoted 8 lines
submodule.h extern int submodule_touches_in_range(struct object_id *a, · line 109
Quoted 6 lines
submodule.h +1
-1const struct remote *remote, - const char **refspec, int refspec_nr, + const struct refspec *rs, const struct string_list *push_options, int dry_run);/* Why do you prefer doing this to having this on top?:
The fewer includes in header files the better, as then the headers themselves don't have dependencies. (Otherwise we'd end up multiplying cache.h ;)
In the source files we have to include all needed headers, but for the headers, it is better if we can just get away with declaring the existence of a struct.
This way we reduce compile time, so I'd am not keen on your patch on top.
This is discussed a lot on stackoverflow, e.g.:
https://softwareengineering.stackexchange.com/questions/195806/forward-declaration-vs-include
https://stackoverflow.com/a/15828094
Stefan
Re: [PATCH 35/35] submodule: convert push_unpushed_submodules to take a struct refspec
In reply to Ævar Arnfjörð BjarmasonQuoted 36 lines · Ævar Arnfjörð Bjarmason
Quoted 9 lines · Brandon Williams
Convert '
push_unpushed_submodules()' to take a 'struct refspec' as a parameter instead of an array of 'const char *'.
[...]submodule.h +0
-0@@ -100,9 +100,10 @@ extern int submodule_touches_in_range(struct object_id *a, extern int find_unpushed_submodules(struct oid_array *commits,submodule.h extern int submodule_touches_in_range(struct object_id *a, · line 109
Quoted 10 lines
submodule.h +2
-1const char *remotes_name, struct string_list *needs_pushing); +struct refspec ;extern int push_unpushed_submodules (struct oid_array *commits,const struct remote *remote, -const char **refspec,int refspec_nr, +const struct refspec *rs,const struct string_list *push_options,int dry_run);/* Why do you prefer doing this to having this on top?:
diff --git a/submodule.h b/submodule.h index aae0c9c8ff..c3f206ce17 100644 --- a/submodule.h +++ b/submodule.h @@ -1,5 +1,6 @@ #ifndef SUBMODULE_H #define SUBMODULE_H +#include "refspec.h" struct repository; struct diff_options;
Quoted 8 lines
@@ -100,7 +101,6 @@ extern int submodule_touches_in_range(struct object_id *a,
extern int find_unpushed_submodules(struct oid_array *commits,
const char *remotes_name,
struct string_list *needs_pushing);
-struct refspec;
extern int push_unpushed_submodules(struct oid_array *commits,
const struct remote *remote,
const struct refspec *rs,Basically for the reason that stefan pointed out, though in practice I don't know how much that would actually impact compile times given we already are including cache.h and a bunch of others everywhere.
Signature · 1 line
Brandon Williams
Quoted 3 lines
22 files changed, 514 insertions(+), 571 deletions(-) create mode 100644 refspec.c create mode 100644 refspec.h
This looks promising. I'll hope to find time to review it.
Stefan
Quoted 5 lines · Brandon Williams
This series refactors how refspecs are handled through out the code base by renaming the existing struct refspec to
refspec_itemand introducing a new 'struct refspec' which is a container ofrefspec_items, much like how a pathspec containspathspec_items. This simplifies many callers and makes handling pathspecs a bit easier.
Good. IOW, a refspec is a set of refspec items, just like a pathspec is a set of pathspec items. The two level abstraction would naturally let us work on individual items as well as the whole thing as a single set, which is quite nice.
Quoted 8 lines · Brandon Williams
When working on protocol v2 I noticed that working with refspecs was a little difficult because of the various api's that existed. Some functions expected an array of "const char *" while others expected an array of "struct refspec". In all cases a length parameter needed to be passed as a parameter as well. This makes working with refspecs a little challenging because of the different expectations different parts of the code base have.
Quoted 5 lines
This series refactors how refspecs are handled through out the code base by renaming the existing struct refspec to
refspec_itemand introducing a new 'struct refspec' which is a container ofrefspec_items, much like how a pathspec containspathspec_items. This simplifies many callers and makes handling pathspecs a bit easier.
This looks really good to me. The API you're replacing is one of the worst I've had a chance to encounter in git.git (as noted in my
https://public-inbox.org/git/[email protected]/ but maybe I haven't looked widely enough), and now it's really nice.
Quoted 3 lines
I have some follow on work which I'll build on top of this series, but since this was already getting a bit lengthy at 35 patches I'll save that for another time.
In addition to my other suggestions for stuff to put on top, which I see now you may have just had in your local tree but didn't submit, I think this makes sense:
diff --git a/remote.c b/remote.c
index 946b95d18d..cb97e662e8 100644
--- a/remote.c
+++ b/remote.c
@@ -77,16 +77,6 @@ static const char *alias_url(const char *url, struct rewrites *r)
return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len);
}
-static void add_push_refspec(struct remote *remote, const char *ref)
-{
- refspec_append(&remote->push, ref);
-}
-
-static void add_fetch_refspec(struct remote *remote, const char *ref)
-{
- refspec_append(&remote->fetch, ref);
-}
-
static void add_url(struct remote *remote, const char *url)
{
ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
@@ -261,9 +251,9 @@ static void read_remotes_file(struct remote *remote)
if (skip_prefix(buf.buf, "URL:", &v))
add_url_alias(remote, xstrdup(skip_spaces(v)));
else if (skip_prefix(buf.buf, "Push:", &v))
- add_push_refspec(remote, xstrdup(skip_spaces(v)));
+ refspec_append(&remote->push, xstrdup(skip_spaces(v)));
else if (skip_prefix(buf.buf, "Pull:", &v))
- add_fetch_refspec(remote, xstrdup(skip_spaces(v)));
+ refspec_append(&remote->fetch, xstrdup(skip_spaces(v)));
}
strbuf_release(&buf);
fclose(f);
@@ -302,14 +292,14 @@ static void read_branches_file(struct remote *remote)
frag = "master";
add_url_alias(remote, strbuf_detach(&buf, NULL));
- add_fetch_refspec(remote, xstrfmt("refs/heads/%s:refs/heads/%s",
- frag, remote->name));
+ refspec_append(&remote->fetch, xstrfmt("refs/heads/%s:refs/heads/%s",
+ frag, remote->name));
/*
* Cogito compatible push: push current HEAD to remote #branch
* (master if missing)
*/
- add_push_refspec(remote, xstrfmt("HEAD:refs/heads/%s", frag));
+ refspec_append(&remote->push, xstrfmt("HEAD:refs/heads/%s", frag));
remote->fetch_tags = 1; /* always auto-follow */
}
@@ -395,12 +385,12 @@ static int handle_config(const char *key, const char *value, void *cb)
const char *v;
if (git_config_string(&v, key, value))
return -1;
- add_push_refspec(remote, v);
+ refspec_append(&remote->push, v);
} else if (!strcmp(subkey, "fetch")) {
const char *v;
if (git_config_string(&v, key, value))
return -1;
- add_fetch_refspec(remote, v);
+ refspec_append(&remote->fetch, v);
} else if (!strcmp(subkey, "receivepack")) {
const char *v;
if (git_config_string(&v, key, value))I.e. the reason we have add_{push,fetch}_refspec() in the first place is because without your series it's tricky to add new ones, but now it's trivial, so let's not leave behind wrapper static functions whose sole purpose is to just call another exported API as-is.
I've pushed all the patches I quoted inline in this review at avar-bwill/refspec in github.com/avar/git, consider them all signed-off, and depending on whether you agree/disagree etc. please squash them/adapt them/drop them however you see fit.
Quoted 17 lines · Ævar Arnfjörð Bjarmason
Quoted 8 lines · Brandon Williams
When working on protocol v2 I noticed that working with refspecs was a little difficult because of the various api's that existed. Some functions expected an array of "const char *" while others expected an array of "struct refspec". In all cases a length parameter needed to be passed as a parameter as well. This makes working with refspecs a little challenging because of the different expectations different parts of the code base have.
Quoted 5 lines
This series refactors how refspecs are handled through out the code base by renaming the existing struct refspec to
refspec_itemand introducing a new 'struct refspec' which is a container ofrefspec_items, much like how a pathspec containspathspec_items. This simplifies many callers and makes handling pathspecs a bit easier.
Quoted 4 lines
This looks really good to me. The API you're replacing is one of the worst I've had a chance to encounter in git.git (as noted in my
https://public-inbox.org/git/[email protected]/ but maybe I haven't looked widely enough), and now it's really nice.
Thanks! Yeah its one of the rougher edges I've worked with and I'm glad I finally got around to fixing it.
Quoted 8 lines
Quoted 4 lines
I have some follow on work which I'll build on top of this series, but since this was already getting a bit lengthy at 35 patches I'll save that for another time.
In addition to my other suggestions for stuff to put on top, which I see now you may have just had in your local tree but didn't submit, I think this makes sense:
Yes these changes make sense, though I'll need to tweak them to avoid some memory leaks. I'll probably go ahead and squash it into the two patches which effect those two functions.
Thanks for catching this.
Quoted 77 lines
diff --git a/remote.c b/remote.c index 946b95d18d..cb97e662e8 100644 --- a/remote.c +++ b/remote.c @@ -77,16 +77,6 @@ static const char *alias_url(const char *url, struct rewrites *r) return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len); } -static void add_push_refspec(struct remote *remote, const char *ref) -{ - refspec_append(&remote->push, ref); -} - -static void add_fetch_refspec(struct remote *remote, const char *ref) -{ - refspec_append(&remote->fetch, ref); -} - static void add_url(struct remote *remote, const char *url) { ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc); @@ -261,9 +251,9 @@ static void read_remotes_file(struct remote *remote) if (skip_prefix(buf.buf, "URL:", &v)) add_url_alias(remote, xstrdup(skip_spaces(v))); else if (skip_prefix(buf.buf, "Push:", &v)) - add_push_refspec(remote, xstrdup(skip_spaces(v))); + refspec_append(&remote->push, xstrdup(skip_spaces(v))); else if (skip_prefix(buf.buf, "Pull:", &v)) - add_fetch_refspec(remote, xstrdup(skip_spaces(v))); + refspec_append(&remote->fetch, xstrdup(skip_spaces(v))); } strbuf_release(&buf); fclose(f); @@ -302,14 +292,14 @@ static void read_branches_file(struct remote *remote) frag = "master"; add_url_alias(remote, strbuf_detach(&buf, NULL)); - add_fetch_refspec(remote, xstrfmt("refs/heads/%s:refs/heads/%s", - frag, remote->name)); + refspec_append(&remote->fetch, xstrfmt("refs/heads/%s:refs/heads/%s", + frag, remote->name)); /* * Cogito compatible push: push current HEAD to remote #branch * (master if missing) */ - add_push_refspec(remote, xstrfmt("HEAD:refs/heads/%s", frag)); + refspec_append(&remote->push, xstrfmt("HEAD:refs/heads/%s", frag)); remote->fetch_tags = 1; /* always auto-follow */ } @@ -395,12 +385,12 @@ static int handle_config(const char *key, const char *value, void *cb) const char *v; if (git_config_string(&v, key, value)) return -1; - add_push_refspec(remote, v); + refspec_append(&remote->push, v); } else if (!strcmp(subkey, "fetch")) { const char *v; if (git_config_string(&v, key, value)) return -1; - add_fetch_refspec(remote, v); + refspec_append(&remote->fetch, v); } else if (!strcmp(subkey, "receivepack")) { const char *v; if (git_config_string(&v, key, value))I.e. the reason we have add_{push,fetch}_refspec() in the first place is because without your series it's tricky to add new ones, but now it's trivial, so let's not leave behind wrapper static functions whose sole purpose is to just call another exported API as-is.
I've pushed all the patches I quoted inline in this review at avar-bwill/refspec in github.com/avar/git, consider them all signed-off, and depending on whether you agree/disagree etc. please squash them/adapt them/drop them however you see fit.
Signature · 1 line
Brandon Williams
v2 cover refactoring refspecs
In reply to Brandon WilliamsChanges in v2:
* added missing extern keyword in the first patch
* reordered patch 2 and 3 and updated some comments to be clearer.
* fixed some memory leaks
* squashed in some changes recommended by Aevar
Brandon Williams (36):
refspec: move refspec parsing logic into its own file
refspec: rename struct refspec to struct refspec_item
refspec: factor out parsing a single refspec
refspec: introduce struct refspec
refspec: convert valid_fetch_refspec to use parse_refspec
submodule--helper: convert push_check to use struct refspec
pull: convert get_tracking_branch to use refspec_item_init
transport: convert transport_push to use struct refspec
remote: convert check_push_refs to use struct refspec
remote: convert match_push_refs to use struct refspec
clone: convert cmd_clone to use refspec_item_init
fast-export: convert to use struct refspec
remote: convert push refspecs to struct refspec
remote: convert fetch refspecs to struct refspec
remote: remove add_prune_tags_to_fetch_refspec
transport-helper: convert to use struct refspec
fetch: convert fetch_one to use struct refspec
fetch: convert refmap to use struct refspec
refspec: remove the deprecated functions
fetch: convert do_fetch to take a struct refspec
fetch: convert get_ref_map to take a struct refspec
fetch: convert prune_refs to take a struct refspec
remote: convert get_stale_heads to take a struct refspec
remote: convert apply_refspecs to take a struct refspec
remote: convert query_refspecs to take a struct refspec
remote: convert get_ref_match to take a struct refspec
remote: convert match_explicit_refs to take a struct refspec
push: check for errors earlier
push: convert to use struct refspec
transport: convert transport_push to take a struct refspec
send-pack: store refspecs in a struct refspec
transport: remove transport_verify_remote_names
http-push: store refspecs in a struct refspec
remote: convert match_push_refs to take a struct refspec
remote: convert check_push_refs to take a struct refspec
submodule: convert push_unpushed_submodules to take a struct refspec
Makefile | 1 + branch.c | 7 +- builtin/clone.c | 13 +- builtin/fast-export.c | 22 +-- builtin/fetch.c | 134 ++++++-------- builtin/merge.c | 1 + builtin/pull.c | 9 +- builtin/push.c | 80 ++++---- builtin/remote.c | 37 ++-- builtin/send-pack.c | 24 +-- builtin/submodule--helper.c | 14 +- checkout.c | 5 +- http-push.c | 18 +- refspec.c | 194 ++++++++++++++++++++ refspec.h | 44 +++++ remote.c | 353 ++++++++---------------------------- remote.h | 50 ++--- submodule.c | 19 +- submodule.h | 3 +- transport-helper.c | 39 ++-- transport.c | 51 ++---- transport.h | 4 +- 22 files changed, 527 insertions(+), 595 deletions(-) create mode 100644 refspec.c create mode 100644 refspec.h
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 1/36 refspec: move refspec parsing logic into its own file
In preparation for performing a refactor on refspec related code, move the refspec parsing logic into its own file.
--- Makefile | 1 + branch.c | 1 + builtin/clone.c | 1 + builtin/fast-export.c | 1 + builtin/fetch.c | 1 + builtin/merge.c | 1 + builtin/pull.c | 1 + builtin/push.c | 1 + builtin/remote.c | 1 + builtin/submodule--helper.c | 1 + checkout.c | 1 + refspec.c | 168 ++++++++++++++++++++++++++++++++++++ refspec.h | 23 +++++ remote.c | 165 +---------------------------------- remote.h | 20 ----- transport-helper.c | 1 + transport.c | 1 + 17 files changed, 205 insertions(+), 184 deletions(-) create mode 100644 refspec.c create mode 100644 refspec.h
Makefile +1 -0
@@ -928,6 +928,7 @@ LIB_OBJS += refs/files-backend.o LIB_OBJS += refs/iterator.o LIB_OBJS += refs/packed-backend.o LIB_OBJS += refs/ref-cache.o +LIB_OBJS += refspec.o LIB_OBJS += ref-filter.o LIB_OBJS += remote.o LIB_OBJS += replace-object.o
branch.c +1 -0
@@ -3,6 +3,7 @@#include "config.h" #include "branch.h" #include "refs.h" +#include "refspec.h" #include "remote.h" #include "commit.h" #include "worktree.h"
builtin/clone.c +1 -0
@@ -14,6 +14,7 @@#include "parse-options.h" #include "fetch-pack.h" #include "refs.h" +#include "refspec.h" #include "tree.h" #include "tree-walk.h" #include "unpack-trees.h"
builtin/fast-export.c +1 -0
@@ -7,6 +7,7 @@#include "cache.h" #include "config.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "object.h" #include "tag.h"
builtin/fetch.c +1 -0
@@ -5,6 +5,7 @@#include "config.h" #include "repository.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "builtin.h" #include "string-list.h"
builtin/merge.c +1 -0
@@ -14,6 +14,7 @@#include "run-command.h" #include "diff.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "diffcore.h" #include "revision.h"
builtin/pull.c +1 -0
@@ -15,6 +15,7 @@#include "remote.h" #include "dir.h" #include "refs.h" +#include "refspec.h" #include "revision.h" #include "submodule.h" #include "submodule-config.h"
builtin/push.c +1 -0
@@ -4,6 +4,7 @@#include "cache.h" #include "config.h" #include "refs.h" +#include "refspec.h" #include "run-command.h" #include "builtin.h" #include "remote.h"
builtin/remote.c +1 -0
@@ -7,6 +7,7 @@#include "strbuf.h" #include "run-command.h" #include "refs.h" +#include "refspec.h" #include "argv-array.h" static const char *const builtin_remote_usage[] = {
builtin/submodule--helper.c +1 -0
@@ -12,6 +12,7 @@#include "run-command.h" #include "remote.h" #include "refs.h" +#include "refspec.h" #include "connect.h" #include "revision.h" #include "diffcore.h"
checkout.c +1 -0
@@ -1,5 +1,6 @@#include "cache.h" #include "remote.h" +#include "refspec.h" #include "checkout.h" struct tracking_name_data {
refspec.c new file +168 -0
168 lines not on this page · raw message
refspec.h new file +23 -0
@@ -0,0 +1,23 @@ +#ifndef REFSPEC_H +#define REFSPEC_H + +#define TAG_REFSPEC "refs/tags/*:refs/tags/*" +extern const struct refspec *tag_refspec; + +struct refspec { +unsigned force : 1; +unsigned pattern : 1; +unsigned matching : 1; +unsigned exact_sha1 : 1; + +char *src; +char *dst; +}; + +int valid_fetch_refspec(const char *refspec); +struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec); +struct refspec *parse_push_refspec(int nr_refspec, const char **refspec); + +void free_refspec(int nr_refspec, struct refspec *refspec); + +#endif /* REFSPEC_H */
remote.c +1 -164
183 lines not on this page · raw message
remote.h +0 -20
@@ -68,18 +68,6 @@ int for_each_remote(each_remote_fn fn, void *priv);int remote_has_url (struct remote *remote,const char *url); -struct refspec { -unsigned force :1 ; -unsigned pattern :1 ; -unsigned matching :1 ; -unsigned exact_sha1 :1 ; - -char *src; -char *dst; -}; - -extern const struct refspec *tag_refspec; -struct ref {struct ref *next;struct object_id old_oid;
@@ -175,12 +163,6 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);*/ struct ref *ref_remove_duplicates (struct ref *ref_map); -int valid_fetch_refspec (const char *refspec); -struct refspec *parse_fetch_refspec (int nr_refspec,const char **refspec); -extern struct refspec *parse_push_refspec (int nr_refspec,const char **refspec); - -void free_refspec (int nr_refspec,struct refspec *refspec); -extern int query_refspecs (struct refspec *specs,int nr,struct refspec *query);char *apply_refspecs (struct refspec *refspecs,int nr_refspec,const char *name);
@@ -313,8 +295,6 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, intextern int is_empty_cas (const struct push_cas_option *);void apply_push_cas (struct push_cas_option *,struct remote *,struct ref *); -#define TAG_REFSPEC "refs/tags/*:refs/tags/*" -void add_prune_tags_to_fetch_refspec (struct remote *remote);#endif
transport-helper.c +1 -0
@@ -11,6 +11,7 @@#include "sigchain.h" #include "argv-array.h" #include "refs.h" +#include "refspec.h" #include "transport-internal.h" #include "protocol.h"
transport.c +1 -0
@@ -11,6 +11,7 @@#include "bundle.h" #include "dir.h" #include "refs.h" +#include "refspec.h" #include "branch.h" #include "url.h" #include "submodule.h"
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 2/36 refspec: rename struct refspec to struct refspec_item
In reply to Brandon WilliamsIn preparation for introducing an abstraction around a collection of refspecs (much like how a 'struct pathspec' is a collection of 'struct pathspec_item's) rename the existing 'struct refspec' to 'struct refspec_item'.
--- branch.c | 6 ++--- builtin/clone.c | 4 +-- builtin/fast-export.c | 4 +-- builtin/fetch.c | 12 ++++----- builtin/pull.c | 2 +- builtin/push.c | 4 +-- builtin/remote.c | 8 +++--- builtin/submodule--helper.c | 4 +-- checkout.c | 4 +-- refspec.c | 17 ++++++------- refspec.h | 10 ++++---- remote.c | 50 ++++++++++++++++++------------------- remote.h | 16 ++++++------ transport-helper.c | 2 +- transport.c | 4 +-- 15 files changed, 73 insertions(+), 74 deletions(-)
branch.c +3 -3
@@ -9,7 +9,7 @@#include "worktree.h" struct tracking { -struct refspec spec; +struct refspec_item spec;char *src;const char *remote;int matches;
@@ -219,8 +219,8 @@ int validate_new_branchname(const char *name, struct strbuf *ref, int force)static int check_tracking_branch (struct remote *remote,void *cb_data) {char *tracking_branch = cb_data; -struct refspec query; -memset (&query,0 ,sizeof (struct refspec )); +struct refspec_item query; +memset (&query,0 ,sizeof (struct refspec_item )); query.dst = tracking_branch;return !remote_find_tracking (remote, &query); }
builtin/clone.c +2 -2
@@ -547,7 +547,7 @@ static struct ref *find_remote_branch(const struct ref *refs, const char *branch }static struct ref *wanted_peer_refs (const struct ref *refs, -struct refspec *refspec) +struct refspec_item *refspec) {struct ref *head =copy_ref (find_ref_by_name (refs,"HEAD" ));struct ref *local_refs = head;
@@ -895,7 +895,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)int err =0 , complete_refs_before_fetch =1 ;int submodule_progress; -struct refspec *refspec; +struct refspec_item *refspec;const char *fetch_pattern; fetch_if_missing =0 ;
builtin/fast-export.c +2 -2
@@ -36,7 +36,7 @@ static int use_done_feature;static int no_data;static int full_tree;static struct string_list extra_refs =STRING_LIST_INIT_NODUP ; -static struct refspec *refspecs; +static struct refspec_item *refspecs;static int refspecs_nr;static int anonymize;
@@ -979,7 +979,7 @@ static void handle_deletes(void) {int i;for (i =0 ; i < refspecs_nr; i++) { -struct refspec *refspec = &refspecs[i]; +struct refspec_item *refspec = &refspecs[i];if (*refspec->src)continue ;
builtin/fetch.c +6 -6
@@ -203,7 +203,7 @@ static void add_merge_config(struct ref **head,for (i =0 ; i < branch->merge_nr; i++) {struct ref *rm, **old_tail = *tail; -struct refspec refspec; +struct refspec_item refspec;for (rm = *head; rm; rm = rm->next) {if (branch_merge_matches (branch, i, rm->name)) {
@@ -340,7 +340,7 @@ static void find_non_local_tags(struct transport *transport, }static struct ref *get_ref_map (struct transport *transport, -struct refspec *refspecs,int refspec_count, +struct refspec_item *refspecs,int refspec_count,int tags,int *autotags) {int i;
@@ -371,7 +371,7 @@ static struct ref *get_ref_map(struct transport *transport,argv_array_clear (&ref_prefixes);if (refspec_count) { -struct refspec *fetch_refspec; +struct refspec_item *fetch_refspec;int fetch_refspec_nr;for (i =0 ; i < refspec_count; i++) {
@@ -965,7 +965,7 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)return ret; } -static int prune_refs (struct refspec *refs,int ref_count,struct ref *ref_map, +static int prune_refs (struct refspec_item *refs,int ref_count,struct ref *ref_map,const char *raw_url) {int url_len, i, result =0 ;
@@ -1115,7 +1115,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map) }static int do_fetch (struct transport *transport, -struct refspec *refs,int ref_count) +struct refspec_item *refs,int ref_count) {struct string_list existing_refs =STRING_LIST_INIT_DUP ;struct ref *ref_map;
@@ -1357,7 +1357,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)static int fetch_one (struct remote *remote,int argc,const char **argv,int prune_tags_ok) {static const char **refs =NULL ; -struct refspec *refspec; +struct refspec_item *refspec;int ref_nr =0 ;int j =0 ;int exit_code;
builtin/pull.c +1 -1
@@ -676,7 +676,7 @@ static const char *get_upstream_branch(const char *remote)*/ static const char *get_tracking_branch (const char *remote,const char *refspec) { -struct refspec *spec; +struct refspec_item *spec;const char *spec_src;const char *merge_branch;
builtin/push.c +2 -2
@@ -80,8 +80,8 @@ static const char *map_refspec(const char *ref,return ref;if (remote->push) { -struct refspec query; -memset (&query,0 ,sizeof (struct refspec )); +struct refspec_item query; +memset (&query,0 ,sizeof (struct refspec_item )); query.src = matched->name;if (!query_refspecs (remote->push, remote->push_refspec_nr, &query) && query.dst) {
builtin/remote.c +4 -4
@@ -442,7 +442,7 @@ static int get_push_ref_states_noquery(struct ref_states *states) info->dest =xstrdup (item->string); }for (i =0 ; i < remote->push_refspec_nr; i++) { -struct refspec *spec = remote->push + i; +struct refspec_item *spec = remote->push + i;if (spec->matching) item =string_list_append (&states->push,_ ("(matching)" ));else if (strlen (spec->src))
@@ -462,7 +462,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat {struct ref *ref, *matches;struct ref *fetch_map =NULL , **fetch_map_tail = &fetch_map; -struct refspec refspec; +struct refspec_item refspec; refspec.force =0 ; refspec.pattern =1 ;
@@ -515,7 +515,7 @@ static int add_branch_for_removal(const char *refname, const struct object_id *oid, int flags, void *cb_data) { struct branches_for_remote *branches = cb_data; -struct refspec refspec; +struct refspec_item refspec;struct known_remote *kr;memset (&refspec,0 ,sizeof (refspec));
@@ -834,7 +834,7 @@ static int append_ref_to_tracked_list(const char *refname, const struct object_id *oid, int flags, void *cb_data) { struct ref_states *states = cb_data; -struct refspec refspec; +struct refspec_item refspec;if (flags &REF_ISSYMREF )return 0 ;
builtin/submodule--helper.c +2 -2
@@ -1746,11 +1746,11 @@ static int push_check(int argc, const char **argv, const char *prefix)if (argc >2 ) {int i, refspec_nr = argc -2 ;struct ref *local_refs =get_local_heads (); -struct refspec *refspec =parse_push_refspec (refspec_nr, +struct refspec_item *refspec =parse_push_refspec (refspec_nr, argv +2 );for (i =0 ; i < refspec_nr; i++) { -struct refspec *rs = refspec + i; +struct refspec_item *rs = refspec + i;if (rs->pattern || rs->matching)continue ;
checkout.c +2 -2
@@ -13,8 +13,8 @@ struct tracking_name_data {static int check_tracking_name (struct remote *remote,void *cb_data) {struct tracking_name_data *cb = cb_data; -struct refspec query; -memset (&query,0 ,sizeof (struct refspec )); +struct refspec_item query; +memset (&query,0 ,sizeof (struct refspec_item )); query.src = cb->src_ref;if (remote_find_tracking (remote, &query) ||get_oid (query.dst, cb->dst_oid)) {
refspec.c +8 -9
@@ -2,7 +2,7 @@#include "refs.h" #include "refspec.h" -static struct refspec s_tag_refspec = { +static struct refspec_item s_tag_refspec = {0 ,1 ,0 ,
@@ -12,12 +12,12 @@ static struct refspec s_tag_refspec = { };/* See TAG_REFSPEC for the string version */ -const struct refspec *tag_refspec = &s_tag_refspec; +const struct refspec_item *tag_refspec = &s_tag_refspec; -static struct refspec *parse_refspec_internal (int nr_refspec,const char **refspec,int fetch,int verify) +static struct refspec_item *parse_refspec_internal (int nr_refspec,const char **refspec,int fetch,int verify) {int i; -struct refspec *rs =xcalloc (nr_refspec,sizeof (*rs)); +struct refspec_item *rs =xcalloc (nr_refspec,sizeof (*rs));for (i =0 ; i < nr_refspec; i++) {size_t llen;
@@ -135,24 +135,24 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspint valid_fetch_refspec (const char *fetch_refspec_str) { -struct refspec *refspec; +struct refspec_item *refspec; refspec =parse_refspec_internal (1 , &fetch_refspec_str,1 ,1 );free_refspec (1 , refspec);return !!refspec; } -struct refspec *parse_fetch_refspec (int nr_refspec,const char **refspec) +struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec) {return parse_refspec_internal (nr_refspec, refspec,1 ,0 ); } -struct refspec *parse_push_refspec (int nr_refspec,const char **refspec) +struct refspec_item *parse_push_refspec (int nr_refspec,const char **refspec) {return parse_refspec_internal (nr_refspec, refspec,0 ,0 ); } -void free_refspec (int nr_refspec,struct refspec *refspec) +void free_refspec (int nr_refspec,struct refspec_item *refspec) {int i;
@@ -165,4 +165,3 @@ void free_refspec(int nr_refspec, struct refspec *refspec) }free (refspec); } -
refspec.h +5 -5
@@ -2,9 +2,9 @@#define REFSPEC_H #define TAG_REFSPEC "refs/tags/*:refs/tags/*" -extern const struct refspec *tag_refspec; +extern const struct refspec_item *tag_refspec; -struct refspec { +struct refspec_item {unsigned force :1 ;unsigned pattern :1 ;unsigned matching :1 ;
@@ -15,9 +15,9 @@ struct refspec { };int valid_fetch_refspec (const char *refspec); -struct refspec *parse_fetch_refspec (int nr_refspec,const char **refspec); -struct refspec *parse_push_refspec (int nr_refspec,const char **refspec); +struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec); +struct refspec_item *parse_push_refspec (int nr_refspec,const char **refspec); -void free_refspec (int nr_refspec,struct refspec *refspec); +void free_refspec (int nr_refspec,struct refspec_item *refspec);#endif /* REFSPEC_H */
remote.c +25 -25
173 lines not on this page · raw message
remote.h +8 -8
@@ -28,12 +28,12 @@ struct remote {int pushurl_alloc;const char **push_refspec; -struct refspec *push; +struct refspec_item *push;int push_refspec_nr;int push_refspec_alloc;const char **fetch_refspec; -struct refspec *fetch; +struct refspec_item *fetch;int fetch_refspec_nr;int fetch_refspec_alloc;
@@ -163,8 +163,8 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);*/ struct ref *ref_remove_duplicates (struct ref *ref_map); -extern int query_refspecs (struct refspec *specs,int nr,struct refspec *query); -char *apply_refspecs (struct refspec *refspecs,int nr_refspec, +extern int query_refspecs (struct refspec_item *specs,int nr,struct refspec_item *query); +char *apply_refspecs (struct refspec_item *refspecs,int nr_refspec,const char *name);int check_push_refs (struct ref *src,int nr_refspec,const char **refspec);
@@ -185,7 +185,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,* missing_ok is usually false, but when we are adding branch.$name.merge * it is Ok if the branch is not at the remote anymore. */ -int get_fetch_map (const struct ref *remote_refs,const struct refspec *refspec, +int get_fetch_map (const struct ref *remote_refs,const struct refspec_item *refspec,struct ref ***tail,int missing_ok);struct ref *get_remote_ref (const struct ref *remote_refs,const char *name);
@@ -193,7 +193,7 @@ struct ref *get_remote_ref(const struct ref *remote_refs, const char *name);/* * For the given remote, reads the refspec's src and sets the other fields. */ -int remote_find_tracking (struct remote *remote,struct refspec *refspec); +int remote_find_tracking (struct remote *remote,struct refspec_item *refspec);struct branch {const char *name;
@@ -203,7 +203,7 @@ struct branch {const char *pushremote_name;const char **merge_name; -struct refspec **merge; +struct refspec_item **merge;int merge_nr;int merge_alloc;
@@ -272,7 +272,7 @@ struct ref *guess_remote_head(const struct ref *head, int all);/* Return refs which no longer exist on remote */ -struct ref *get_stale_heads (struct refspec *refs,int ref_count,struct ref *fetch_map); +struct ref *get_stale_heads (struct refspec_item *refs,int ref_count,struct ref *fetch_map);/* * Compare-and-swap
transport-helper.c +1 -1
@@ -36,7 +36,7 @@ struct helper_data {char *export_marks;char *import_marks;/* These go from remote name (as in "list") to private name */ -struct refspec *refspecs; +struct refspec_item *refspecs;int refspec_nr;/* Transport options for fetch-pack/send-pack (should one of * those be invoked).
transport.c +2 -2
@@ -390,7 +390,7 @@ int transport_refs_pushed(struct ref *ref)void transport_update_tracking_ref (struct remote *remote,struct ref *ref,int verbose) { -struct refspec rs; +struct refspec_item rs;if (ref->status !=REF_STATUS_OK && ref->status !=REF_STATUS_UPTODATE )return ;
@@ -1111,7 +1111,7 @@ int transport_push(struct transport *transport,int porcelain = flags &TRANSPORT_PUSH_PORCELAIN ;int pretend = flags &TRANSPORT_PUSH_DRY_RUN ;int push_ret, ret, err; -struct refspec *tmp_rs; +struct refspec_item *tmp_rs;struct argv_array ref_prefixes =ARGV_ARRAY_INIT ;int i;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 3/36 refspec: factor out parsing a single refspec
In reply to Brandon WilliamsFactor out the logic which parses a single refspec into its own function. This makes it easier to reuse this logic in a future patch.
--- refspec.c | 195 +++++++++++++++++++++++++++++------------------------- 1 file changed, 104 insertions(+), 91 deletions(-)
refspec.c +104 -91
@@ -14,110 +14,123 @@ static struct refspec_item s_tag_refspec = {/* See TAG_REFSPEC for the string version */ const struct refspec_item *tag_refspec = &s_tag_refspec; -static struct refspec_item *parse_refspec_internal (int nr_refspec,const char **refspec,int fetch,int verify) +/* +* Parses the provided refspec 'refspec' and populates the refspec_item 'item'. +* Returns 1 if successful and 0 if the refspec is invalid. +*/ +static int parse_refspec (struct refspec_item *item,const char *refspec,int fetch) { -int i; -struct refspec_item *rs =xcalloc (nr_refspec,sizeof (*rs)); +size_t llen; +int is_glob; +const char *lhs, *rhs; +int flags; -for (i =0 ; i < nr_refspec; i++) { -size_t llen; -int is_glob; -const char *lhs, *rhs; -int flags; + is_glob =0 ; - is_glob =0 ; + lhs = refspec; +if (*lhs =='+' ) { + item->force =1 ; + lhs++; + } - lhs = refspec[i]; -if (*lhs =='+' ) { - rs[i].force =1 ; - lhs++; - } + rhs =strrchr (lhs,':' ); - rhs =strrchr (lhs,':' ); +/* +* Before going on, special case ":" (or "+:") as a refspec +* for pushing matching refs. +*/ +if (!fetch && rhs == lhs && rhs[1 ] =='\0' ) { + item->matching =1 ; +return 1 ; + } +if (rhs) { +size_t rlen =strlen (++rhs); + is_glob = (1 <= rlen &&strchr (rhs,'*' )); + item->dst =xstrndup (rhs, rlen); + } + + llen = (rhs ? (rhs - lhs -1 ) :strlen (lhs)); +if (1 <= llen &&memchr (lhs,'*' , llen)) { +if ((rhs && !is_glob) || (!rhs && fetch)) +return 0 ; + is_glob =1 ; + }else if (rhs && is_glob) { +return 0 ; + } + + item->pattern = is_glob; + item->src =xstrndup (lhs, llen); + flags =REFNAME_ALLOW_ONELEVEL | (is_glob ?REFNAME_REFSPEC_PATTERN :0 ); + +if (fetch) { +struct object_id unused; + +/* LHS */ +if (!*item->src) + ;/* empty is ok; it means "HEAD" */ +else if (llen ==GIT_SHA1_HEXSZ && !get_oid_hex (item->src, &unused)) + item->exact_sha1 =1 ;/* ok */ +else if (!check_refname_format (item->src, flags)) + ;/* valid looking ref is ok */ +else +return 0 ; +/* RHS */ +if (!item->dst) + ;/* missing is ok; it is the same as empty */ +else if (!*item->dst) + ;/* empty is ok; it means "do not store" */ +else if (!check_refname_format (item->dst, flags)) + ;/* valid looking ref is ok */ +else +return 0 ; + }else {/* -* Before going on, special case ":" (or "+:") as a refspec -* for pushing matching refs. +* LHS +* - empty is allowed; it means delete. +* - when wildcarded, it must be a valid looking ref. +* - otherwise, it must be an extended SHA-1, but +* there is no existing way to validate this. */ -if (!fetch && rhs == lhs && rhs[1 ] =='\0' ) { - rs[i].matching =1 ; -continue ; +if (!*item->src) + ;/* empty is ok */ +else if (is_glob) { +if (check_refname_format (item->src, flags)) +return 0 ; } - -if (rhs) { -size_t rlen =strlen (++rhs); - is_glob = (1 <= rlen &&strchr (rhs,'*' )); - rs[i].dst =xstrndup (rhs, rlen); +else + ;/* anything goes, for now */ +/* +* RHS +* - missing is allowed, but LHS then must be a +* valid looking ref. +* - empty is not allowed. +* - otherwise it must be a valid looking ref. +*/ +if (!item->dst) { +if (check_refname_format (item->src, flags)) +return 0 ; + }else if (!*item->dst) { +return 0 ; + }else { +if (check_refname_format (item->dst, flags)) +return 0 ; } + } - llen = (rhs ? (rhs - lhs -1 ) :strlen (lhs)); -if (1 <= llen &&memchr (lhs,'*' , llen)) { -if ((rhs && !is_glob) || (!rhs && fetch)) - goto invalid; - is_glob =1 ; - }else if (rhs && is_glob) { - goto invalid; - } +return 1 ; +} - rs[i].pattern = is_glob; - rs[i].src =xstrndup (lhs, llen); - flags =REFNAME_ALLOW_ONELEVEL | (is_glob ?REFNAME_REFSPEC_PATTERN :0 ); - -if (fetch) { -struct object_id unused; - -/* LHS */ -if (!*rs[i].src) - ;/* empty is ok; it means "HEAD" */ -else if (llen ==GIT_SHA1_HEXSZ && !get_oid_hex (rs[i].src, &unused)) - rs[i].exact_sha1 =1 ;/* ok */ -else if (!check_refname_format (rs[i].src, flags)) - ;/* valid looking ref is ok */ -else - goto invalid; -/* RHS */ -if (!rs[i].dst) - ;/* missing is ok; it is the same as empty */ -else if (!*rs[i].dst) - ;/* empty is ok; it means "do not store" */ -else if (!check_refname_format (rs[i].dst, flags)) - ;/* valid looking ref is ok */ -else - goto invalid; - }else { -/* -* LHS -* - empty is allowed; it means delete. -* - when wildcarded, it must be a valid looking ref. -* - otherwise, it must be an extended SHA-1, but -* there is no existing way to validate this. -*/ -if (!*rs[i].src) - ;/* empty is ok */ -else if (is_glob) { -if (check_refname_format (rs[i].src, flags)) - goto invalid; - } -else - ;/* anything goes, for now */ -/* -* RHS -* - missing is allowed, but LHS then must be a -* valid looking ref. -* - empty is not allowed. -* - otherwise it must be a valid looking ref. -*/ -if (!rs[i].dst) { -if (check_refname_format (rs[i].src, flags)) - goto invalid; - }else if (!*rs[i].dst) { - goto invalid; - }else { -if (check_refname_format (rs[i].dst, flags)) - goto invalid; - } - } +static struct refspec_item *parse_refspec_internal (int nr_refspec,const char **refspec,int fetch,int verify) +{ +int i; +struct refspec_item *rs =xcalloc (nr_refspec,sizeof (*rs)); + +for (i =0 ; i < nr_refspec; i++) { +if (!parse_refspec (&rs[i], refspec[i], fetch)) + goto invalid; } +return rs; invalid:
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 4/36 refspec: introduce struct refspec
In reply to Brandon WilliamsIntroduce 'struct refspec', an abstraction around a collection of 'struct refspec_item's much like how 'struct pathspec' holds a collection of 'struct pathspec_item's.
A refspec struct also contains an array of the original refspec strings which will be used to facilitate the migration to using this new abstraction throughout the code base.
--- refspec.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ refspec.h | 25 ++++++++++++++++++++++ 2 files changed, 89 insertions(+)
refspec.c +64 -0
@@ -178,3 +178,67 @@ void free_refspec(int nr_refspec, struct refspec_item *refspec) }free (refspec); } + +void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch) +{ +memset (item,0 ,sizeof (*item)); + +if (!parse_refspec (item, refspec, fetch)) +die ("Invalid refspec '%s'" , refspec); +} + +void refspec_item_clear (struct refspec_item *item) +{ +FREE_AND_NULL (item->src); +FREE_AND_NULL (item->dst); + item->force =0 ; + item->pattern =0 ; + item->matching =0 ; + item->exact_sha1 =0 ; +} + +void refspec_init (struct refspec *rs,int fetch) +{ +memset (rs,0 ,sizeof (*rs)); + rs->fetch = fetch; +} + +void refspec_append (struct refspec *rs,const char *refspec) +{ +struct refspec_item item; + +refspec_item_init (&item, refspec, rs->fetch); + +ALLOC_GROW (rs->items, rs->nr +1 , rs->alloc); + rs->items[rs->nr++] = item; + +ALLOC_GROW (rs->raw, rs->raw_nr +1 , rs->raw_alloc); + rs->raw[rs->raw_nr++] =xstrdup (refspec); +} + +void refspec_appendn (struct refspec *rs,const char **refspecs,int nr) +{ +int i; +for (i =0 ; i < nr; i++) +refspec_append (rs, refspecs[i]); +} + +void refspec_clear (struct refspec *rs) +{ +int i; + +for (i =0 ; i < rs->nr; i++) +refspec_item_clear (&rs->items[i]); + +FREE_AND_NULL (rs->items); + rs->alloc =0 ; + rs->nr =0 ; + +for (i =0 ; i < rs->raw_nr; i++) +free ((char *)rs->raw[i]); +FREE_AND_NULL (rs->raw); + rs->raw_alloc =0 ; + rs->raw_nr =0 ; + + rs->fetch =0 ; +}
refspec.h +25 -0
@@ -20,4 +20,29 @@ struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);void free_refspec (int nr_refspec,struct refspec_item *refspec); +#define REFSPEC_FETCH 1 +#define REFSPEC_PUSH 0 + +#define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH } +#define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH } + +struct refspec { +struct refspec_item *items; +int alloc; +int nr; + +const char **raw; +int raw_alloc; +int raw_nr; + +int fetch; +}; + +void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch); +void refspec_item_clear (struct refspec_item *item); +void refspec_init (struct refspec *rs,int fetch); +void refspec_append (struct refspec *rs,const char *refspec); +void refspec_appendn (struct refspec *rs,const char **refspecs,int nr); +void refspec_clear (struct refspec *rs); +#endif /* REFSPEC_H */
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 5/36 refspec: convert valid_fetch_refspec to use parse_refspec
In reply to Brandon WilliamsConvert 'valid_fetch_refspec()' to use the new 'parse_refspec()' function to only parse a single refspec and eliminate an allocation.
--- refspec.c | 17 ++++++++--------- refspec.h | 3 ++- 2 files changed, 10 insertions(+), 10 deletions(-)
refspec.c +8 -9
@@ -146,15 +146,6 @@ static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **die ("Invalid refspec '%s'" , refspec[i]); } -int valid_fetch_refspec (const char *fetch_refspec_str) -{ -struct refspec_item *refspec; - - refspec =parse_refspec_internal (1 , &fetch_refspec_str,1 ,1 ); -free_refspec (1 , refspec); -return !!refspec; -} -struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec) {return parse_refspec_internal (nr_refspec, refspec,1 ,0 );
@@ -242,3 +233,11 @@ void refspec_clear(struct refspec *rs) rs->fetch =0 ; } + +int valid_fetch_refspec (const char *fetch_refspec_str) +{ +struct refspec_item refspec; +int ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH ); +refspec_item_clear (&refspec); +return ret; +}
refspec.h +2 -1
@@ -14,7 +14,6 @@ struct refspec_item {char *dst; }; -int valid_fetch_refspec (const char *refspec);struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec);struct refspec_item *parse_push_refspec (int nr_refspec,const char **refspec);
@@ -45,4 +44,6 @@ void refspec_append(struct refspec *rs, const char *refspec);void refspec_appendn (struct refspec *rs,const char **refspecs,int nr);void refspec_clear (struct refspec *rs); +int valid_fetch_refspec (const char *refspec); +#endif /* REFSPEC_H */
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Re: [PATCH v2 05/36] refspec: convert valid_fetch_refspec to use parse_refspec
Hi Brandon,
Quoted 31 lines · Brandon Williams
Convert '
valid_fetch_refspec()' to use the new 'parse_refspec()' function to only parse a single refspec and eliminate an allocation.Signed-off-by Brandon Williams <[email protected]>--- refspec.c | 17 ++++++++--------- refspec.h | 3 ++- 2 files changed, 10 insertions(+), 10 deletions(-)refspec.c +0
-9@@ -146,15 +146,6 @@ static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **die ("Invalid refspec '%s'" , refspec[i]); } -int valid_fetch_refspec (const char *fetch_refspec_str) -{ -struct refspec_item *refspec; - - refspec =parse_refspec_internal (1 , &fetch_refspec_str,1 ,1 ); -free_refspec (1 , refspec); -return !!refspec; -} -struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec) {return parse_refspec_internal (nr_refspec, refspec,1 ,0 );@@ -242,3 +233,11 @@ void refspec_clear(struct refspec *rs)
refspec.c void refspec_clear(struct refspec *rs) · line 243
Quoted 10 lines
refspec.c +8
-0rs->fetch =0 ; } + +int valid_fetch_refspec (const char *fetch_refspec_str) +{ +struct refspec_item refspec; +int ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH ); +refspec_item_clear (&refspec); +return ret; +}
My compiler warned about this function. The dst and src pointers will equal some random data on the stack, then they may or may not be assigned to, then we will call free() on them.
At least I *think* that we "may or may not" assign to them. I don't have much or any time to really dig into this right now unfortunately.
I suppose this could use a REFSPEC_ITEM_INIT, or a memset inside parse_refspec(), but I am very unfamiliar with this code.
Martin
PATCH 1/1 refspec: initalize `refspec_item` in `valid_fetch_refspec()`
We allocate a struct refspec_item on the stack without initializing it. In particular, its dst and src members will contain some random data from the stack. When we later call refspec_item_clear(), it will call free() on those pointers. So if the call to parse_refspec() did not assign to them, we will be freeing some random "pointers". This is undefined behavior.
To the best of my understanding, this cannot currently be triggered by user-provided data. And for what it's worth, the test-suite does not trigger this with SANITIZE=address. It can be provoked by calling valid_fetch_refspec(":*").
Zero the struct, as is done in other users of struct refspec_item.
---
I found some time to look into this. It does not seem to be a user-visible bug, so not particularly critical.
refspec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
refspec.c +4 -1
@@ -189,7 +189,10 @@ void refspec_clear(struct refspec *rs)int valid_fetch_refspec (const char *fetch_refspec_str) {struct refspec_item refspec; -int ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH ); +int ret; + +memset (&refspec,0 ,sizeof (refspec)); + ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH );refspec_item_clear (&refspec);return ret; }
Signature · 1 line
2.18.0.rc0.43.gb85e7bcbff
Re: [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()`
Quoted 12 lines · Martin Ågren
We allocate a
struct refspec_itemon the stack without initializing it. In particular, itsdstandsrcmembers will contain some random data from the stack. When we later callrefspec_item_clear(), it will callfree()on those pointers. So if the call toparse_refspec()did not assign to them, we will be freeing some random "pointers". This is undefined behavior.To the best of my understanding, this cannot currently be triggered by user-provided data. And for what it's worth, the test-suite does not trigger this with SANITIZE=address. It can be provoked by calling
valid_fetch_refspec(":*").
Quoted 6 lines
Zero the struct, as is done in other users of
struct refspec_item.Signed-off-by Martin Ågren <[email protected]>---
I found some time to look into this. It does not seem to be a user-visible bug, so not particularly critical.
Thanks for fixing this. I don't think I noticed this because at some point in developing this series I had a memset call in parse_refspec. I don't remember why I ended up removing it, but maybe it would have been better to leave it in there.
Quoted 23 lines
refspec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)refspec.c +4
-1@@ -189,7 +189,10 @@ void refspec_clear(struct refspec *rs)int valid_fetch_refspec (const char *fetch_refspec_str) {struct refspec_item refspec; -int ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH ); +int ret; + +memset (&refspec,0 ,sizeof (refspec)); + ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH );refspec_item_clear (&refspec);return ret; }Signature · 1 line
2.18.0.rc0.43.gb85e7bcbff
Signature · 1 line
Brandon Williams
Re: [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()`
In reply to Martin ÅgrenQuoted 28 lines · Martin Ågren
We allocate a
struct refspec_itemon the stack without initializing it. In particular, itsdstandsrcmembers will contain some random data from the stack. When we later callrefspec_item_clear(), it will callfree()on those pointers. So if the call toparse_refspec()did not assign to them, we will be freeing some random "pointers". This is undefined behavior.To the best of my understanding, this cannot currently be triggered by user-provided data. And for what it's worth, the test-suite does not trigger this with SANITIZE=address. It can be provoked by calling
valid_fetch_refspec(":*").Zero the struct, as is done in other users of
struct refspec_item.Signed-off-by Martin Ågren <[email protected]>---
I found some time to look into this. It does not seem to be a user-visible bug, so not particularly critical.refspec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)refspec.c +0
-0@@ -189,7 +189,10 @@ void refspec_clear(struct refspec *rs)int valid_fetch_refspec (const char *fetch_refspec_str)
refspec.c void refspec_clear(struct refspec *rs) · line 198
Quoted 10 lines
refspec.c +4
-1{struct refspec_item refspec; -int ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH ); +int ret; + +memset (&refspec,0 ,sizeof (refspec)); + ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH );refspec_item_clear (&refspec);return ret; }
I think this makes more sense instead of this fix:
builtin/clone.c +1 -1
@@ -1077,7 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (option_required_reference.nr || option_optional_reference.nr)setup_reference (); -refspec_item_init (&refspec, value.buf,REFSPEC_FETCH ); +refspec_item_init_or_die (&refspec, value.buf,REFSPEC_FETCH );strbuf_reset (&value);
builtin/pull.c +1 -1
@@ -684,7 +684,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)const char *spec_src;const char *merge_branch; -refspec_item_init (&spec, refspec,REFSPEC_FETCH ); +refspec_item_init_or_die (&spec, refspec,REFSPEC_FETCH ); spec_src = spec.src;if (!*spec_src || !strcmp (spec_src,"HEAD" )) spec_src ="HEAD" ;
refspec.c +9 -4
@@ -124,11 +124,16 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fetreturn 1 ; } -void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch) +int refspec_item_init (struct refspec_item *item,const char *refspec,int fetch) {memset (item,0 ,sizeof (*item)); +int ret =parse_refspec (item, refspec, fetch); +return ret; +} -if (!parse_refspec (item, refspec, fetch)) +void refspec_item_init_or_die (struct refspec_item *item,const char *refspec,int fetch) +{ +if (!refspec_item_init (item, refspec, fetch))die ("Invalid refspec '%s'" , refspec); }
@@ -152,7 +157,7 @@ void refspec_append(struct refspec *rs, const char *refspec) {struct refspec_item item; -refspec_item_init (&item, refspec, rs->fetch); +refspec_item_init_or_die (&item, refspec, rs->fetch);ALLOC_GROW (rs->items, rs->nr +1 , rs->alloc); rs->items[rs->nr++] = item;
@@ -191,7 +196,7 @@ void refspec_clear(struct refspec *rs)int valid_fetch_refspec (const char *fetch_refspec_str) {struct refspec_item refspec; -int ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH ); +int ret =refspec_item_init (&refspec, fetch_refspec_str,REFSPEC_FETCH );refspec_item_clear (&refspec);return ret; }
refspec.h +2 -1
@@ -32,7 +32,8 @@ struct refspec {int fetch; }; -void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch); +int refspec_item_init (struct refspec_item *item,const char *refspec,int fetch); +void refspec_item_init_or_die (struct refspec_item *item,const char *refspec,int fetch);void refspec_item_clear (struct refspec_item *item);void refspec_init (struct refspec *rs,int fetch);void refspec_append (struct refspec *rs,const char *refspec);
I.e. let's fix the bug, but with this admittedly more verbose fix we're left with exactly two memset() in refspec.c, one for each type of struct that's initialized by the API.
The reason this is difficult now is because the current API conflates the init function with an init_or_die, which is what most callers want, so let's just split those concerns up. Then we're left with one init function that does the memset.
Re: [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()`
Quoted 1 line · Ævar Arnfjörð Bjarmason
I think this makes more sense instead of this fix:
[...]
refspec.c static int parse_refspec(struct refspec_item *item, const char *refspec, int fet · line 132
Quoted 7 lines
refspec.c +4
-1-void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch) +int refspec_item_init (struct refspec_item *item,const char *refspec,int fetch) {memset (item,0 ,sizeof (*item)); +int ret =parse_refspec (item, refspec, fetch); +return ret; +}
Nit: Declaration after statement. Intriguingly, you do use a ret variable, so I suspect you sort of thought about it but left the final cleaning up for later. ;-)
Quoted 7 lines
refspec.h +2
-1-void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch); +int refspec_item_init (struct refspec_item *item,const char *refspec,int fetch); +void refspec_item_init_or_die (struct refspec_item *item,const char *refspec,int fetch);void refspec_item_clear (struct refspec_item *item);void refspec_init (struct refspec *rs,int fetch);void refspec_append (struct refspec *rs,const char *refspec);
Quoted 8 lines
I.e. let's fix the bug, but with this admittedly more verbose fix we're left with exactly two
memset()inrefspec.c, one for each type of struct that's initialized by the API.The reason this is difficult now is because the current API conflates the init function with an
init_or_die, which is what most callers want, so let's just split those concerns up. Then we're left with one init function that does the memset.
I didn't test this, but it looks sane in general IMHO, and should fix the issue I saw. Should we be worried that someone might already depend on refspec_item_init() to die, and we'll silently break that assumption?
Martin
Re: [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()`
In reply to Ævar Arnfjörð BjarmasonQuoted 35 lines · Ævar Arnfjörð Bjarmason
Quoted 32 lines · Martin Ågren
We allocate a
struct refspec_itemon the stack without initializing it. In particular, itsdstandsrcmembers will contain some random data from the stack. When we later callrefspec_item_clear(), it will callfree()on those pointers. So if the call toparse_refspec()did not assign to them, we will be freeing some random "pointers". This is undefined behavior.To the best of my understanding, this cannot currently be triggered by user-provided data. And for what it's worth, the test-suite does not trigger this with SANITIZE=address. It can be provoked by calling
valid_fetch_refspec(":*").Zero the struct, as is done in other users of
struct refspec_item.Signed-off-by Martin Ågren <[email protected]>---
I found some time to look into this. It does not seem to be a user-visible bug, so not particularly critical.refspec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)refspec.c +1
-1@@ -189,7 +189,10 @@ void refspec_clear(struct refspec *rs)int valid_fetch_refspec (const char *fetch_refspec_str) {struct refspec_item refspec; -int ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH ); +int ret;
Quoted 8 lines
refspec.c void refspec_clear(struct refspec *rs) · line 202
Quoted 6 lines
refspec.c +3
-0+ +memset (&refspec,0 ,sizeof (refspec)); + ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH );refspec_item_clear (&refspec);return ret; }I think this makes more sense instead of this fix:
I like this diff. The only nit I have is the same as what Martin pointed out. At least this way all memory will be initialized by the time a call to parse_refspec is made.
Quoted 91 lines
builtin/clone.c +1
-1@@ -1077,7 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (option_required_reference.nr || option_optional_reference.nr)setup_reference (); -refspec_item_init (&refspec, value.buf,REFSPEC_FETCH ); +refspec_item_init_or_die (&refspec, value.buf,REFSPEC_FETCH );strbuf_reset (&value);builtin/pull.c +1
-1@@ -684,7 +684,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)const char *spec_src;const char *merge_branch; -refspec_item_init (&spec, refspec,REFSPEC_FETCH ); +refspec_item_init_or_die (&spec, refspec,REFSPEC_FETCH ); spec_src = spec.src;if (!*spec_src || !strcmp (spec_src,"HEAD" )) spec_src ="HEAD" ;refspec.c +9
-4@@ -124,11 +124,16 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fetreturn 1 ; } -void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch) +int refspec_item_init (struct refspec_item *item,const char *refspec,int fetch) {memset (item,0 ,sizeof (*item)); +int ret =parse_refspec (item, refspec, fetch); +return ret; +} -if (!parse_refspec (item, refspec, fetch)) +void refspec_item_init_or_die (struct refspec_item *item,const char *refspec,int fetch) +{ +if (!refspec_item_init (item, refspec, fetch))die ("Invalid refspec '%s'" , refspec); }@@ -152,7 +157,7 @@ void refspec_append(struct refspec *rs, const char *refspec) {struct refspec_item item; -refspec_item_init (&item, refspec, rs->fetch); +refspec_item_init_or_die (&item, refspec, rs->fetch);ALLOC_GROW (rs->items, rs->nr +1 , rs->alloc); rs->items[rs->nr++] = item;@@ -191,7 +196,7 @@ void refspec_clear(struct refspec *rs)int valid_fetch_refspec (const char *fetch_refspec_str) {struct refspec_item refspec; -int ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH ); +int ret =refspec_item_init (&refspec, fetch_refspec_str,REFSPEC_FETCH );refspec_item_clear (&refspec);return ret; }refspec.h +2
-1@@ -32,7 +32,8 @@ struct refspec {int fetch; }; -void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch); +int refspec_item_init (struct refspec_item *item,const char *refspec,int fetch); +void refspec_item_init_or_die (struct refspec_item *item,const char *refspec,int fetch);void refspec_item_clear (struct refspec_item *item);void refspec_init (struct refspec *rs,int fetch);void refspec_append (struct refspec *rs,const char *refspec);I.e. let's fix the bug, but with this admittedly more verbose fix we're left with exactly two
memset()inrefspec.c, one for each type of struct that's initialized by the API.The reason this is difficult now is because the current API conflates the init function with an
init_or_die, which is what most callers want, so let's just split those concerns up. Then we're left with one init function that does the memset.
Signature · 1 line
Brandon Williams
cover refspec: refactor & fix free() behavior
Since Martin & Brandon both liked this direction I've fixed it up.
Martin: I didn't want to be the author of the actual fix for the bug you found, so I rewrote your commit in 3/3. The diff is different, and I slightly modified the 3rd paragraph of the commit message & added my sign-off, but otherwise it's the same.
Martin Ågren (1):
refspec: initalize refspec_item in valid_fetch_refspec()
Ævar Arnfjörð Bjarmason (2):
refspec: s/refspec_item_init/&_or_die/g
refspec: add back a refspec_item_init() function
builtin/clone.c | 2 +- builtin/pull.c | 2 +- refspec.c | 13 +++++++++---- refspec.h | 5 ++++- 4 files changed, 15 insertions(+), 7 deletions(-)
Signature · 1 line
2.17.0.290.gded63e768a
PATCH 1/3 refspec: s/refspec_item_init/&_or_die/g
Rename the refspec_item_init() function introduced in 6d4c057859 ("refspec: introduce struct refspec", 2018-05-16) to refspec_item_init_or_die().
This follows the convention of other *_or_die() functions, and is done in preparation for making it a wrapper for a non-fatal variant.
--- builtin/clone.c | 2 +- builtin/pull.c | 2 +- refspec.c | 5 +++-- refspec.h | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-)
builtin/clone.c +1 -1
@@ -1077,7 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (option_required_reference.nr || option_optional_reference.nr)setup_reference (); -refspec_item_init (&refspec, value.buf,REFSPEC_FETCH ); +refspec_item_init_or_die (&refspec, value.buf,REFSPEC_FETCH );strbuf_reset (&value);
builtin/pull.c +1 -1
@@ -684,7 +684,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)const char *spec_src;const char *merge_branch; -refspec_item_init (&spec, refspec,REFSPEC_FETCH ); +refspec_item_init_or_die (&spec, refspec,REFSPEC_FETCH ); spec_src = spec.src;if (!*spec_src || !strcmp (spec_src,"HEAD" )) spec_src ="HEAD" ;
refspec.c +3 -2
@@ -124,7 +124,8 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fetreturn 1 ; } -void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch) +void refspec_item_init_or_die (struct refspec_item *item,const char *refspec, +int fetch) {memset (item,0 ,sizeof (*item));
@@ -152,7 +153,7 @@ void refspec_append(struct refspec *rs, const char *refspec) {struct refspec_item item; -refspec_item_init (&item, refspec, rs->fetch); +refspec_item_init_or_die (&item, refspec, rs->fetch);ALLOC_GROW (rs->items, rs->nr +1 , rs->alloc); rs->items[rs->nr++] = item;
refspec.h +2 -1
@@ -32,7 +32,8 @@ struct refspec {int fetch; }; -void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch); +void refspec_item_init_or_die (struct refspec_item *item,const char *refspec, +int fetch);void refspec_item_clear (struct refspec_item *item);void refspec_init (struct refspec *rs,int fetch);void refspec_append (struct refspec *rs,const char *refspec);
Signature · 1 line
2.17.0.290.gded63e768a
PATCH 2/3 refspec: add back a refspec_item_init() function
In reply to Ævar Arnfjörð BjarmasonRe-add the non-fatal version of refspec_item_init_or_die() renamed away in an earlier change to get a more minimal diff. This should be used by callers that have their own error handling.
This new function could be marked "static" since nothing outside of refspec.c uses it, but expecting future use of it, let's make it available to other users.
--- refspec.c | 10 +++++++--- refspec.h | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-)
refspec.c +7 -3
@@ -124,12 +124,16 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fetreturn 1 ; } -void refspec_item_init_or_die (struct refspec_item *item,const char *refspec, -int fetch) +int refspec_item_init (struct refspec_item *item,const char *refspec,int fetch) {memset (item,0 ,sizeof (*item)); +return parse_refspec (item, refspec, fetch); +} -if (!parse_refspec (item, refspec, fetch)) +void refspec_item_init_or_die (struct refspec_item *item,const char *refspec, +int fetch) +{ +if (!refspec_item_init (item, refspec, fetch))die ("Invalid refspec '%s'" , refspec); }
refspec.h +2 -0
@@ -32,6 +32,8 @@ struct refspec {int fetch; }; +int refspec_item_init (struct refspec_item *item,const char *refspec, +int fetch);void refspec_item_init_or_die (struct refspec_item *item,const char *refspec,int fetch);void refspec_item_clear (struct refspec_item *item);
Signature · 1 line
2.17.0.290.gded63e768a
PATCH 3/3 refspec: initalize `refspec_item` in `valid_fetch_refspec()`
In reply to Ævar Arnfjörð BjarmasonFrom: Martin Ågren <[email protected]>
We allocate a struct refspec_item on the stack without initializing it. In particular, its dst and src members will contain some random data from the stack. When we later call refspec_item_clear(), it will call free() on those pointers. So if the call to parse_refspec() did not assign to them, we will be freeing some random "pointers". This is undefined behavior.
To the best of my understanding, this cannot currently be triggered by user-provided data. And for what it's worth, the test-suite does not trigger this with SANITIZE=address. It can be provoked by calling valid_fetch_refspec(":*").
Zero the struct, as is done in other users of struct refspec_item by using the refspec_item_init() initialization function.
--- refspec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
refspec.c +1 -1
@@ -196,7 +196,7 @@ void refspec_clear(struct refspec *rs)int valid_fetch_refspec (const char *fetch_refspec_str) {struct refspec_item refspec; -int ret =parse_refspec (&refspec, fetch_refspec_str,REFSPEC_FETCH ); +int ret =refspec_item_init (&refspec, fetch_refspec_str,REFSPEC_FETCH );refspec_item_clear (&refspec);return ret; }
Signature · 1 line
2.17.0.290.gded63e768a
Re: [PATCH 0/3] refspec: refactor & fix free() behavior
In reply to Ævar Arnfjörð BjarmasonQuoted 7 lines · Ævar Arnfjörð Bjarmason
Since Martin & Brandon both liked this direction I've fixed it up.
Martin: I didn't want to be the author of the actual fix for the bug you found, so I rewrote your commit in 3/3. The diff is different, and I slightly modified the 3rd paragraph of the commit message & added my sign-off, but otherwise it's the same.
Thanks for writing up a proper patch series for this fix. I liked breaking up your diff into two different patches to make it clear that all callers of refpsec_item_init relying on dieing.
Quoted 17 lines
Martin Ågren (1):
refspec: initalizerefspec_iteminvalid_fetch_refspec()Ævar Arnfjörð Bjarmason (2):
refspec: s/refspec_item_init/&_or_die/g
refspec: add back arefspec_item_init()functionbuiltin/clone.c | 2 +- builtin/pull.c | 2 +- refspec.c | 13 +++++++++---- refspec.h | 5 ++++- 4 files changed, 15 insertions(+), 7 deletions(-)Signature · 1 line
2.17.0.290.gded63e768a
Signature · 1 line
Brandon Williams
Re: [PATCH 0/3] refspec: refactor & fix free() behavior
Quoted 4 lines · Brandon Williams
Quoted 3 lines · Ævar Arnfjörð Bjarmason
Since Martin & Brandon both liked this direction I've fixed it up.
Quoted 8 lines
Quoted 4 lines
Martin: I didn't want to be the author of the actual fix for the bug you found, so I rewrote your commit in 3/3. The diff is different, and I slightly modified the 3rd paragraph of the commit message & added my sign-off, but otherwise it's the same.
Thanks for writing up a proper patch series for this fix. I liked breaking up your diff into two different patches to make it clear that all callers of
refpsec_item_initrelying on dieing.
Me too.
Quoted 2 lines
Quoted 2 lines
Martin Ågren (1):
refspec: initalizerefspec_iteminvalid_fetch_refspec()
I was a bit surprised at first that this wasn't a "while at it" in the second patch, but on second thought, it does make sense to keep this separate. Thanks for picking this up and polishing it.
Just noticed: s/initalize/initialize/. That would be my fault...
Martin
PATCH v2 6/36 submodule--helper: convert push_check to use struct refspec
In reply to Brandon WilliamsConvert 'push_check()' to use 'struct refspec'.
--- builtin/submodule--helper.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
builtin/submodule--helper.c +7 -6
@@ -1744,13 +1744,14 @@ static int push_check(int argc, const char **argv, const char *prefix)/* Check the refspec */ if (argc >2 ) { -int i, refspec_nr = argc -2 ; +int i;struct ref *local_refs =get_local_heads (); -struct refspec_item *refspec =parse_push_refspec (refspec_nr, - argv +2 ); +struct refspec refspec =REFSPEC_INIT_PUSH ; -for (i =0 ; i < refspec_nr; i++) { -struct refspec_item *rs = refspec + i; +refspec_appendn (&refspec, argv +2 , argc -2 ); + +for (i =0 ; i < refspec.nr; i++) { +const struct refspec_item *rs = &refspec.items[i];if (rs->pattern || rs->matching)continue ;
@@ -1777,7 +1778,7 @@ static int push_check(int argc, const char **argv, const char *prefix) rs->src); } } -free_refspec (refspec_nr, refspec); +refspec_clear (&refspec); }free (head);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 7/36 pull: convert get_tracking_branch to use refspec_item_init
In reply to Brandon WilliamsConvert 'get_tracking_branch()' to use 'refspec_item_init()' instead of the old 'parse_fetch_refspec()' function.
--- builtin/pull.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
builtin/pull.c +4 -4
@@ -676,12 +676,12 @@ static const char *get_upstream_branch(const char *remote)*/ static const char *get_tracking_branch (const char *remote,const char *refspec) { -struct refspec_item *spec; +struct refspec_item spec;const char *spec_src;const char *merge_branch; - spec =parse_fetch_refspec (1 , &refspec); - spec_src = spec->src; +refspec_item_init (&spec, refspec,REFSPEC_FETCH ); + spec_src = spec.src;if (!*spec_src || !strcmp (spec_src,"HEAD" )) spec_src ="HEAD" ;else if (skip_prefix (spec_src,"heads/" , &spec_src))
@@ -701,7 +701,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec) }else merge_branch =NULL ; -free_refspec (1 , spec); +refspec_item_clear (&spec);return merge_branch; }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 8/36 transport: convert transport_push to use struct refspec
In reply to Brandon WilliamsConvert the logic in 'transport_push()' which calculates a list of ref-prefixes to use 'struct refspec'.
--- transport.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
transport.c +9 -8
@@ -1111,21 +1111,22 @@ int transport_push(struct transport *transport,int porcelain = flags &TRANSPORT_PUSH_PORCELAIN ;int pretend = flags &TRANSPORT_PUSH_DRY_RUN ;int push_ret, ret, err; -struct refspec_item *tmp_rs; +struct refspec tmp_rs =REFSPEC_INIT_PUSH ;struct argv_array ref_prefixes =ARGV_ARRAY_INIT ;int i;if (check_push_refs (local_refs, refspec_nr, refspec) <0 )return -1 ; - tmp_rs =parse_push_refspec (refspec_nr, refspec); -for (i =0 ; i < refspec_nr; i++) { +refspec_appendn (&tmp_rs, refspec, refspec_nr); +for (i =0 ; i < tmp_rs.nr; i++) { +const struct refspec_item *item = &tmp_rs.items[i];const char *prefix =NULL ; -if (tmp_rs[i].dst) - prefix = tmp_rs[i].dst; -else if (tmp_rs[i].src && !tmp_rs[i].exact_sha1) - prefix = tmp_rs[i].src; +if (item->dst) + prefix = item->dst; +else if (item->src && !item->exact_sha1) + prefix = item->src;if (prefix) {const char *glob =strchr (prefix,'*' );
@@ -1142,7 +1143,7 @@ int transport_push(struct transport *transport, &ref_prefixes);argv_array_clear (&ref_prefixes); -free_refspec (refspec_nr, tmp_rs); +refspec_clear (&tmp_rs);if (flags &TRANSPORT_PUSH_ALL ) match_flags |=MATCH_REFS_ALL ;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 9/36 remote: convert check_push_refs to use struct refspec
In reply to Brandon WilliamsConvert 'check_push_refs()' to use 'struct refspec'.
--- remote.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
remote.c +6 -4
@@ -1282,12 +1282,14 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)*/ int check_push_refs (struct ref *src,int nr_refspec,const char **refspec_names) { -struct refspec_item *refspec =parse_push_refspec (nr_refspec, refspec_names); +struct refspec refspec =REFSPEC_INIT_PUSH ;int ret =0 ;int i; -for (i =0 ; i < nr_refspec; i++) { -struct refspec_item *rs = refspec + i; +refspec_appendn (&refspec, refspec_names, nr_refspec); + +for (i =0 ; i < refspec.nr; i++) { +struct refspec_item *rs = &refspec.items[i];if (rs->pattern || rs->matching)continue ;
@@ -1295,7 +1297,7 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names) ret |=match_explicit_lhs (src, rs,NULL ,NULL ); } -free_refspec (nr_refspec, refspec); +refspec_clear (&refspec);return ret; }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 10/36 remote: convert match_push_refs to use struct refspec
In reply to Brandon WilliamsConvert 'match_push_refs()' to use struct refspec.
--- remote.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
remote.c +8 -5
@@ -1312,7 +1312,7 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)int match_push_refs (struct ref *src,struct ref **dst,int nr_refspec,const char **refspec,int flags) { -struct refspec_item *rs; +struct refspec rs =REFSPEC_INIT_PUSH ;int send_all = flags &MATCH_REFS_ALL ;int send_mirror = flags &MATCH_REFS_MIRROR ;int send_prune = flags &MATCH_REFS_PRUNE ;
@@ -1325,8 +1325,8 @@ int match_push_refs(struct ref *src, struct ref **dst, nr_refspec =1 ; refspec = default_refspec; } - rs =parse_push_refspec (nr_refspec, (const char **) refspec); - errs =match_explicit_refs (src, *dst, &dst_tail, rs, nr_refspec); +refspec_appendn (&rs, refspec, nr_refspec); + errs =match_explicit_refs (src, *dst, &dst_tail, rs.items, rs.nr);/* pick the remainder */ for (ref = src; ref; ref = ref->next) {
@@ -1335,7 +1335,7 @@ int match_push_refs(struct ref *src, struct ref **dst,const struct refspec_item *pat =NULL ;char *dst_name; - dst_name =get_ref_match (rs, nr_refspec, ref, send_mirror,FROM_SRC , &pat); + dst_name =get_ref_match (rs.items, rs.nr, ref, send_mirror,FROM_SRC , &pat);if (!dst_name)continue ;
@@ -1384,7 +1384,7 @@ int match_push_refs(struct ref *src, struct ref **dst,/* We're already sending something to this ref. */ continue ; - src_name =get_ref_match (rs, nr_refspec, ref, send_mirror,FROM_DST ,NULL ); + src_name =get_ref_match (rs.items, rs.nr, ref, send_mirror,FROM_DST ,NULL );if (src_name) {if (!src_ref_index.nr)prepare_ref_index (&src_ref_index, src);
@@ -1396,6 +1396,9 @@ int match_push_refs(struct ref *src, struct ref **dst, }string_list_clear (&src_ref_index,0 ); } + +refspec_clear (&rs); +if (errs)return -1 ;return 0 ;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 11/36 clone: convert cmd_clone to use refspec_item_init
In reply to Brandon WilliamsConvert 'cmd_clone()' to use 'refspec_item_init()' instead of relying on the old 'parse_fetch_refspec()' to initialize a single refspec item.
--- builtin/clone.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
builtin/clone.c +4 -6
@@ -895,8 +895,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)int err =0 , complete_refs_before_fetch =1 ;int submodule_progress; -struct refspec_item *refspec; -const char *fetch_pattern; +struct refspec_item refspec; fetch_if_missing =0 ;
@@ -1078,8 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)if (option_required_reference.nr || option_optional_reference.nr)setup_reference (); - fetch_pattern = value.buf; - refspec =parse_fetch_refspec (1 , &fetch_pattern); +refspec_item_init (&refspec, value.buf,REFSPEC_FETCH );strbuf_reset (&value);
@@ -1139,7 +1137,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) refs =transport_get_remote_refs (transport,NULL );if (refs) { - mapped_refs =wanted_peer_refs (refs, refspec); + mapped_refs =wanted_peer_refs (refs, &refspec);/* * transport_get_remote_refs() may return refs with null sha-1 * in mapped_refs (see struct transport->get_refs_list
@@ -1233,6 +1231,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)strbuf_release (&value); junk_mode =JUNK_LEAVE_ALL ; -free (refspec); +refspec_item_clear (&refspec);return err; }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 12/36 fast-export: convert to use struct refspec
In reply to Brandon WilliamsConvert fast-export to use 'struct refspec' instead of using a list of refspec_item's.
--- builtin/fast-export.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-)
builtin/fast-export.c +7 -14
@@ -36,8 +36,7 @@ static int use_done_feature;static int no_data;static int full_tree;static struct string_list extra_refs =STRING_LIST_INIT_NODUP ; -static struct refspec_item *refspecs; -static int refspecs_nr; +static struct refspec refspecs =REFSPEC_INIT_FETCH ;static int anonymize; static int parse_opt_signed_tag_mode(const struct option *opt,
@@ -830,9 +829,9 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)if (dwim_ref (e->name,strlen (e->name), &oid, &full_name) !=1 )continue ; -if (refspecs) { +if (refspecs.nr) {char *private; - private =apply_refspecs (refspecs, refspecs_nr, full_name); + private =apply_refspecs (refspecs.items, refspecs.nr, full_name);if (private) {free (full_name); full_name = private;
@@ -978,8 +977,8 @@ static void import_marks(char *input_file)static void handle_deletes (void ) {int i; -for (i =0 ; i < refspecs_nr; i++) { -struct refspec_item *refspec = &refspecs[i]; +for (i =0 ; i < refspecs.nr; i++) { +struct refspec_item *refspec = &refspecs.items[i];if (*refspec->src)continue ;
@@ -1040,18 +1039,12 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)usage_with_options (fast_export_usage, options);if (refspecs_list.nr) { -const char **refspecs_str;int i; -ALLOC_ARRAY (refspecs_str, refspecs_list.nr);for (i =0 ; i < refspecs_list.nr; i++) - refspecs_str[i] = refspecs_list.items[i].string; - - refspecs_nr = refspecs_list.nr; - refspecs =parse_fetch_refspec (refspecs_nr, refspecs_str); +refspec_append (&refspecs, refspecs_list.items[i].string);string_list_clear (&refspecs_list,1 ); -free (refspecs_str); }if (use_done_feature)
@@ -1090,7 +1083,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)if (use_done_feature)printf ("done\n" ); -free_refspec (refspecs_nr, refspecs); +refspec_clear (&refspecs);return 0 ; }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 13/36 remote: convert push refspecs to struct refspec
In reply to Brandon WilliamsConvert the set of push refspecs stored in 'struct remote' to use 'struct refspec'.
--- builtin/push.c | 10 +++++----- builtin/remote.c | 14 +++++++------- remote.c | 35 ++++++++++++++--------------------- remote.h | 6 ++---- 4 files changed, 28 insertions(+), 37 deletions(-)
builtin/push.c +5 -5
@@ -79,11 +79,11 @@ static const char *map_refspec(const char *ref,if (count_refspec_match (ref, local_refs, &matched) !=1 )return ref; -if (remote->push) { +if (remote->push.nr) {struct refspec_item query;memset (&query,0 ,sizeof (struct refspec_item )); query.src = matched->name; -if (!query_refspecs (remote->push, remote->push_refspec_nr, &query) && +if (!query_refspecs (remote->push.items, remote->push.nr, &query) && query.dst) {struct strbuf buf =STRBUF_INIT ; strbuf_addf(&buf, "%s%s:%s",
@@ -436,9 +436,9 @@ static int do_push(const char *repo, int flags, }if (!refspec && !(flags &TRANSPORT_PUSH_ALL )) { -if (remote->push_refspec_nr) { - refspec = remote->push_refspec; - refspec_nr = remote->push_refspec_nr; +if (remote->push.raw_nr) { + refspec = remote->push.raw; + refspec_nr = remote->push.raw_nr; }else if (!(flags &TRANSPORT_PUSH_MIRROR ))setup_default_push_refspecs (remote); }
builtin/remote.c +7 -7
@@ -388,8 +388,8 @@ static int get_push_ref_states(const struct ref *remote_refs, local_refs =get_local_heads (); push_map =copy_ref_list (remote_refs); -match_push_refs (local_refs, &push_map, remote->push_refspec_nr, - remote->push_refspec,MATCH_REFS_NONE ); +match_push_refs (local_refs, &push_map, remote->push.raw_nr, + remote->push.raw,MATCH_REFS_NONE ); states->push.strdup_strings =1 ;for (ref = push_map; ref; ref = ref->next) {
@@ -435,14 +435,14 @@ static int get_push_ref_states_noquery(struct ref_states *states)return 0 ; states->push.strdup_strings =1 ; -if (!remote->push_refspec_nr) { +if (!remote->push.nr) { item =string_list_append (&states->push,_ ("(matching)" )); info = item->util =xcalloc (1 ,sizeof (struct push_info )); info->status =PUSH_STATUS_NOTQUERIED ; info->dest =xstrdup (item->string); } -for (i =0 ; i < remote->push_refspec_nr; i++) { -struct refspec_item *spec = remote->push + i; +for (i =0 ; i < remote->push.nr; i++) { +const struct refspec_item *spec = &remote->push.items[i];if (spec->matching) item =string_list_append (&states->push,_ ("(matching)" ));else if (strlen (spec->src))
@@ -586,8 +586,8 @@ static int migrate_file(struct remote *remote)git_config_set_multivar (buf.buf, remote->url[i],"^$" ,0 );strbuf_reset (&buf);strbuf_addf (&buf,"remote.%s.push" , remote->name); -for (i =0 ; i < remote->push_refspec_nr; i++) -git_config_set_multivar (buf.buf, remote->push_refspec[i],"^$" ,0 ); +for (i =0 ; i < remote->push.raw_nr; i++) +git_config_set_multivar (buf.buf, remote->push.raw[i],"^$" ,0 );strbuf_reset (&buf);strbuf_addf (&buf,"remote.%s.fetch" , remote->name);for (i =0 ; i < remote->fetch_refspec_nr; i++)
remote.c +14 -21
@@ -77,14 +77,6 @@ static const char *alias_url(const char *url, struct rewrites *r)return xstrfmt ("%s%s" , r->rewrite[longest_i]->base, url + longest->len); } -static void add_push_refspec (struct remote *remote,const char *ref) -{ -ALLOC_GROW (remote->push_refspec, - remote->push_refspec_nr +1 , - remote->push_refspec_alloc); - remote->push_refspec[remote->push_refspec_nr++] = ref; -} -static void add_fetch_refspec (struct remote *remote,const char *ref) { ALLOC_GROW(remote->fetch_refspec,
@@ -175,9 +167,11 @@ static struct remote *make_remote(const char *name, int len) ret =xcalloc (1 ,sizeof (struct remote )); ret->prune =-1 ;/* unspecified */ ret->prune_tags =-1 ;/* unspecified */ + ret->name =xstrndup (name, len); +refspec_init (&ret->push,REFSPEC_PUSH ); +ALLOC_GROW (remotes, remotes_nr +1 , remotes_alloc); remotes[remotes_nr++] = ret; - ret->name =xstrndup (name, len);hashmap_entry_init (ret, lookup_entry.hash); replaced =hashmap_put (&remotes_hash, ret);
@@ -275,7 +269,7 @@ static void read_remotes_file(struct remote *remote)if (skip_prefix (buf.buf,"URL:" , &v))add_url_alias (remote,xstrdup (skip_spaces (v)));else if (skip_prefix (buf.buf,"Push:" , &v)) -add_push_refspec (remote,xstrdup (skip_spaces (v))); +refspec_append (&remote->push,skip_spaces (v));else if (skip_prefix (buf.buf,"Pull:" , &v))add_fetch_refspec (remote,xstrdup (skip_spaces (v))); }
@@ -323,8 +317,10 @@ static void read_branches_file(struct remote *remote)* Cogito compatible push: push current HEAD to remote #branch * (master if missing) */ -add_push_refspec (remote,xstrfmt ("HEAD:refs/heads/%s" , frag)); +strbuf_addf (&buf,"HEAD:refs/heads/%s" , frag); +refspec_append (&remote->push, buf.buf); remote->fetch_tags =1 ;/* always auto-follow */ +strbuf_release (&buf); }static int handle_config (const char *key,const char *value,void *cb)
@@ -409,7 +405,8 @@ static int handle_config(const char *key, const char *value, void *cb)const char *v;if (git_config_string (&v, key, value))return -1 ; -add_push_refspec (remote, v); +refspec_append (&remote->push, v); +free ((char *)v); }else if (!strcmp (subkey,"fetch" )) {const char *v;if (git_config_string (&v, key, value))
@@ -542,9 +539,9 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push,pushremote_for_branch (branch,NULL );struct remote *remote =remote_get (remote_name); -if (remote && remote->push_refspec_nr && - (dst =apply_refspecs (remote->push, - remote->push_refspec_nr, +if (remote && remote->push.nr && + (dst =apply_refspecs (remote->push.items, + remote->push.nr, branch->refname))) {if (explicit) *explicit =1 ;
@@ -582,7 +579,6 @@ static struct remote *remote_get_1(const char *name,if (!valid_remote (ret))return NULL ; ret->fetch =parse_fetch_refspec (ret->fetch_refspec_nr, ret->fetch_refspec); - ret->push =parse_push_refspec (ret->push_refspec_nr, ret->push_refspec);return ret; }
@@ -616,9 +612,6 @@ int for_each_remote(each_remote_fn fn, void *priv)if (!r->fetch) r->fetch =parse_fetch_refspec (r->fetch_refspec_nr, r->fetch_refspec); -if (!r->push) - r->push =parse_push_refspec (r->push_refspec_nr, - r->push_refspec); result =fn (r, priv); }return result;
@@ -1613,11 +1606,11 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err)_ ("branch '%s' has no remote for pushing" ), branch->name); -if (remote->push_refspec_nr) { +if (remote->push.nr) {char *dst;const char *ret; - dst =apply_refspecs (remote->push, remote->push_refspec_nr, + dst =apply_refspecs (remote->push.items, remote->push.nr, branch->refname);if (!dst) return error_buf(err,
remote.h +2 -4
@@ -3,6 +3,7 @@#include "parse-options.h" #include "hashmap.h" +#include "refspec.h" enum {REMOTE_UNCONFIGURED =0 ,
@@ -27,10 +28,7 @@ struct remote {int pushurl_nr;int pushurl_alloc; -const char **push_refspec; -struct refspec_item *push; -int push_refspec_nr; -int push_refspec_alloc; +struct refspec push;const char **fetch_refspec;struct refspec_item *fetch;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 14/36 remote: convert fetch refspecs to struct refspec
In reply to Brandon WilliamsConvert the set of fetch refspecs stored in 'struct remote' to use 'struct refspec'.
--- builtin/fetch.c | 20 ++++++++++---------- builtin/remote.c | 18 +++++++++--------- remote.c | 38 ++++++++++++-------------------------- remote.h | 5 +---- 4 files changed, 32 insertions(+), 49 deletions(-)
builtin/fetch.c +10 -10
@@ -407,8 +407,8 @@ static struct ref *get_ref_map(struct transport *transport, fetch_refspec =parse_fetch_refspec (refmap_nr, refmap_array); fetch_refspec_nr = refmap_nr; }else { - fetch_refspec = transport->remote->fetch; - fetch_refspec_nr = transport->remote->fetch_refspec_nr; + fetch_refspec = transport->remote->fetch.items; + fetch_refspec_nr = transport->remote->fetch.nr; }for (i =0 ; i < fetch_refspec_nr; i++)
@@ -421,16 +421,16 @@ static struct ref *get_ref_map(struct transport *transport,struct branch *branch =branch_get (NULL );int has_merge =branch_has_merge_config (branch);if (remote && - (remote->fetch_refspec_nr || + (remote->fetch.nr ||/* Note: has_merge implies non-NULL branch->remote_name */ (has_merge && !strcmp (branch->remote_name, remote->name)))) { -for (i =0 ; i < remote->fetch_refspec_nr; i++) { -get_fetch_map (remote_refs, &remote->fetch[i], &tail,0 ); -if (remote->fetch[i].dst && - remote->fetch[i].dst[0 ]) +for (i =0 ; i < remote->fetch.nr; i++) { +get_fetch_map (remote_refs, &remote->fetch.items[i], &tail,0 ); +if (remote->fetch.items[i].dst && + remote->fetch.items[i].dst[0 ]) *autotags =1 ;if (!i && !has_merge && ref_map && - !remote->fetch[0 ].pattern) + !remote->fetch.items[0 ].pattern) ref_map->fetch_head_status =FETCH_HEAD_MERGE ; }/*
@@ -1166,8 +1166,8 @@ static int do_fetch(struct transport *transport,if (ref_count) {prune_refs (refs, ref_count, ref_map, transport->url); }else { -prune_refs (transport->remote->fetch, - transport->remote->fetch_refspec_nr, +prune_refs (transport->remote->fetch.items, + transport->remote->fetch.nr, ref_map, transport->url); }
builtin/remote.c +9 -9
@@ -333,10 +333,10 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *statstruct ref *ref, *stale_refs;int i; -for (i =0 ; i < states->remote->fetch_refspec_nr; i++) -if (get_fetch_map (remote_refs, states->remote->fetch + i, &tail,1 )) +for (i =0 ; i < states->remote->fetch.nr; i++) +if (get_fetch_map (remote_refs, &states->remote->fetch.items[i], &tail,1 ))die (_ ("Could not get fetch map for refspec %s" ), - states->remote->fetch_refspec[i]); + states->remote->fetch.raw[i]); states->new_refs.strdup_strings =1 ; states->tracked.strdup_strings =1 ;
@@ -347,8 +347,8 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *statelse string_list_append (&states->tracked,abbrev_branch (ref->name)); } - stale_refs =get_stale_heads (states->remote->fetch, - states->remote->fetch_refspec_nr, fetch_map); + stale_refs =get_stale_heads (states->remote->fetch.items, + states->remote->fetch.nr, fetch_map);for (ref = stale_refs; ref; ref = ref->next) {struct string_list_item *item =string_list_append (&states->stale,abbrev_branch (ref->name));
@@ -590,8 +590,8 @@ static int migrate_file(struct remote *remote)git_config_set_multivar (buf.buf, remote->push.raw[i],"^$" ,0 );strbuf_reset (&buf);strbuf_addf (&buf,"remote.%s.fetch" , remote->name); -for (i =0 ; i < remote->fetch_refspec_nr; i++) -git_config_set_multivar (buf.buf, remote->fetch_refspec[i],"^$" ,0 ); +for (i =0 ; i < remote->fetch.raw_nr; i++) +git_config_set_multivar (buf.buf, remote->fetch.raw[i],"^$" ,0 );if (remote->origin ==REMOTE_REMOTES )unlink_or_warn (git_path ("remotes/%s" , remote->name));else if (remote->origin ==REMOTE_BRANCHES )
@@ -646,11 +646,11 @@ static int mv(int argc, const char **argv)strbuf_addf (&buf,"remote.%s.fetch" , rename.new_name);git_config_set_multivar (buf.buf,NULL ,NULL ,1 );strbuf_addf (&old_remote_context,":refs/remotes/%s/" , rename.old_name); -for (i =0 ; i < oldremote->fetch_refspec_nr; i++) { +for (i =0 ; i < oldremote->fetch.raw_nr; i++) {char *ptr;strbuf_reset (&buf2); -strbuf_addstr (&buf2, oldremote->fetch_refspec[i]); +strbuf_addstr (&buf2, oldremote->fetch.raw[i]); ptr =strstr (buf2.buf, old_remote_context.buf);if (ptr) { refspec_updated =1 ;
remote.c +12 -26
@@ -77,23 +77,9 @@ static const char *alias_url(const char *url, struct rewrites *r)return xstrfmt ("%s%s" , r->rewrite[longest_i]->base, url + longest->len); } -static void add_fetch_refspec (struct remote *remote,const char *ref) -{ -ALLOC_GROW (remote->fetch_refspec, - remote->fetch_refspec_nr +1 , - remote->fetch_refspec_alloc); - remote->fetch_refspec[remote->fetch_refspec_nr++] = ref; -} -void add_prune_tags_to_fetch_refspec (struct remote *remote) { -int nr = remote->fetch_refspec_nr; -int bufsize = nr +1 ; -int size =sizeof (struct refspec_item ); - - remote->fetch =xrealloc (remote->fetch, size * bufsize); -memcpy (&remote->fetch[nr], tag_refspec, size); -add_fetch_refspec (remote,xstrdup (TAG_REFSPEC )); +refspec_append (&remote->fetch,TAG_REFSPEC ); }static void add_url (struct remote *remote,const char *url)
@@ -169,6 +155,7 @@ static struct remote *make_remote(const char *name, int len) ret->prune_tags =-1 ;/* unspecified */ ret->name =xstrndup (name, len);refspec_init (&ret->push,REFSPEC_PUSH ); +refspec_init (&ret->fetch,REFSPEC_FETCH );ALLOC_GROW (remotes, remotes_nr +1 , remotes_alloc); remotes[remotes_nr++] = ret;
@@ -271,7 +258,7 @@ static void read_remotes_file(struct remote *remote)else if (skip_prefix (buf.buf,"Push:" , &v))refspec_append (&remote->push,skip_spaces (v));else if (skip_prefix (buf.buf,"Pull:" , &v)) -add_fetch_refspec (remote,xstrdup (skip_spaces (v))); +refspec_append (&remote->fetch,skip_spaces (v)); }strbuf_release (&buf);fclose (f);
@@ -310,13 +297,15 @@ static void read_branches_file(struct remote *remote) frag ="master" ;add_url_alias (remote,strbuf_detach (&buf,NULL )); -add_fetch_refspec (remote,xstrfmt ("refs/heads/%s:refs/heads/%s" , - frag, remote->name)); +strbuf_addf (&buf,"refs/heads/%s:refs/heads/%s" , + frag, remote->name); +refspec_append (&remote->fetch, buf.buf);/* * Cogito compatible push: push current HEAD to remote #branch * (master if missing) */ +strbuf_reset (&buf);strbuf_addf (&buf,"HEAD:refs/heads/%s" , frag);refspec_append (&remote->push, buf.buf); remote->fetch_tags =1 ;/* always auto-follow */
@@ -411,7 +400,8 @@ static int handle_config(const char *key, const char *value, void *cb)const char *v;if (git_config_string (&v, key, value))return -1 ; -add_fetch_refspec (remote, v); +refspec_append (&remote->fetch, v); +free ((char *)v); }else if (!strcmp (subkey,"receivepack" )) {const char *v;if (git_config_string (&v, key, value))
@@ -578,7 +568,6 @@ static struct remote *remote_get_1(const char *name,add_url_alias (ret, name);if (!valid_remote (ret))return NULL ; - ret->fetch =parse_fetch_refspec (ret->fetch_refspec_nr, ret->fetch_refspec);return ret; }
@@ -609,9 +598,6 @@ int for_each_remote(each_remote_fn fn, void *priv)struct remote *r = remotes[i];if (!r)continue ; -if (!r->fetch) - r->fetch =parse_fetch_refspec (r->fetch_refspec_nr, - r->fetch_refspec); result =fn (r, priv); }return result;
@@ -790,7 +776,7 @@ char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec,int remote_find_tracking (struct remote *remote,struct refspec_item *refspec) { -return query_refspecs (remote->fetch, remote->fetch_refspec_nr, refspec); +return query_refspecs (remote->fetch.items, remote->fetch.nr, refspec); } static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
@@ -1588,7 +1574,7 @@ static const char *tracking_for_push_dest(struct remote *remote, {char *ret; - ret =apply_refspecs (remote->fetch, remote->fetch_refspec_nr, refname); + ret =apply_refspecs (remote->fetch.items, remote->fetch.nr, refname);if (!ret) return error_buf(err, _("push destination '%s' on remote '%s' has no local tracking branch"),
@@ -2222,7 +2208,7 @@ static int remote_tracking(struct remote *remote, const char *refname, {char *dst; - dst =apply_refspecs (remote->fetch, remote->fetch_refspec_nr, refname); + dst =apply_refspecs (remote->fetch.items, remote->fetch.nr, refname);if (!dst)return -1 ;/* no tracking ref for refname at remote */ if (read_ref (dst, oid))
remote.h +1 -4
@@ -30,10 +30,7 @@ struct remote {struct refspec push; -const char **fetch_refspec; -struct refspec_item *fetch; -int fetch_refspec_nr; -int fetch_refspec_alloc; +struct refspec fetch;/* * -1 to never fetch tags
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 15/36 remote: remove add_prune_tags_to_fetch_refspec
In reply to Brandon WilliamsRemove 'add_prune_tags_to_fetch_refspec()' function and instead have the only caller directly add the tag refspec using 'refspec_append()'.
--- builtin/fetch.c | 2 +- remote.c | 5 ----- remote.h | 2 -- 3 files changed, 1 insertion(+), 8 deletions(-)
builtin/fetch.c +1 -1
@@ -1392,7 +1392,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru maybe_prune_tags = prune_tags_ok && prune_tags;if (maybe_prune_tags && remote_via_config) -add_prune_tags_to_fetch_refspec (remote); +refspec_append (&remote->fetch,TAG_REFSPEC );if (argc >0 || (maybe_prune_tags && !remote_via_config)) {size_t nr_alloc =st_add3 (argc, maybe_prune_tags,1 );
remote.c +0 -5
@@ -77,11 +77,6 @@ static const char *alias_url(const char *url, struct rewrites *r)return xstrfmt ("%s%s" , r->rewrite[longest_i]->base, url + longest->len); } -void add_prune_tags_to_fetch_refspec (struct remote *remote) -{ -refspec_append (&remote->fetch,TAG_REFSPEC ); -} -static void add_url (struct remote *remote,const char *url) {ALLOC_GROW (remote->url, remote->url_nr +1 , remote->url_alloc);
remote.h +0 -2
@@ -290,6 +290,4 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, intextern int is_empty_cas (const struct push_cas_option *);void apply_push_cas (struct push_cas_option *,struct remote *,struct ref *); -void add_prune_tags_to_fetch_refspec (struct remote *remote); -#endif
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 16/36 transport-helper: convert to use struct refspec
In reply to Brandon WilliamsConvert the refspecs in transport-helper.c to be stored in a 'struct refspec'.
--- transport-helper.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-)
transport-helper.c +12 -26
@@ -36,8 +36,7 @@ struct helper_data {char *export_marks;char *import_marks;/* These go from remote name (as in "list") to private name */ -struct refspec_item *refspecs; -int refspec_nr; +struct refspec rs;/* Transport options for fetch-pack/send-pack (should one of * those be invoked). */
@@ -107,9 +106,6 @@ static struct child_process *get_helper(struct transport *transport)struct helper_data *data = transport->data;struct strbuf buf =STRBUF_INIT ;struct child_process *helper; -const char **refspecs =NULL ; -int refspec_nr =0 ; -int refspec_alloc =0 ;int duped;int code;
@@ -139,6 +135,7 @@ static struct child_process *get_helper(struct transport *transport) data->helper = helper; data->no_disconnect_req =0 ; +refspec_init (&data->rs,REFSPEC_FETCH );/* * Open the output as FILE* so strbuf_getline_*() family of
@@ -184,11 +181,8 @@ static struct child_process *get_helper(struct transport *transport) data->export =1 ; else if (!strcmp(capname, "check-connectivity")) data->check_connectivity =1 ; - else if (!data->refspecs && skip_prefix(capname, "refspec ", &arg)) { -ALLOC_GROW (refspecs, - refspec_nr +1 , - refspec_alloc); - refspecs[refspec_nr++] =xstrdup (arg); + else if (skip_prefix(capname, "refspec ", &arg)) { +refspec_append (&data->rs, arg); } else if (!strcmp(capname, "connect")) { data->connect =1 ; } else if (!strcmp(capname, "stateless-connect")) {
@@ -207,14 +201,7 @@ static struct child_process *get_helper(struct transport *transport) capname); } } -if (refspecs) { -int i; - data->refspec_nr = refspec_nr; - data->refspecs =parse_fetch_refspec (refspec_nr, refspecs); -for (i =0 ; i < refspec_nr; i++) -free ((char *)refspecs[i]); -free (refspecs); - }else if (data->import || data->bidi_import || data->export) { +if (!data->rs.nr && (data->import || data->bidi_import || data->export)) {warning ("This remote helper should implement refspec capability." ); }strbuf_release (&buf);
@@ -378,8 +365,7 @@ static int release_helper(struct transport *transport) {int res =0 ;struct helper_data *data = transport->data; -free_refspec (data->refspec_nr, data->refspecs); - data->refspecs =NULL ; +refspec_clear (&data->rs); res =disconnect_helper (transport);free (transport->data);return res;
@@ -536,8 +522,8 @@ static int fetch_with_import(struct transport *transport,if (posn->status &REF_STATUS_UPTODATE )continue ; name = posn->symref ? posn->symref : posn->name; -if (data->refspecs) - private =apply_refspecs (data->refspecs, data->refspec_nr, name); +if (data->rs.nr) + private =apply_refspecs (data->rs.items, data->rs.nr, name);else private =xstrdup (name);if (private) {
@@ -815,11 +801,11 @@ static int push_update_refs_status(struct helper_data *data,if (push_update_ref_status (&buf, &ref, remote_refs))continue ; -if (flags &TRANSPORT_PUSH_DRY_RUN || !data->refspecs || data->no_private_update) +if (flags &TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update)continue ;/* propagate back the update to the remote namespace */ - private =apply_refspecs (data->refspecs, data->refspec_nr, ref->name); + private =apply_refspecs (data->rs.items, data->rs.nr, ref->name);if (!private)continue ; update_ref("update by helper", private, &ref->new_oid, NULL,
@@ -939,7 +925,7 @@ static int push_refs_with_export(struct transport *transport,struct string_list revlist_args =STRING_LIST_INIT_DUP ;struct strbuf buf =STRBUF_INIT ; -if (!data->refspecs) +if (!data->rs.nr)die ("remote-helper doesn't support push; refspec needed" );set_common_push_options (transport, data->name, flags);
@@ -956,7 +942,7 @@ static int push_refs_with_export(struct transport *transport,char *private;struct object_id oid; - private =apply_refspecs (data->refspecs, data->refspec_nr, ref->name); + private =apply_refspecs (data->rs.items, data->rs.nr, ref->name);if (private && !get_oid (private, &oid)) {strbuf_addf (&buf,"^%s" , private); string_list_append_nodup(&revlist_args,
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 17/36 fetch: convert fetch_one to use struct refspec
In reply to Brandon WilliamsConvert 'fetch_one()' to use 'struct refspec'.
--- builtin/fetch.c | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-)
builtin/fetch.c +19 -27
@@ -1356,10 +1356,8 @@ static inline void fetch_one_setup_partial(struct remote *remote)static int fetch_one (struct remote *remote,int argc,const char **argv,int prune_tags_ok) { -static const char **refs =NULL ; -struct refspec_item *refspec; -int ref_nr =0 ; -int j =0 ; +struct refspec rs =REFSPEC_INIT_FETCH ; +int i;int exit_code;int maybe_prune_tags;int remote_via_config =remote_is_configured (remote,0 );
@@ -1394,35 +1392,29 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pruif (maybe_prune_tags && remote_via_config)refspec_append (&remote->fetch,TAG_REFSPEC ); -if (argc >0 || (maybe_prune_tags && !remote_via_config)) { -size_t nr_alloc =st_add3 (argc, maybe_prune_tags,1 ); - refs =xcalloc (nr_alloc,sizeof (const char *)); -if (maybe_prune_tags) { - refs[j++] =xstrdup ("refs/tags/*:refs/tags/*" ); - ref_nr++; - } - } +if (maybe_prune_tags && (argc || !remote_via_config)) +refspec_append (&rs,TAG_REFSPEC ); -if (argc >0 ) { -int i; -for (i =0 ; i < argc; i++) { -if (!strcmp (argv[i],"tag" )) { - i++; -if (i >= argc) -die (_ ("You need to specify a tag name." )); - refs[j++] =xstrfmt ("refs/tags/%s:refs/tags/%s" , - argv[i], argv[i]); - }else - refs[j++] = argv[i]; - ref_nr++; +for (i =0 ; i < argc; i++) { +if (!strcmp (argv[i],"tag" )) { +char *tag; + i++; +if (i >= argc) +die (_ ("You need to specify a tag name." )); + + tag =xstrfmt ("refs/tags/%s:refs/tags/%s" , + argv[i], argv[i]); +refspec_append (&rs, tag); +free (tag); + }else { +refspec_append (&rs, argv[i]); } }sigchain_push_common (unlock_pack_on_signal);atexit (unlock_pack); - refspec =parse_fetch_refspec (ref_nr, refs); - exit_code =do_fetch (gtransport, refspec, ref_nr); -free_refspec (ref_nr, refspec); + exit_code =do_fetch (gtransport, rs.items, rs.nr); +refspec_clear (&rs);transport_disconnect (gtransport); gtransport =NULL ;return exit_code;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 18/36 fetch: convert refmap to use struct refspec
In reply to Brandon WilliamsConvert the refmap in builtin/fetch.c to be stored in a 'struct refspec'.
--- builtin/fetch.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)
builtin/fetch.c +7 -10
@@ -60,8 +60,7 @@ static const char *submodule_prefix = "";static int recurse_submodules =RECURSE_SUBMODULES_DEFAULT ;static int recurse_submodules_default =RECURSE_SUBMODULES_ON_DEMAND ;static int shown_url =0 ; -static int refmap_alloc, refmap_nr; -static const char **refmap_array; +static struct refspec refmap =REFSPEC_INIT_FETCH ;static struct list_objects_filter_options filter_options;static int git_fetch_config (const char *k,const char *v,void *cb)
@@ -108,14 +107,12 @@ static int gitmodules_fetch_config(const char *var, const char *value, void *cb)static int parse_refmap_arg (const struct option *opt,const char *arg,int unset) { -ALLOC_GROW (refmap_array, refmap_nr +1 , refmap_alloc); -/* * "git fetch --refmap='' origin foo" * can be used to tell the command not to store anywhere */ -if (*arg) - refmap_array[refmap_nr++] = arg; +refspec_append (&refmap, arg); +return 0 ; }
@@ -403,9 +400,9 @@ static struct ref *get_ref_map(struct transport *transport,* by ref_remove_duplicates() in favor of one of these * opportunistic entries with FETCH_HEAD_IGNORE. */ -if (refmap_array) { - fetch_refspec =parse_fetch_refspec (refmap_nr, refmap_array); - fetch_refspec_nr = refmap_nr; +if (refmap.nr) { + fetch_refspec = refmap.items; + fetch_refspec_nr = refmap.nr; }else { fetch_refspec = transport->remote->fetch.items; fetch_refspec_nr = transport->remote->fetch.nr;
@@ -413,7 +410,7 @@ static struct ref *get_ref_map(struct transport *transport,for (i =0 ; i < fetch_refspec_nr; i++)get_fetch_map (ref_map, &fetch_refspec[i], &oref_tail,1 ); - }else if (refmap_array) { + }else if (refmap.nr) {die ("--refmap option is only meaningful with command-line refspec(s)." ); }else {/* Use the defaults */
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 19/36 refspec: remove the deprecated functions
In reply to Brandon WilliamsNow that there are no callers of 'parse_push_refspec()', 'parse_fetch_refspec()', and 'free_refspec()', remove these functions.
--- refspec.c | 49 ------------------------------------------------- refspec.h | 5 ----- 2 files changed, 54 deletions(-)
refspec.c +0 -49
@@ -121,55 +121,6 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fetreturn 1 ; } -static struct refspec_item *parse_refspec_internal (int nr_refspec,const char **refspec,int fetch,int verify) -{ -int i; -struct refspec_item *rs =xcalloc (nr_refspec,sizeof (*rs)); - -for (i =0 ; i < nr_refspec; i++) { -if (!parse_refspec (&rs[i], refspec[i], fetch)) - goto invalid; - } - -return rs; - - invalid: -if (verify) { -/* -* nr_refspec must be greater than zero and i must be valid -* since it is only possible to reach this point from within -* the for loop above. -*/ -free_refspec (i+1 , rs); -return NULL ; - } -die ("Invalid refspec '%s'" , refspec[i]); -} - -struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec) -{ -return parse_refspec_internal (nr_refspec, refspec,1 ,0 ); -} - -struct refspec_item *parse_push_refspec (int nr_refspec,const char **refspec) -{ -return parse_refspec_internal (nr_refspec, refspec,0 ,0 ); -} - -void free_refspec (int nr_refspec,struct refspec_item *refspec) -{ -int i; - -if (!refspec) -return ; - -for (i =0 ; i < nr_refspec; i++) { -free (refspec[i].src); -free (refspec[i].dst); - } -free (refspec); -} -void refspec_item_init (struct refspec_item *item,const char *refspec,int fetch) {memset (item,0 ,sizeof (*item));
refspec.h +0 -5
@@ -14,11 +14,6 @@ struct refspec_item {char *dst; }; -struct refspec_item *parse_fetch_refspec (int nr_refspec,const char **refspec); -struct refspec_item *parse_push_refspec (int nr_refspec,const char **refspec); - -void free_refspec (int nr_refspec,struct refspec_item *refspec); -#define REFSPEC_FETCH 1#define REFSPEC_PUSH 0
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 20/36 fetch: convert do_fetch to take a struct refspec
In reply to Brandon WilliamsConvert 'do_fetch()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- builtin/fetch.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
builtin/fetch.c +5 -5
@@ -1112,7 +1112,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map) }static int do_fetch (struct transport *transport, -struct refspec_item *refs,int ref_count) +struct refspec *rs) {struct string_list existing_refs =STRING_LIST_INIT_DUP ;struct ref *ref_map;
@@ -1136,7 +1136,7 @@ static int do_fetch(struct transport *transport, goto cleanup; } - ref_map =get_ref_map (transport, refs, ref_count, tags, &autotags); + ref_map =get_ref_map (transport, rs->items, rs->nr, tags, &autotags);if (!update_head_ok)check_not_current_branch (ref_map);
@@ -1160,8 +1160,8 @@ static int do_fetch(struct transport *transport,* explicitly (via command line or configuration); we * don't care whether --tags was specified. */ -if (ref_count) { -prune_refs (refs, ref_count, ref_map, transport->url); +if (rs->nr) { +prune_refs (rs->items, rs->nr, ref_map, transport->url); }else { prune_refs(transport->remote->fetch.items, transport->remote->fetch.nr,
@@ -1410,7 +1410,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int prusigchain_push_common (unlock_pack_on_signal);atexit (unlock_pack); - exit_code =do_fetch (gtransport, rs.items, rs.nr); + exit_code =do_fetch (gtransport, &rs);refspec_clear (&rs);transport_disconnect (gtransport); gtransport =NULL ;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 21/36 fetch: convert get_ref_map to take a struct refspec
In reply to Brandon WilliamsConvert 'get_ref_map()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- builtin/fetch.c | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-)
builtin/fetch.c +20 -23
@@ -337,7 +337,7 @@ static void find_non_local_tags(struct transport *transport, }static struct ref *get_ref_map (struct transport *transport, -struct refspec_item *refspecs,int refspec_count, +struct refspec *rs,int tags,int *autotags) {int i;
@@ -351,15 +351,16 @@ static struct ref *get_ref_map(struct transport *transport,const struct ref *remote_refs; -for (i =0 ; i < refspec_count; i++) { -if (!refspecs[i].exact_sha1) { -const char *glob =strchr (refspecs[i].src,'*' ); +for (i =0 ; i < rs->nr; i++) { +const struct refspec_item *item = &rs->items[i]; +if (!item->exact_sha1) { +const char *glob =strchr (item->src,'*' );if (glob)argv_array_pushf (&ref_prefixes,"%.*s" , - (int )(glob - refspecs[i].src), - refspecs[i].src); + (int )(glob - item->src), + item->src);else -expand_ref_prefix (&ref_prefixes, refspecs[i].src); +expand_ref_prefix (&ref_prefixes, item->src); } }
@@ -367,13 +368,12 @@ static struct ref *get_ref_map(struct transport *transport,argv_array_clear (&ref_prefixes); -if (refspec_count) { -struct refspec_item *fetch_refspec; -int fetch_refspec_nr; +if (rs->nr) { +struct refspec *fetch_refspec; -for (i =0 ; i < refspec_count; i++) { -get_fetch_map (remote_refs, &refspecs[i], &tail,0 ); -if (refspecs[i].dst && refspecs[i].dst[0 ]) +for (i =0 ; i < rs->nr; i++) { +get_fetch_map (remote_refs, &rs->items[i], &tail,0 ); +if (rs->items[i].dst && rs->items[i].dst[0 ]) *autotags =1 ; }/* Merge everything on the command line (but not --tags) */
@@ -400,16 +400,13 @@ static struct ref *get_ref_map(struct transport *transport,* by ref_remove_duplicates() in favor of one of these * opportunistic entries with FETCH_HEAD_IGNORE. */ -if (refmap.nr) { - fetch_refspec = refmap.items; - fetch_refspec_nr = refmap.nr; - }else { - fetch_refspec = transport->remote->fetch.items; - fetch_refspec_nr = transport->remote->fetch.nr; - } +if (refmap.nr) + fetch_refspec = &refmap; +else + fetch_refspec = &transport->remote->fetch; -for (i =0 ; i < fetch_refspec_nr; i++) -get_fetch_map (ref_map, &fetch_refspec[i], &oref_tail,1 ); +for (i =0 ; i < fetch_refspec->nr; i++) +get_fetch_map (ref_map, &fetch_refspec->items[i], &oref_tail,1 ); }else if (refmap.nr) {die ("--refmap option is only meaningful with command-line refspec(s)." ); }else {
@@ -1136,7 +1133,7 @@ static int do_fetch(struct transport *transport, goto cleanup; } - ref_map =get_ref_map (transport, rs->items, rs->nr, tags, &autotags); + ref_map =get_ref_map (transport, rs, tags, &autotags);if (!update_head_ok)check_not_current_branch (ref_map);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 22/36 fetch: convert prune_refs to take a struct refspec
In reply to Brandon WilliamsConvert 'prune_refs()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- builtin/fetch.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
builtin/fetch.c +5 -6
@@ -959,11 +959,11 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)return ret; } -static int prune_refs (struct refspec_item *refs,int ref_count,struct ref *ref_map, -const char *raw_url) +static int prune_refs (struct refspec *rs,struct ref *ref_map, +const char *raw_url) {int url_len, i, result =0 ; -struct ref *ref, *stale_refs =get_stale_heads (refs, ref_count, ref_map); +struct ref *ref, *stale_refs =get_stale_heads (rs->items, rs->nr, ref_map);char *url;int summary_width =transport_summary_width (stale_refs);const char *dangling_msg = dry_run
@@ -1158,10 +1158,9 @@ static int do_fetch(struct transport *transport,* don't care whether --tags was specified. */ if (rs->nr) { -prune_refs (rs->items, rs->nr, ref_map, transport->url); +prune_refs (rs, ref_map, transport->url); }else { -prune_refs (transport->remote->fetch.items, - transport->remote->fetch.nr, +prune_refs (&transport->remote->fetch, ref_map, transport->url); }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 23/36 remote: convert get_stale_heads to take a struct refspec
In reply to Brandon WilliamsConvert 'get_stale_heads()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- builtin/fetch.c | 2 +- builtin/remote.c | 3 +-- remote.c | 18 +++++++++--------- remote.h | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-)
builtin/fetch.c +1 -1
@@ -963,7 +963,7 @@ static int prune_refs(struct refspec *rs, struct ref *ref_map, const char *raw_url) {int url_len, i, result =0 ; -struct ref *ref, *stale_refs =get_stale_heads (rs->items, rs->nr, ref_map); +struct ref *ref, *stale_refs =get_stale_heads (rs, ref_map);char *url;int summary_width =transport_summary_width (stale_refs);const char *dangling_msg = dry_run
builtin/remote.c +1 -2
@@ -347,8 +347,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *statelse string_list_append (&states->tracked,abbrev_branch (ref->name)); } - stale_refs =get_stale_heads (states->remote->fetch.items, - states->remote->fetch.nr, fetch_map); + stale_refs =get_stale_heads (&states->remote->fetch, fetch_map);for (ref = stale_refs; ref; ref = ref->next) {struct string_list_item *item =string_list_append (&states->stale,abbrev_branch (ref->name));
remote.c +9 -9
@@ -698,7 +698,9 @@ static int match_name_with_pattern(const char *key, const char *name,return ret; } -static void query_refspecs_multiple (struct refspec_item *refs,int ref_count,struct refspec_item *query,struct string_list *results) +static void query_refspecs_multiple (struct refspec *rs, +struct refspec_item *query, +struct string_list *results) {int i;int find_src = !query->src;
@@ -706,8 +708,8 @@ static void query_refspecs_multiple(struct refspec_item *refs, int ref_count, stif (find_src && !query->dst)error ("query_refspecs_multiple: need either src or dst" ); -for (i =0 ; i < ref_count; i++) { -struct refspec_item *refspec = &refs[i]; +for (i =0 ; i < rs->nr; i++) { +struct refspec_item *refspec = &rs->items[i];const char *key = find_src ? refspec->dst : refspec->src;const char *value = find_src ? refspec->src : refspec->dst;const char *needle = find_src ? query->dst : query->src;
@@ -2068,8 +2070,7 @@ struct ref *guess_remote_head(const struct ref *head,struct stale_heads_info {struct string_list *ref_names;struct ref **stale_refs_tail; -struct refspec_item *refs; -int ref_count; +struct refspec *rs; }; static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
@@ -2082,7 +2083,7 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,memset (&query,0 ,sizeof (struct refspec_item )); query.dst = (char *)refname; -query_refspecs_multiple (info->refs, info->ref_count, &query, &matches); +query_refspecs_multiple (info->rs, &query, &matches);if (matches.nr ==0 ) goto clean_exit;/* No matches */
@@ -2110,7 +2111,7 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,return 0 ; } -struct ref *get_stale_heads (struct refspec_item *refs,int ref_count,struct ref *fetch_map) +struct ref *get_stale_heads (struct refspec *rs,struct ref *fetch_map) {struct ref *ref, *stale_refs =NULL ;struct string_list ref_names =STRING_LIST_INIT_NODUP ;
@@ -2118,8 +2119,7 @@ struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref info.ref_names = &ref_names; info.stale_refs_tail = &stale_refs; - info.refs = refs; - info.ref_count = ref_count; + info.rs = rs;for (ref = fetch_map; ref; ref = ref->next)string_list_append (&ref_names, ref->name);string_list_sort (&ref_names);
remote.h +1 -1
@@ -267,7 +267,7 @@ struct ref *guess_remote_head(const struct ref *head, int all);/* Return refs which no longer exist on remote */ -struct ref *get_stale_heads (struct refspec_item *refs,int ref_count,struct ref *fetch_map); +struct ref *get_stale_heads (struct refspec *rs,struct ref *fetch_map);/* * Compare-and-swap
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 24/36 remote: convert apply_refspecs to take a struct refspec
In reply to Brandon WilliamsConvert 'apply_refspecs()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- builtin/fast-export.c | 2 +- remote.c | 15 ++++++--------- remote.h | 3 +-- transport-helper.c | 6 +++--- 4 files changed, 11 insertions(+), 15 deletions(-)
builtin/fast-export.c +1 -1
@@ -831,7 +831,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)if (refspecs.nr) {char *private; - private =apply_refspecs (refspecs.items, refspecs.nr, full_name); + private =apply_refspecs (&refspecs, full_name);if (private) {free (full_name); full_name = private;
remote.c +6 -9
@@ -525,8 +525,7 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push,struct remote *remote =remote_get (remote_name);if (remote && remote->push.nr && - (dst =apply_refspecs (remote->push.items, - remote->push.nr, + (dst =apply_refspecs (&remote->push, branch->refname))) {if (explicit) *explicit =1 ;
@@ -757,15 +756,14 @@ int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_itemreturn -1 ; } -char *apply_refspecs (struct refspec_item *refspecs,int nr_refspec, -const char *name) +char *apply_refspecs (struct refspec *rs,const char *name) {struct refspec_item query;memset (&query,0 ,sizeof (struct refspec_item )); query.src = (char *)name; -if (query_refspecs (refspecs, nr_refspec, &query)) +if (query_refspecs (rs->items, rs->nr, &query))return NULL ;return query.dst;
@@ -1571,7 +1569,7 @@ static const char *tracking_for_push_dest(struct remote *remote, {char *ret; - ret =apply_refspecs (remote->fetch.items, remote->fetch.nr, refname); + ret =apply_refspecs (&remote->fetch, refname);if (!ret) return error_buf(err, _("push destination '%s' on remote '%s' has no local tracking branch"),
@@ -1593,8 +1591,7 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err)char *dst;const char *ret; - dst =apply_refspecs (remote->push.items, remote->push.nr, - branch->refname); + dst =apply_refspecs (&remote->push, branch->refname);if (!dst) return error_buf(err, _("push refspecs for '%s' do not include '%s'"),
@@ -2203,7 +2200,7 @@ static int remote_tracking(struct remote *remote, const char *refname, {char *dst; - dst =apply_refspecs (remote->fetch.items, remote->fetch.nr, refname); + dst =apply_refspecs (&remote->fetch, refname);if (!dst)return -1 ;/* no tracking ref for refname at remote */ if (read_ref (dst, oid))
remote.h +1 -2
@@ -159,8 +159,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);struct ref *ref_remove_duplicates (struct ref *ref_map);extern int query_refspecs (struct refspec_item *specs,int nr,struct refspec_item *query); -char *apply_refspecs (struct refspec_item *refspecs,int nr_refspec, -const char *name); +char *apply_refspecs (struct refspec *rs,const char *name);int check_push_refs (struct ref *src,int nr_refspec,const char **refspec); int match_push_refs(struct ref *src, struct ref **dst,
transport-helper.c +3 -3
@@ -523,7 +523,7 @@ static int fetch_with_import(struct transport *transport,continue ; name = posn->symref ? posn->symref : posn->name;if (data->rs.nr) - private =apply_refspecs (data->rs.items, data->rs.nr, name); + private =apply_refspecs (&data->rs, name);else private =xstrdup (name);if (private) {
@@ -805,7 +805,7 @@ static int push_update_refs_status(struct helper_data *data,continue ;/* propagate back the update to the remote namespace */ - private =apply_refspecs (data->rs.items, data->rs.nr, ref->name); + private =apply_refspecs (&data->rs, ref->name);if (!private)continue ; update_ref("update by helper", private, &ref->new_oid, NULL,
@@ -942,7 +942,7 @@ static int push_refs_with_export(struct transport *transport,char *private;struct object_id oid; - private =apply_refspecs (data->rs.items, data->rs.nr, ref->name); + private =apply_refspecs (&data->rs, ref->name);if (private && !get_oid (private, &oid)) {strbuf_addf (&buf,"^%s" , private); string_list_append_nodup(&revlist_args,
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 25/36 remote: convert query_refspecs to take a struct refspec
In reply to Brandon WilliamsConvert 'query_refspecs()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- builtin/push.c | 3 +-- remote.c | 10 +++++----- remote.h | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-)
builtin/push.c +1 -2
@@ -83,8 +83,7 @@ static const char *map_refspec(const char *ref,struct refspec_item query;memset (&query,0 ,sizeof (struct refspec_item )); query.src = matched->name; -if (!query_refspecs (remote->push.items, remote->push.nr, &query) && - query.dst) { +if (!query_refspecs (&remote->push, &query) && query.dst) {struct strbuf buf =STRBUF_INIT ; strbuf_addf(&buf, "%s%s:%s", query.force ? "+" : "",
remote.c +5 -5
@@ -725,7 +725,7 @@ static void query_refspecs_multiple(struct refspec *rs, } } -int query_refspecs (struct refspec_item *refs,int ref_count,struct refspec_item *query) +int query_refspecs (struct refspec *rs,struct refspec_item *query) {int i;int find_src = !query->src;
@@ -735,8 +735,8 @@ int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_itemif (find_src && !query->dst)return error ("query_refspecs: need either src or dst" ); -for (i =0 ; i < ref_count; i++) { -struct refspec_item *refspec = &refs[i]; +for (i =0 ; i < rs->nr; i++) { +struct refspec_item *refspec = &rs->items[i];const char *key = find_src ? refspec->dst : refspec->src;const char *value = find_src ? refspec->src : refspec->dst;
@@ -763,7 +763,7 @@ char *apply_refspecs(struct refspec *rs, const char *name)memset (&query,0 ,sizeof (struct refspec_item )); query.src = (char *)name; -if (query_refspecs (rs->items, rs->nr, &query)) +if (query_refspecs (rs, &query))return NULL ;return query.dst;
@@ -771,7 +771,7 @@ char *apply_refspecs(struct refspec *rs, const char *name)int remote_find_tracking (struct remote *remote,struct refspec_item *refspec) { -return query_refspecs (remote->fetch.items, remote->fetch.nr, refspec); +return query_refspecs (&remote->fetch, refspec); } static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
remote.h +1 -1
@@ -158,7 +158,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);*/ struct ref *ref_remove_duplicates (struct ref *ref_map); -extern int query_refspecs (struct refspec_item *specs,int nr,struct refspec_item *query); +int query_refspecs (struct refspec *rs,struct refspec_item *query);char *apply_refspecs (struct refspec *rs,const char *name);int check_push_refs (struct ref *src,int nr_refspec,const char **refspec);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 26/36 remote: convert get_ref_match to take a struct refspec
In reply to Brandon WilliamsConvert 'get_ref_match()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- remote.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-)
remote.c +14 -12
@@ -1082,27 +1082,29 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,return errs; } -static char *get_ref_match (const struct refspec_item *rs,int rs_nr,const struct ref *ref, -int send_mirror,int direction,const struct refspec_item **ret_pat) +static char *get_ref_match (const struct refspec *rs,const struct ref *ref, +int send_mirror,int direction, +const struct refspec_item **ret_pat) {const struct refspec_item *pat;char *name;int i;int matching_refs =-1 ; -for (i =0 ; i < rs_nr; i++) { -if (rs[i].matching && - (matching_refs ==-1 || rs[i].force)) { +for (i =0 ; i < rs->nr; i++) { +const struct refspec_item *item = &rs->items[i]; +if (item->matching && + (matching_refs ==-1 || item->force)) { matching_refs = i;continue ; } -if (rs[i].pattern) { -const char *dst_side = rs[i].dst ? rs[i].dst : rs[i].src; +if (item->pattern) { +const char *dst_side = item->dst ? item->dst : item->src;int match;if (direction ==FROM_SRC ) - match =match_name_with_pattern (rs[i].src, ref->name, dst_side, &name); + match =match_name_with_pattern (item->src, ref->name, dst_side, &name);else - match =match_name_with_pattern (dst_side, ref->name, rs[i].src, &name); + match =match_name_with_pattern (dst_side, ref->name, item->src, &name);if (match) { matching_refs = i;break ;
@@ -1112,7 +1114,7 @@ static char *get_ref_match(const struct refspec_item *rs, int rs_nr, const strucif (matching_refs ==-1 )return NULL ; - pat = rs + matching_refs; + pat = &rs->items[matching_refs];if (pat->matching) {/* * "matching refs"; traditionally we pushed everything
@@ -1309,7 +1311,7 @@ int match_push_refs(struct ref *src, struct ref **dst,const struct refspec_item *pat =NULL ;char *dst_name; - dst_name =get_ref_match (rs.items, rs.nr, ref, send_mirror,FROM_SRC , &pat); + dst_name =get_ref_match (&rs, ref, send_mirror,FROM_SRC , &pat);if (!dst_name)continue ;
@@ -1358,7 +1360,7 @@ int match_push_refs(struct ref *src, struct ref **dst,/* We're already sending something to this ref. */ continue ; - src_name =get_ref_match (rs.items, rs.nr, ref, send_mirror,FROM_DST ,NULL ); + src_name =get_ref_match (&rs, ref, send_mirror,FROM_DST ,NULL );if (src_name) {if (!src_ref_index.nr)prepare_ref_index (&src_ref_index, src);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 27/36 remote: convert match_explicit_refs to take a struct refspec
In reply to Brandon WilliamsConvert 'match_explicit_refs()' to take a 'struct refspec' as a parameter instead of a list of 'struct refspec_item'.
--- remote.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
remote.c +4 -5
@@ -1073,12 +1073,11 @@ static int match_explicit(struct ref *src, struct ref *dst, }static int match_explicit_refs (struct ref *src,struct ref *dst, -struct ref ***dst_tail,struct refspec_item *rs, -int rs_nr) +struct ref ***dst_tail,struct refspec *rs) {int i, errs; -for (i = errs =0 ; i < rs_nr; i++) - errs +=match_explicit (src, dst, dst_tail, &rs[i]); +for (i = errs =0 ; i < rs->nr; i++) + errs +=match_explicit (src, dst, dst_tail, &rs->items[i]);return errs; }
@@ -1302,7 +1301,7 @@ int match_push_refs(struct ref *src, struct ref **dst, refspec = default_refspec; }refspec_appendn (&rs, refspec, nr_refspec); - errs =match_explicit_refs (src, *dst, &dst_tail, rs.items, rs.nr); + errs =match_explicit_refs (src, *dst, &dst_tail, &rs);/* pick the remainder */ for (ref = src; ref; ref = ref->next) {
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 28/36 push: check for errors earlier
In reply to Brandon WilliamsMove the error checking for using the "--mirror", "--all", and "--tags" options earlier and explicitly check for the presence of the flags instead of checking for a side-effect of the flag.
--- builtin/push.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-)
builtin/push.c +14 -17
@@ -417,23 +417,6 @@ static int do_push(const char *repo, int flags,if (push_options->nr) flags |=TRANSPORT_PUSH_OPTIONS ; -if ((flags &TRANSPORT_PUSH_ALL ) && refspec) { -if (!strcmp (*refspec,"refs/tags/*" )) -return error (_ ("--all and --tags are incompatible" )); -return error (_ ("--all can't be combined with refspecs" )); - } - -if ((flags &TRANSPORT_PUSH_MIRROR ) && refspec) { -if (!strcmp (*refspec,"refs/tags/*" )) -return error (_ ("--mirror and --tags are incompatible" )); -return error (_ ("--mirror can't be combined with refspecs" )); - } - -if ((flags & (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) == - (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) { -return error (_ ("--all and --mirror are incompatible" )); - } -if (!refspec && !(flags &TRANSPORT_PUSH_ALL )) {if (remote->push.raw_nr) { refspec = remote->push.raw;
@@ -625,6 +608,20 @@ int cmd_push(int argc, const char **argv, const char *prefix)die (_ ("--delete is incompatible with --all, --mirror and --tags" ));if (deleterefs && argc <2 )die (_ ("--delete doesn't make sense without any refs" )); +if (flags &TRANSPORT_PUSH_ALL ) { +if (tags) +die (_ ("--all and --tags are incompatible" )); +if (argc >=2 ) +die (_ ("--all can't be combined with refspecs" )); + } +if (flags &TRANSPORT_PUSH_MIRROR ) { +if (tags) +die (_ ("--mirror and --tags are incompatible" )); +if (argc >=2 ) +die (_ ("--mirror can't be combined with refspecs" )); + } +if ((flags &TRANSPORT_PUSH_ALL ) && (flags &TRANSPORT_PUSH_MIRROR )) +die (_ ("--all and --mirror are incompatible" ));if (recurse_submodules ==RECURSE_SUBMODULES_CHECK ) flags |=TRANSPORT_RECURSE_SUBMODULES_CHECK ;
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 29/36 push: convert to use struct refspec
In reply to Brandon WilliamsConvert the refspecs in builtin/push.c to be stored in a 'struct refspec' instead of being stored in a list of 'struct refspec_item's.
--- builtin/push.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-)
builtin/push.c +15 -23
@@ -57,19 +57,10 @@ static enum transport_family family;static struct push_cas_option cas; -static const char **refspec; -static int refspec_nr; -static int refspec_alloc; +static struct refspec rs =REFSPEC_INIT_PUSH ;static struct string_list push_options_config =STRING_LIST_INIT_DUP ; -static void add_refspec (const char *ref) -{ - refspec_nr++; -ALLOC_GROW (refspec, refspec_nr, refspec_alloc); - refspec[refspec_nr-1 ] = ref; -} -static const char *map_refspec (const char *ref,struct remote *remote,struct ref *local_refs) {
@@ -138,7 +129,7 @@ static void set_refspecs(const char **refs, int nr, const char *repo) } ref =map_refspec (ref, remote, local_refs); } -add_refspec (ref); +refspec_append (&rs, ref); } }
@@ -226,7 +217,7 @@ static void setup_push_upstream(struct remote *remote, struct branch *branch, }strbuf_addf (&refspec,"%s:%s" , branch->refname, branch->merge[0 ]->src); -add_refspec (refspec.buf); +refspec_append (&rs, refspec.buf); }static void setup_push_current (struct remote *remote,struct branch *branch)
@@ -236,7 +227,7 @@ static void setup_push_current(struct remote *remote, struct branch *branch)if (!branch)die (_ (message_detached_head_die), remote->name);strbuf_addf (&refspec,"%s:%s" , branch->refname, branch->refname); -add_refspec (refspec.buf); +refspec_append (&rs, refspec.buf); }static int is_workflow_triangular (struct remote *remote)
@@ -253,7 +244,7 @@ static void setup_default_push_refspecs(struct remote *remote)switch (push_default) {default :case PUSH_DEFAULT_MATCHING : -add_refspec (":" ); +refspec_append (&rs,":" );break ;case PUSH_DEFAULT_UNSPECIFIED :
@@ -341,7 +332,8 @@ static void advise_ref_needs_force(void)advise (_ (message_advice_ref_needs_force)); } -static int push_with_options (struct transport *transport,int flags) +static int push_with_options (struct transport *transport,struct refspec *rs, +int flags) {int err;unsigned int reject_reasons;
@@ -363,7 +355,7 @@ static int push_with_options(struct transport *transport, int flags)if (verbosity >0 )fprintf (stderr,_ ("Pushing to %s\n" ), transport->url); - err =transport_push (transport, refspec_nr, refspec, flags, + err =transport_push (transport, rs->raw_nr, rs->raw, flags, &reject_reasons);if (err !=0 ) {fprintf (stderr,"%s" ,push_get_color (PUSH_COLOR_ERROR ));
@@ -397,6 +389,7 @@ static int do_push(const char *repo, int flags,struct remote *remote =pushremote_get (repo);const char **url;int url_nr; +struct refspec *push_refspec = &rs;if (!remote) {if (repo)
@@ -417,10 +410,9 @@ static int do_push(const char *repo, int flags,if (push_options->nr) flags |=TRANSPORT_PUSH_OPTIONS ; -if (!refspec && !(flags &TRANSPORT_PUSH_ALL )) { -if (remote->push.raw_nr) { - refspec = remote->push.raw; - refspec_nr = remote->push.raw_nr; +if (!push_refspec->nr && !(flags &TRANSPORT_PUSH_ALL )) { +if (remote->push.nr) { + push_refspec = &remote->push; }else if (!(flags &TRANSPORT_PUSH_MIRROR ))setup_default_push_refspecs (remote); }
@@ -432,7 +424,7 @@ static int do_push(const char *repo, int flags,transport_get (remote, url[i]);if (flags &TRANSPORT_PUSH_OPTIONS ) transport->push_options = push_options; -if (push_with_options (transport, flags)) +if (push_with_options (transport, push_refspec, flags)) errs++; } }else {
@@ -440,7 +432,7 @@ static int do_push(const char *repo, int flags,transport_get (remote,NULL );if (flags &TRANSPORT_PUSH_OPTIONS ) transport->push_options = push_options; -if (push_with_options (transport, flags)) +if (push_with_options (transport, push_refspec, flags)) errs++; }return !!errs;
@@ -631,7 +623,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) flags |=TRANSPORT_RECURSE_SUBMODULES_ONLY ;if (tags) -add_refspec ("refs/tags/*" ); +refspec_append (&rs,"refs/tags/*" );if (argc >0 ) { repo = argv[0 ];
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 30/36 transport: convert transport_push to take a struct refspec
In reply to Brandon WilliamsConvert 'transport_push()' to take a 'struct refspec' as a parameter instead of an array of strings which represent refspecs.
--- builtin/push.c | 3 +-- transport.c | 17 +++++++---------- transport.h | 2 +- 3 files changed, 9 insertions(+), 13 deletions(-)
builtin/push.c +1 -2
@@ -355,8 +355,7 @@ static int push_with_options(struct transport *transport, struct refspec *rs,if (verbosity >0 )fprintf (stderr,_ ("Pushing to %s\n" ), transport->url); - err =transport_push (transport, rs->raw_nr, rs->raw, flags, - &reject_reasons); + err =transport_push (transport, rs, flags, &reject_reasons);if (err !=0 ) {fprintf (stderr,"%s" ,push_get_color (PUSH_COLOR_ERROR ));error (_ ("failed to push some refs to '%s'" ), transport->url);
transport.c +7 -10
@@ -1093,11 +1093,11 @@ static int run_pre_push_hook(struct transport *transport, }int transport_push (struct transport *transport, -int refspec_nr,const char **refspec,int flags, +struct refspec *rs,int flags,unsigned int *reject_reasons) { *reject_reasons =0 ; -transport_verify_remote_names (refspec_nr, refspec); +transport_verify_remote_names (rs->raw_nr, rs->raw);if (transport_color_config () <0 )return -1 ;
@@ -1111,16 +1111,14 @@ int transport_push(struct transport *transport,int porcelain = flags &TRANSPORT_PUSH_PORCELAIN ;int pretend = flags &TRANSPORT_PUSH_DRY_RUN ;int push_ret, ret, err; -struct refspec tmp_rs =REFSPEC_INIT_PUSH ;struct argv_array ref_prefixes =ARGV_ARRAY_INIT ;int i; -if (check_push_refs (local_refs, refspec_nr, refspec) <0 ) +if (check_push_refs (local_refs, rs->raw_nr, rs->raw) <0 )return -1 ; -refspec_appendn (&tmp_rs, refspec, refspec_nr); -for (i =0 ; i < tmp_rs.nr; i++) { -const struct refspec_item *item = &tmp_rs.items[i]; +for (i =0 ; i < rs->nr; i++) { +const struct refspec_item *item = &rs->items[i];const char *prefix =NULL ;if (item->dst)
@@ -1143,7 +1141,6 @@ int transport_push(struct transport *transport, &ref_prefixes);argv_array_clear (&ref_prefixes); -refspec_clear (&tmp_rs);if (flags &TRANSPORT_PUSH_ALL ) match_flags |=MATCH_REFS_ALL ;
@@ -1155,7 +1152,7 @@ int transport_push(struct transport *transport, match_flags |=MATCH_REFS_FOLLOW_TAGS ;if (match_push_refs (local_refs, &remote_refs, - refspec_nr, refspec, match_flags)) { + rs->raw_nr, rs->raw, match_flags)) {return -1 ; }
@@ -1186,7 +1183,7 @@ int transport_push(struct transport *transport,if (!push_unpushed_submodules (&commits, transport->remote, - refspec, refspec_nr, + rs->raw, rs->raw_nr, transport->push_options, pretend)) {oid_array_clear (&commits);
transport.h +1 -1
@@ -197,7 +197,7 @@ void transport_set_verbosity(struct transport *transport, int verbosity,#define REJECT_NEEDS_FORCE 0x10int transport_push (struct transport *connection, -int refspec_nr,const char **refspec,int flags, +struct refspec *rs,int flags,unsigned int * reject_reasons);/*
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 31/36 send-pack: store refspecs in a struct refspec
In reply to Brandon WilliamsConvert send-pack.c to store refspecs in a 'struct refspec' instead of as an array of 'const char *'.
--- builtin/send-pack.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-)
builtin/send-pack.c +7 -17
@@ -126,8 +126,7 @@ static int send_pack_config(const char *k, const char *v, void *cb)int cmd_send_pack (int argc,const char **argv,const char *prefix) { -int i, nr_refspecs =0 ; -const char **refspecs =NULL ; +struct refspec rs =REFSPEC_INIT_PUSH ;const char *remote_name =NULL ;struct remote *remote =NULL ;const char *dest =NULL ;
@@ -189,8 +188,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) argc =parse_options (argc, argv, prefix, options, send_pack_usage,0 );if (argc >0 ) { dest = argv[0 ]; - refspecs = (const char **)(argv +1 ); - nr_refspecs = argc -1 ; +refspec_appendn (&rs, argv +1 , argc -1 ); }if (!dest)
@@ -209,31 +207,23 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) args.push_options = push_options.nr ? &push_options :NULL ;if (from_stdin) { -struct argv_array all_refspecs =ARGV_ARRAY_INIT ; - -for (i =0 ; i < nr_refspecs; i++) -argv_array_push (&all_refspecs, refspecs[i]); -if (args.stateless_rpc) {const char *buf;while ((buf =packet_read_line (0 ,NULL ))) -argv_array_push (&all_refspecs, buf); +refspec_append (&rs, buf); }else {struct strbuf line =STRBUF_INIT ;while (strbuf_getline (&line, stdin) !=EOF ) -argv_array_push (&all_refspecs, line.buf); +refspec_append (&rs, line.buf);strbuf_release (&line); } - - refspecs = all_refspecs.argv; - nr_refspecs = all_refspecs.argc; }/* * --all and --mirror are incompatible; neither makes sense * with any refspecs. */ -if ((nr_refspecs >0 && (send_all || args.send_mirror)) || +if ((rs.nr >0 && (send_all || args.send_mirror)) || (send_all && args.send_mirror))usage_with_options (send_pack_usage, options);
@@ -275,7 +265,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)BUG ("unknown protocol version" ); } -transport_verify_remote_names (nr_refspecs, refspecs); +transport_verify_remote_names (rs.raw_nr, rs.raw); local_refs =get_local_heads ();
@@ -287,7 +277,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) flags |=MATCH_REFS_MIRROR ;/* match them up */ -if (match_push_refs (local_refs, &remote_refs, nr_refspecs, refspecs, flags)) +if (match_push_refs (local_refs, &remote_refs, rs.raw_nr, rs.raw, flags))return -1 ;if (!is_empty_cas (&cas))
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 32/36 transport: remove transport_verify_remote_names
In reply to Brandon WilliamsRemove 'transprot_verify_remote_names()' because all callers have migrated to using 'struct refspec' which performs the same checks in 'parse_refspec()'.
--- builtin/send-pack.c | 2 -- transport.c | 24 ------------------------ transport.h | 2 -- 3 files changed, 28 deletions(-)
builtin/send-pack.c +0 -2
@@ -265,8 +265,6 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)BUG ("unknown protocol version" ); } -transport_verify_remote_names (rs.raw_nr, rs.raw); - local_refs =get_local_heads (); flags =MATCH_REFS_NONE ;
transport.c +0 -24
@@ -619,29 +619,6 @@ void transport_print_push_status(const char *dest, struct ref *refs,free (head); } -void transport_verify_remote_names (int nr_heads,const char **heads) -{ -int i; - -for (i =0 ; i < nr_heads; i++) { -const char *local = heads[i]; -const char *remote =strrchr (heads[i],':' ); - -if (*local =='+' ) - local++; - -/* A matching refspec is okay. */ -if (remote == local && remote[1 ] =='\0' ) -continue ; - - remote = remote ? (remote +1 ) : local; -if (check_refname_format (remote, -REFNAME_ALLOW_ONELEVEL |REFNAME_REFSPEC_PATTERN )) -die ("remote part of refspec is not a valid name in %s" , - heads[i]); - } -} -static int git_transport_push (struct transport *transport,struct ref *remote_refs,int flags) {struct git_transport_data *data = transport->data;
@@ -1097,7 +1074,6 @@ int transport_push(struct transport *transport, unsigned int *reject_reasons) { *reject_reasons =0 ; -transport_verify_remote_names (rs->raw_nr, rs->raw);if (transport_color_config () <0 )return -1 ;
transport.h +0 -2
@@ -227,8 +227,6 @@ int transport_helper_init(struct transport *transport, const char *name);int bidirectional_transfer_loop (int input,int output);/* common methods used by transport.c and builtin/send-pack.c */ -void transport_verify_remote_names (int nr_heads,const char **heads); -void transport_update_tracking_ref (struct remote *remote,struct ref *ref,int verbose);int transport_refs_pushed (struct ref *ref);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 33/36 http-push: store refspecs in a struct refspec
In reply to Brandon WilliamsConvert http-push.c to store refspecs in a 'struct refspec' instead of in an array of 'const char *'.
--- http-push.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
http-push.c +8 -9
@@ -1692,8 +1692,7 @@ int cmd_main(int argc, const char **argv) {struct transfer_request *request;struct transfer_request *next_request; -int nr_refspec =0 ; -const char **refspec =NULL ; +struct refspec rs =REFSPEC_INIT_PUSH ;struct remote_lock *ref_lock =NULL ;struct remote_lock *info_ref_lock =NULL ;struct rev_info revs;
@@ -1756,8 +1755,7 @@ int cmd_main(int argc, const char **argv) }continue ; } - refspec = argv; - nr_refspec = argc - i; +refspec_appendn (&rs, argv, argc - i);break ; }
@@ -1768,7 +1766,7 @@ int cmd_main(int argc, const char **argv)if (!repo->url)usage (http_push_usage); -if (delete_branch && nr_refspec !=1 ) +if (delete_branch && rs.nr !=1 )die ("You must specify only one branch name when deleting a remote branch" );setup_git_directory ();
@@ -1814,18 +1812,19 @@ int cmd_main(int argc, const char **argv)/* Remove a remote branch if -d or -D was specified */ if (delete_branch) { -if (delete_remote_branch (refspec[0 ], force_delete) ==-1 ) { +const char *branch = rs.items[i].src; +if (delete_remote_branch (branch, force_delete) ==-1 ) {fprintf (stderr,"Unable to delete remote branch %s\n" , - refspec[0 ]); + branch);if (helper_status) -printf ("error %s cannot remove\n" , refspec[0 ]); +printf ("error %s cannot remove\n" , branch); } goto cleanup; }/* match them up */ if (match_push_refs (local_refs, &remote_refs, - nr_refspec, (const char **) refspec, push_all)) { + rs.raw_nr, rs.raw, push_all)) { rc =-1 ; goto cleanup; }
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 34/36 remote: convert match_push_refs to take a struct refspec
In reply to Brandon WilliamsConvert 'match_push_refs()' to take a 'struct refspec' as a parameter instead of an array of 'const char *'.
--- builtin/remote.c | 3 +-- builtin/send-pack.c | 2 +- http-push.c | 3 +-- remote.c | 21 ++++++++------------- remote.h | 2 +- transport.c | 4 +--- 6 files changed, 13 insertions(+), 22 deletions(-)
builtin/remote.c +1 -2
@@ -387,8 +387,7 @@ static int get_push_ref_states(const struct ref *remote_refs, local_refs =get_local_heads (); push_map =copy_ref_list (remote_refs); -match_push_refs (local_refs, &push_map, remote->push.raw_nr, - remote->push.raw,MATCH_REFS_NONE ); +match_push_refs (local_refs, &push_map, &remote->push,MATCH_REFS_NONE ); states->push.strdup_strings =1 ;for (ref = push_map; ref; ref = ref->next) {
builtin/send-pack.c +1 -1
@@ -275,7 +275,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) flags |=MATCH_REFS_MIRROR ;/* match them up */ -if (match_push_refs (local_refs, &remote_refs, rs.raw_nr, rs.raw, flags)) +if (match_push_refs (local_refs, &remote_refs, &rs, flags))return -1 ;if (!is_empty_cas (&cas))
http-push.c +1 -2
@@ -1823,8 +1823,7 @@ int cmd_main(int argc, const char **argv) }/* match them up */ -if (match_push_refs (local_refs, &remote_refs, - rs.raw_nr, rs.raw, push_all)) { +if (match_push_refs (local_refs, &remote_refs, &rs, push_all)) { rc =-1 ; goto cleanup; }
remote.c +8 -13
@@ -1285,23 +1285,20 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)* dst (e.g. pushing to a new branch, done in match_explicit_refs). */ int match_push_refs (struct ref *src,struct ref **dst, -int nr_refspec,const char **refspec,int flags) +struct refspec *rs,int flags) { -struct refspec rs =REFSPEC_INIT_PUSH ;int send_all = flags &MATCH_REFS_ALL ;int send_mirror = flags &MATCH_REFS_MIRROR ;int send_prune = flags &MATCH_REFS_PRUNE ;int errs; -static const char *default_refspec[] = {":" ,NULL };struct ref *ref, **dst_tail =tail_ref (dst);struct string_list dst_ref_index =STRING_LIST_INIT_NODUP ; -if (!nr_refspec) { - nr_refspec =1 ; - refspec = default_refspec; - } -refspec_appendn (&rs, refspec, nr_refspec); - errs =match_explicit_refs (src, *dst, &dst_tail, &rs); +/* If no refspec is provided, use the default ":" */ +if (!rs->nr) +refspec_append (rs,":" ); + + errs =match_explicit_refs (src, *dst, &dst_tail, rs);/* pick the remainder */ for (ref = src; ref; ref = ref->next) {
@@ -1310,7 +1307,7 @@ int match_push_refs(struct ref *src, struct ref **dst,const struct refspec_item *pat =NULL ;char *dst_name; - dst_name =get_ref_match (&rs, ref, send_mirror,FROM_SRC , &pat); + dst_name =get_ref_match (rs, ref, send_mirror,FROM_SRC , &pat);if (!dst_name)continue ;
@@ -1359,7 +1356,7 @@ int match_push_refs(struct ref *src, struct ref **dst,/* We're already sending something to this ref. */ continue ; - src_name =get_ref_match (&rs, ref, send_mirror,FROM_DST ,NULL ); + src_name =get_ref_match (rs, ref, send_mirror,FROM_DST ,NULL );if (src_name) {if (!src_ref_index.nr)prepare_ref_index (&src_ref_index, src);
@@ -1372,8 +1369,6 @@ int match_push_refs(struct ref *src, struct ref **dst,string_list_clear (&src_ref_index,0 ); } -refspec_clear (&rs); -if (errs)return -1 ;return 0 ;
remote.h +1 -1
@@ -163,7 +163,7 @@ char *apply_refspecs(struct refspec *rs, const char *name);int check_push_refs (struct ref *src,int nr_refspec,const char **refspec);int match_push_refs (struct ref *src,struct ref **dst, -int nr_refspec,const char **refspec,int all); +struct refspec *rs,int flags);void set_ref_status_for_push (struct ref *remote_refs,int send_mirror,int force_update);
transport.c +1 -3
@@ -1127,10 +1127,8 @@ int transport_push(struct transport *transport,if (flags &TRANSPORT_PUSH_FOLLOW_TAGS ) match_flags |=MATCH_REFS_FOLLOW_TAGS ; -if (match_push_refs (local_refs, &remote_refs, - rs->raw_nr, rs->raw, match_flags)) { +if (match_push_refs (local_refs, &remote_refs, rs, match_flags))return -1 ; - } if (transport->smart_options && transport->smart_options->cas &&
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 35/36 remote: convert check_push_refs to take a struct refspec
In reply to Brandon WilliamsConvert 'check_push_refs()' to take a 'struct refspec' as a parameter instead of an array of 'const char *'.
--- remote.c | 14 +++++--------- remote.h | 2 +- transport.c | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-)
remote.c +5 -9
@@ -1255,24 +1255,20 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)* but we can catch some errors early before even talking to the * remote side. */ -int check_push_refs (struct ref *src,int nr_refspec,const char **refspec_names) +int check_push_refs (struct ref *src,struct refspec *rs) { -struct refspec refspec =REFSPEC_INIT_PUSH ;int ret =0 ;int i; -refspec_appendn (&refspec, refspec_names, nr_refspec); - -for (i =0 ; i < refspec.nr; i++) { -struct refspec_item *rs = &refspec.items[i]; +for (i =0 ; i < rs->nr; i++) { +struct refspec_item *item = &rs->items[i]; -if (rs->pattern || rs->matching) +if (item->pattern || item->matching)continue ; - ret |=match_explicit_lhs (src, rs,NULL ,NULL ); + ret |=match_explicit_lhs (src, item,NULL ,NULL ); } -refspec_clear (&refspec);return ret; }
remote.h +1 -1
@@ -161,7 +161,7 @@ struct ref *ref_remove_duplicates(struct ref *ref_map);int query_refspecs (struct refspec *rs,struct refspec_item *query);char *apply_refspecs (struct refspec *rs,const char *name); -int check_push_refs (struct ref *src,int nr_refspec,const char **refspec); +int check_push_refs (struct ref *src,struct refspec *rs);int match_push_refs (struct ref *src,struct ref **dst,struct refspec *rs,int flags); void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
transport.c +1 -1
@@ -1090,7 +1090,7 @@ int transport_push(struct transport *transport,struct argv_array ref_prefixes =ARGV_ARRAY_INIT ;int i; -if (check_push_refs (local_refs, rs->raw_nr, rs->raw) <0 ) +if (check_push_refs (local_refs, rs) <0 )return -1 ;for (i =0 ; i < rs->nr; i++) {
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH v2 36/36 submodule: convert push_unpushed_submodules to take a struct refspec
In reply to Brandon WilliamsConvert 'push_unpushed_submodules()' to take a 'struct refspec' as a parameter instead of an array of 'const char *'.
--- submodule.c | 19 +++++++++---------- submodule.h | 3 ++- transport.c | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-)
submodule.c +9 -10
@@ -968,7 +968,7 @@ int find_unpushed_submodules(struct oid_array *commits,static int push_submodule (const char *path,const struct remote *remote, -const char **refspec,int refspec_nr, +const struct refspec *rs,const struct string_list *push_options,int dry_run) {
@@ -991,8 +991,8 @@ static int push_submodule(const char *path,if (remote->origin !=REMOTE_UNCONFIGURED ) {int i;argv_array_push (&cp.args, remote->name); -for (i =0 ; i < refspec_nr; i++) -argv_array_push (&cp.args, refspec[i]); +for (i =0 ; i < rs->raw_nr; i++) +argv_array_push (&cp.args, rs->raw[i]); }prepare_submodule_repo_env (&cp.env_array);
@@ -1013,7 +1013,7 @@ static int push_submodule(const char *path,*/ static void submodule_push_check (const char *path,const char *head,const struct remote *remote, -const char **refspec,int refspec_nr) +const struct refspec *rs) {struct child_process cp =CHILD_PROCESS_INIT ;int i;
@@ -1023,8 +1023,8 @@ static void submodule_push_check(const char *path, const char *head,argv_array_push (&cp.args, head);argv_array_push (&cp.args, remote->name); -for (i =0 ; i < refspec_nr; i++) -argv_array_push (&cp.args, refspec[i]); +for (i =0 ; i < rs->raw_nr; i++) +argv_array_push (&cp.args, rs->raw[i]);prepare_submodule_repo_env (&cp.env_array); cp.git_cmd =1 ;
@@ -1043,7 +1043,7 @@ static void submodule_push_check(const char *path, const char *head,int push_unpushed_submodules (struct oid_array *commits,const struct remote *remote, -const char **refspec,int refspec_nr, +const struct refspec *rs,const struct string_list *push_options,int dry_run) {
@@ -1069,8 +1069,7 @@ int push_unpushed_submodules(struct oid_array *commits,for (i =0 ; i < needs_pushing.nr; i++)submodule_push_check (needs_pushing.items[i].string, - head, remote, - refspec, refspec_nr); + head, remote, rs);free (head); }
@@ -1078,7 +1077,7 @@ int push_unpushed_submodules(struct oid_array *commits,for (i =0 ; i < needs_pushing.nr; i++) {const char *path = needs_pushing.items[i].string;fprintf (stderr,"Pushing submodule '%s'\n" , path); -if (!push_submodule (path, remote, refspec, refspec_nr, +if (!push_submodule (path, remote, rs, push_options, dry_run)) {fprintf (stderr,"Unable to push submodule '%s'\n" , path); ret =0 ;
submodule.h +2 -1
@@ -100,9 +100,10 @@ extern int submodule_touches_in_range(struct object_id *a,extern int find_unpushed_submodules (struct oid_array *commits,const char *remotes_name,struct string_list *needs_pushing); +struct refspec ;extern int push_unpushed_submodules (struct oid_array *commits,const struct remote *remote, -const char **refspec,int refspec_nr, +const struct refspec *rs,const struct string_list *push_options,int dry_run);/*
transport.c +1 -1
@@ -1157,7 +1157,7 @@ int transport_push(struct transport *transport,if (!push_unpushed_submodules (&commits, transport->remote, - rs->raw, rs->raw_nr, + rs, transport->push_options, pretend)) {oid_array_clear (&commits);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
cover generating ref-prefixes for configured refspecs
In reply to Brandon WilliamsHere's my short follow on series to the refspec refactoring.
When v2 was introduced ref-prefixes were only generated for user provided refspecs (given via the command line). This means that you can only benefit from server-side ref filtering if you explicitly provide a refspec, so this short series extends this to generate the ref-prefixes even for the refspecs which are configured in 'remote.<name>.fetch'.
This series is based on the v2 of the refspec refactoring series.
Brandon Williams (2):
refspec: consolidate ref-prefix generation logic
fetch: generate ref-prefixes when using a configured refspec
builtin/fetch.c | 19 ++++++++----------- refspec.c | 29 +++++++++++++++++++++++++++++ refspec.h | 4 ++++ t/t5702-protocol-v2.sh | 14 ++++++++++++++ transport.c | 21 +-------------------- 5 files changed, 56 insertions(+), 31 deletions(-)
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
PATCH 1/2 refspec: consolidate ref-prefix generation logic
When using protocol v2 a client constructs a list of ref-prefixes which are sent across the wire so that the server can do server-side filtering of the ref-advertisement. The logic that does this exists for both fetch and push (even though no push support for v2 currently exists yet) and is roughly the same so lets consolidate this logic and make it general enough that it can be used for both the push and fetch cases.
--- builtin/fetch.c | 13 +------------ refspec.c | 29 +++++++++++++++++++++++++++++ refspec.h | 4 ++++ transport.c | 21 +-------------------- 4 files changed, 35 insertions(+), 32 deletions(-)
builtin/fetch.c +1 -12
@@ -351,18 +351,7 @@ static struct ref *get_ref_map(struct transport *transport,const struct ref *remote_refs; -for (i =0 ; i < rs->nr; i++) { -const struct refspec_item *item = &rs->items[i]; -if (!item->exact_sha1) { -const char *glob =strchr (item->src,'*' ); -if (glob) -argv_array_pushf (&ref_prefixes,"%.*s" , - (int )(glob - item->src), - item->src); -else -expand_ref_prefix (&ref_prefixes, item->src); - } - } +refspec_ref_prefixes (rs, &ref_prefixes); remote_refs =transport_get_remote_refs (transport, &ref_prefixes);
refspec.c +29 -0
@@ -1,4 +1,5 @@#include "cache.h" +#include "argv-array.h" #include "refs.h" #include "refspec.h"
@@ -192,3 +193,31 @@ int valid_fetch_refspec(const char *fetch_refspec_str)refspec_item_clear (&refspec);return ret; } + +void refspec_ref_prefixes (const struct refspec *rs, +struct argv_array *ref_prefixes) +{ +int i; +for (i =0 ; i < rs->nr; i++) { +const struct refspec_item *item = &rs->items[i]; +const char *prefix =NULL ; + +if (rs->fetch ==REFSPEC_FETCH ) + prefix = item->src; +else if (item->dst) + prefix = item->dst; +else if (item->src && !item->exact_sha1) + prefix = item->src; + +if (prefix) { +if (item->pattern) { +const char *glob =strchr (prefix,'*' ); +argv_array_pushf (ref_prefixes,"%.*s" , + (int )(glob - prefix), + prefix); + }else { +expand_ref_prefix (ref_prefixes, prefix); + } + } + } +}
refspec.h +4 -0
@@ -41,4 +41,8 @@ void refspec_clear(struct refspec *rs);int valid_fetch_refspec (const char *refspec); +struct argv_array ; +void refspec_ref_prefixes (const struct refspec *rs, +struct argv_array *ref_prefixes); +#endif /* REFSPEC_H */
transport.c +1 -20
@@ -1088,30 +1088,11 @@ int transport_push(struct transport *transport,int pretend = flags &TRANSPORT_PUSH_DRY_RUN ;int push_ret, ret, err;struct argv_array ref_prefixes =ARGV_ARRAY_INIT ; -int i;if (check_push_refs (local_refs, rs) <0 )return -1 ; -for (i =0 ; i < rs->nr; i++) { -const struct refspec_item *item = &rs->items[i]; -const char *prefix =NULL ; - -if (item->dst) - prefix = item->dst; -else if (item->src && !item->exact_sha1) - prefix = item->src; - -if (prefix) { -const char *glob =strchr (prefix,'*' ); -if (glob) -argv_array_pushf (&ref_prefixes,"%.*s" , - (int )(glob - prefix), - prefix); -else -expand_ref_prefix (&ref_prefixes, prefix); - } - } +refspec_ref_prefixes (rs, &ref_prefixes); remote_refs = transport->vtable->get_refs_list (transport,1 , &ref_prefixes);
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Re: [PATCH 1/2] refspec: consolidate ref-prefix generation logic
Hi,
Quoted 7 lines · Brandon Williams
When using protocol v2 a client constructs a list of ref-prefixes which are sent across the wire so that the server can do server-side filtering of the ref-advertisement. The logic that does this exists for both fetch and push (even though no push support for v2 currently exists yet) and is roughly the same so lets consolidate this logic and make it general enough that it can be used for both the push and fetch cases.
Quoted 7 lines
Signed-off-by Brandon Williams <[email protected]>--- builtin/fetch.c | 13 +------------ refspec.c | 29 +++++++++++++++++++++++++++++ refspec.h | 4 ++++ transport.c | 21 +-------------------- 4 files changed, 35 insertions(+), 32 deletions(-)
I assume this is meant to be a refactoring with no functional change. Alas, it's causing fetch-by-SHA-1 to fail for me:
$ rm -fr /tmp/r $ git init /tmp/r Initialized empty Git repository in /tmp/r/.git/ $ bin-wrappers/git -C /tmp/r -c protocol.version=2 fetch \ https://kernel.googlesource.com/pub/scm/git/git \ 6373cb598e1a4e0340583ad75d5abba01ff79774 fatal: no matching remote head
The parent commit succeeds.
Known issue?
Thanks,
Jonathan
Re: [PATCH 1/2] refspec: consolidate ref-prefix generation logic
Quoted 19 lines · Jonathan Nieder
Quoted 7 lines · Brandon Williams
When using protocol v2 a client constructs a list of ref-prefixes which are sent across the wire so that the server can do server-side filtering of the ref-advertisement. The logic that does this exists for both fetch and push (even though no push support for v2 currently exists yet) and is roughly the same so lets consolidate this logic and make it general enough that it can be used for both the push and fetch cases.
Quoted 7 lines
Signed-off-by Brandon Williams <[email protected]>--- builtin/fetch.c | 13 +------------ refspec.c | 29 +++++++++++++++++++++++++++++ refspec.h | 4 ++++ transport.c | 21 +-------------------- 4 files changed, 35 insertions(+), 32 deletions(-)I assume this is meant to be a refactoring with no functional change. Alas, it's causing fetch-by-SHA-1 to fail for me:
[...]
Quoted 4 lines
$ bin-wrappers/git -C /tmp/r -c protocol.version=2 fetch \ https://kernel.googlesource.com/pub/scm/git/git \ 6373cb598e1a4e0340583ad75d5abba01ff79774 fatal: no matching remote head
Backtrace:
#0 0x0000555555671e09 in fetch_pack (args=0x7fffffffda80, fd=0x555555a6a9b0, conn=0x555555a65780, ref=0x0,
dest=0x555555a64900 "https://kernel.googlesource.com/pub/scm/git/git", sought=0x555555a69a80, nr_sought=1, shallow=0x555555a6a9d8, pack_lockfile=0x555555a631c8, version=protocol_v2) at fetch-pack.c:1562 #1 0x00005555557290b9 in fetch_refs_via_pack (transport=0x555555a63190, nr_heads=1, to_fetch=0x555555a69a80) at transport.c:326 #2 0x000055555572b712 in transport_fetch_refs (transport=0x555555a63190, refs=0x555555a65520) at transport.c:1247 #3 0x000055555559a2a6 in fetch_refs (transport=0x555555a63190, ref_map=0x555555a65520) at builtin/fetch.c:942 #4 0x000055555559ac3e in do_fetch (transport=0x555555a63190, rs=0x7fffffffdc30) at builtin/fetch.c:1157 #5 0x000055555559b535 in fetch_one (remote=0x555555a63870, argc=1, argv=0x7fffffffdff8, prune_tags_ok=0) at builtin/fetch.c:1398 #6 0x000055555559b9a3 in cmd_fetch (argc=1, argv=0x7fffffffdff8, prefix=0x0) at builtin/fetch.c:1487 #7 0x000055555556764b in run_builtin (p=0x555555a0fa30 <commands+816>, argc=3, argv=0x7fffffffdff0) at git.c:350 #8 0x000055555556795f in handle_builtin (argc=3, argv=0x7fffffffdff0) at git.c:565 #9 0x0000555555567b07 in run_argv (argcp=0x7fffffffde8c, argv=0x7fffffffde80) at git.c:617
#10 0x0000555555567cbc in cmd_main (argc=3, argv=0x7fffffffdff0) at git.c:694 #11 0x000055555560774c in main (argc=8, argv=0x7fffffffdfc8) at common-main.c:45
Both refs_tmp and transport->remote_refs are NULL.
When refspec_ref_prefixes gets called, it produces the usual argv_array with 6373cb598e1a4e0340583ad75d5abba01ff79774, refs/6373cb598e1a4e0340583ad75d5abba01ff79774, etc.
In the old code, this doesn't happen because we trigger the item->exact_sha1 test.
Would something like the following make sense? It passes tests and appears to avoid trouble but I haven't looked any closer than that.
refspec.c +2 -0
@@ -202,6 +202,8 @@ void refspec_ref_prefixes(const struct refspec *rs,const struct refspec_item *item = &rs->items[i];const char *prefix =NULL ; +if (item->exact_sha1) +continue ;if (rs->fetch ==REFSPEC_FETCH ) prefix = item->src;else if (item->dst)
PATCH 1/1 fetch: do not pass ref-prefixes for fetch by exact SHA1
In reply to Brandon WilliamsWhen v2.18.0-rc0~10^2~1 (refspec: consolidate ref-prefix generation logic, 2018-05-16) factored out the ref-prefix generation code for reuse, it left out the 'if (!item->exact_sha1)' test in the original ref-prefix generation code. As a result, fetches by SHA-1 generate ref-prefixes as though the SHA-1 being fetched were an abbreviated ref name:
$ GIT_TRACE_PACKET=1 bin-wrappers/git -c protocol.version=2 \ fetch origin 12039e008f9a4e3394f3f94f8ea897785cb09448 [...] packet: fetch> ref-prefix 12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/tags/12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/heads/12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448/HEAD packet: fetch> 0000
If there is another ref name on the command line or the object being fetched is already available locally, then that's mostly harmless. But otherwise, we error out with
fatal: no matching remote head
since the server did not send any refs we are interested in. Filter out the exact_sha1 refspecs to avoid this.
This patch adds a test to check this behavior that notices another behavior difference between protocol v0 and v2 in the process. Add a NEEDSWORK comment to clear it up.
---
Here's the change described in
https://public-inbox.org/git/[email protected]/
as a proper patch.
Thoughts of all kinds welcome, as always.
refspec.c | 2 ++ refspec.h | 4 ++++ t/t5516-fetch-push.sh | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+)
refspec.c +2 -0
@@ -202,6 +202,8 @@ void refspec_ref_prefixes(const struct refspec *rs,const struct refspec_item *item = &rs->items[i];const char *prefix =NULL ; +if (item->exact_sha1) +continue ;if (rs->fetch ==REFSPEC_FETCH ) prefix = item->src;else if (item->dst)
refspec.h +4 -0
@@ -42,6 +42,10 @@ void refspec_clear(struct refspec *rs);int valid_fetch_refspec (const char *refspec);struct argv_array ; +/* +* Determine what <prefix> values to pass to the peer in ref-prefix lines +* (see Documentation/technical/protocol-v2.txt). +*/ void refspec_ref_prefixes (const struct refspec *rs,struct argv_array *ref_prefixes);
t/t5516-fetch-push.sh +19 -0
@@ -1121,6 +1121,25 @@ test_expect_success 'fetch exact SHA1' ' ) ' +test_expect_success 'fetch exact SHA1 in protocol v2' ' + mk_test testrepo heads/master hidden/one && + git push testrepo master:refs/hidden/one && + git -C testrepo config transfer.hiderefs refs/hidden && + check_push_result testrepo $the_commit hidden/one && + + mk_child testrepo child && + git -C child config protocol.version 2 && + + # make sure $the_commit does not exist here + git -C child repack -a -d && + git -C child prune && + test_must_fail git -C child cat-file -t $the_commit && + + # fetching the hidden object succeeds by default + # NEEDSWORK: should this match the v0 behavior instead? + git -C child fetch -v ../testrepo $the_commit:refs/heads/copy +' + for configallowtipsha1inwant in true false do test_expect_success "shallow fetch reachable SHA1 (but not a ref), allowtipsha1inwant=$configallowtipsha1inwant" '
Signature · 1 line
2.17.1.1185.g55be947832
Re: [PATCH] fetch: do not pass ref-prefixes for fetch by exact SHA1
Thanks for finding this, I don't know how I missed moving that bit over when factoring it out. Well I guess I sort of rewrote it and combined two pieces of logic so that's how. Anyway, this looks right and thanks for adding the test.
Quoted 105 lines · Jonathan Nieder
When v2.18.0-rc0~10^2~1 (refspec: consolidate ref-prefix generation logic, 2018-05-16) factored out the ref-prefix generation code for reuse, it left out the 'if (!item->exact_sha1)' test in the original ref-prefix generation code. As a result, fetches by SHA-1 generate ref-prefixes as though the SHA-1 being fetched were an abbreviated ref name:
$ GIT_TRACE_PACKET=1 bin-wrappers/git -c protocol.version=2 \ fetch origin 12039e008f9a4e3394f3f94f8ea897785cb09448 [...] packet: fetch> ref-prefix 12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/tags/12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/heads/12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448/HEAD packet: fetch> 0000If there is another ref name on the command line or the object being fetched is already available locally, then that's mostly harmless. But otherwise, we error out with
fatal: no matching remote head
since the server did not send any refs we are interested in. Filter out the
exact_sha1refspecs to avoid this.This patch adds a test to check this behavior that notices another behavior difference between protocol v0 and v2 in the process. Add a NEEDSWORK comment to clear it up.
Signed-off-by Jonathan Nieder <[email protected]>---
Here's the change described in
https://public-inbox.org/git/[email protected]/
as a proper patch.Thoughts of all kinds welcome, as always.
refspec.c | 2 ++ refspec.h | 4 ++++ t/t5516-fetch-push.sh | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+)refspec.c +2
-0@@ -202,6 +202,8 @@ void refspec_ref_prefixes(const struct refspec *rs,const struct refspec_item *item = &rs->items[i];const char *prefix =NULL ; +if (item->exact_sha1) +continue ;if (rs->fetch ==REFSPEC_FETCH ) prefix = item->src;else if (item->dst)refspec.h +4
-0@@ -42,6 +42,10 @@ void refspec_clear(struct refspec *rs);int valid_fetch_refspec (const char *refspec);struct argv_array ; +/* +* Determine what <prefix> values to pass to the peer in ref-prefix lines +* (see Documentation/technical/protocol-v2.txt). +*/ void refspec_ref_prefixes (const struct refspec *rs,struct argv_array *ref_prefixes);t/t5516-fetch-push.sh +19
-1@@ -1121,6 +1121,25 @@ test_expect_success 'fetch exact SHA1' ' ) ' +test_expect_success 'fetch exact SHA1 in protocol v2' ' + mk_test testrepo heads/master hidden/one && + git push testrepo master:refs/hidden/one && + git -C testrepo config transfer.hiderefs refs/hidden && + check_push_result testrepo $the_commit hidden/one && + + mk_child testrepo child && + git -C child config protocol.version 2 && + + # make sure $the_commit does not exist here + git -C child repack -a -d && + git -C child prune && + test_must_fail git -C child cat-file -t $the_commit && + + # fetching the hidden object succeeds by default + # NEEDSWORK: should this match the v0 behavior instead? + git -C child fetch -v ../testrepo $the_commit:refs/heads/copy +' + for configallowtipsha1inwant in true false do test_expect_success "shallow fetch reachable SHA1 (but not a ref), allowtipsha1inwant=$configallowtipsha1inwant" ' --2.17.1.1185.g55be947832
Re: [PATCH] fetch: do not pass ref-prefixes for fetch by exact SHA1
In reply to Jonathan NiederQuoted 22 lines · Jonathan Nieder
When v2.18.0-rc0~10^2~1 (refspec: consolidate ref-prefix generation logic, 2018-05-16) factored out the ref-prefix generation code for reuse, it left out the 'if (!item->exact_sha1)' test in the original ref-prefix generation code. As a result, fetches by SHA-1 generate ref-prefixes as though the SHA-1 being fetched were an abbreviated ref name:
$ GIT_TRACE_PACKET=1 bin-wrappers/git -c protocol.version=2 \ fetch origin 12039e008f9a4e3394f3f94f8ea897785cb09448 [...] packet: fetch> ref-prefix 12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/tags/12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/heads/12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448 packet: fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448/HEAD packet: fetch> 0000If there is another ref name on the command line or the object being fetched is already available locally, then that's mostly harmless. But otherwise, we error out with
Quoted 8 lines
fatal: no matching remote head
since the server did not send any refs we are interested in. Filter out the
exact_sha1refspecs to avoid this.This patch adds a test to check this behavior that notices another behavior difference between protocol v0 and v2 in the process. Add a NEEDSWORK comment to clear it up.
Thanks.
I wonder if there is a more effective way to smoke out other bugs remaining in proto v2. When the fetch-by-SHA1 feature was added originally, we certainly would have added a test or two to make sure it won't break. The root cause of this breakage is that we lack the ability to easily exercise proto v2 on these existing tests that were written back in the proto v0 days. It there were such a way (like, a common set of tests that are run with all supported protos), we would have caught the breakge even before the topic hit 'next'.
Re: [PATCH] fetch: do not pass ref-prefixes for fetch by exact SHA1
Quoted 8 lines · Junio C Hamano
Quoted 3 lines · Jonathan Nieder
This patch adds a test to check this behavior that notices another behavior difference between protocol v0 and v2 in the process. Add a NEEDSWORK comment to clear it up.
Thanks.
Quoted 9 lines
I wonder if there is a more effective way to smoke out other bugs remaining in proto v2. When the fetch-by-SHA1 feature was added originally, we certainly would have added a test or two to make sure it won't break. The root cause of this breakage is that we lack the ability to easily exercise proto v2 on these existing tests that were written back in the proto v0 days. It there were such a way (like, a common set of tests that are run with all supported protos), we would have caught the breakge even before the topic hit 'next'.
I had a similar thought.
I am not sure I agree about the root cause, but root causes are generally slippery to define. Because this bug had significant internal impact, we came up with a few next steps:
- shore up protocol v2 test coverage, as you described
- arrange for long refactoring series we submit to be divided up for the team to review, to avoid reviewer fatigue. Hopefully this will make us a better example for other submitters of long series. We're open to cooperating with others --- maybe we can set up a volunteer reviewer brigade to get a more diverse set of eyes on each series --- though organizing that is harder.
- improve telemetry for our internal deployment, to get earlier notice when Git is producing more errors. I suspect other installations may want something like this too --- e.g. I think this is one of the benefits of what Jeff Hostetler is starting to build with json-writer.
- help internal users triage errors from Git (like those decision trees parents have to help decide when to bring a child to the doctor), so that we get earlier notice and can roll back and report upstream more quickly when they've run into a Git bug
Or in other words, please expect more in this area soon, and feel free to pester me if the test coverage doesn't arrive. :)
Thanks,
Jonathan
PATCH 2/2 fetch: generate ref-prefixes when using a configured refspec
In reply to Brandon WilliamsTeach fetch to generate ref-prefixes, to be used for server-side filtering of the ref-advertisement, based on the configured fetch refspec ('remote.<name>.fetch') when no user provided refspec exists.
--- builtin/fetch.c | 10 +++++++++- t/t5702-protocol-v2.sh | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-)
builtin/fetch.c +9 -1
@@ -351,7 +351,15 @@ static struct ref *get_ref_map(struct transport *transport,const struct ref *remote_refs; -refspec_ref_prefixes (rs, &ref_prefixes); +if (rs->nr) +refspec_ref_prefixes (rs, &ref_prefixes); +else if (transport->remote && transport->remote->fetch.nr) +refspec_ref_prefixes (&transport->remote->fetch, &ref_prefixes); + +if (ref_prefixes.argc && + (tags ==TAGS_SET || (tags ==TAGS_DEFAULT && !rs->nr))) { +argv_array_push (&ref_prefixes,"refs/tags/" ); + } remote_refs =transport_get_remote_refs (transport, &ref_prefixes);
t/t5702-protocol-v2.sh +14 -0
@@ -201,6 +201,20 @@ test_expect_success 'ref advertisment is filtered during fetch using protocol v2 ! grep "refs/tags/three" log ' +test_expect_success 'default refspec is used to filter ref when fetchcing' ' + test_when_finished "rm -f log" && + + GIT_TRACE_PACKET="$(pwd)/log" git -C file_child -c protocol.version=2 \ + fetch origin && + + git -C file_child log -1 --format=%s three >actual && + git -C file_parent log -1 --format=%s three >expect && + test_cmp expect actual && + + grep "ref-prefix refs/heads/" log && + grep "ref-prefix refs/tags/" log +' + # Test protocol v2 with 'http://' transport # . "$TEST_DIRECTORY"/lib-httpd.sh
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
Re: [PATCH 0/2] generating ref-prefixes for configured refspecs
In reply to Brandon WilliamsQuoted 9 lines · Brandon Williams
Here's my short follow on series to the refspec refactoring.
When v2 was introduced ref-prefixes were only generated for user provided refspecs (given via the command line). This means that you can only benefit from server-side ref filtering if you explicitly provide a refspec, so this short series extends this to generate the ref-prefixes even for the refspecs which are configured in 'remote.<name>.fetch'.
This series is based on the v2 of the refspec refactoring series.
Makes sense.
Quoted 11 lines
Brandon Williams (2):
refspec: consolidate ref-prefix generation logic
fetch: generate ref-prefixes when using a configured refspecbuiltin/fetch.c | 19 ++++++++----------- refspec.c | 29 +++++++++++++++++++++++++++++ refspec.h | 4 ++++ t/t5702-protocol-v2.sh | 14 ++++++++++++++ transport.c | 21 +-------------------- 5 files changed, 56 insertions(+), 31 deletions(-)