* [PATCH/RFC 0/3] teach fetch --prune
@ 2009-11-06 5:10 Jay Soffian
2009-11-06 5:10 ` [PATCH/RFC 1/3] remote: refactor some logic into get_stale_heads() Jay Soffian
2009-11-06 7:05 ` [PATCH/RFC 0/3] teach fetch --prune Junio C Hamano
0 siblings, 2 replies; 5+ messages in thread
From: Jay Soffian @ 2009-11-06 5:10 UTC (permalink / raw)
To: git; +Cc: Jay Soffian
This is just a start so I can get some feedback. Some things still missing:
1) "git remote prune <remote>" calls warn_dangling_symref(), but
"git fetch --prune" does not. I ran out of time tonight to refactor
warn_dangling_symref() to do something more intelligent than just spew to
stdout (which doesn't get along with fetch, which spews to stderr...).
2) Perhaps "git remote update --prune" should be refactored to call
"git fetch --prune". If so, then fetch should gain a "--prune-only" option
so that "git remote prune" can just call "got fetch --prune-only".
3) Perhaps add a config option for users who wish to prune by default.
Thoughts, comments, flames?
Jay Soffian (3):
remote: refactor some logic into get_stale_heads()
builtin-fetch: add --dry-run option
builtin-fetch: add --prune option
builtin-fetch.c | 30 +++++++++++++++++++++++++++---
builtin-remote.c | 32 ++++++++------------------------
remote.c | 40 ++++++++++++++++++++++++++++++++++++++++
remote.h | 3 +++
4 files changed, 78 insertions(+), 27 deletions(-)
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH/RFC 1/3] remote: refactor some logic into get_stale_heads()
2009-11-06 5:10 [PATCH/RFC 0/3] teach fetch --prune Jay Soffian
@ 2009-11-06 5:10 ` Jay Soffian
2009-11-06 5:10 ` [PATCH/RFC 2/3] builtin-fetch: add --dry-run option Jay Soffian
2009-11-06 7:05 ` [PATCH/RFC 0/3] teach fetch --prune Junio C Hamano
1 sibling, 1 reply; 5+ messages in thread
From: Jay Soffian @ 2009-11-06 5:10 UTC (permalink / raw)
To: git; +Cc: Jay Soffian
Move the logic in builtin-remote.c which determines which local heads are stale
to remote.c so it can be used by other builtins.
---
builtin-remote.c | 32 ++++++++------------------------
remote.c | 40 ++++++++++++++++++++++++++++++++++++++++
remote.h | 3 +++
3 files changed, 51 insertions(+), 24 deletions(-)
diff --git a/builtin-remote.c b/builtin-remote.c
index 0777dd7..b48267b 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -227,32 +227,10 @@ struct ref_states {
int queried;
};
-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 string_list_item *item;
- const char *name = abbrev_branch(refspec.src);
- /* symbolic refs pointing nowhere were handled already */
- if ((flags & REF_ISSYMREF) ||
- string_list_has_string(&states->tracked, name) ||
- string_list_has_string(&states->new, name))
- return 0;
- item = string_list_append(name, &states->stale);
- item->util = xstrdup(refname);
- }
- return 0;
-}
-
static int get_ref_states(const struct ref *remote_refs, struct ref_states *states)
{
struct ref *fetch_map = NULL, **tail = &fetch_map;
- struct ref *ref;
+ struct ref *ref, *stale_refs;
int i;
for (i = 0; i < states->remote->fetch_refspec_nr; i++)
@@ -268,11 +246,17 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
else
string_list_append(abbrev_branch(ref->name), &states->tracked);
}
+ stale_refs = get_stale_heads(states->remote, fetch_map);
+ for (ref = stale_refs; ref; ref = ref->next) {
+ struct string_list_item *item =
+ string_list_append(abbrev_branch(ref->name), &states->stale);
+ item->util = xstrdup(ref->name);
+ }
+ free_refs(stale_refs);
free_refs(fetch_map);
sort_string_list(&states->new);
sort_string_list(&states->tracked);
- for_each_ref(handle_one_branch, states);
sort_string_list(&states->stale);
return 0;
diff --git a/remote.c b/remote.c
index 73d33f2..ee48b49 100644
--- a/remote.c
+++ b/remote.c
@@ -6,6 +6,7 @@
#include "revision.h"
#include "dir.h"
#include "tag.h"
+#include "string-list.h"
static struct refspec s_tag_refspec = {
0,
@@ -1586,3 +1587,42 @@ struct ref *guess_remote_head(const struct ref *head,
return list;
}
+
+struct stale_heads_info {
+ struct remote *remote;
+ struct string_list *ref_names;
+ struct ref **stale_refs_tail;
+};
+
+static int get_stale_heads_cb(const char *refname,
+ const unsigned char *sha1, int flags, void *cb_data)
+{
+ struct stale_heads_info *info = cb_data;
+ struct refspec refspec;
+ memset(&refspec, 0, sizeof(refspec));
+ refspec.dst = (char *)refname;
+ if (!remote_find_tracking(info->remote, &refspec)) {
+ if (!((flags & REF_ISSYMREF) ||
+ string_list_has_string(info->ref_names, refspec.src))) {
+ struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail);
+ hashcpy(ref->new_sha1, sha1);
+ }
+ }
+ return 0;
+}
+
+struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map)
+{
+ struct ref *ref, *stale_refs = NULL;
+ struct string_list ref_names = { NULL, 0, 0, 0 };
+ struct stale_heads_info info;
+ info.remote = remote;
+ info.ref_names = &ref_names;
+ info.stale_refs_tail = &stale_refs;
+ for (ref = fetch_map; ref; ref = ref->next)
+ string_list_append(ref->name, &ref_names);
+ sort_string_list(&ref_names);
+ for_each_ref(get_stale_heads_cb, &info);
+ string_list_clear(&ref_names, 0);
+ return stale_refs;
+}
diff --git a/remote.h b/remote.h
index 5db8420..d0aba81 100644
--- a/remote.h
+++ b/remote.h
@@ -154,4 +154,7 @@ struct ref *guess_remote_head(const struct ref *head,
const struct ref *refs,
int all);
+/* Return refs which no longer exist on remote */
+struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map);
+
#endif
--
1.6.4.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH/RFC 2/3] builtin-fetch: add --dry-run option
2009-11-06 5:10 ` [PATCH/RFC 1/3] remote: refactor some logic into get_stale_heads() Jay Soffian
@ 2009-11-06 5:10 ` Jay Soffian
2009-11-06 5:10 ` [PATCH/RFC 3/3] builtin-fetch: add --prune option Jay Soffian
0 siblings, 1 reply; 5+ messages in thread
From: Jay Soffian @ 2009-11-06 5:10 UTC (permalink / raw)
To: git; +Cc: Jay Soffian
Teach fetch --dry-run. Unfortunately OPT__DRY_RUN() cannot be used as fetch
already uses "-n" for something else.
---
builtin-fetch.c | 10 +++++++---
1 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/builtin-fetch.c b/builtin-fetch.c
index cb48c57..985b36b 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -23,7 +23,7 @@ enum {
TAGS_SET = 2
};
-static int append, force, keep, update_head_ok, verbosity;
+static int append, dry_run, force, keep, update_head_ok, verbosity;
static int tags = TAGS_DEFAULT;
static const char *depth;
static const char *upload_pack;
@@ -42,6 +42,8 @@ static struct option builtin_fetch_options[] = {
"fetch all tags and associated objects", TAGS_SET),
OPT_SET_INT('n', NULL, &tags,
"do not fetch all tags (--no-tags)", TAGS_UNSET),
+ OPT_BOOLEAN(0, "dry-run", &dry_run,
+ "dry run"),
OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
"allow updating of HEAD ref"),
@@ -178,6 +180,8 @@ static int s_update_ref(const char *action,
char *rla = getenv("GIT_REFLOG_ACTION");
static struct ref_lock *lock;
+ if (dry_run)
+ return 0;
if (!rla)
rla = default_rla.buf;
snprintf(msg, sizeof(msg), "%s: %s", rla, action);
@@ -303,7 +307,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
char note[1024];
const char *what, *kind;
struct ref *rm;
- char *url, *filename = git_path("FETCH_HEAD");
+ char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
fp = fopen(filename, "a");
if (!fp)
@@ -586,7 +590,7 @@ static int do_fetch(struct transport *transport,
die("Don't know how to fetch from %s", transport->url);
/* if not appending, truncate FETCH_HEAD */
- if (!append) {
+ if (!append && !dry_run) {
char *filename = git_path("FETCH_HEAD");
FILE *fp = fopen(filename, "w");
if (!fp)
--
1.6.4.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH/RFC 3/3] builtin-fetch: add --prune option
2009-11-06 5:10 ` [PATCH/RFC 2/3] builtin-fetch: add --dry-run option Jay Soffian
@ 2009-11-06 5:10 ` Jay Soffian
0 siblings, 0 replies; 5+ messages in thread
From: Jay Soffian @ 2009-11-06 5:10 UTC (permalink / raw)
To: git; +Cc: Jay Soffian
Teach fetch --prune, as an alternative to git remote prune.
---
builtin-fetch.c | 22 +++++++++++++++++++++-
1 files changed, 21 insertions(+), 1 deletions(-)
diff --git a/builtin-fetch.c b/builtin-fetch.c
index 985b36b..e8a5b9b 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -23,7 +23,7 @@ enum {
TAGS_SET = 2
};
-static int append, dry_run, force, keep, update_head_ok, verbosity;
+static int append, dry_run, force, keep, prune, update_head_ok, verbosity;
static int tags = TAGS_DEFAULT;
static const char *depth;
static const char *upload_pack;
@@ -42,6 +42,8 @@ static struct option builtin_fetch_options[] = {
"fetch all tags and associated objects", TAGS_SET),
OPT_SET_INT('n', NULL, &tags,
"do not fetch all tags (--no-tags)", TAGS_UNSET),
+ OPT_BOOLEAN('p', "prune", &prune,
+ "prune tracking branches no longer on remote"),
OPT_BOOLEAN(0, "dry-run", &dry_run,
"dry run"),
OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
@@ -489,6 +491,22 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
return ret;
}
+static int prune_refs(struct transport *transport, struct ref *ref_map)
+{
+ int result = 0;
+ struct ref *ref, *stale_refs = get_stale_heads(transport->remote, ref_map);
+ for (ref = stale_refs; ref; ref = ref->next) {
+ if (!dry_run)
+ result |= delete_ref(ref->name, NULL, 0);
+ if (verbosity >= 0)
+ fprintf(stderr, " x %-*s %-*s -> %s\n",
+ SUMMARY_WIDTH, "[deleted]",
+ REFCOL_WIDTH, "(none)", prettify_refname(ref->name));
+ }
+ free_refs(stale_refs);
+ return 0;
+}
+
static int add_existing(const char *refname, const unsigned char *sha1,
int flag, void *cbdata)
{
@@ -613,6 +631,8 @@ static int do_fetch(struct transport *transport,
free_refs(ref_map);
return 1;
}
+ if (prune)
+ prune_refs(transport, ref_map);
free_refs(ref_map);
/* if neither --no-tags nor --tags was specified, do automated tag
--
1.6.4.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH/RFC 0/3] teach fetch --prune
2009-11-06 5:10 [PATCH/RFC 0/3] teach fetch --prune Jay Soffian
2009-11-06 5:10 ` [PATCH/RFC 1/3] remote: refactor some logic into get_stale_heads() Jay Soffian
@ 2009-11-06 7:05 ` Junio C Hamano
1 sibling, 0 replies; 5+ messages in thread
From: Junio C Hamano @ 2009-11-06 7:05 UTC (permalink / raw)
To: Jay Soffian; +Cc: git
Jay Soffian <jaysoffian@gmail.com> writes:
> This is just a start so I can get some feedback. Some things still missing:
>
> 1) "git remote prune <remote>" calls warn_dangling_symref(), but
> "git fetch --prune" does not. I ran out of time tonight to refactor
> warn_dangling_symref() to do something more intelligent than just spew to
> stdout (which doesn't get along with fetch, which spews to stderr...).
>
> 2) Perhaps "git remote update --prune" should be refactored to call
> "git fetch --prune". If so, then fetch should gain a "--prune-only" option
> so that "git remote prune" can just call "got fetch --prune-only".
>
> 3) Perhaps add a config option for users who wish to prune by default.
>
> Thoughts, comments, flames?
I usually refrain from talking about multi-year long term plans, because I
do not have one, but in a longer term (across 1.7.0 boundary and beyond),
the general direction would be:
- "fetch" will eventually prune by default; I expect we will have a
configuration option "fetch.autoprune = yes" to allow early adopters to
let it prune until 1.7.0, and in 1.7.0 we will change the default for
the configuration variable to "yes", i.e. we prune unless the user
explicitly declines with "fetch.autoprune = no".
- In general, "remote" should go back to its roots of being the
management interface to [remote "nick"] configuration section. We
should start planning to remove extra features that were piled on top
of the original "remote definition management tool". "update/prune"
should have been the duty of "fetch" in the first place, but they were
added to "remote" primarily because it was easier to do so ("remote"
used to be script but "fetch" was already written in "C").
This means two things:
* "remote prune" that only prunes without updating remaining tracking
will be largely become unnecessary [*1*], once we have a way to tell
"fetch" to prune at the same time. As soon as "fetch --prune"
becomes available, "remote prune" should become an alias to it. And
"remote prune" itself should eventually be removed.
* "remote update" that runs "fetch" for multiple remotes should be
deprecated and eventually removed. "remote update" is a band-aid
that exists only because "fetch" started as a strange chimera between
plumbing and Porcelain, and we did not want to add too much features
to it. "fetch" itself should learn to do the "from multiple places"
part as a full-fledged Porcelain.
Of course, a removal of a subcommand ("remote update" and "remote prune")
will have to happen way after 1.7.0 boundary, but the above should be the
longer term direction.
Don't worry about keeping the "only prune without updating" misfeature. If
omission of it simplifies what you are trying to do, it is Ok if "git
prune" becomes a synonym to "git update --prune" aka "git fetch --prune"
and starts updating the tracking refs.
[Footnote]
*1* "remote prune" is a band-aid that exists only because "fetch"
currently has no-way to prune at the same time.
One could argue that a user may want to prune _only_ stale refs without
getting the state of remaining refs updated to his tracking refs. That
certainly is _possible_ with "remote prune", but being possible and being
sensible are two different things.
What is the reason the user does not want to update a tracking ref that
corresponds to a branch that remains at the remote, when he runs "prune
only" version if it existed? It cannot be because the branch may have
been rewound and you may lose the only remaining history---the user is
actively asking to prune and is willing to lose the history of stale
branches.
In other words, once we have "fetch --prune" (either default or
optional---the important part is that there is a way to cause fetch to do
this), there is no sane reason to have a separate command that only prunes
without updating the remaining tracking refs.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-11-06 7:05 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-06 5:10 [PATCH/RFC 0/3] teach fetch --prune Jay Soffian
2009-11-06 5:10 ` [PATCH/RFC 1/3] remote: refactor some logic into get_stale_heads() Jay Soffian
2009-11-06 5:10 ` [PATCH/RFC 2/3] builtin-fetch: add --dry-run option Jay Soffian
2009-11-06 5:10 ` [PATCH/RFC 3/3] builtin-fetch: add --prune option Jay Soffian
2009-11-06 7:05 ` [PATCH/RFC 0/3] teach fetch --prune Junio C Hamano
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox