summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml25
-rw-r--r--CMakeLists.txt2
-rw-r--r--deps/http-parser/CMakeLists.txt2
-rw-r--r--deps/regex/CMakeLists.txt2
-rw-r--r--deps/zlib/CMakeLists.txt2
-rw-r--r--examples/general.c31
-rw-r--r--include/git2/graph.h3
-rw-r--r--include/git2/remote.h20
-rwxr-xr-xscript/install-deps-linux.sh12
-rw-r--r--src/CMakeLists.txt37
-rw-r--r--src/checkout.c19
-rw-r--r--src/curl_stream.c3
-rw-r--r--src/posix.h3
-rw-r--r--src/proxy.c6
-rw-r--r--src/proxy.h1
-rw-r--r--src/refs.c8
-rw-r--r--src/socket_stream.c2
-rw-r--r--src/transports/smart_protocol.c12
-rw-r--r--tests/CMakeLists.txt6
-rw-r--r--tests/checkout/tree.c52
-rw-r--r--tests/refs/peel.c12
21 files changed, 197 insertions, 63 deletions
diff --git a/.travis.yml b/.travis.yml
index 8bbcb3929..13143458f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,6 @@
# see travis-ci.org for details
language: c
-dist: trusty
os:
- linux
@@ -22,7 +21,23 @@ env:
- OPTIONS="-DTHREADSAFE=OFF -DBUILD_EXAMPLES=ON -DENABLE_WERROR=ON"
dist: trusty
-sudo: true
+sudo: false
+
+addons:
+ apt:
+ sources:
+ - sourceline: 'deb http://libgit2deps.edwardthomson.com trusty libgit2deps'
+ key_url: 'https://pgp.mit.edu/pks/lookup?op=get&search=0x5656187599131CD5'
+ packages:
+ cmake
+ curl
+ libcurl3
+ libcurl3-gnutls
+ libcurl4-gnutls-dev
+ libssh2-1-dev
+ openssh-client
+ openssh-server
+ valgrind
matrix:
fast_finish: true
@@ -31,10 +46,6 @@ matrix:
compiler: gcc
include:
- compiler: gcc
- env: PRECISE=1
- os: linux
- dist: precise
- - compiler: gcc
env: COVERITY=1
os: linux
dist: trusty
@@ -48,7 +59,7 @@ matrix:
- env: COVERITY=1
install:
- - ./script/install-deps-${TRAVIS_OS_NAME}.sh
+ - if [ -f ./script/install-deps-${TRAVIS_OS_NAME}.sh ]; then ./script/install-deps-${TRAVIS_OS_NAME}.sh; fi
# Run the Build script and tests
script:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6d0479f81..b988f6110 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,7 +12,7 @@
# > cmake --build . --target install
PROJECT(libgit2 C)
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11)
CMAKE_POLICY(SET CMP0015 NEW)
IF (CMAKE_VERSION VERSION_GREATER 3.0)
CMAKE_POLICY(SET CMP0051 NEW)
diff --git a/deps/http-parser/CMakeLists.txt b/deps/http-parser/CMakeLists.txt
index 9309841db..77d9de7a3 100644
--- a/deps/http-parser/CMakeLists.txt
+++ b/deps/http-parser/CMakeLists.txt
@@ -1,3 +1,3 @@
FILE(GLOB SRC_HTTP "*.c" "*.h")
-ADD_LIBRARY(http-parser STATIC ${SRC_HTTP})
+ADD_LIBRARY(http-parser OBJECT ${SRC_HTTP})
diff --git a/deps/regex/CMakeLists.txt b/deps/regex/CMakeLists.txt
index 6ef8a270f..141b54c4c 100644
--- a/deps/regex/CMakeLists.txt
+++ b/deps/regex/CMakeLists.txt
@@ -1,2 +1,2 @@
INCLUDE_DIRECTORIES(".")
-ADD_LIBRARY(regex STATIC "regex.c" "regex.h")
+ADD_LIBRARY(regex OBJECT "regex.c" "regex.h")
diff --git a/deps/zlib/CMakeLists.txt b/deps/zlib/CMakeLists.txt
index ca50d80c4..b0cb7f7ea 100644
--- a/deps/zlib/CMakeLists.txt
+++ b/deps/zlib/CMakeLists.txt
@@ -1,4 +1,4 @@
ADD_DEFINITIONS(-DNO_VIZ -DSTDC -DNO_GZIP)
FILE(GLOB SRC_ZLIB "*.c" "*.h")
INCLUDE_DIRECTORIES(".")
-ADD_LIBRARY(zlib STATIC ${SRC_ZLIB})
+ADD_LIBRARY(zlib OBJECT ${SRC_ZLIB})
diff --git a/examples/general.c b/examples/general.c
index ff984a36c..0780d3d49 100644
--- a/examples/general.c
+++ b/examples/general.c
@@ -724,6 +724,7 @@ static void config_files(const char *repo_path, git_repository* repo)
int32_t autocorrect;
git_config *cfg;
git_config *snap_cfg;
+ int error_code;
printf("\n*Config Listing*\n");
@@ -740,9 +741,33 @@ static void config_files(const char *repo_path, git_repository* repo)
git_config_get_string(&email, snap_cfg, "user.email");
printf("Email: %s\n", email);
- /**
- * Remember to free the configurations after usage.
- */
+ error_code = git_config_get_int32(&autocorrect, cfg, "help.autocorrect");
+ switch (error_code)
+ {
+ case 0:
+ printf("Autocorrect: %d\n", autocorrect);
+ break;
+ case GIT_ENOTFOUND:
+ printf("Autocorrect: Undefined\n");
+ break;
+ default:
+ check_error(error_code, "get_int32 failed");
+ }
git_config_free(cfg);
+
+ check_error(git_repository_config_snapshot(&snap_cfg, repo), "config snapshot");
+ error_code = git_config_get_string(&email, snap_cfg, "user.email");
+ switch (error_code)
+ {
+ case 0:
+ printf("Email: %s\n", email);
+ break;
+ case GIT_ENOTFOUND:
+ printf("Email: Undefined\n");
+ break;
+ default:
+ check_error(error_code, "get_string failed");
+ }
+
git_config_free(snap_cfg);
}
diff --git a/include/git2/graph.h b/include/git2/graph.h
index c997d8ca9..213ae9777 100644
--- a/include/git2/graph.h
+++ b/include/git2/graph.h
@@ -40,6 +40,9 @@ GIT_EXTERN(int) git_graph_ahead_behind(size_t *ahead, size_t *behind, git_reposi
/**
* Determine if a commit is the descendant of another commit.
*
+ * Note that a commit is not considered a descendant of itself, in contrast
+ * to `git merge-base --is-ancestor`.
+ *
* @param commit a previously loaded commit.
* @param ancestor a potential ancestor commit.
* @return 1 if the given commit is a descendant of the potential ancestor,
diff --git a/include/git2/remote.h b/include/git2/remote.h
index b1e04d557..22e2291d0 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -386,6 +386,20 @@ typedef struct {
typedef int (*git_push_negotiation)(const git_push_update **updates, size_t len, void *payload);
/**
+ * Callback used to inform of the update status from the remote.
+ *
+ * Called for each updated reference on push. If `status` is
+ * not `NULL`, the update was rejected by the remote server
+ * and `status` contains the reason given.
+ *
+ * @param refname refname specifying to the remote ref
+ * @param status status message sent from the remote
+ * @param data data provided by the caller
+ * @return 0 on success, otherwise an error
+ */
+typedef int (*git_push_update_reference_cb)(const char *refname, const char *status, void *data);
+
+/**
* The callback settings structure
*
* Set the callbacks to be called by the remote when informing the user
@@ -452,11 +466,9 @@ struct git_remote_callbacks {
git_push_transfer_progress push_transfer_progress;
/**
- * Called for each updated reference on push. If `status` is
- * not `NULL`, the update was rejected by the remote server
- * and `status` contains the reason given.
+ * See documentation of git_push_update_reference_cb
*/
- int (*push_update_reference)(const char *refname, const char *status, void *data);
+ git_push_update_reference_cb push_update_reference;
/**
* Called once between the negotiation step and the upload. It
diff --git a/script/install-deps-linux.sh b/script/install-deps-linux.sh
deleted file mode 100755
index 15bac4d08..000000000
--- a/script/install-deps-linux.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-
-set -x
-
-if [ -z "$PRECISE" ]; then
- echo "deb http://libgit2deps.edwardthomson.com trusty libgit2deps" | sudo tee -a /etc/apt/sources.list
- sudo apt-key adv --keyserver pgp.mit.edu --recv 99131CD5
- sudo apt-get update -qq
- sudo apt-get install -y curl libcurl3 libcurl3-gnutls libcurl4-gnutls-dev
-fi
-
-sudo apt-get install -y cmake libssh2-1-dev openssh-client openssh-server valgrind
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3392a4218..db10e882b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -2,6 +2,11 @@ IF(DEBUG_POOL)
SET(GIT_DEBUG_POOL 1)
ENDIF()
+# Add the features.h file as a dummy. This is required for Xcode
+# to successfully build the libgit2 library when using only
+# object libraries.
+SET(LIBGIT2_OBJECTS "${CMAKE_CURRENT_BINARY_DIR}/git2/sys/features.h")
+
# This variable will contain the libraries we need to put into
# libgit2.pc's Requires.private. That is, what we're linking to or
# what someone who's statically linking us needs to link to.
@@ -181,7 +186,7 @@ ENDIF()
IF(WIN32 OR AMIGA OR CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
ADD_SUBDIRECTORY("${CMAKE_SOURCE_DIR}/deps/regex" "${CMAKE_BINARY_DIR}/deps/regex")
LIST(APPEND LIBGIT2_INCLUDES "${CMAKE_SOURCE_DIR}/deps/regex")
- LIST(APPEND LIBGIT2_LIBS regex)
+ LIST(APPEND LIBGIT2_OBJECTS $<TARGET_OBJECTS:regex>)
ENDIF()
# Optional external dependency: http-parser
@@ -194,7 +199,7 @@ ELSE()
MESSAGE(STATUS "http-parser version 2 was not found or disabled; using bundled 3rd-party sources.")
ADD_SUBDIRECTORY("${CMAKE_SOURCE_DIR}/deps/http-parser" "${CMAKE_BINARY_DIR}/deps/http-parser")
LIST(APPEND LIBGIT2_INCLUDES "${CMAKE_SOURCE_DIR}/deps/http-parser")
- LIST(APPEND LIBGIT2_LIBS http-parser)
+ LIST(APPEND LIBGIT2_OBJECTS "$<TARGET_OBJECTS:http-parser>")
ENDIF()
# Optional external dependency: zlib
@@ -212,7 +217,7 @@ ELSE()
MESSAGE(STATUS "zlib was not found; using bundled 3rd-party sources." )
ADD_SUBDIRECTORY("${CMAKE_SOURCE_DIR}/deps/zlib" "${CMAKE_BINARY_DIR}/deps/zlib")
LIST(APPEND LIBGIT2_INCLUDES "${CMAKE_SOURCE_DIR}/deps/zlib")
- LIST(APPEND LIBGIT2_LIBS zlib)
+ LIST(APPEND LIBGIT2_OBJECTS $<TARGET_OBJECTS:zlib>)
ENDIF()
# Optional external dependency: libssh2
@@ -330,32 +335,28 @@ ENDIF()
CONFIGURE_FILE(features.h.in git2/sys/features.h)
-SET(GIT2INTERNAL_OBJECTS ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_SSH} ${SRC_SHA1})
+SET(LIBGIT2_SOURCES ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_SSH} ${SRC_SHA1})
-IF (CMAKE_VERSION VERSION_GREATER 2.8.7)
- ADD_LIBRARY(git2internal OBJECT ${GIT2INTERNAL_OBJECTS})
- IDE_SPLIT_SOURCES(git2internal)
- SET(GIT2INTERNAL_OBJECTS $<TARGET_OBJECTS:git2internal>)
+ADD_LIBRARY(git2internal OBJECT ${LIBGIT2_SOURCES})
+IDE_SPLIT_SOURCES(git2internal)
+LIST(APPEND LIBGIT2_OBJECTS $<TARGET_OBJECTS:git2internal>)
- IF (${CMAKE_VERSION} VERSION_LESS 2.8.12)
- INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
- ELSE()
- TARGET_INCLUDE_DIRECTORIES(git2internal
- PRIVATE ${LIBGIT2_INCLUDES}
- PUBLIC ${CMAKE_SOURCE_DIR}/include)
- ENDIF()
-ELSE()
+IF (${CMAKE_VERSION} VERSION_LESS 2.8.12)
INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
+ELSE()
+ TARGET_INCLUDE_DIRECTORIES(git2internal
+ PRIVATE ${LIBGIT2_INCLUDES}
+ PUBLIC ${CMAKE_SOURCE_DIR}/include)
ENDIF()
-SET(GIT2INTERNAL_OBJECTS ${GIT2INTERNAL_OBJECTS} PARENT_SCOPE)
+SET(LIBGIT2_OBJECTS ${LIBGIT2_OBJECTS} PARENT_SCOPE)
SET(LIBGIT2_INCLUDES ${LIBGIT2_INCLUDES} PARENT_SCOPE)
SET(LIBGIT2_LIBS ${LIBGIT2_LIBS} PARENT_SCOPE)
SET(LIBGIT2_LIBDIRS ${LIBGIT2_LIBDIRS} PARENT_SCOPE)
# Compile and link libgit2
LINK_DIRECTORIES(${LIBGIT2_LIBDIRS})
-ADD_LIBRARY(git2 ${WIN_RC} ${GIT2INTERNAL_OBJECTS})
+ADD_LIBRARY(git2 ${WIN_RC} ${LIBGIT2_OBJECTS})
TARGET_LINK_LIBRARIES(git2 ${LIBGIT2_LIBS})
SET_TARGET_PROPERTIES(git2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
diff --git a/src/checkout.c b/src/checkout.c
index 6c7a94441..caed6cdf1 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -159,6 +159,19 @@ GIT_INLINE(bool) is_workdir_base_or_new(
git_oid__cmp(&newitem->id, workdir_id) == 0);
}
+GIT_INLINE(bool) is_file_mode_changed(git_filemode_t a, git_filemode_t b)
+{
+#ifdef GIT_WIN32
+ /*
+ * On Win32 we do not support the executable bit; the file will
+ * always be 0100644 on disk, don't bother doing a test.
+ */
+ return false;
+#else
+ return (S_ISREG(a) && S_ISREG(b) && a != b);
+#endif
+}
+
static bool checkout_is_workdir_modified(
checkout_data *data,
const git_diff_file *baseitem,
@@ -200,7 +213,8 @@ static bool checkout_is_workdir_modified(
*/
if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) {
if (git_index_time_eq(&wditem->mtime, &ie->mtime) &&
- wditem->file_size == ie->file_size)
+ wditem->file_size == ie->file_size &&
+ !is_file_mode_changed(wditem->mode, ie->mode))
return !is_workdir_base_or_new(&ie->id, baseitem, newitem);
}
@@ -214,6 +228,9 @@ static bool checkout_is_workdir_modified(
if (S_ISDIR(wditem->mode))
return false;
+ if (is_file_mode_changed(baseitem->mode, wditem->mode))
+ return true;
+
if (git_diff__oid_for_entry(&oid, data->diff, wditem, wditem->mode, NULL) < 0)
return false;
diff --git a/src/curl_stream.c b/src/curl_stream.c
index 24bf62635..a895cb8bd 100644
--- a/src/curl_stream.c
+++ b/src/curl_stream.c
@@ -195,6 +195,7 @@ static int curls_set_proxy(git_stream *stream, const git_proxy_options *proxy_op
CURLcode res;
curl_stream *s = (curl_stream *) stream;
+ git_proxy_options_clear(&s->proxy);
if ((error = git_proxy_options_dup(&s->proxy, proxy_opts)) < 0)
return error;
@@ -295,6 +296,8 @@ static void curls_free(git_stream *stream)
curls_close(stream);
git_strarray_free(&s->cert_info_strings);
+ git_proxy_options_clear(&s->proxy);
+ git_cred_free(s->proxy_cred);
git__free(s);
}
diff --git a/src/posix.h b/src/posix.h
index 3e3bcb287..2934f2479 100644
--- a/src/posix.h
+++ b/src/posix.h
@@ -60,6 +60,9 @@
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
/* access() mode parameter #defines */
#ifndef F_OK
diff --git a/src/proxy.c b/src/proxy.c
index b07371d48..9bc2c7fb1 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -31,3 +31,9 @@ int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src)
return 0;
}
+
+void git_proxy_options_clear(git_proxy_options *opts)
+{
+ git__free((char *) opts->url);
+ opts->url = NULL;
+}
diff --git a/src/proxy.h b/src/proxy.h
index 7582301c9..f8b5c4b50 100644
--- a/src/proxy.h
+++ b/src/proxy.h
@@ -12,5 +12,6 @@
#include "git2/proxy.h"
extern int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src);
+extern void git_proxy_options_clear(git_proxy_options *opts);
#endif
diff --git a/src/refs.c b/src/refs.c
index 942054001..550963e56 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -1360,7 +1360,13 @@ int git_reference_peel(
return peel_error(error, ref, "Cannot resolve reference");
}
- if (!git_oid_iszero(&resolved->peel)) {
+ /*
+ * If we try to peel an object to a tag, we cannot use
+ * the fully peeled object, as that will always resolve
+ * to a commit. So we only want to use the peeled value
+ * if it is not zero and the target is not a tag.
+ */
+ if (target_type != GIT_OBJ_TAG && !git_oid_iszero(&resolved->peel)) {
error = git_object_lookup(&target,
git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY);
} else {
diff --git a/src/socket_stream.c b/src/socket_stream.c
index 4c795e462..3c2a07c02 100644
--- a/src/socket_stream.c
+++ b/src/socket_stream.c
@@ -104,7 +104,7 @@ int socket_connect(git_stream *stream)
}
for (p = info; p != NULL; p = p->ai_next) {
- s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ s = socket(p->ai_family, p->ai_socktype | SOCK_CLOEXEC, p->ai_protocol);
if (s == INVALID_SOCKET)
continue;
diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c
index d51238f12..aecfece0a 100644
--- a/src/transports/smart_protocol.c
+++ b/src/transports/smart_protocol.c
@@ -273,7 +273,7 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
git_revwalk *walk = NULL;
git_strarray refs;
unsigned int i;
- git_reference *ref;
+ git_reference *ref = NULL;
int error;
if ((error = git_reference_list(&refs, repo)) < 0)
@@ -285,6 +285,9 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
git_revwalk_sorting(walk, GIT_SORT_TIME);
for (i = 0; i < refs.count; ++i) {
+ git_reference_free(ref);
+ ref = NULL;
+
/* No tags */
if (!git__prefixcmp(refs.strings[i], GIT_REFS_TAGS_DIR))
continue;
@@ -297,16 +300,13 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
if ((error = git_revwalk_push(walk, git_reference_target(ref))) < 0)
goto on_error;
-
- git_reference_free(ref);
}
- git_strarray_free(&refs);
*out = walk;
- return 0;
on_error:
- git_revwalk_free(walk);
+ if (error)
+ git_revwalk_free(walk);
git_reference_free(ref);
git_strarray_free(&refs);
return error;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 5aba2914a..53265cc55 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -33,11 +33,13 @@ SET_SOURCE_FILES_PROPERTIES(
LINK_DIRECTORIES(${LIBGIT2_LIBDIRS})
INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
-ADD_EXECUTABLE(libgit2_clar ${SRC_CLAR} ${SRC_TEST} ${GIT2INTERNAL_OBJECTS})
+ADD_EXECUTABLE(libgit2_clar ${SRC_CLAR} ${SRC_TEST} ${LIBGIT2_OBJECTS})
SET_TARGET_PROPERTIES(libgit2_clar PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
-IF (${CMAKE_VERSION} VERSION_GREATER 2.8.11)
+IF (${CMAKE_VERSION} VERSION_LESS 2.8.12)
+ # Already handled by a global INCLUDE_DIRECTORY()
+ELSE()
TARGET_INCLUDE_DIRECTORIES(libgit2_clar PRIVATE ../src PUBLIC ../include)
ENDIF()
diff --git a/tests/checkout/tree.c b/tests/checkout/tree.c
index b3b860c63..56513eab7 100644
--- a/tests/checkout/tree.c
+++ b/tests/checkout/tree.c
@@ -10,6 +10,16 @@ static git_repository *g_repo;
static git_checkout_options g_opts;
static git_object *g_object;
+static void assert_status_entrycount(git_repository *repo, size_t count)
+{
+ git_status_list *status;
+
+ cl_git_pass(git_status_list_new(&status, repo, NULL));
+ cl_assert_equal_i(count, git_status_list_entrycount(status));
+
+ git_status_list_free(status);
+}
+
void test_checkout_tree__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
@@ -1480,7 +1490,6 @@ void test_checkout_tree__baseline_is_empty_when_no_index(void)
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
git_reference *head;
git_object *obj;
- git_status_list *status;
size_t conflicts = 0;
assert_on_branch(g_repo, "master");
@@ -1506,14 +1515,49 @@ void test_checkout_tree__baseline_is_empty_when_no_index(void)
opts.checkout_strategy |= GIT_CHECKOUT_FORCE;
cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
- cl_git_pass(git_status_list_new(&status, g_repo, NULL));
- cl_assert_equal_i(0, git_status_list_entrycount(status));
- git_status_list_free(status);
+ assert_status_entrycount(g_repo, 0);
git_object_free(obj);
git_reference_free(head);
}
+void test_checkout_tree__mode_change_is_force_updated(void)
+{
+ git_index *index;
+ git_reference *head;
+ git_object *obj;
+
+ if (!cl_is_chmod_supported())
+ clar__skip();
+
+ assert_on_branch(g_repo, "master");
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_repository_head(&head, g_repo));
+ cl_git_pass(git_reference_peel(&obj, head, GIT_OBJ_COMMIT));
+
+ cl_git_pass(git_reset(g_repo, obj, GIT_RESET_HARD, NULL));
+ assert_status_entrycount(g_repo, 0);
+
+ /* update the mode on-disk */
+ cl_must_pass(p_chmod("testrepo/README", 0755));
+
+ assert_status_entrycount(g_repo, 1);
+ cl_git_pass(git_checkout_tree(g_repo, obj, &g_opts));
+ assert_status_entrycount(g_repo, 0);
+
+ /* update the mode on-disk and in the index */
+ cl_must_pass(p_chmod("testrepo/README", 0755));
+ cl_must_pass(git_index_add_bypath(index, "README"));
+
+ assert_status_entrycount(g_repo, 1);
+ cl_git_pass(git_checkout_tree(g_repo, obj, &g_opts));
+ assert_status_entrycount(g_repo, 0);
+
+ git_object_free(obj);
+ git_reference_free(head);
+ git_index_free(index);
+}
+
void test_checkout_tree__nullopts(void)
{
cl_git_pass(git_checkout_tree(g_repo, NULL, NULL));
diff --git a/tests/refs/peel.c b/tests/refs/peel.c
index 83f6109c0..09809e19e 100644
--- a/tests/refs/peel.c
+++ b/tests/refs/peel.c
@@ -117,3 +117,15 @@ void test_refs_peel__can_peel_fully_peeled_packed_refs(void)
"0df1a5865c8abfc09f1f2182e6a31be550e99f07",
GIT_OBJ_COMMIT);
}
+
+void test_refs_peel__can_peel_fully_peeled_tag_to_tag(void)
+{
+ assert_peel_generic(g_peel_repo,
+ "refs/tags/tag-inside-tags", GIT_OBJ_TAG,
+ "c2596aa0151888587ec5c0187f261e63412d9e11",
+ GIT_OBJ_TAG);
+ assert_peel_generic(g_peel_repo,
+ "refs/foo/tag-outside-tags", GIT_OBJ_TAG,
+ "c2596aa0151888587ec5c0187f261e63412d9e11",
+ GIT_OBJ_TAG);
+}