summaryrefslogtreecommitdiff
path: root/remote.c
diff options
context:
space:
mode:
authorFelipe Contreras <felipe.contreras@gmail.com>2012-02-23 00:43:41 +0200
committerJunio C Hamano <gitster@pobox.com>2012-02-22 18:17:39 -0800
commit6ddba5e241ebe484d53e3573c72386f487e25697 (patch)
tree836c5b5f1ee5d900e87ea9d60c32e576e219b68f /remote.c
parent676552464a871564835e1cb9d0484277b1b75e79 (diff)
downloadgit-6ddba5e241ebe484d53e3573c72386f487e25697.tar.gz
push: add '--prune' optionfc/push-prune
When pushing groups of refs to a remote, there is no simple way to remove old refs that still exist at the remote that is no longer updated from us. This will allow us to remove such refs from the remote. With this change, running this command $ git push --prune remote refs/heads/*:refs/remotes/laptop/* removes refs/remotes/laptop/foo from the remote if we do not have branch "foo" locally anymore. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'remote.c')
-rw-r--r--remote.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/remote.c b/remote.c
index c3cf736600..b296d17404 100644
--- a/remote.c
+++ b/remote.c
@@ -8,6 +8,8 @@
#include "tag.h"
#include "string-list.h"
+enum map_direction { FROM_SRC, FROM_DST };
+
static struct refspec s_tag_refspec = {
0,
1,
@@ -1115,7 +1117,7 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,
}
static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref,
- int send_mirror, const struct refspec **ret_pat)
+ int send_mirror, int direction, const struct refspec **ret_pat)
{
const struct refspec *pat;
char *name;
@@ -1130,7 +1132,12 @@ static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref
if (rs[i].pattern) {
const char *dst_side = rs[i].dst ? rs[i].dst : rs[i].src;
- if (match_name_with_pattern(rs[i].src, ref->name, dst_side, &name)) {
+ int match;
+ if (direction == FROM_SRC)
+ match = match_name_with_pattern(rs[i].src, ref->name, dst_side, &name);
+ else
+ match = match_name_with_pattern(dst_side, ref->name, rs[i].src, &name);
+ if (match) {
matching_refs = i;
break;
}
@@ -1177,6 +1184,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
struct refspec *rs;
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);
@@ -1197,7 +1205,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
if (ref->peer_ref)
continue;
- dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, &pat);
+ dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat);
if (!dst_name)
continue;
@@ -1224,6 +1232,23 @@ int match_push_refs(struct ref *src, struct ref **dst,
free_name:
free(dst_name);
}
+ if (send_prune) {
+ /* check for missing refs on the remote */
+ for (ref = *dst; ref; ref = ref->next) {
+ char *src_name;
+
+ if (ref->peer_ref)
+ /* We're already sending something to this ref. */
+ continue;
+
+ src_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_DST, NULL);
+ if (src_name) {
+ if (!find_ref_by_name(src, src_name))
+ ref->peer_ref = alloc_delete_ref();
+ free(src_name);
+ }
+ }
+ }
if (errs)
return -1;
return 0;