Merge pull request #4261 from RogerGee/fix_wait_while_ack

smart_protocol: fix parsing of server ACK responses
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bcf8160..1b9e0c9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,19 +1,100 @@
-v0.25 + 1
--------
+v0.26 + 1
+---------
 
 ### Changes or improvements
 
+### API additions
+
+### API removals
+
+### Breaking API changes
+
+v0.26
+-----
+
+### Changes or improvements
+
+* Support for opening, creating and modifying worktrees.
+
+* We can now detect SHA1 collisions resulting from the SHAttered attack. These
+  checks can be enabled at build time via `-DUSE_SHA1DC`.
+
+* Fix for missing implementation of `git_merge_driver_source` getters.
+
+* Fix for installed pkg-config file being broken when the prefix contains
+  spaces.
+
+* We now detect when the hashsum of on-disk objects does not match their
+  expected hashsum.
+
+* We now support open-ended ranges (e.g. "master..", "...master") in our
+  revision range parsing code.
+
+* We now correctly compute ignores with leading "/" in subdirectories.
+
+* We now optionally call `fsync` on loose objects, packfiles and their indexes,
+  loose references and packed reference files.
+
+* We can now build against OpenSSL v1.1 and against LibreSSL.
+
 * `GIT_MERGE_OPTIONS_INIT` now includes a setting to perform rename detection.
   This aligns this structure with the default by `git_merge` and
   `git_merge_trees` when `NULL` was provided for the options.
 
+* Improvements for reading index v4 files.
+
+* Perform additional retries for filesystem operations on Windows when files
+  are temporarily locked by other processes.
+
 ### API additions
 
+* New family of functions to handle worktrees:
+
+    * `git_worktree_list()` lets you look up worktrees for a repository.
+    * `git_worktree_lookup()` lets you get a specific worktree.
+    * `git_worktree_open_from_repository()` lets you get the associated worktree
+      of a repository.
+      a worktree.
+    * `git_worktree_add` lets you create new worktrees.
+    * `git_worktree_prune` lets you remove worktrees from disk.
+    * `git_worktree_lock()` and `git_worktree_unlock()` let you lock
+      respectively unlock a worktree.
+    * `git_repository_open_from_worktree()` lets you open a repository via
+    * `git_repository_head_for_worktree()` lets you get the current `HEAD` for a
+      linked worktree.
+    * `git_repository_head_detached_for_worktree()` lets you check whether a
+      linked worktree is in detached HEAD mode.
+
+* `git_repository_item_path()` lets you retrieve paths for various repository
+  files.
+
+* `git_repository_commondir()` lets you retrieve the common directory of a
+  repository.
+
+* `git_branch_is_checked_out()` allows you to check whether a branch is checked
+  out in a repository or any of its worktrees.
+
+* `git_repository_submodule_cache_all()` and
+  `git_repository_submodule_cache_clear()` functions allow you to prime or clear
+  the submodule cache of a repository.
+
+* You can disable strict hash verifications via the
+  `GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION` option with `git_libgit2_opts()`.
+
+* You can enable us calling `fsync` for various files inside the ".git"
+  directory by setting the `GIT_OPT_ENABLE_FSYNC_GITDIR` option with
+  `git_libgit2_opts()`.
+
+* You can now enable "offset deltas" when creating packfiles and negotiating
+  packfiles with a remote server by setting `GIT_OPT_ENABLE_OFS_DELTA` option
+  with `GIT_libgit2_opts()`.
+
 * You can now set the default share mode on Windows for opening files using
   `GIT_OPT_SET_WINDOWS_SHAREMODE` option with `git_libgit2_opts()`.
   You can query the current share mode with `GIT_OPT_GET_WINDOWS_SHAREMODE`.
 
-### API removals
+* `git_transport_smart_proxy_options()' enables you to get the proxy options for
+  smart transports.
 
 ### Breaking API changes
 
diff --git a/include/git2/version.h b/include/git2/version.h
index 0df191f..becf97b 100644
--- a/include/git2/version.h
+++ b/include/git2/version.h
@@ -7,12 +7,12 @@
 #ifndef INCLUDE_git_version_h__
 #define INCLUDE_git_version_h__
 
-#define LIBGIT2_VERSION "0.25.0"
+#define LIBGIT2_VERSION "0.26.0"
 #define LIBGIT2_VER_MAJOR 0
-#define LIBGIT2_VER_MINOR 25
+#define LIBGIT2_VER_MINOR 26
 #define LIBGIT2_VER_REVISION 0
 #define LIBGIT2_VER_PATCH 0
 
-#define LIBGIT2_SOVERSION 25
+#define LIBGIT2_SOVERSION 26
 
 #endif
diff --git a/src/checkout.c b/src/checkout.c
index 9d1eed5..25018d2 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -370,10 +370,8 @@
 			 */
 			const git_index_entry *e = git_index_get_byindex(data->index, pos);
 
-			if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0) {
-				notify = GIT_CHECKOUT_NOTIFY_DIRTY;
-				remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0);
-			}
+			if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0)
+				return git_iterator_advance_into(wditem, workdir);
 		}
 	}
 
diff --git a/src/fileops.c b/src/fileops.c
index bda17f0..2f3f58d 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -770,6 +770,9 @@
 
 		if (en == ENOENT || en == ENOTDIR) {
 			/* do nothing */
+		} else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0 &&
+			en == EBUSY) {
+			error = git_path_set_error(errno, path, "rmdir");
 		} else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) {
 			error = GIT_ITEROVER;
 		} else {
diff --git a/src/indexer.c b/src/indexer.c
index 68cd205..15f6cc2 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -937,7 +937,6 @@
 	git_buf filename = GIT_BUF_INIT;
 	struct entry *entry;
 	git_oid trailer_hash, file_hash;
-	git_hash_ctx ctx;
 	git_filebuf index_file = {0};
 	void *packfile_trailer;
 
@@ -946,9 +945,6 @@
 		return -1;
 	}
 
-	if (git_hash_ctx_init(&ctx) < 0)
-		return -1;
-
 	/* Test for this before resolve_deltas(), as it plays with idx->off */
 	if (idx->off + 20 < idx->pack->mwf.size) {
 		giterr_set(GITERR_INDEXER, "unexpected data at the end of the pack");
@@ -992,6 +988,10 @@
 
 	git_vector_sort(&idx->objects);
 
+	/* Use the trailer hash as the pack file name to ensure
+	 * files with different contents have different names */
+	git_oid_cpy(&idx->hash, &trailer_hash);
+
 	git_buf_sets(&filename, idx->pack->pack_name);
 	git_buf_shorten(&filename, strlen("pack"));
 	git_buf_puts(&filename, "idx");
@@ -1018,9 +1018,7 @@
 	/* Write out the object names (SHA-1 hashes) */
 	git_vector_foreach(&idx->objects, i, entry) {
 		git_filebuf_write(&index_file, &entry->oid, sizeof(git_oid));
-		git_hash_update(&ctx, &entry->oid, GIT_OID_RAWSZ);
 	}
-	git_hash_final(&idx->hash, &ctx);
 
 	/* Write out the CRC32 values */
 	git_vector_foreach(&idx->objects, i, entry) {
@@ -1106,14 +1104,12 @@
 	idx->pack_committed = 1;
 
 	git_buf_free(&filename);
-	git_hash_ctx_cleanup(&ctx);
 	return 0;
 
 on_error:
 	git_mwindow_free_all(&idx->pack->mwf);
 	git_filebuf_cleanup(&index_file);
 	git_buf_free(&filename);
-	git_hash_ctx_cleanup(&ctx);
 	return -1;
 }
 
diff --git a/src/odb.c b/src/odb.c
index b66324f..ae8f247 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -1116,8 +1116,11 @@
 		if (b->read_prefix != NULL) {
 			git_oid full_oid;
 			error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, key, len);
-			if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH)
+
+			if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) {
+				error = 0;
 				continue;
+			}
 
 			if (error)
 				goto out;
diff --git a/tests/checkout/head.c b/tests/checkout/head.c
index 07cc1d2..ded86df 100644
--- a/tests/checkout/head.c
+++ b/tests/checkout/head.c
@@ -38,7 +38,7 @@
 	cl_git_pass(git_repository_index(&index, g_repo));
 
 	p_mkdir("testrepo/newdir", 0777);
-    cl_git_mkfile("testrepo/newdir/newfile.txt", "new file\n");
+	cl_git_mkfile("testrepo/newdir/newfile.txt", "new file\n");
 
 	cl_git_pass(git_index_add_bypath(index, "newdir/newfile.txt"));
 	cl_git_pass(git_index_write(index));
@@ -60,3 +60,79 @@
 
 	git_index_free(index);
 }
+
+void test_checkout_head__do_not_remove_untracked_file(void)
+{
+	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+	git_index *index;
+
+	cl_git_pass(p_mkdir("testrepo/tracked", 0755));
+	cl_git_mkfile("testrepo/tracked/tracked", "tracked\n");
+	cl_git_mkfile("testrepo/tracked/untracked", "untracked\n");
+
+	cl_git_pass(git_repository_index(&index, g_repo));
+	cl_git_pass(git_index_add_bypath(index, "tracked/tracked"));
+	cl_git_pass(git_index_write(index));
+
+	git_index_free(index);
+
+	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+	cl_git_pass(git_checkout_head(g_repo, &opts));
+
+	cl_assert(!git_path_isfile("testrepo/tracked/tracked"));
+	cl_assert(git_path_isfile("testrepo/tracked/untracked"));
+}
+
+void test_checkout_head__do_not_remove_untracked_file_in_subdir(void)
+{
+	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+	git_index *index;
+
+	cl_git_pass(p_mkdir("testrepo/tracked", 0755));
+	cl_git_pass(p_mkdir("testrepo/tracked/subdir", 0755));
+	cl_git_mkfile("testrepo/tracked/tracked", "tracked\n");
+	cl_git_mkfile("testrepo/tracked/subdir/tracked", "tracked\n");
+	cl_git_mkfile("testrepo/tracked/subdir/untracked", "untracked\n");
+
+	cl_git_pass(git_repository_index(&index, g_repo));
+	cl_git_pass(git_index_add_bypath(index, "tracked/tracked"));
+	cl_git_pass(git_index_add_bypath(index, "tracked/subdir/tracked"));
+	cl_git_pass(git_index_write(index));
+
+	git_index_free(index);
+
+	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+	cl_git_pass(git_checkout_head(g_repo, &opts));
+
+	cl_assert(!git_path_isfile("testrepo/tracked/tracked"));
+	cl_assert(!git_path_isfile("testrepo/tracked/subdir/tracked"));
+	cl_assert(git_path_isfile("testrepo/tracked/subdir/untracked"));
+}
+
+void test_checkout_head__do_remove_tracked_subdir(void)
+{
+	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+	git_index *index;
+
+	cl_git_pass(p_mkdir("testrepo/subdir", 0755));
+	cl_git_pass(p_mkdir("testrepo/subdir/tracked", 0755));
+	cl_git_mkfile("testrepo/subdir/tracked-file", "tracked\n");
+	cl_git_mkfile("testrepo/subdir/untracked-file", "untracked\n");
+	cl_git_mkfile("testrepo/subdir/tracked/tracked1", "tracked\n");
+	cl_git_mkfile("testrepo/subdir/tracked/tracked2", "tracked\n");
+
+	cl_git_pass(git_repository_index(&index, g_repo));
+	cl_git_pass(git_index_add_bypath(index, "subdir/tracked-file"));
+	cl_git_pass(git_index_add_bypath(index, "subdir/tracked/tracked1"));
+	cl_git_pass(git_index_add_bypath(index, "subdir/tracked/tracked2"));
+	cl_git_pass(git_index_write(index));
+
+	git_index_free(index);
+
+	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+	cl_git_pass(git_checkout_head(g_repo, &opts));
+
+	cl_assert(!git_path_isdir("testrepo/subdir/tracked"));
+	cl_assert(!git_path_isfile("testrepo/subdir/tracked-file"));
+	cl_assert(git_path_isfile("testrepo/subdir/untracked-file"));
+}
diff --git a/tests/pack/indexer.c b/tests/pack/indexer.c
index 1e514b2..c73d397 100644
--- a/tests/pack/indexer.c
+++ b/tests/pack/indexer.c
@@ -85,7 +85,7 @@
 	cl_assert_equal_i(stats.indexed_objects, 2);
 	cl_assert_equal_i(stats.local_objects, 1);
 
-	git_oid_fromstr(&should_id, "11f0f69b334728fdd8bc86b80499f22f29d85b15");
+	git_oid_fromstr(&should_id, "fefdb2d740a3a6b6c03a0c7d6ce431c6d5810e13");
 	cl_assert_equal_oid(&should_id, git_indexer_hash(idx));
 
 	git_indexer_free(idx);
@@ -102,7 +102,7 @@
 		int fd;
 		ssize_t read;
 		struct stat st;
-		const char *name = "pack-11f0f69b334728fdd8bc86b80499f22f29d85b15.pack";
+		const char *name = "pack-fefdb2d740a3a6b6c03a0c7d6ce431c6d5810e13.pack";
 
 		fd = p_open(name, O_RDONLY);
 		cl_assert(fd != -1);
diff --git a/tests/pack/packbuilder.c b/tests/pack/packbuilder.c
index 9bea203..13ee073 100644
--- a/tests/pack/packbuilder.c
+++ b/tests/pack/packbuilder.c
@@ -116,7 +116,7 @@
 	 * $ cd tests/resources/testrepo.git
 	 * $ git rev-list --objects HEAD | \
 	 * 	git pack-objects -q --no-reuse-delta --threads=1 pack
-	 * $ sha1sum git-80e61eb315239ef3c53033e37fee43b744d57122.pack
+	 * $ sha1sum pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack
 	 * 5d410bdf97cf896f9007681b92868471d636954b
 	 *
 	 */
@@ -145,7 +145,7 @@
 	git_packbuilder_write(_packbuilder, ".", 0, NULL, NULL);
 	git_oid_fmt(hex, git_packbuilder_hash(_packbuilder));
 
-	cl_assert_equal_s(hex, "80e61eb315239ef3c53033e37fee43b744d57122");
+	cl_assert_equal_s(hex, "7f5fa362c664d68ba7221259be1cbd187434b2f0");
 }
 
 static void test_write_pack_permission(mode_t given, mode_t expected)
@@ -169,10 +169,10 @@
 	mask = p_umask(0);
 	p_umask(mask);
 
-	cl_git_pass(p_stat("pack-80e61eb315239ef3c53033e37fee43b744d57122.idx", &statbuf));
+	cl_git_pass(p_stat("pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.idx", &statbuf));
 	cl_assert_equal_i(statbuf.st_mode & os_mask, (expected & ~mask) & os_mask);
 
-	cl_git_pass(p_stat("pack-80e61eb315239ef3c53033e37fee43b744d57122.pack", &statbuf));
+	cl_git_pass(p_stat("pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack", &statbuf));
 	cl_assert_equal_i(statbuf.st_mode & os_mask, (expected & ~mask) & os_mask);
 }