Skip to content

Commit

Permalink
Merge branch 'cr/push-force-tag-update'
Browse files Browse the repository at this point in the history
Regression fix to stop "git push" complaining "target ref already
exists", when it is not the real reason the command rejected the
request (e.g. non-fast-forward).

* cr/push-force-tag-update:
  push: fix "refs/tags/ hierarchy cannot be updated without --force"
  • Loading branch information
Junio C Hamano committed Jan 24, 2013
2 parents a29e711 + 256b9d7 commit d82dd26
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 58 deletions.
1 change: 0 additions & 1 deletion cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -1011,7 +1011,6 @@ struct ref {
requires_force:1,
merge:1,
nonfastforward:1,
not_forwardable:1,
update:1,
deletion:1;
enum {
Expand Down
43 changes: 7 additions & 36 deletions remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -1279,26 +1279,6 @@ int match_push_refs(struct ref *src, struct ref **dst,
return 0;
}

static inline int is_forwardable(struct ref* ref)
{
struct object *o;

if (!prefixcmp(ref->name, "refs/tags/"))
return 0;

/* old object must be a commit */
o = parse_object(ref->old_sha1);
if (!o || o->type != OBJ_COMMIT)
return 0;

/* new object must be commit-ish */
o = deref_tag(parse_object(ref->new_sha1), NULL, 0);
if (!o || o->type != OBJ_COMMIT)
return 0;

return 1;
}

void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
int force_update)
{
Expand All @@ -1320,32 +1300,23 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
}

/*
* The below logic determines whether an individual
* refspec A:B can be pushed. The push will succeed
* if any of the following are true:
* Decide whether an individual refspec A:B can be
* pushed. The push will succeed if any of the
* following are true:
*
* (1) the remote reference B does not exist
*
* (2) the remote reference B is being removed (i.e.,
* pushing :B where no source is specified)
*
* (3) the update meets all fast-forwarding criteria:
*
* (a) the destination is not under refs/tags/
* (b) the old is a commit
* (c) the new is a descendant of the old
*
* NOTE: We must actually have the old object in
* order to overwrite it in the remote reference,
* and the new object must be commit-ish. These are
* implied by (b) and (c) respectively.
* (3) the destination is not under refs/tags/, and
* if the old and new value is a commit, the new
* is a descendant of the old.
*
* (4) it is forced using the +A:B notation, or by
* passing the --force argument
*/

ref->not_forwardable = !is_forwardable(ref);

ref->update =
!ref->deletion &&
!is_null_sha1(ref->old_sha1);
Expand All @@ -1355,7 +1326,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
!has_sha1_file(ref->old_sha1)
|| !ref_newer(ref->new_sha1, ref->old_sha1);

if (ref->not_forwardable) {
if (!prefixcmp(ref->name, "refs/tags/")) {
ref->requires_force = 1;
if (!force_ref_update) {
ref->status = REF_STATUS_REJECT_ALREADY_EXISTS;
Expand Down
21 changes: 0 additions & 21 deletions t/t5516-fetch-push.sh
Original file line number Diff line number Diff line change
Expand Up @@ -950,27 +950,6 @@ test_expect_success 'push requires --force to update lightweight tag' '
)
'

test_expect_success 'push requires --force to update annotated tag' '
mk_test heads/master &&
mk_child child1 &&
mk_child child2 &&
(
cd child1 &&
git tag -a -m "message 1" Tag &&
git push ../child2 Tag:refs/tmp/Tag &&
git push ../child2 Tag:refs/tmp/Tag &&
>file1 &&
git add file1 &&
git commit -m "file1" &&
git tag -f -a -m "message 2" Tag &&
test_must_fail git push ../child2 Tag:refs/tmp/Tag &&
git push --force ../child2 Tag:refs/tmp/Tag &&
git tag -f -a -m "message 3" Tag HEAD~ &&
test_must_fail git push ../child2 Tag:refs/tmp/Tag &&
git push --force ../child2 Tag:refs/tmp/Tag
)
'

test_expect_success 'push --porcelain' '
mk_empty &&
echo >.git/foo "To testrepo" &&
Expand Down

0 comments on commit d82dd26

Please sign in to comment.