Re: [PATCH 05/38] refs: create a base class "ref_store" for files_ref_store

2 messages, 2 authors, 2016-06-16 · open the first message on its own page

Re: [PATCH 05/38] refs: create a base class "ref_store" for files_ref_store

From: Junio C Hamano <hidden>
Date: 2016-06-16 02:19:47

This is a tangent, but your series that ends at 4aa2c475 (grep: -W:
don't extend context to trailing empty lines, 2016-05-28) does not
seem to have much effect when viewing the change to refs.c this
patch makes (it modifies a function in an early part, and then adds
bunch of new functions at the end) with "git show -W".

Thanks.

Michael Haggerty [off-list ref] writes:
quoted hunk
We want ref_stores to be polymorphic, so invent a base class of which
files_ref_store is a derived class. For now there is a one-to-one
relationship between ref_stores and submodules.

Signed-off-by: Michael Haggerty <redacted>
---
 refs.c               |  91 ++++++++++++++++++++++++++
 refs/files-backend.c | 179 +++++++++++++++++++++++++++++----------------------
 refs/refs-internal.h |  78 ++++++++++++++++++++++
 3 files changed, 271 insertions(+), 77 deletions(-)
diff --git a/refs.c b/refs.c
index f57a93e..5e20ae0 100644
--- a/refs.c
+++ b/refs.c
@@ -1151,8 +1151,12 @@ int head_ref(each_ref_fn fn, void *cb_data)
 static int do_for_each_ref(const char *submodule, const char *prefix,
 			   each_ref_fn fn, int trim, int flags, void *cb_data)
 {
+	struct ref_store *refs = get_ref_store(submodule);
 	struct ref_iterator *iter;
 
+	if (!refs)
+		return 0;
+
 	iter = files_ref_iterator_begin(submodule, prefix, flags);
 	iter = prefix_ref_iterator_begin(iter, prefix, trim);
 
@@ -1284,3 +1288,90 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
 	errno = ELOOP;
 	return NULL;
 }
+
+static struct ref_store *main_ref_store = NULL;
+
+static struct ref_store *submodule_ref_stores = NULL;
+
+void base_ref_store_init(struct ref_store *refs,
+			 const struct ref_storage_be *be,
+			 const char *submodule)
+{
+	refs->be = be;
+	if (!submodule) {
+		if (main_ref_store)
+			die("BUG: main_ref_store initialized twice");
+
+		refs->submodule = "";
+		refs->next = NULL;
+		main_ref_store = refs;
+	} else {
+		if (lookup_ref_store(submodule))
+			die("BUG: ref_store for submodule '%s' initialized twice",
+			    submodule);
+
+		refs->submodule = xstrdup(submodule);
+		refs->next = submodule_ref_stores;
+		submodule_ref_stores = refs;
+	}
+}
+
+struct ref_store *ref_store_init(const char *submodule)
+{
+	const char *be_name = "files";
+	struct ref_storage_be *be = find_ref_storage_backend(be_name);
+
+	if (!be)
+		die("BUG: reference backend %s is unknown", be_name);
+
+	if (!submodule || !*submodule)
+		return be->init(NULL);
+	else
+		return be->init(submodule);
+}
+
+struct ref_store *lookup_ref_store(const char *submodule)
+{
+	struct ref_store *refs;
+
+	if (!submodule || !*submodule)
+		return main_ref_store;
+
+	for (refs = submodule_ref_stores; refs; refs = refs->next) {
+		if (!strcmp(submodule, refs->submodule))
+			return refs;
+	}
+
+	return NULL;
+}
+
+struct ref_store *get_ref_store(const char *submodule)
+{
+	struct ref_store *refs;
+
+	if (!submodule || !*submodule) {
+		refs = lookup_ref_store(NULL);
+
+		if (!refs)
+			refs = ref_store_init(NULL);
+	} else {
+		refs = lookup_ref_store(submodule);
+
+		if (!refs) {
+			struct strbuf submodule_sb = STRBUF_INIT;
+
+			strbuf_addstr(&submodule_sb, submodule);
+			if (is_nonbare_repository_dir(&submodule_sb))
+				refs = ref_store_init(submodule);
+			strbuf_release(&submodule_sb);
+		}
+	}
+
+	return refs;
+}
+
+void assert_main_repository(struct ref_store *refs, const char *caller)
+{
+	if (*refs->submodule)
+		die("BUG: %s called for a submodule", caller);
+}
diff --git a/refs/files-backend.c b/refs/files-backend.c
index bde6f0e..8ef79c2 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -910,17 +910,11 @@ struct packed_ref_cache {
  * Future: need to be in "struct repository"
  * when doing a full libification.
  */
-static struct files_ref_store {
-	struct files_ref_store *next;
+struct files_ref_store {
+	struct ref_store base;
 	struct ref_entry *loose;
 	struct packed_ref_cache *packed;
-	/*
-	 * The submodule name, or "" for the main repo. We allocate
-	 * length 1 rather than FLEX_ARRAY so that the main
-	 * files_ref_store is initialized correctly.
-	 */
-	char name[1];
-} ref_store, *submodule_ref_stores;
+};
 
 /* Lock used for the main packed-refs file: */
 static struct lock_file packlock;
@@ -973,53 +967,54 @@ static void clear_loose_ref_cache(struct files_ref_store *refs)
  * Create a new submodule ref cache and add it to the internal
  * set of caches.
  */
-static struct files_ref_store *create_ref_store(const char *submodule)
+static struct ref_store *files_ref_store_create(const char *submodule)
 {
-	struct files_ref_store *refs;
-	if (!submodule)
-		submodule = "";
-	FLEX_ALLOC_STR(refs, name, submodule);
-	refs->next = submodule_ref_stores;
-	submodule_ref_stores = refs;
-	return refs;
+	struct files_ref_store *refs = xcalloc(1, sizeof(*refs));
+	struct ref_store *ref_store = (struct ref_store *)refs;
+
+	base_ref_store_init(ref_store, &refs_be_files, submodule);
+
+	return ref_store;
 }
 
-static struct files_ref_store *lookup_ref_store(const char *submodule)
+/*
+ * Downcast ref_store to files_ref_store. Die if ref_store is not a
+ * files_ref_store. If submodule_allowed is not true, then also die if
+ * files_ref_store is for a submodule (i.e., not for the main
+ * repository). caller is used in any necessary error messages.
+ */
+static struct files_ref_store *files_downcast(
+		struct ref_store *ref_store, int submodule_allowed,
+		const char *caller)
 {
 	struct files_ref_store *refs;
 
-	if (!submodule || !*submodule)
-		return &ref_store;
+	if (ref_store->be != &refs_be_files)
+		die("BUG: ref_store is type \"%s\" not \"files\" in %s",
+		    ref_store->be->name, caller);
 
-	for (refs = submodule_ref_stores; refs; refs = refs->next)
-		if (!strcmp(submodule, refs->name))
-			return refs;
-	return NULL;
+	refs = (struct files_ref_store *)ref_store;
+
+	if (!submodule_allowed)
+		assert_main_repository(ref_store, caller);
+
+	return refs;
 }
 
 /*
- * Return a pointer to a files_ref_store for the specified submodule. For
- * the main repository, use submodule==NULL; such a call cannot fail.
- * For a submodule, the submodule must exist and be a nonbare
- * repository, otherwise return NULL.
- *
- * The returned structure will be allocated and initialized but not
- * necessarily populated; it should not be freed.
+ * Return a pointer to the reference store for the specified
+ * submodule. For the main repository, use submodule==NULL; such a
+ * call cannot fail. For a submodule, the submodule must exist and be
+ * a nonbare repository, otherwise return NULL. Verify that the
+ * reference store is a files_ref_store, and cast it to that type
+ * before returning it.
  */
-static struct files_ref_store *get_ref_store(const char *submodule)
+static struct files_ref_store *get_files_ref_store(const char *submodule,
+						   const char *caller)
 {
-	struct files_ref_store *refs = lookup_ref_store(submodule);
+	struct ref_store *refs = get_ref_store(submodule);
 
-	if (!refs) {
-		struct strbuf submodule_sb = STRBUF_INIT;
-
-		strbuf_addstr(&submodule_sb, submodule);
-		if (is_nonbare_repository_dir(&submodule_sb))
-			refs = create_ref_store(submodule);
-		strbuf_release(&submodule_sb);
-	}
-
-	return refs;
+	return refs ? files_downcast(refs, 1, caller) : NULL;
 }
 
 /* The length of a peeled reference line in packed-refs, including EOL: */
@@ -1158,8 +1153,9 @@ static struct packed_ref_cache *get_packed_ref_cache(struct files_ref_store *ref
 {
 	char *packed_refs_file;
 
-	if (*refs->name)
-		packed_refs_file = git_pathdup_submodule(refs->name, "packed-refs");
+	if (*refs->base.submodule)
+		packed_refs_file = git_pathdup_submodule(refs->base.submodule,
+							 "packed-refs");
 	else
 		packed_refs_file = git_pathdup("packed-refs");
 
@@ -1202,8 +1198,9 @@ static struct ref_dir *get_packed_refs(struct files_ref_store *refs)
  */
 static void add_packed_ref(const char *refname, const unsigned char *sha1)
 {
-	struct packed_ref_cache *packed_ref_cache =
-		get_packed_ref_cache(&ref_store);
+	struct files_ref_store *refs =
+		get_files_ref_store(NULL, "add_packed_ref");
+	struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(refs);
 
 	if (!packed_ref_cache->lock)
 		die("internal error: packed refs not locked");
@@ -1226,8 +1223,8 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
 	struct strbuf path = STRBUF_INIT;
 	size_t path_baselen;
 
-	if (*refs->name)
-		strbuf_git_path_submodule(&path, refs->name, "%s", dirname);
+	if (*refs->base.submodule)
+		strbuf_git_path_submodule(&path, refs->base.submodule, "%s", dirname);
 	else
 		strbuf_git_path(&path, "%s", dirname);
 	path_baselen = path.len;
@@ -1262,10 +1259,10 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
 		} else {
 			int read_ok;
 
-			if (*refs->name) {
+			if (*refs->base.submodule) {
 				hashclr(sha1);
 				flag = 0;
-				read_ok = !resolve_gitlink_ref(refs->name,
+				read_ok = !resolve_gitlink_ref(refs->base.submodule,
 							       refname.buf, sha1);
 			} else {
 				read_ok = !read_ref_full(refname.buf,
@@ -1355,8 +1352,8 @@ static int resolve_gitlink_ref_recursive(struct files_ref_store *refs,
 
 	if (recursion > SYMREF_MAXDEPTH || strlen(refname) > MAXREFLEN)
 		return -1;
-	path = *refs->name
-		? git_pathdup_submodule(refs->name, "%s", refname)
+	path = *refs->base.submodule
+		? git_pathdup_submodule(refs->base.submodule, "%s", refname)
 		: git_pathdup("%s", refname);
 	fd = open(path, O_RDONLY);
 	free(path);
@@ -1397,7 +1394,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh
 		return -1;
 
 	strbuf_add(&submodule, path, len);
-	refs = get_ref_store(submodule.buf);
+	refs = get_files_ref_store(submodule.buf, "resolve_gitlink_ref");
 	if (!refs) {
 		strbuf_release(&submodule);
 		return -1;
@@ -1413,7 +1410,10 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh
  */
 static struct ref_entry *get_packed_ref(const char *refname)
 {
-	return find_ref(get_packed_refs(&ref_store), refname);
+	struct files_ref_store *refs =
+		get_files_ref_store(NULL, "get_packed_ref");
+
+	return find_ref(get_packed_refs(refs), refname);
 }
 
 /*
@@ -1613,6 +1613,8 @@ static int lock_raw_ref(const char *refname, int mustexist,
 			unsigned int *type,
 			struct strbuf *err)
 {
+	struct files_ref_store *refs =
+		get_files_ref_store(NULL, "lock_raw_ref");
 	struct ref_lock *lock;
 	struct strbuf ref_file = STRBUF_INIT;
 	int attempts_remaining = 3;
@@ -1745,7 +1747,7 @@ retry:
 							  REMOVE_DIR_EMPTY_ONLY)) {
 				if (verify_refname_available_dir(
 						    refname, extras, skip,
-						    get_loose_refs(&ref_store),
+						    get_loose_refs(refs),
 						    err)) {
 					/*
 					 * The error message set by
@@ -1784,7 +1786,7 @@ retry:
 		 */
 		if (verify_refname_available_dir(
 				    refname, extras, skip,
-				    get_packed_refs(&ref_store),
+				    get_packed_refs(refs),
 				    err)) {
 			goto error_return;
 		}
@@ -1942,7 +1944,8 @@ struct ref_iterator *files_ref_iterator_begin(
 		const char *submodule,
 		const char *prefix, unsigned int flags)
 {
-	struct files_ref_store *refs = get_ref_store(submodule);
+	struct files_ref_store *refs =
+		get_files_ref_store(submodule, "ref_iterator_begin");
 	struct ref_dir *loose_dir, *packed_dir;
 	struct ref_iterator *loose_iter, *packed_iter;
 	struct files_ref_iterator *iter;
@@ -2065,6 +2068,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
 					    unsigned int flags, int *type,
 					    struct strbuf *err)
 {
+	struct files_ref_store *refs =
+		get_files_ref_store(NULL, "lock_ref_sha1_basic");
 	struct strbuf ref_file = STRBUF_INIT;
 	struct ref_lock *lock;
 	int last_errno = 0;
@@ -2095,8 +2100,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
 		 */
 		if (remove_empty_directories(&ref_file)) {
 			last_errno = errno;
-			if (!verify_refname_available_dir(refname, extras, skip,
-							  get_loose_refs(&ref_store), err))
+			if (!verify_refname_available_dir(
+					    refname, extras, skip,
+					    get_loose_refs(refs), err))
 				strbuf_addf(err, "there are still refs under '%s'",
 					    refname);
 			goto error_return;
@@ -2107,8 +2113,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
 	if (!resolved) {
 		last_errno = errno;
 		if (last_errno != ENOTDIR ||
-		    !verify_refname_available_dir(refname, extras, skip,
-						  get_loose_refs(&ref_store), err))
+		    !verify_refname_available_dir(
+				    refname, extras, skip,
+				    get_loose_refs(refs), err))
 			strbuf_addf(err, "unable to resolve reference '%s': %s",
 				    refname, strerror(last_errno));
 
@@ -2123,7 +2130,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
 	 */
 	if (is_null_oid(&lock->old_oid) &&
 	    verify_refname_available_dir(refname, extras, skip,
-					 get_packed_refs(&ref_store), err)) {
+					 get_packed_refs(refs),
+					 err)) {
 		last_errno = ENOTDIR;
 		goto error_return;
 	}
@@ -2212,9 +2220,10 @@ static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
  */
 static int lock_packed_refs(int flags)
 {
+	struct files_ref_store *refs =
+		get_files_ref_store(NULL, "lock_packed_refs");
 	static int timeout_configured = 0;
 	static int timeout_value = 1000;
-
 	struct packed_ref_cache *packed_ref_cache;
 
 	if (!timeout_configured) {
@@ -2232,7 +2241,7 @@ static int lock_packed_refs(int flags)
 	 * this will automatically invalidate the cache and re-read
 	 * the packed-refs file.
 	 */
-	packed_ref_cache = get_packed_ref_cache(&ref_store);
+	packed_ref_cache = get_packed_ref_cache(refs);
 	packed_ref_cache->lock = &packlock;
 	/* Increment the reference count to prevent it from being freed: */
 	acquire_packed_ref_cache(packed_ref_cache);
@@ -2247,8 +2256,10 @@ static int lock_packed_refs(int flags)
  */
 static int commit_packed_refs(void)
 {
+	struct files_ref_store *refs =
+		get_files_ref_store(NULL, "commit_packed_refs");
 	struct packed_ref_cache *packed_ref_cache =
-		get_packed_ref_cache(&ref_store);
+		get_packed_ref_cache(refs);
 	int error = 0;
 	int save_errno = 0;
 	FILE *out;
@@ -2281,15 +2292,17 @@ static int commit_packed_refs(void)
  */
 static void rollback_packed_refs(void)
 {
+	struct files_ref_store *refs =
+		get_files_ref_store(NULL, "rollback_packed_refs");
 	struct packed_ref_cache *packed_ref_cache =
-		get_packed_ref_cache(&ref_store);
+		get_packed_ref_cache(refs);
 
 	if (!packed_ref_cache->lock)
 		die("internal error: packed-refs not locked");
 	rollback_lock_file(packed_ref_cache->lock);
 	packed_ref_cache->lock = NULL;
 	release_packed_ref_cache(packed_ref_cache);
-	clear_packed_ref_cache(&ref_store);
+	clear_packed_ref_cache(refs);
 }
 
 struct ref_to_prune {
@@ -2422,15 +2435,17 @@ static void prune_refs(struct ref_to_prune *r)
 
 int pack_refs(unsigned int flags)
 {
+	struct files_ref_store *refs =
+		get_files_ref_store(NULL, "pack_refs");
 	struct pack_refs_cb_data cbdata;
 
 	memset(&cbdata, 0, sizeof(cbdata));
 	cbdata.flags = flags;
 
 	lock_packed_refs(LOCK_DIE_ON_ERROR);
-	cbdata.packed_refs = get_packed_refs(&ref_store);
+	cbdata.packed_refs = get_packed_refs(refs);
 
-	do_for_each_entry_in_dir(get_loose_refs(&ref_store), 0,
+	do_for_each_entry_in_dir(get_loose_refs(refs), 0,
 				 pack_if_possible_fn, &cbdata);
 
 	if (commit_packed_refs())
@@ -2449,6 +2464,8 @@ int pack_refs(unsigned int flags)
  */
 static int repack_without_refs(struct string_list *refnames, struct strbuf *err)
 {
+	struct files_ref_store *refs =
+		get_files_ref_store(NULL, "repack_without_refs");
 	struct ref_dir *packed;
 	struct string_list_item *refname;
 	int ret, needs_repacking = 0, removed = 0;
@@ -2471,7 +2488,7 @@ static int repack_without_refs(struct string_list *refnames, struct strbuf *err)
 		unable_to_lock_message(git_path("packed-refs"), errno, err);
 		return -1;
 	}
-	packed = get_packed_refs(&ref_store);
+	packed = get_packed_refs(refs);
 
 	/* Remove refnames from the cache */
 	for_each_string_list_item(refname, refnames)
@@ -2616,8 +2633,10 @@ int verify_refname_available(const char *newname,
 			     const struct string_list *skip,
 			     struct strbuf *err)
 {
-	struct ref_dir *packed_refs = get_packed_refs(&ref_store);
-	struct ref_dir *loose_refs = get_loose_refs(&ref_store);
+	struct files_ref_store *refs =
+		get_files_ref_store(NULL, "verify_refname_available");
+	struct ref_dir *packed_refs = get_packed_refs(refs);
+	struct ref_dir *loose_refs = get_loose_refs(refs);
 
 	if (verify_refname_available_dir(newname, extras, skip,
 					 packed_refs, err) ||
@@ -2968,7 +2987,10 @@ static int commit_ref_update(struct ref_lock *lock,
 			     const unsigned char *sha1, const char *logmsg,
 			     struct strbuf *err)
 {
-	clear_loose_ref_cache(&ref_store);
+	struct files_ref_store *refs =
+		get_files_ref_store(NULL, "commit_ref_update");
+
+	clear_loose_ref_cache(refs);
 	if (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, 0, err)) {
 		char *old_msg = strbuf_detach(err, NULL);
 		strbuf_addf(err, "cannot update the ref '%s': %s",
@@ -3683,6 +3705,8 @@ static int lock_ref_for_update(struct ref_update *update,
 int ref_transaction_commit(struct ref_transaction *transaction,
 			   struct strbuf *err)
 {
+	struct files_ref_store *refs =
+		get_files_ref_store(NULL, "ref_transaction_commit");
 	int ret = 0, i;
 	struct ref_update **updates = transaction->updates;
 	struct string_list refs_to_delete = STRING_LIST_INIT_NODUP;
@@ -3790,7 +3814,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
 			}
 		}
 		if (update->flags & REF_NEEDS_COMMIT) {
-			clear_loose_ref_cache(&ref_store);
+			clear_loose_ref_cache(refs);
 			if (commit_ref(lock)) {
 				strbuf_addf(err, "couldn't set '%s'", lock->ref_name);
 				unlock_ref(lock);
@@ -3823,7 +3847,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
 	}
 	for_each_string_list_item(ref_to_delete, &refs_to_delete)
 		unlink_or_warn(git_path("logs/%s", ref_to_delete->string));
-	clear_loose_ref_cache(&ref_store);
+	clear_loose_ref_cache(refs);
 
 cleanup:
 	transaction->state = REF_TRANSACTION_CLOSED;
@@ -4069,5 +4093,6 @@ int reflog_expire(const char *refname, const unsigned char *sha1,
 
 struct ref_storage_be refs_be_files = {
 	NULL,
-	"files"
+	"files",
+	files_ref_store_create
 };
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index 4d88849..d6c74cf 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -521,11 +521,89 @@ int read_raw_ref(const char *refname, unsigned char *sha1,
 		 struct strbuf *referent, unsigned int *type);
 
 /* refs backends */
+
+/*
+ * Initialize the ref_store for the specified submodule, or for the
+ * main repository if submodule == NULL. These functions should call
+ * base_ref_store_init() to initialize the shared part of the
+ * ref_store and to record the ref_store for later lookup.
+ */
+typedef struct ref_store *ref_store_init_fn(const char *submodule);
+
 struct ref_storage_be {
 	struct ref_storage_be *next;
 	const char *name;
+	ref_store_init_fn *init;
 };
 
 extern struct ref_storage_be refs_be_files;
 
+/*
+ * A representation of the reference store for the main repository or
+ * a submodule. The ref_store instances for submodules are kept in a
+ * linked list.
+ */
+struct ref_store {
+	/* The backend describing this ref_store's storage scheme: */
+	const struct ref_storage_be *be;
+
+	/*
+	 * The name of the submodule represented by this object, or
+	 * the empty string if it represents the main repository's
+	 * reference store:
+	 */
+	const char *submodule;
+
+	/*
+	 * Submodule reference store instances are stored in a linked
+	 * list using this pointer.
+	 */
+	struct ref_store *next;
+};
+
+/*
+ * Fill in the generic part of refs for the specified submodule and
+ * add it to our collection of reference stores.
+ */
+void base_ref_store_init(struct ref_store *refs,
+			 const struct ref_storage_be *be,
+			 const char *submodule);
+
+/*
+ * Create, record, and return a ref_store instance for the specified
+ * submodule (or the main repository if submodule is NULL).
+ *
+ * For backwards compatibility, submodule=="" is treated the same as
+ * submodule==NULL.
+ */
+struct ref_store *ref_store_init(const char *submodule);
+
+/*
+ * Return the ref_store instance for the specified submodule (or the
+ * main repository if submodule is NULL). If that ref_store hasn't
+ * been initialized yet, return NULL.
+ *
+ * For backwards compatibility, submodule=="" is treated the same as
+ * submodule==NULL.
+ */
+struct ref_store *lookup_ref_store(const char *submodule);
+
+/*
+ * Return the ref_store instance for the specified submodule. For the
+ * main repository, use submodule==NULL; such a call cannot fail. For
+ * a submodule, the submodule must exist and be a nonbare repository,
+ * otherwise return NULL. If the requested reference store has not yet
+ * been initialized, initialize it first.
+ *
+ * For backwards compatibility, submodule=="" is treated the same as
+ * submodule==NULL.
+ */
+struct ref_store *get_ref_store(const char *submodule);
+
+/*
+ * Die if refs is for a submodule (i.e., not for the main repository).
+ * caller is used in any necessary error messages.
+ */
+void assert_main_repository(struct ref_store *refs, const char *caller);
+
 #endif /* REFS_REFS_INTERNAL_H */

Re: [PATCH 05/38] refs: create a base class "ref_store" for files_ref_store

From: René Scharfe <hidden>
Date: 2016-06-16 02:19:50

Am 07.06.2016 um 18:31 schrieb Junio C Hamano:
This is a tangent, but your series that ends at 4aa2c475 (grep: -W:
don't extend context to trailing empty lines, 2016-05-28) does not
seem to have much effect when viewing the change to refs.c this
patch makes (it modifies a function in an early part, and then adds
bunch of new functions at the end) with "git show -W".

Thanks.
Good catch, thanks!

-- >8 --
Subject: [PATCH] xdiff: fix merging of appended hunk with -W

When -W is given we search the lines between the end of the current
context and the next change for a function line.  If there is none then
we merge those two hunks as they must be part of the same function.

If the next change is an appended chunk we abort the search early in
get_func_line(), however, because its line number is out of range.  Fix
that by searching from the end of the pre-image in that case instead.

Reported-by: Junio C Hamano <redacted>
Signed-off-by: Rene Scharfe <redacted>
---
 t/t4051-diff-function-context.sh | 24 +++++++++++++++++++++++-
 xdiff/xemit.c                    |  3 ++-
 2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/t/t4051-diff-function-context.sh b/t/t4051-diff-function-context.sh
index b6bb04a..b79b877 100755
--- a/t/t4051-diff-function-context.sh
+++ b/t/t4051-diff-function-context.sh
@@ -64,7 +64,13 @@ test_expect_success 'setup' '
 
 	grep -v "Begin of second part" <file.c >file.c.new &&
 	mv file.c.new file.c &&
-	commit_and_tag long_common_tail file.c
+	commit_and_tag long_common_tail file.c &&
+
+	git checkout initial &&
+	grep -v "delete me from hello" <file.c >file.c.new &&
+	mv file.c.new file.c &&
+	cat "$dir/appended1.c" >>file.c &&
+	commit_and_tag changed_hello_appended file.c
 '
 
 check_diff changed_hello 'changed function'
@@ -157,4 +163,20 @@ test_expect_success ' context does not include preceding empty lines' '
 	test "$(first_context_line <long_common_tail.diff.diff)" != " "
 '
 
+check_diff changed_hello_appended 'changed function plus appended function'
+
+test_expect_success ' context includes begin' '
+	grep "^ .*Begin of hello" changed_hello_appended.diff &&
+	grep "^[+].*Begin of first part" changed_hello_appended.diff
+'
+
+test_expect_success ' context includes end' '
+	grep "^ .*End of hello" changed_hello_appended.diff &&
+	grep "^[+].*End of first part" changed_hello_appended.diff
+'
+
+test_expect_success ' context does not include other functions' '
+	test $(grep -c "^[ +-].*Begin" changed_hello_appended.diff) -le 2
+'
+
 test_done
diff --git a/xdiff/xemit.c b/xdiff/xemit.c
index bfa53d3..49aa16f 100644
--- a/xdiff/xemit.c
+++ b/xdiff/xemit.c
@@ -246,7 +246,8 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
 			 * its new end.
 			 */
 			if (xche->next) {
-				long l = xche->next->i1;
+				long l = XDL_MIN(xche->next->i1,
+						 xe->xdf1.nrec - 1);
 				if (l <= e1 ||
 				    get_func_line(xe, xecfg, NULL, l, e1) < 0) {
 					xche = xche->next;
-- 
2.8.3
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help