* [PATCH 0/6] builtin-remote @ 2007-12-05 19:00 Johannes Schindelin 2007-12-05 19:00 ` (unknown) Johannes Schindelin ` (5 more replies) 0 siblings, 6 replies; 14+ messages in thread From: Johannes Schindelin @ 2007-12-05 19:00 UTC (permalink / raw) To: git, gitster Hi, this series introduces remote as a builtin, and fixes a long-standing bug (if you created a remote with --mirror, prune would not do the right thing). I know it is pretty late in the game for 1.5.4, but then, I do not expect this to go into that version... Ciao, Dscho ^ permalink raw reply [flat|nested] 14+ messages in thread
* (unknown) 2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin @ 2007-12-05 19:00 ` Johannes Schindelin 2007-12-05 19:01 ` your mail Johannes Schindelin 2007-12-05 19:05 ` [PATCH 1/6] path-list: add functions to work with unsorted lists Johannes Schindelin 2007-12-05 19:01 ` [PATCH 2/6] parseopt: add flag to stop on first non option Johannes Schindelin ` (4 subsequent siblings) 5 siblings, 2 replies; 14+ messages in thread From: Johannes Schindelin @ 2007-12-05 19:00 UTC (permalink / raw) To: git, gitster [PATCH 1/6] path-list: add functions to work with unsorted lists Up to now, path-lists were sorted at all times. But sometimes it is much more convenient to build the list and sort it at the end, or sort it not at all. Add path_list_append() and sort_path_list() to allow that. Also, add the unsorted_path_list_has_path() function, to do a linear search. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> --- I should have done this much earlier... path-list.c | 30 ++++++++++++++++++++++++++++++ path-list.h | 8 +++++++- 2 files changed, 37 insertions(+), 1 deletions(-) diff --git a/path-list.c b/path-list.c index 3d83b7b..92e5cf2 100644 --- a/path-list.c +++ b/path-list.c @@ -102,3 +102,33 @@ void print_path_list(const char *text, const struct path_list *p) for (i = 0; i < p->nr; i++) printf("%s:%p\n", p->items[i].path, p->items[i].util); } + +struct path_list_item *path_list_append(const char *path, struct path_list *list) +{ + ALLOC_GROW(list->items, list->nr + 1, list->alloc); + list->items[list->nr].path = + list->strdup_paths ? xstrdup(path) : (char *)path; + return list->items + list->nr++; +} + +static int cmp_items(const void *a, const void *b) +{ + const struct path_list_item *one = a; + const struct path_list_item *two = b; + return strcmp(one->path, two->path); +} + +void sort_path_list(struct path_list *list) +{ + qsort(list->items, list->nr, sizeof(*list->items), cmp_items); +} + +int unsorted_path_list_has_path(struct path_list *list, const char *path) +{ + int i; + for (i = 0; i < list->nr; i++) + if (!strcmp(path, list->items[i].path)) + return 1; + return 0; +} + diff --git a/path-list.h b/path-list.h index 5931e2c..ca2cbba 100644 --- a/path-list.h +++ b/path-list.h @@ -13,10 +13,16 @@ struct path_list }; void print_path_list(const char *text, const struct path_list *p); +void path_list_clear(struct path_list *list, int free_util); +/* Use these functions only on sorted lists: */ int path_list_has_path(const struct path_list *list, const char *path); -void path_list_clear(struct path_list *list, int free_util); struct path_list_item *path_list_insert(const char *path, struct path_list *list); struct path_list_item *path_list_lookup(const char *path, struct path_list *list); +/* Use these functions only on unsorted lists: */ +struct path_list_item *path_list_append(const char *path, struct path_list *list); +void sort_path_list(struct path_list *list); +int unsorted_path_list_has_path(struct path_list *list, const char *path); + #endif /* PATH_LIST_H */ -- 1.5.3.7.2157.g9598e ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: your mail 2007-12-05 19:00 ` (unknown) Johannes Schindelin @ 2007-12-05 19:01 ` Johannes Schindelin 2007-12-05 19:05 ` [PATCH 1/6] path-list: add functions to work with unsorted lists Johannes Schindelin 1 sibling, 0 replies; 14+ messages in thread From: Johannes Schindelin @ 2007-12-05 19:01 UTC (permalink / raw) To: git, gitster Hi, On Wed, 5 Dec 2007, Johannes Schindelin wrote: > [PATCH 1/6] path-list: add functions to work with unsorted lists Ooops. Sorry, Dscho ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/6] path-list: add functions to work with unsorted lists 2007-12-05 19:00 ` (unknown) Johannes Schindelin 2007-12-05 19:01 ` your mail Johannes Schindelin @ 2007-12-05 19:05 ` Johannes Schindelin 1 sibling, 0 replies; 14+ messages in thread From: Johannes Schindelin @ 2007-12-05 19:05 UTC (permalink / raw) To: git, gitster Up to now, path-lists were sorted at all times. But sometimes it is much more convenient to build the list and sort it at the end, or sort it not at all. Add path_list_append() and sort_path_list() to allow that. Also, add the unsorted_path_list_has_path() function, to do a linear search. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> --- I should have done that long ago. path-list.c | 30 ++++++++++++++++++++++++++++++ path-list.h | 8 +++++++- 2 files changed, 37 insertions(+), 1 deletions(-) diff --git a/path-list.c b/path-list.c index 3d83b7b..92e5cf2 100644 --- a/path-list.c +++ b/path-list.c @@ -102,3 +102,33 @@ void print_path_list(const char *text, const struct path_list *p) for (i = 0; i < p->nr; i++) printf("%s:%p\n", p->items[i].path, p->items[i].util); } + +struct path_list_item *path_list_append(const char *path, struct path_list *list) +{ + ALLOC_GROW(list->items, list->nr + 1, list->alloc); + list->items[list->nr].path = + list->strdup_paths ? xstrdup(path) : (char *)path; + return list->items + list->nr++; +} + +static int cmp_items(const void *a, const void *b) +{ + const struct path_list_item *one = a; + const struct path_list_item *two = b; + return strcmp(one->path, two->path); +} + +void sort_path_list(struct path_list *list) +{ + qsort(list->items, list->nr, sizeof(*list->items), cmp_items); +} + +int unsorted_path_list_has_path(struct path_list *list, const char *path) +{ + int i; + for (i = 0; i < list->nr; i++) + if (!strcmp(path, list->items[i].path)) + return 1; + return 0; +} + diff --git a/path-list.h b/path-list.h index 5931e2c..ca2cbba 100644 --- a/path-list.h +++ b/path-list.h @@ -13,10 +13,16 @@ struct path_list }; void print_path_list(const char *text, const struct path_list *p); +void path_list_clear(struct path_list *list, int free_util); +/* Use these functions only on sorted lists: */ int path_list_has_path(const struct path_list *list, const char *path); -void path_list_clear(struct path_list *list, int free_util); struct path_list_item *path_list_insert(const char *path, struct path_list *list); struct path_list_item *path_list_lookup(const char *path, struct path_list *list); +/* Use these functions only on unsorted lists: */ +struct path_list_item *path_list_append(const char *path, struct path_list *list); +void sort_path_list(struct path_list *list); +int unsorted_path_list_has_path(struct path_list *list, const char *path); + #endif /* PATH_LIST_H */ -- 1.5.3.7.2157.g9598e ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/6] parseopt: add flag to stop on first non option 2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin 2007-12-05 19:00 ` (unknown) Johannes Schindelin @ 2007-12-05 19:01 ` Johannes Schindelin 2007-12-05 19:02 ` [PATCH 3/6] Test "git remote show" and "git remote prune" Johannes Schindelin ` (3 subsequent siblings) 5 siblings, 0 replies; 14+ messages in thread From: Johannes Schindelin @ 2007-12-05 19:01 UTC (permalink / raw) To: git, gitster Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> --- This allows "git remote --option command --command-option". parse-options.c | 2 ++ parse-options.h | 1 + 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/parse-options.c b/parse-options.c index e12b428..6df1230 100644 --- a/parse-options.c +++ b/parse-options.c @@ -229,6 +229,8 @@ int parse_options(int argc, const char **argv, const struct option *options, const char *arg = args.argv[0]; if (*arg != '-' || !arg[1]) { + if (flags & PARSE_OPT_STOP_AT_NON_OPTION) + break; argv[j++] = args.argv[0]; continue; } diff --git a/parse-options.h b/parse-options.h index 102ac31..0d40cd2 100644 --- a/parse-options.h +++ b/parse-options.h @@ -18,6 +18,7 @@ enum parse_opt_type { enum parse_opt_flags { PARSE_OPT_KEEP_DASHDASH = 1, + PARSE_OPT_STOP_AT_NON_OPTION = 2, }; enum parse_opt_option_flags { -- 1.5.3.7.2157.g9598e ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/6] Test "git remote show" and "git remote prune" 2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin 2007-12-05 19:00 ` (unknown) Johannes Schindelin 2007-12-05 19:01 ` [PATCH 2/6] parseopt: add flag to stop on first non option Johannes Schindelin @ 2007-12-05 19:02 ` Johannes Schindelin 2007-12-05 21:59 ` René Scharfe 2007-12-05 19:02 ` [PATCH 4/6] Make git-remote a builtin Johannes Schindelin ` (2 subsequent siblings) 5 siblings, 1 reply; 14+ messages in thread From: Johannes Schindelin @ 2007-12-05 19:02 UTC (permalink / raw) To: git, gitster While at it, also fix a few instances where a cd was done outside of a subshell. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> --- t/t5505-remote.sh | 34 ++++++++++++++++++++++++++++++++++ 1 files changed, 34 insertions(+), 0 deletions(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 636aec2..c7d7242 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -97,4 +97,38 @@ test_expect_success 'remove remote' ' ) ' +cat > test/expect << EOF +* remote origin + URL: $(pwd)/one/.git + Remote branch(es) merged with 'git pull' while on branch master + master + New remote branches (next fetch will store in remotes/origin) + master + Tracked remote branches + side master +EOF + +test_expect_success 'show' ' + (cd test && + git config --add remote.origin.fetch \ + refs/heads/master:refs/heads/upstream && + git fetch && + git branch -d -r origin/master && + (cd ../one && + echo 1 > file && + git commit -m update file) && + git remote show origin > output && + git diff expect output) +' + +test_expect_success 'prune' ' + (cd one && + git branch -m side side2) && + (cd test && + git fetch origin && + git remote prune origin && + git rev-parse refs/remotes/origin/side2 && + ! git rev-parse refs/remotes/origin/side) +' + test_done -- 1.5.3.7.2157.g9598e ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 3/6] Test "git remote show" and "git remote prune" 2007-12-05 19:02 ` [PATCH 3/6] Test "git remote show" and "git remote prune" Johannes Schindelin @ 2007-12-05 21:59 ` René Scharfe 2007-12-05 22:38 ` Johannes Schindelin 0 siblings, 1 reply; 14+ messages in thread From: René Scharfe @ 2007-12-05 21:59 UTC (permalink / raw) To: Johannes Schindelin; +Cc: git, gitster Johannes Schindelin schrieb: > While at it, also fix a few instances where a cd was done outside of a > subshell. > > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> > --- > t/t5505-remote.sh | 34 ++++++++++++++++++++++++++++++++++ > 1 files changed, 34 insertions(+), 0 deletions(-) It seems to me the patch only adds tests, but doesn't fix existing ones. And looking at t5505-remote.sh, every call of cd is already done inside of a subshell, so there doesn't seem to be anything to fix either. :-? ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/6] Test "git remote show" and "git remote prune" 2007-12-05 21:59 ` René Scharfe @ 2007-12-05 22:38 ` Johannes Schindelin 0 siblings, 0 replies; 14+ messages in thread From: Johannes Schindelin @ 2007-12-05 22:38 UTC (permalink / raw) To: René Scharfe; +Cc: git, gitster Hi, On Wed, 5 Dec 2007, Ren? Scharfe wrote: > Johannes Schindelin schrieb: > > While at it, also fix a few instances where a cd was done outside of a > > subshell. > > > > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> > > --- > > t/t5505-remote.sh | 34 ++++++++++++++++++++++++++++++++++ > > 1 files changed, 34 insertions(+), 0 deletions(-) > > It seems to me the patch only adds tests, but doesn't fix existing ones. > And looking at t5505-remote.sh, every call of cd is already done inside > of a subshell, so there doesn't seem to be anything to fix either. :-? Right. This comment is from a long time ago, back when I had my own (incomplete) t5505-remote.sh. It was funny to me that Junio chose exactly the same name... but his implementation was different ;-) I agree that this comment is obsolete. Thanks, Dscho ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 4/6] Make git-remote a builtin 2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin ` (2 preceding siblings ...) 2007-12-05 19:02 ` [PATCH 3/6] Test "git remote show" and "git remote prune" Johannes Schindelin @ 2007-12-05 19:02 ` Johannes Schindelin 2007-12-05 21:40 ` [PATCH 7/6] builtin-remote: guard remote->url accesses by remote->url_nr check Johannes Schindelin 2007-12-05 19:02 ` [PATCH 5/6] builtin-remote: prune remotes correctly that were added with --mirror Johannes Schindelin 2007-12-05 19:03 ` [PATCH 6/6] DWIM "git add remote ..." Johannes Schindelin 5 siblings, 1 reply; 14+ messages in thread From: Johannes Schindelin @ 2007-12-05 19:02 UTC (permalink / raw) To: git, gitster Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> --- Makefile | 3 +- builtin-remote.c | 517 ++++++++++++++++++++ builtin.h | 1 + .../examples/git-remote.perl | 0 git.c | 1 + remote.c | 3 +- remote.h | 1 + t/t5505-remote.sh | 4 +- 8 files changed, 526 insertions(+), 4 deletions(-) create mode 100644 builtin-remote.c rename git-remote.perl => contrib/examples/git-remote.perl (100%) diff --git a/Makefile b/Makefile index 233bb5f..e840ca3 100644 --- a/Makefile +++ b/Makefile @@ -228,7 +228,7 @@ SCRIPT_SH = \ SCRIPT_PERL = \ git-add--interactive.perl \ git-archimport.perl git-cvsimport.perl git-relink.perl \ - git-cvsserver.perl git-remote.perl git-cvsexportcommit.perl \ + git-cvsserver.perl git-cvsexportcommit.perl \ git-send-email.perl git-svn.perl SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ @@ -362,6 +362,7 @@ BUILTIN_OBJS = \ builtin-push.o \ builtin-read-tree.o \ builtin-reflog.o \ + builtin-remote.o \ builtin-send-pack.o \ builtin-config.o \ builtin-rerere.o \ diff --git a/builtin-remote.c b/builtin-remote.c new file mode 100644 index 0000000..41ac4a1 --- /dev/null +++ b/builtin-remote.c @@ -0,0 +1,517 @@ +#include "cache.h" +#include "parse-options.h" +#include "transport.h" +#include "remote.h" +#include "path-list.h" +#include "strbuf.h" +#include "run-command.h" +#include "refs.h" + +static const char * const builtin_remote_usage[] = { + "git remote", + "git remote add <name> <url>", + "git remote rm <name>", + "git remote show <name>", + "git remote prune <name>", + "git remote update [group]", + NULL +}; + +static int verbose; + +static inline int postfixcmp(const char *string, const char *postfix) +{ + int len1 = strlen(string), len2 = strlen(postfix); + if (len1 < len2) + return 1; + return strcmp(string + len1 - len2, postfix); +} + +static inline const char *skip_prefix(const char *name, const char *prefix) +{ + return !name ? "" : + prefixcmp(name, prefix) ? name : name + strlen(prefix); +} + +static int opt_parse_track(const struct option *opt, const char *arg, int not) +{ + struct path_list *list = opt->value; + if (not) + path_list_clear(list, 0); + else + path_list_append(arg, list); + return 0; +} + +static int fetch_remote(const char *name) +{ + const char *argv[] = { "fetch", name, NULL }; + if (run_command_v_opt(argv, RUN_GIT_CMD)) + return error ("Could not fetch %s", name); + return 0; +} + +static int add(int argc, const char **argv) +{ + int fetch = 0, mirror = 0; + struct path_list track = { NULL, 0, 0 }; + const char *master = NULL; + struct remote *remote; + struct strbuf buf, buf2; + const char *name, *url; + int i; + + struct option options[] = { + OPT_GROUP("add specific options"), + OPT_BOOLEAN('f', "fetch", &fetch, "fetch the remote branches"), + OPT_CALLBACK('t', "track", &track, "branch", + "branch(es) to track", opt_parse_track), + OPT_STRING('m', "master", &master, "branch", "master branch"), + OPT_BOOLEAN(0, "mirror", &mirror, "no separate remotes"), + OPT_END() + }; + + argc = parse_options(argc, argv, options, builtin_remote_usage, 0); + + if (argc < 2) + usage_with_options(builtin_remote_usage, options); + + name = argv[0]; + url = argv[1]; + + remote = remote_get(name); + if (remote && (remote->url_nr > 1 || strcmp(name, remote->url[0]) || + remote->fetch_refspec_nr)) + die ("remote %s already exists.", name); + + strbuf_init(&buf, 0); + strbuf_init(&buf2, 0); + + strbuf_addf(&buf, "remote.%s.url", name); + if (git_config_set(buf.buf, url)) + return 1; + + if (track.nr == 0) + path_list_append("*", &track); + for (i = 0; i < track.nr; i++) { + struct path_list_item *item = track.items + i; + + strbuf_reset(&buf); + strbuf_addf(&buf, "remote.%s.fetch", name); + + strbuf_reset(&buf2); + if (mirror) + strbuf_addf(&buf2, "refs/%s:refs/%s", + item->path, item->path); + else + strbuf_addf(&buf2, "refs/heads/%s:refs/remotes/%s/%s", + item->path, name, item->path); + if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0)) + return 1; + } + + if (fetch && fetch_remote(name)) + return 1; + + if (master) { + strbuf_reset(&buf); + strbuf_addf(&buf, "refs/remotes/%s/HEAD", name); + + strbuf_reset(&buf2); + strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master); + + if (create_symref(buf.buf, buf2.buf, "remote add")) + return error ("Could not setup master '%s'", master); + } + + strbuf_release(&buf); + strbuf_release(&buf2); + path_list_clear(&track, 0); + + return 0; +} + +struct branch_info { + char *remote; + struct path_list merge; +}; + +static struct path_list branch_list; + +static int config_read_branches(const char *key, const char *value) +{ + if (!prefixcmp(key, "branch.")) { + char *name; + struct path_list_item *item; + struct branch_info *info; + enum { REMOTE, MERGE } type; + + key += 7; + if (!postfixcmp(key, ".remote")) { + name = xstrndup(key, strlen(key) - 7); + type = REMOTE; + } else if (!postfixcmp(key, ".merge")) { + name = xstrndup(key, strlen(key) - 6); + type = MERGE; + } else + return 0; + + item = path_list_insert(name, &branch_list); + + if (!item->util) + item->util = xcalloc(sizeof(struct branch_info), 1); + info = item->util; + if (type == REMOTE) { + if (info->remote) + warning ("more than one branch.%s", key); + info->remote = xstrdup(value); + } else { + char *space = strchr(value, ' '); + value = skip_prefix(value, "refs/heads/"); + while (space) { + char *merge; + merge = xstrndup(value, space - value); + path_list_append(merge, &info->merge); + value = skip_prefix(space + 1, "refs/heads/"); + space = strchr(value, ' '); + } + path_list_append(xstrdup(value), &info->merge); + } + } + return 0; +} + +static void read_branches() +{ + if (branch_list.nr) + return; + git_config(config_read_branches); + sort_path_list(&branch_list); +} + +struct ref_states { + struct remote *remote; + struct strbuf remote_prefix; + struct path_list new, stale, tracked; +}; + +static int handle_one_branch(const char *refname, + const unsigned char *sha1, int flags, void *cb_data) +{ + struct ref_states *states = cb_data; + struct refspec refspec; + + memset(&refspec, 0, sizeof(refspec)); + refspec.dst = (char *)refname; + if (!remote_find_tracking(states->remote, &refspec)) { + struct path_list_item *item; + const char *name = skip_prefix(refspec.src, "refs/heads/"); + if (unsorted_path_list_has_path(&states->tracked, name) || + unsorted_path_list_has_path(&states->new, + name)) + return 0; + item = path_list_append(name, &states->stale); + item->util = xstrdup(refname); + } + return 0; +} + +static int get_ref_states(const struct ref *ref, struct ref_states *states) +{ + struct ref *fetch_map = NULL, **tail = &fetch_map; + int i; + + for (i = 0; i < states->remote->fetch_refspec_nr; i++) + if (get_fetch_map(ref, states->remote->fetch +i, &tail, 1)) + die ("Could not get fetch map for refspec %s", + states->remote->fetch_refspec[i]); + + states->new.strdup_paths = states->tracked.strdup_paths = 1; + for (ref = fetch_map; ref; ref = ref->next) { + struct path_list *target = &states->tracked; + unsigned char sha1[20]; + void *util = NULL; + + if (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1)) + target = &states->new; + else { + target = &states->tracked; + if (hashcmp(sha1, ref->new_sha1)) + util = &states; + } + path_list_append(skip_prefix(ref->name, "refs/heads/"), + target)->util = util; + } + free_refs(fetch_map); + + strbuf_addf(&states->remote_prefix, + "refs/remotes/%s/", states->remote->name); + for_each_ref(handle_one_branch, states); + sort_path_list(&states->stale); + + return 0; +} + +static int remove_tracking_branch(const char *refname, + const unsigned char *sha1, int flags, void *cb_data) +{ + const char *remote_prefix = cb_data; + + if (!prefixcmp(refname, remote_prefix) && + delete_ref(refname, sha1)) + return error("Could not remove branch %s", refname); + return 0; +} + +static int rm(int argc, const char **argv) +{ + struct option options[] = { + OPT_END() + }; + struct remote *remote; + struct strbuf buf; + int i; + + if (argc != 2) + usage_with_options(builtin_remote_usage, options); + + remote = remote_get(argv[1]); + if (!remote) + die ("No such remote: %s", argv[1]); + + strbuf_init(&buf, 0); + strbuf_addf(&buf, "remote.%s", remote->name); + if (git_config_rename_section(buf.buf, NULL) < 1) + return error("Could not remove config section '%s'", buf.buf); + + read_branches(); + for (i = 0; i < branch_list.nr; i++) { + struct path_list_item *item = branch_list.items +i; + struct branch_info *info = item->util; + if (info->remote && !strcmp(info->remote, remote->name)) { + const char *keys[] = { "remote", "merge", NULL }, **k; + for (k = keys; *k; k++) { + strbuf_reset(&buf); + strbuf_addf(&buf, "branch.%s.%s", + item->path, *k); + if (git_config_set(buf.buf, NULL)) { + strbuf_release(&buf); + return -1; + } + } + } + } + + /* + * NEEDSTHOUGHT: this could check something like + * !remote_find_tracking(remote, &refspec) to know if the + * branch was really tracked. But then we'll have to make + * sure that no other remote writes into that branch. + * Probably not worth it. + */ + strbuf_reset(&buf); + strbuf_addf(&buf, "refs/remotes/%s/", remote->name); + i = for_each_ref(remove_tracking_branch, buf.buf); + strbuf_release(&buf); + + return i; +} + +static void show_list(const char *title, struct path_list *list) +{ + int i; + + if (!list->nr) + return; + + printf(title, list->nr > 1 ? "es" : ""); + printf("\n "); + for (i = 0; i < list->nr; i++) + printf("%s%s", i ? " " : "", list->items[i].path); + printf("\n"); +} + +static int show_or_prune(int argc, const char **argv, int prune) +{ + int dry_run = 0, result = 0; + struct option options[] = { + OPT_GROUP("show specific options"), + OPT__DRY_RUN(&dry_run), + OPT_END() + }; + struct ref_states states; + + argc = parse_options(argc, argv, options, builtin_remote_usage, 0); + + if (argc < 1) + usage_with_options(builtin_remote_usage, options); + + memset(&states, 0, sizeof(states)); + for (; argc; argc--, argv++) { + struct transport *transport; + const struct ref *ref; + struct strbuf buf; + int i, got_states; + + states.remote = remote_get(*argv); + if (!states.remote) + return error("No such remote: %s", *argv); + transport = transport_get(NULL, states.remote->url[0]); + ref = transport_get_remote_refs(transport); + + read_branches(); + got_states = get_ref_states(ref, &states); + if (got_states) + result = error("Error getting local info for '%s'", + states.remote->name); + + if (prune) { + struct strbuf buf; + + strbuf_init(&buf, 0); + for (i = 0; i < states.stale.nr; i++) { + strbuf_reset(&buf); + strbuf_addf(&buf, "refs/remotes/%s/%s", *argv, + states.stale.items[i].path); + result |= delete_ref(buf.buf, NULL); + } + + strbuf_release(&buf); + goto cleanup_states; + } + + printf("* remote %s\n URL: %s\n", *argv, + states.remote->url[0] ? + states.remote->url[0] : "(no URL)"); + + for (i = 0; i < branch_list.nr; i++) { + struct path_list_item *branch = branch_list.items + i; + struct branch_info *info = branch->util; + int j; + + if (!info->merge.nr || strcmp(*argv, info->remote)) + continue; + printf(" Remote branch%s merged with 'git pull' " + "while on branch %s\n ", + info->merge.nr > 1 ? "es" : "", + branch->path); + for (j = 0; j < info->merge.nr; j++) + printf(" %s", info->merge.items[j].path); + printf("\n"); + } + + if (got_states) + continue; + strbuf_init(&buf, 0); + strbuf_addf(&buf, " New remote branch%%s (next fetch will " + "store in remotes/%s)", states.remote->name); + show_list(buf.buf, &states.new); + strbuf_release(&buf); + show_list(" Stale tracking branch%s (use 'git remote prune')", + &states.stale); + show_list(" Tracked remote branch%s", + &states.tracked); + + if (states.remote->push_refspec_nr) { + printf(" Local branch%s pushed with 'git push'\n ", + states.remote->push_refspec_nr > 1 ? + "es" : ""); + for (i = 0; i < states.remote->push_refspec_nr; i++) { + struct refspec *spec = states.remote->push + i; + printf(" %s%s%s%s", spec->force ? "+" : "", + skip_prefix(spec->src, "refs/heads/"), + spec->dst ? ":" : "", + skip_prefix(spec->dst, "refs/heads/")); + } + } +cleanup_states: + /* NEEDSWORK: free remote */ + path_list_clear(&states.new, 0); + path_list_clear(&states.stale, 0); + path_list_clear(&states.tracked, 0); + } + + return result; +} + +static int update_one(struct remote *remote, void *priv) +{ + if (!remote->skip_default_update) + return fetch_remote(remote->name); + return 0; +} + +static int update(int argc, const char **argv) +{ + int i; + + if (argc < 2) + return for_each_remote(update_one, NULL); + + for (i = 1; i < argc; i++) + if (fetch_remote(argv[i])) + return 1; + return 0; +} + +static int get_one_entry(struct remote *remote, void *priv) +{ + struct path_list *list = priv; + + path_list_append(remote->name, list)->util = (void *)remote->url[0]; + if (remote->url[0] && remote->url[1]) + warning ("Remote %s has more than one URL", remote->name); + + return 0; +} + +static int show_all() +{ + struct path_list list = { NULL, 0, 0 }; + int result = for_each_remote(get_one_entry, &list); + + if (!result) { + int i; + + sort_path_list(&list); + for (i = 0; i < list.nr; i++) { + struct path_list_item *item = list.items + i; + printf("%s%s%s\n", item->path, + verbose ? "\t" : "", + verbose && item->util ? + (const char *)item->util : ""); + } + } + return result; +} + +int cmd_remote(int argc, const char **argv, const char *prefix) +{ + struct option options[] = { + OPT__VERBOSE(&verbose), + OPT_END() + }; + int result; + + argc = parse_options(argc, argv, options, builtin_remote_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + + if (argc < 1) + result = show_all(); + else if (!strcmp(argv[0], "add")) + result = add(argc, argv); + else if (!strcmp(argv[0], "rm")) + result = rm(argc, argv); + else if (!strcmp(argv[0], "show")) + result = show_or_prune(argc, argv, 0); + else if (!strcmp(argv[0], "prune")) + result = show_or_prune(argc, argv, 1); + else if (!strcmp(argv[0], "update")) + result = update(argc, argv); + else { + error ("Unknown subcommand: %s", argv[0]); + usage_with_options(builtin_remote_usage, options); + } + + return result ? 1 : 0; +} diff --git a/builtin.h b/builtin.h index cb675c4..20b6e75 100644 --- a/builtin.h +++ b/builtin.h @@ -66,6 +66,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix); extern int cmd_push(int argc, const char **argv, const char *prefix); extern int cmd_read_tree(int argc, const char **argv, const char *prefix); extern int cmd_reflog(int argc, const char **argv, const char *prefix); +extern int cmd_remote(int argc, const char **argv, const char *prefix); extern int cmd_config(int argc, const char **argv, const char *prefix); extern int cmd_rerere(int argc, const char **argv, const char *prefix); extern int cmd_reset(int argc, const char **argv, const char *prefix); diff --git a/git-remote.perl b/contrib/examples/git-remote.perl similarity index 100% rename from git-remote.perl rename to contrib/examples/git-remote.perl diff --git a/git.c b/git.c index c8b7e74..80e9082 100644 --- a/git.c +++ b/git.c @@ -349,6 +349,7 @@ static void handle_internal_command(int argc, const char **argv) { "push", cmd_push, RUN_SETUP }, { "read-tree", cmd_read_tree, RUN_SETUP }, { "reflog", cmd_reflog, RUN_SETUP }, + { "remote", cmd_remote, RUN_SETUP }, { "repo-config", cmd_config }, { "rerere", cmd_rerere, RUN_SETUP }, { "reset", cmd_reset, RUN_SETUP }, diff --git a/remote.c b/remote.c index 3fb0f99..ae7abe4 100644 --- a/remote.c +++ b/remote.c @@ -280,7 +280,8 @@ static int handle_config(const char *key, const char *value) remote->fetch_tags = -1; } else if (!strcmp(subkey, ".proxy")) { remote->http_proxy = xstrdup(value); - } + } else if (!strcmp(subkey, ".skipdefaultupdate")) + remote->skip_default_update = 1; return 0; } diff --git a/remote.h b/remote.h index 86e036d..bb26d3c 100644 --- a/remote.h +++ b/remote.h @@ -22,6 +22,7 @@ struct remote { * 2 to always fetch tags */ int fetch_tags; + int skip_default_update; const char *receivepack; const char *uploadpack; diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index c7d7242..d343a96 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -100,9 +100,9 @@ test_expect_success 'remove remote' ' cat > test/expect << EOF * remote origin URL: $(pwd)/one/.git - Remote branch(es) merged with 'git pull' while on branch master + Remote branch merged with 'git pull' while on branch master master - New remote branches (next fetch will store in remotes/origin) + New remote branch (next fetch will store in remotes/origin) master Tracked remote branches side master -- 1.5.3.7.2157.g9598e ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 7/6] builtin-remote: guard remote->url accesses by remote->url_nr check 2007-12-05 19:02 ` [PATCH 4/6] Make git-remote a builtin Johannes Schindelin @ 2007-12-05 21:40 ` Johannes Schindelin 0 siblings, 0 replies; 14+ messages in thread From: Johannes Schindelin @ 2007-12-05 21:40 UTC (permalink / raw) To: git, gitster; +Cc: Johannes Sixt struct remote's url member is not a NULL terminated list. Instead, we have to check url_nr before accessing it. Noticed by Johannes Sixt. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> --- For your viewing pleasure, this is not a resend, but an amend. Feel free to squash with 4/6, or to bug me to do it. builtin-remote.c | 10 ++++++---- 1 files changed, 6 insertions(+), 4 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index 142eb97..ea323e2 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -356,7 +356,8 @@ static int show_or_prune(int argc, const char **argv, int prune) states.remote = remote_get(*argv); if (!states.remote) return error("No such remote: %s", *argv); - transport = transport_get(NULL, states.remote->url[0]); + transport = transport_get(NULL, states.remote->url_nr > 0 ? + states.remote->url[0] : NULL); ref = transport_get_remote_refs(transport); read_branches(); @@ -391,7 +392,7 @@ static int show_or_prune(int argc, const char **argv, int prune) } printf("* remote %s\n URL: %s\n", *argv, - states.remote->url[0] ? + states.remote->url_nr > 0 ? states.remote->url[0] : "(no URL)"); for (i = 0; i < branch_list.nr; i++) { @@ -468,8 +469,9 @@ static int get_one_entry(struct remote *remote, void *priv) { struct path_list *list = priv; - path_list_append(remote->name, list)->util = (void *)remote->url[0]; - if (remote->url[0] && remote->url[1]) + path_list_append(remote->name, list)->util = remote->url_nr ? + (void *)remote->url[0] : NULL; + if (remote->url_nr > 1) warning ("Remote %s has more than one URL", remote->name); return 0; -- 1.5.3.7.2157.g9598e ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 5/6] builtin-remote: prune remotes correctly that were added with --mirror 2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin ` (3 preceding siblings ...) 2007-12-05 19:02 ` [PATCH 4/6] Make git-remote a builtin Johannes Schindelin @ 2007-12-05 19:02 ` Johannes Schindelin 2007-12-05 19:03 ` [PATCH 6/6] DWIM "git add remote ..." Johannes Schindelin 5 siblings, 0 replies; 14+ messages in thread From: Johannes Schindelin @ 2007-12-05 19:02 UTC (permalink / raw) To: git, gitster This adds special handling for mirror remotes. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> --- This fixes a real bug in git-remote, which I tried to fix in the perl script, failing. builtin-remote.c | 16 +++++++++++++--- t/t5505-remote.sh | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index 41ac4a1..142eb97 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -367,12 +367,22 @@ static int show_or_prune(int argc, const char **argv, int prune) if (prune) { struct strbuf buf; + int prefix_len; strbuf_init(&buf, 0); + if (states.remote->fetch_refspec_nr == 1 && + states.remote->fetch->pattern && + !strcmp(states.remote->fetch->src, + states.remote->fetch->dst)) + /* handle --mirror remote */ + strbuf_addstr(&buf, "refs/heads/"); + else + strbuf_addf(&buf, "refs/remotes/%s/", *argv); + prefix_len = buf.len; + for (i = 0; i < states.stale.nr; i++) { - strbuf_reset(&buf); - strbuf_addf(&buf, "refs/remotes/%s/%s", *argv, - states.stale.items[i].path); + strbuf_setlen(&buf, prefix_len); + strbuf_addstr(&buf, states.stale.items[i].path); result |= delete_ref(buf.buf, NULL); } diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index d343a96..2376e0a 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -131,4 +131,20 @@ test_expect_success 'prune' ' ! git rev-parse refs/remotes/origin/side) ' +test_expect_success 'add --mirror && prune' ' + (mkdir mirror && + cd mirror && + git init && + git remote add --mirror -f origin ../one) && + (cd one && + git branch -m side2 side) && + (cd mirror && + git rev-parse --verify refs/heads/side2 && + ! git rev-parse --verify refs/heads/side && + git fetch origin && + git remote prune origin && + ! git rev-parse --verify refs/heads/side2 && + git rev-parse --verify refs/heads/side) +' + test_done -- 1.5.3.7.2157.g9598e ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 6/6] DWIM "git add remote ..." 2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin ` (4 preceding siblings ...) 2007-12-05 19:02 ` [PATCH 5/6] builtin-remote: prune remotes correctly that were added with --mirror Johannes Schindelin @ 2007-12-05 19:03 ` Johannes Schindelin 2007-12-05 19:34 ` Linus Torvalds 5 siblings, 1 reply; 14+ messages in thread From: Johannes Schindelin @ 2007-12-05 19:03 UTC (permalink / raw) To: git, gitster It is wrong to divert to "git remote add" when you typed the (more English) "git add remote". But is it also pretty convenient. So implement it, but do not document it ;-) Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> --- builtin-add.c | 7 +++++++ t/t5505-remote.sh | 6 ++++++ 2 files changed, 13 insertions(+), 0 deletions(-) diff --git a/builtin-add.c b/builtin-add.c index 5c29cc2..b5b4c2f 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -196,6 +196,13 @@ int cmd_add(int argc, const char **argv, const char *prefix) const char **pathspec; struct dir_struct dir; + if (argc > 1 && !strcmp(argv[1], "remote") && + access("remote", F_OK)) { + argv[1] = argv[0]; + argv[0] = "remote"; + return cmd_remote(argc, argv, prefix); + } + argc = parse_options(argc, argv, builtin_add_options, builtin_add_usage, 0); if (patch_interactive) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 2376e0a..83ed70c 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -147,4 +147,10 @@ test_expect_success 'add --mirror && prune' ' git rev-parse --verify refs/heads/side) ' +test_expect_success 'add remote' ' + (cd test && + git add remote -f another-one ../one && + git diff master remotes/another-one/master) +' + test_done -- 1.5.3.7.2157.g9598e ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 6/6] DWIM "git add remote ..." 2007-12-05 19:03 ` [PATCH 6/6] DWIM "git add remote ..." Johannes Schindelin @ 2007-12-05 19:34 ` Linus Torvalds 2007-12-05 19:47 ` Johannes Schindelin 0 siblings, 1 reply; 14+ messages in thread From: Linus Torvalds @ 2007-12-05 19:34 UTC (permalink / raw) To: Johannes Schindelin; +Cc: git, gitster On Wed, 5 Dec 2007, Johannes Schindelin wrote: > > It is wrong to divert to "git remote add" when you typed the > (more English) "git add remote". But is it also pretty convenient. Please don't do cute things like this. Suddenly "git add remote" has two different meanings depending on whether you have a file called "remote" or not. That is *not* ok. Not to mention the fact that your patch is also a horrible piece of bug-infested shit, to put it less-than-politely. Namely, you now broke "git add remote" when "remote" is a symbolic link pointing to hyperspace. But even if you fix that bug, it only goes to show just how misguided things like these are. It's a *lot* more important to make sense and not have surprising special cases, than to try to make git command lines act as if they were free-form English. Linus ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 6/6] DWIM "git add remote ..." 2007-12-05 19:34 ` Linus Torvalds @ 2007-12-05 19:47 ` Johannes Schindelin 0 siblings, 0 replies; 14+ messages in thread From: Johannes Schindelin @ 2007-12-05 19:47 UTC (permalink / raw) To: Linus Torvalds; +Cc: git, gitster Hi, On Wed, 5 Dec 2007, Linus Torvalds wrote: > On Wed, 5 Dec 2007, Johannes Schindelin wrote: > > > > It is wrong to divert to "git remote add" when you typed the (more > > English) "git add remote". But is it also pretty convenient. > > Please don't do cute things like this. Suddenly "git add remote" has two > different meanings depending on whether you have a file called "remote" > or not. That is *not* ok. > > Not to mention the fact that your patch is also a horrible piece of > bug-infested shit, to put it less-than-politely. Namely, you now broke > "git add remote" when "remote" is a symbolic link pointing to > hyperspace. > > But even if you fix that bug, it only goes to show just how misguided > things like these are. It's a *lot* more important to make sense and not > have surprising special cases, than to try to make git command lines act > as if they were free-form English. Hehe. You're right, of course. But I could not resist showing off that patch which I wrote after I mixed up the command line of "remote add" for the 926th time. Ciao, Dscho ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2007-12-05 22:39 UTC | newest] Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-12-05 19:00 [PATCH 0/6] builtin-remote Johannes Schindelin 2007-12-05 19:00 ` (unknown) Johannes Schindelin 2007-12-05 19:01 ` your mail Johannes Schindelin 2007-12-05 19:05 ` [PATCH 1/6] path-list: add functions to work with unsorted lists Johannes Schindelin 2007-12-05 19:01 ` [PATCH 2/6] parseopt: add flag to stop on first non option Johannes Schindelin 2007-12-05 19:02 ` [PATCH 3/6] Test "git remote show" and "git remote prune" Johannes Schindelin 2007-12-05 21:59 ` René Scharfe 2007-12-05 22:38 ` Johannes Schindelin 2007-12-05 19:02 ` [PATCH 4/6] Make git-remote a builtin Johannes Schindelin 2007-12-05 21:40 ` [PATCH 7/6] builtin-remote: guard remote->url accesses by remote->url_nr check Johannes Schindelin 2007-12-05 19:02 ` [PATCH 5/6] builtin-remote: prune remotes correctly that were added with --mirror Johannes Schindelin 2007-12-05 19:03 ` [PATCH 6/6] DWIM "git add remote ..." Johannes Schindelin 2007-12-05 19:34 ` Linus Torvalds 2007-12-05 19:47 ` Johannes Schindelin
Code repositories for project(s) associated with this public inbox https://80x24.org/mirrors/git.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).