From 47a59185369b8905ad3a4012688cba92fd2ac1ff Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 8 Jul 2013 13:56:53 -0700 Subject: cache.h: move remote/connect API out of it The definition of "struct ref" in "cache.h", a header file so central to the system, always confused me. This structure is not about the local ref used by sha1-name API to name local objects. It is what refspecs are expanded into, after finding out what refs the other side has, to define what refs are updated after object transfer succeeds to what values. It belongs to "remote.h" together with "struct refspec". While we are at it, also move the types and functions related to the Git transport connection to a new header file connect.h Signed-off-by: Junio C Hamano --- remote.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'remote.h') diff --git a/remote.h b/remote.h index cf56724661..a850059804 100644 --- a/remote.h +++ b/remote.h @@ -71,6 +71,52 @@ struct refspec { extern const struct refspec *tag_refspec; +struct ref { + struct ref *next; + unsigned char old_sha1[20]; + unsigned char new_sha1[20]; + char *symref; + unsigned int + force:1, + forced_update:1, + deletion:1, + matched:1; + + /* + * Order is important here, as we write to FETCH_HEAD + * in numeric order. And the default NOT_FOR_MERGE + * should be 0, so that xcalloc'd structures get it + * by default. + */ + enum { + FETCH_HEAD_MERGE = -1, + FETCH_HEAD_NOT_FOR_MERGE = 0, + FETCH_HEAD_IGNORE = 1 + } fetch_head_status; + + enum { + REF_STATUS_NONE = 0, + REF_STATUS_OK, + REF_STATUS_REJECT_NONFASTFORWARD, + REF_STATUS_REJECT_ALREADY_EXISTS, + REF_STATUS_REJECT_NODELETE, + REF_STATUS_REJECT_FETCH_FIRST, + REF_STATUS_REJECT_NEEDS_FORCE, + REF_STATUS_UPTODATE, + REF_STATUS_REMOTE_REJECT, + REF_STATUS_EXPECTING_REPORT + } status; + char *remote_status; + struct ref *peer_ref; /* when renaming */ + char name[FLEX_ARRAY]; /* more */ +}; + +#define REF_NORMAL (1u << 0) +#define REF_HEADS (1u << 1) +#define REF_TAGS (1u << 2) + +extern struct ref *find_ref_by_name(const struct ref *list, const char *name); + struct ref *alloc_ref(const char *name); struct ref *copy_ref(const struct ref *ref); struct ref *copy_ref_list(const struct ref *ref); @@ -84,6 +130,14 @@ int check_ref_type(const struct ref *ref, int flags); */ void free_refs(struct ref *ref); +struct extra_have_objects { + int nr, alloc; + unsigned char (*array)[20]; +}; +extern struct ref **get_remote_heads(int in, char *src_buf, size_t src_len, + struct ref **list, unsigned int flags, + struct extra_have_objects *); + int resolve_remote_symref(struct ref *ref, struct ref *list); int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1); -- cgit v1.2.3 From 28f5d176110d2ed768a0a49159993c7a02d8cb15 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 8 Jul 2013 15:34:36 -0700 Subject: remote.c: add command line option parser for "--force-with-lease" Update "git push" and "git send-pack" to parse this commnd line option. The intended sematics is: * "--force-with-lease" alone, without specifying the details, will protect _all_ remote refs that are going to be updated by requiring their current value to be the same as some reasonable default, unless otherwise specified; * "--force-with-lease=refname", without specifying the expected value, will protect that refname, if it is going to be updated, by requiring its current value to be the same as some reasonable default. * "--force-with-lease=refname:value" will protect that refname, if it is going to be updated, by requiring its current value to be the same as the specified value; and * "--no-force-with-lease" will cancel all the previous --force-with-lease on the command line. For now, "some reasonable default" is tentatively defined as "the value of the remote-tracking branch we have for the ref of the remote being updated", and it is an error if we do not have such a remote-tracking branch. But this is known to be fragile, its use is not yet recommended, and hopefully we will find more reasonable default as we gain experience with this feature. The manual marks the feature as experimental unless the expected value is specified explicitly for this reason. Because the command line options are parsed _before_ we know which remote we are pushing to, there needs further processing to the parsed data after we instantiate the transport object to: * expand "refname" given by the user to a full refname to be matched with the list of "struct ref" used in match_push_refs() and set_ref_status_for_push(); and * learning the actual local ref that is the remote-tracking branch for the specified remote ref. Further, some processing need to be deferred until we find the set of remote refs and match_push_refs() returns in order to find the ones that need to be checked after explicit ones have been processed for "--force-with-lease" (no specific details). These post-processing will be the topic of the next patch. This option was originally called "cas" (for "compare and swap"), the name which nobody liked because it was too technical. The second attempt called it "lockref" (because it is conceptually like pushing after taking a lock) but the word "lock" was hated because it implied that it may reject push by others, which is not the way this option works. This round calls it "force-with-lease". You assume you took the lease on the ref when you fetched to decide what the rebased history should be, and you can push back only if the lease has not been broken. Signed-off-by: Junio C Hamano --- remote.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'remote.h') diff --git a/remote.h b/remote.h index a850059804..843c3cef45 100644 --- a/remote.h +++ b/remote.h @@ -1,6 +1,8 @@ #ifndef REMOTE_H #define REMOTE_H +#include "parse-options.h" + enum { REMOTE_CONFIG, REMOTE_REMOTES, @@ -226,4 +228,24 @@ struct ref *guess_remote_head(const struct ref *head, /* Return refs which no longer exist on remote */ struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map); +/* + * Compare-and-swap + */ +#define CAS_OPT_NAME "force-with-lease" + +struct push_cas_option { + unsigned use_tracking_for_rest:1; + struct push_cas { + unsigned char expect[20]; + unsigned use_tracking:1; + char *refname; + } *entry; + int nr; + int alloc; +}; + +extern int parseopt_push_cas_option(const struct option *, const char *arg, int unset); +extern int parse_push_cas_option(struct push_cas_option *, const char *arg, int unset); +extern void clear_cas_option(struct push_cas_option *); + #endif -- cgit v1.2.3 From 91048a9537a4716c84934e4f8ed114a20606d3ff Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 9 Jul 2013 11:01:06 -0700 Subject: push --force-with-lease: implement logic to populate old_sha1_expect[] This plugs the push_cas_option data collected by the command line option parser to the transport system with a new function apply_push_cas(), which is called after match_push_refs() has already been called. At this point, we know which remote we are talking to, and what remote refs we are going to update, so we can fill in the details that may have been missing from the command line, such as (1) what abbreviated refname the user gave us matches the actual refname at the remote; and (2) which remote-tracking branch in our local repository to read the value of the object to expect at the remote. to populate the old_sha1_expect[] field of each of the remote ref. As stated in the documentation, the use of remote-tracking branch as the default is a tentative one, and we may come up with a better logic as we gain experience. Still nobody uses this information, which is the topic of the next patch. Signed-off-by: Junio C Hamano --- remote.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'remote.h') diff --git a/remote.h b/remote.h index 843c3cef45..ca3c8c8de8 100644 --- a/remote.h +++ b/remote.h @@ -77,10 +77,13 @@ struct ref { struct ref *next; unsigned char old_sha1[20]; unsigned char new_sha1[20]; + unsigned char old_sha1_expect[20]; /* used by expect-old */ char *symref; unsigned int force:1, forced_update:1, + expect_old_sha1:1, + expect_old_no_trackback:1, deletion:1, matched:1; @@ -248,4 +251,7 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int extern int parse_push_cas_option(struct push_cas_option *, const char *arg, int unset); extern void clear_cas_option(struct push_cas_option *); +extern int is_empty_cas(const struct push_cas_option *); +void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *); + #endif -- cgit v1.2.3 From 631b5ef219c41027c144218e25075062b91f9471 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 8 Jul 2013 14:42:40 -0700 Subject: push --force-with-lease: tie it all together This teaches the deepest part of the callchain for "git push" (and "git send-pack") to enforce "the old value of the ref must be this, otherwise fail this push" (aka "compare-and-swap" / "--lockref"). Signed-off-by: Junio C Hamano --- remote.h | 1 + 1 file changed, 1 insertion(+) (limited to 'remote.h') diff --git a/remote.h b/remote.h index ca3c8c8de8..6c42554cc2 100644 --- a/remote.h +++ b/remote.h @@ -107,6 +107,7 @@ struct ref { REF_STATUS_REJECT_NODELETE, REF_STATUS_REJECT_FETCH_FIRST, REF_STATUS_REJECT_NEEDS_FORCE, + REF_STATUS_REJECT_STALE, REF_STATUS_UPTODATE, REF_STATUS_REMOTE_REJECT, REF_STATUS_EXPECTING_REPORT -- cgit v1.2.3