mirror of
https://github.com/libgit2/libgit2.git
synced 2026-06-22 06:26:26 +00:00
Merge branch 'main' into ethomson/worktree-config
This commit is contained in:
1
.github/actions/run-build/action.yml
vendored
1
.github/actions/run-build/action.yml
vendored
@@ -40,6 +40,7 @@ runs:
|
||||
-e PKG_CONFIG_PATH \
|
||||
-e SKIP_NEGOTIATE_TESTS \
|
||||
-e SKIP_SSH_TESTS \
|
||||
-e SKIP_PUSHOPTIONS_TESTS \
|
||||
-e TSAN_OPTIONS \
|
||||
-e UBSAN_OPTIONS \
|
||||
${{ inputs.container-version }} \
|
||||
|
||||
8
.github/workflows/nightly.yml
vendored
8
.github/workflows/nightly.yml
vendored
@@ -178,6 +178,7 @@ jobs:
|
||||
CMAKE_OPTIONS: -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON
|
||||
PKG_CONFIG_PATH: /usr/local/lib/pkgconfig
|
||||
SKIP_NEGOTIATE_TESTS: true
|
||||
SKIP_PUSHOPTIONS_TESTS: true
|
||||
- name: "Linux (CentOS 7, dynamically-loaded OpenSSL)"
|
||||
id: centos7-dynamicopenssl
|
||||
os: ubuntu-latest
|
||||
@@ -187,6 +188,7 @@ jobs:
|
||||
CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON
|
||||
PKG_CONFIG_PATH: /usr/local/lib/pkgconfig
|
||||
SKIP_NEGOTIATE_TESTS: true
|
||||
SKIP_PUSHOPTIONS_TESTS: true
|
||||
- name: "Linux (CentOS 8, OpenSSL)"
|
||||
id: centos8-openssl
|
||||
os: ubuntu-latest
|
||||
@@ -218,6 +220,7 @@ jobs:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL-Dynamic -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON
|
||||
RUN_INVASIVE_TESTS: true
|
||||
SKIP_PUSHOPTIONS_TESTS: true
|
||||
os: ubuntu-latest
|
||||
- name: "Linux (x86, Bionic, Clang, OpenSSL)"
|
||||
container:
|
||||
@@ -229,6 +232,7 @@ jobs:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON
|
||||
RUN_INVASIVE_TESTS: true
|
||||
SKIP_PUSHOPTIONS_TESTS: true
|
||||
os: ubuntu-latest
|
||||
- name: "Linux (x86, Bionic, GCC, OpenSSL)"
|
||||
container:
|
||||
@@ -239,6 +243,7 @@ jobs:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON
|
||||
RUN_INVASIVE_TESTS: true
|
||||
SKIP_PUSHOPTIONS_TESTS: true
|
||||
os: ubuntu-latest
|
||||
- name: "Linux (arm32, Bionic, GCC, OpenSSL)"
|
||||
container:
|
||||
@@ -251,6 +256,7 @@ jobs:
|
||||
CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON -DUSE_SSH=ON
|
||||
RUN_INVASIVE_TESTS: true
|
||||
SKIP_PROXY_TESTS: true
|
||||
SKIP_PUSHOPTIONS_TESTS: true
|
||||
GITTEST_FLAKY_STAT: true
|
||||
os: ubuntu-latest
|
||||
- name: "Linux (arm64, Bionic, GCC, OpenSSL)"
|
||||
@@ -264,6 +270,7 @@ jobs:
|
||||
CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_GSSAPI=ON -DUSE_SSH=ON
|
||||
RUN_INVASIVE_TESTS: true
|
||||
SKIP_PROXY_TESTS: true
|
||||
SKIP_PUSHOPTIONS_TESTS: true
|
||||
os: ubuntu-latest
|
||||
|
||||
# Nightly builds: ensure we fallback when missing core functionality
|
||||
@@ -276,6 +283,7 @@ jobs:
|
||||
CC: gcc
|
||||
CMAKE_OPTIONS: -DTHREADSAFE=OFF -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON
|
||||
CMAKE_GENERATOR: Ninja
|
||||
SKIP_PUSHOPTIONS_TESTS: true
|
||||
- name: "Linux (no mmap)"
|
||||
id: noble-nommap
|
||||
os: ubuntu-latest
|
||||
|
||||
@@ -113,7 +113,7 @@ Getting Help
|
||||
**Getting Help**
|
||||
|
||||
If you have questions about the library, please be sure to check out the
|
||||
[API documentation](http://libgit2.github.com/libgit2/). If you still have
|
||||
[API documentation](https://libgit2.org/libgit2/). If you still have
|
||||
questions, reach out to us on Slack or post a question on
|
||||
[StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) (with the `libgit2` tag).
|
||||
|
||||
|
||||
16
ci/test.sh
16
ci/test.sh
@@ -18,6 +18,11 @@ if [[ "$(uname -s)" == MINGW* ]]; then
|
||||
SKIP_NTLM_TESTS=1
|
||||
fi
|
||||
|
||||
# older versions of git don't support push options
|
||||
if [ -z "$SKIP_PUSHOPTIONS_TESTS" ]; then
|
||||
export GITTEST_PUSH_OPTIONS=true
|
||||
fi
|
||||
|
||||
SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
|
||||
BUILD_DIR=$(pwd)
|
||||
BUILD_PATH=${BUILD_PATH:=$PATH}
|
||||
@@ -207,7 +212,6 @@ if should_run "SSH_TESTS"; then
|
||||
echo "Starting SSH server..."
|
||||
SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX`
|
||||
cp -R "${SOURCE_DIR}/tests/resources/pushoptions.git" "${SSHD_DIR}/test.git"
|
||||
ls -FlasR "${SSHD_DIR}"
|
||||
|
||||
cat >"${SSHD_DIR}/sshd_config" <<-EOF
|
||||
Port 2222
|
||||
@@ -325,10 +329,8 @@ if should_run "GITDAEMON_TESTS"; then
|
||||
echo ""
|
||||
|
||||
export GITTEST_REMOTE_URL="git://localhost/test.git"
|
||||
export GITTEST_PUSH_OPTIONS=true
|
||||
run_test gitdaemon
|
||||
unset GITTEST_REMOTE_URL
|
||||
unset GITTEST_PUSH_OPTIONS
|
||||
|
||||
echo ""
|
||||
echo "Running gitdaemon (namespace) tests"
|
||||
@@ -383,12 +385,10 @@ if should_run "NTLM_TESTS"; then
|
||||
export GITTEST_REMOTE_URL="http://localhost:9000/ntlm/test.git"
|
||||
export GITTEST_REMOTE_USER="foo"
|
||||
export GITTEST_REMOTE_PASS="baz"
|
||||
export GITTEST_PUSH_OPTIONS=true
|
||||
run_test auth_clone_and_push
|
||||
unset GITTEST_REMOTE_URL
|
||||
unset GITTEST_REMOTE_USER
|
||||
unset GITTEST_REMOTE_PASS
|
||||
unset GITTEST_PUSH_OPTIONS
|
||||
|
||||
echo ""
|
||||
echo "Running NTLM tests (Apache emulation)"
|
||||
@@ -397,12 +397,10 @@ if should_run "NTLM_TESTS"; then
|
||||
export GITTEST_REMOTE_URL="http://localhost:9000/broken-ntlm/test.git"
|
||||
export GITTEST_REMOTE_USER="foo"
|
||||
export GITTEST_REMOTE_PASS="baz"
|
||||
export GITTEST_PUSH_OPTIONS=true
|
||||
run_test auth_clone_and_push
|
||||
unset GITTEST_REMOTE_URL
|
||||
unset GITTEST_REMOTE_USER
|
||||
unset GITTEST_REMOTE_PASS
|
||||
unset GITTEST_PUSH_OPTIONS
|
||||
fi
|
||||
|
||||
if should_run "NEGOTIATE_TESTS" && -n "$GITTEST_NEGOTIATE_PASSWORD" ; then
|
||||
@@ -452,20 +450,16 @@ if should_run "SSH_TESTS"; then
|
||||
echo ""
|
||||
|
||||
export GITTEST_REMOTE_URL="ssh://localhost:2222/$SSHD_DIR/test.git"
|
||||
export GITTEST_PUSH_OPTIONS=true
|
||||
run_test ssh
|
||||
unset GITTEST_REMOTE_URL
|
||||
unset GITTEST_PUSH_OPTIONS
|
||||
|
||||
echo ""
|
||||
echo "Running ssh tests (scp-style paths)"
|
||||
echo ""
|
||||
|
||||
export GITTEST_REMOTE_URL="[localhost:2222]:$SSHD_DIR/test.git"
|
||||
export GITTEST_PUSH_OPTIONS=true
|
||||
run_test ssh
|
||||
unset GITTEST_REMOTE_URL
|
||||
unset GITTEST_PUSH_OPTIONS
|
||||
|
||||
unset GITTEST_SSH_CMD
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ so there are no restrictions on their use.
|
||||
|
||||
For annotated HTML versions, see the "Examples" section of:
|
||||
|
||||
http://libgit2.github.com/libgit2
|
||||
https://libgit2.org/libgit2
|
||||
|
||||
such as:
|
||||
|
||||
http://libgit2.github.com/libgit2/ex/HEAD/general.html
|
||||
https://libgit2.org/libgit2/ex/HEAD/general.html
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
* Git Internals that you will need to know to work with Git at this level,
|
||||
* check out [Chapter 10][pg] of the Pro Git book.
|
||||
*
|
||||
* [lg]: http://libgit2.github.com
|
||||
* [ap]: http://libgit2.github.com/libgit2
|
||||
* [lg]: https://libgit2.org
|
||||
* [ap]: https://libgit2.org/libgit2
|
||||
* [pg]: https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain
|
||||
*/
|
||||
|
||||
@@ -97,7 +97,7 @@ int lg2_general(git_repository *repo, int argc, char** argv)
|
||||
*
|
||||
* (Try running this program against tests/resources/testrepo.git.)
|
||||
*
|
||||
* [me]: http://libgit2.github.com/libgit2/#HEAD/group/repository
|
||||
* [me]: https://libgit2.org/libgit2/#HEAD/group/repository
|
||||
*/
|
||||
repo_path = (argc > 1) ? argv[1] : "/opt/libgit2-test/.git";
|
||||
|
||||
@@ -173,7 +173,7 @@ static void oid_parsing(git_oid *oid)
|
||||
* working with raw objects, we'll need to get this structure from the
|
||||
* repository.
|
||||
*
|
||||
* [odb]: http://libgit2.github.com/libgit2/#HEAD/group/odb
|
||||
* [odb]: https://libgit2.org/libgit2/#HEAD/group/odb
|
||||
*/
|
||||
static void object_database(git_repository *repo, git_oid *oid)
|
||||
{
|
||||
@@ -262,7 +262,7 @@ static void object_database(git_repository *repo, git_oid *oid)
|
||||
* of them here. You can read about the other ones in the [commit API
|
||||
* docs][cd].
|
||||
*
|
||||
* [cd]: http://libgit2.github.com/libgit2/#HEAD/group/commit
|
||||
* [cd]: https://libgit2.org/libgit2/#HEAD/group/commit
|
||||
*/
|
||||
static void commit_writing(git_repository *repo)
|
||||
{
|
||||
@@ -347,7 +347,7 @@ static void commit_writing(git_repository *repo)
|
||||
* data in the commit - the author (name, email, datetime), committer
|
||||
* (same), tree, message, encoding and parent(s).
|
||||
*
|
||||
* [pco]: http://libgit2.github.com/libgit2/#HEAD/group/commit
|
||||
* [pco]: https://libgit2.org/libgit2/#HEAD/group/commit
|
||||
*/
|
||||
static void commit_parsing(git_repository *repo)
|
||||
{
|
||||
@@ -418,7 +418,7 @@ static void commit_parsing(git_repository *repo)
|
||||
* functions very similarly to the commit lookup, parsing and creation
|
||||
* methods, since the objects themselves are very similar.
|
||||
*
|
||||
* [tm]: http://libgit2.github.com/libgit2/#HEAD/group/tag
|
||||
* [tm]: https://libgit2.org/libgit2/#HEAD/group/tag
|
||||
*/
|
||||
static void tag_parsing(git_repository *repo)
|
||||
{
|
||||
@@ -472,7 +472,7 @@ static void tag_parsing(git_repository *repo)
|
||||
* object type in Git, but a useful structure for parsing and traversing
|
||||
* tree entries.
|
||||
*
|
||||
* [tp]: http://libgit2.github.com/libgit2/#HEAD/group/tree
|
||||
* [tp]: https://libgit2.org/libgit2/#HEAD/group/tree
|
||||
*/
|
||||
static void tree_parsing(git_repository *repo)
|
||||
{
|
||||
@@ -536,7 +536,7 @@ static void tree_parsing(git_repository *repo)
|
||||
* from disk and writing it to the db and getting the oid back so you
|
||||
* don't have to do all those steps yourself.
|
||||
*
|
||||
* [ba]: http://libgit2.github.com/libgit2/#HEAD/group/blob
|
||||
* [ba]: https://libgit2.org/libgit2/#HEAD/group/blob
|
||||
*/
|
||||
static void blob_parsing(git_repository *repo)
|
||||
{
|
||||
@@ -578,7 +578,7 @@ static void blob_parsing(git_repository *repo)
|
||||
* that were ancestors of (reachable from) a given starting point. This
|
||||
* can allow you to create `git log` type functionality.
|
||||
*
|
||||
* [rw]: http://libgit2.github.com/libgit2/#HEAD/group/revwalk
|
||||
* [rw]: https://libgit2.org/libgit2/#HEAD/group/revwalk
|
||||
*/
|
||||
static void revwalking(git_repository *repo)
|
||||
{
|
||||
@@ -643,7 +643,7 @@ static void revwalking(git_repository *repo)
|
||||
* The [index file API][gi] allows you to read, traverse, update and write
|
||||
* the Git index file (sometimes thought of as the staging area).
|
||||
*
|
||||
* [gi]: http://libgit2.github.com/libgit2/#HEAD/group/index
|
||||
* [gi]: https://libgit2.org/libgit2/#HEAD/group/index
|
||||
*/
|
||||
static void index_walking(git_repository *repo)
|
||||
{
|
||||
@@ -687,7 +687,7 @@ static void index_walking(git_repository *repo)
|
||||
* references such as branches, tags and remote references (everything in
|
||||
* the .git/refs directory).
|
||||
*
|
||||
* [ref]: http://libgit2.github.com/libgit2/#HEAD/group/reference
|
||||
* [ref]: https://libgit2.org/libgit2/#HEAD/group/reference
|
||||
*/
|
||||
static void reference_listing(git_repository *repo)
|
||||
{
|
||||
@@ -740,7 +740,7 @@ static void reference_listing(git_repository *repo)
|
||||
* The [config API][config] allows you to list and update config values
|
||||
* in any of the accessible config file locations (system, global, local).
|
||||
*
|
||||
* [config]: http://libgit2.github.com/libgit2/#HEAD/group/config
|
||||
* [config]: https://libgit2.org/libgit2/#HEAD/group/config
|
||||
*/
|
||||
static void config_files(const char *repo_path, git_repository* repo)
|
||||
{
|
||||
|
||||
@@ -50,6 +50,7 @@ static int add_revision(struct log_state *s, const char *revstr);
|
||||
/** log_options holds other command line options that affect log output */
|
||||
struct log_options {
|
||||
int show_diff;
|
||||
int show_oneline;
|
||||
int show_log_size;
|
||||
int skip, limit;
|
||||
int min_parents, max_parents;
|
||||
@@ -81,9 +82,11 @@ int lg2_log(git_repository *repo, int argc, char *argv[])
|
||||
git_commit *commit = NULL;
|
||||
git_pathspec *ps = NULL;
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
|
||||
/** Parse arguments and set up revwalker. */
|
||||
last_arg = parse_options(&s, &opt, argc, argv);
|
||||
s.repo = repo;
|
||||
last_arg = parse_options(&s, &opt, argc, argv);
|
||||
|
||||
diffopts.pathspec.strings = &argv[last_arg];
|
||||
diffopts.pathspec.count = argc - last_arg;
|
||||
@@ -335,34 +338,45 @@ static void print_commit(git_commit *commit, struct log_options *opts)
|
||||
const char *scan, *eol;
|
||||
|
||||
git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
|
||||
printf("commit %s\n", buf);
|
||||
|
||||
if (opts->show_log_size) {
|
||||
printf("log size %d\n", (int)strlen(git_commit_message(commit)));
|
||||
}
|
||||
if (opts->show_oneline) {
|
||||
printf("%s ", buf);
|
||||
} else {
|
||||
printf("commit %s\n", buf);
|
||||
|
||||
if ((count = (int)git_commit_parentcount(commit)) > 1) {
|
||||
printf("Merge:");
|
||||
for (i = 0; i < count; ++i) {
|
||||
git_oid_tostr(buf, 8, git_commit_parent_id(commit, i));
|
||||
printf(" %s", buf);
|
||||
if (opts->show_log_size) {
|
||||
printf("log size %d\n", (int)strlen(git_commit_message(commit)));
|
||||
}
|
||||
|
||||
if ((count = (int)git_commit_parentcount(commit)) > 1) {
|
||||
printf("Merge:");
|
||||
for (i = 0; i < count; ++i) {
|
||||
git_oid_tostr(buf, 8, git_commit_parent_id(commit, i));
|
||||
printf(" %s", buf);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if ((sig = git_commit_author(commit)) != NULL) {
|
||||
printf("Author: %s <%s>\n", sig->name, sig->email);
|
||||
print_time(&sig->when, "Date: ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if ((sig = git_commit_author(commit)) != NULL) {
|
||||
printf("Author: %s <%s>\n", sig->name, sig->email);
|
||||
print_time(&sig->when, "Date: ");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for (scan = git_commit_message(commit); scan && *scan; ) {
|
||||
for (eol = scan; *eol && *eol != '\n'; ++eol) /* find eol */;
|
||||
|
||||
printf(" %.*s\n", (int)(eol - scan), scan);
|
||||
if (opts->show_oneline)
|
||||
printf("%.*s\n", (int)(eol - scan), scan);
|
||||
else
|
||||
printf(" %.*s\n", (int)(eol - scan), scan);
|
||||
scan = *eol ? eol + 1 : NULL;
|
||||
if (opts->show_oneline)
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
if (!opts->show_oneline)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/** Helper to find how many files in a commit changed from its nth parent. */
|
||||
@@ -407,8 +421,6 @@ static int parse_options(
|
||||
struct log_state *s, struct log_options *opt, int argc, char **argv)
|
||||
{
|
||||
struct args_info args = ARGS_INFO_INIT;
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->sorting = GIT_SORT_TIME;
|
||||
|
||||
memset(opt, 0, sizeof(*opt));
|
||||
@@ -424,7 +436,7 @@ static int parse_options(
|
||||
else
|
||||
/** Try failed revision parse as filename. */
|
||||
break;
|
||||
} else if (!match_arg_separator(&args)) {
|
||||
} else if (match_arg_separator(&args)) {
|
||||
break;
|
||||
}
|
||||
else if (!strcmp(a, "--date-order"))
|
||||
@@ -474,6 +486,8 @@ static int parse_options(
|
||||
opt->show_diff = 1;
|
||||
else if (!strcmp(a, "--log-size"))
|
||||
opt->show_log_size = 1;
|
||||
else if (!strcmp(a, "--oneline"))
|
||||
opt->show_oneline = 1;
|
||||
else
|
||||
usage("Unsupported argument", a);
|
||||
}
|
||||
|
||||
@@ -19,20 +19,20 @@ GIT_BEGIN_DECL
|
||||
|
||||
/** Generic return codes */
|
||||
typedef enum {
|
||||
GIT_OK = 0, /**< No error */
|
||||
GIT_OK = 0, /**< No error */
|
||||
|
||||
GIT_ERROR = -1, /**< Generic error */
|
||||
GIT_ENOTFOUND = -3, /**< Requested object could not be found */
|
||||
GIT_EEXISTS = -4, /**< Object exists preventing operation */
|
||||
GIT_EAMBIGUOUS = -5, /**< More than one object matches */
|
||||
GIT_EBUFS = -6, /**< Output buffer too short to hold data */
|
||||
GIT_ERROR = -1, /**< Generic error */
|
||||
GIT_ENOTFOUND = -3, /**< Requested object could not be found */
|
||||
GIT_EEXISTS = -4, /**< Object exists preventing operation */
|
||||
GIT_EAMBIGUOUS = -5, /**< More than one object matches */
|
||||
GIT_EBUFS = -6, /**< Output buffer too short to hold data */
|
||||
|
||||
/**
|
||||
* GIT_EUSER is a special error that is never generated by libgit2
|
||||
* code. You can return it from a callback (e.g to stop an iteration)
|
||||
* to know that it was generated by the callback and not by libgit2.
|
||||
*/
|
||||
GIT_EUSER = -7,
|
||||
GIT_EUSER = -7,
|
||||
|
||||
GIT_EBAREREPO = -8, /**< Operation not allowed on bare repository */
|
||||
GIT_EUNBORNBRANCH = -9, /**< HEAD refers to branch with no commits */
|
||||
@@ -61,7 +61,8 @@ typedef enum {
|
||||
GIT_EOWNER = -36, /**< The object is not owned by the current user */
|
||||
GIT_TIMEOUT = -37, /**< The operation timed out */
|
||||
GIT_EUNCHANGED = -38, /**< There were no changes */
|
||||
GIT_EREADONLY = -39 /**< The subject is read-only */
|
||||
GIT_ENOTSUPPORTED = -39, /**< An option is not supported */
|
||||
GIT_EREADONLY = -40 /**< The subject is read-only */
|
||||
} git_error_code;
|
||||
|
||||
/**
|
||||
|
||||
@@ -85,8 +85,9 @@ GIT_EXTERN(int) git_worktree_validate(const git_worktree *wt);
|
||||
typedef struct git_worktree_add_options {
|
||||
unsigned int version;
|
||||
|
||||
int lock; /**< lock newly created worktree */
|
||||
git_reference *ref; /**< reference to use for the new worktree HEAD */
|
||||
int lock; /**< lock newly created worktree */
|
||||
int checkout_existing; /**< allow checkout of existing branch matching worktree name */
|
||||
git_reference *ref; /**< reference to use for the new worktree HEAD */
|
||||
|
||||
/**
|
||||
* Options for the checkout.
|
||||
@@ -95,7 +96,8 @@ typedef struct git_worktree_add_options {
|
||||
} git_worktree_add_options;
|
||||
|
||||
#define GIT_WORKTREE_ADD_OPTIONS_VERSION 1
|
||||
#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION,0,NULL,GIT_CHECKOUT_OPTIONS_INIT}
|
||||
#define GIT_WORKTREE_ADD_OPTIONS_INIT { GIT_WORKTREE_ADD_OPTIONS_VERSION, \
|
||||
0, 0, NULL, GIT_CHECKOUT_OPTIONS_INIT }
|
||||
|
||||
/**
|
||||
* Initialize git_worktree_add_options structure
|
||||
|
||||
@@ -29,6 +29,7 @@ typedef struct {
|
||||
const char *new_prefix;
|
||||
uint32_t flags;
|
||||
int id_strlen;
|
||||
unsigned int sent_file_header;
|
||||
git_oid_t oid_type;
|
||||
|
||||
int (*strcomp)(const char *, const char *);
|
||||
@@ -579,6 +580,30 @@ static int diff_print_patch_file_binary(
|
||||
return error;
|
||||
}
|
||||
|
||||
GIT_INLINE(int) should_force_header(const git_diff_delta *delta)
|
||||
{
|
||||
if (delta->old_file.mode != delta->new_file.mode)
|
||||
return 1;
|
||||
|
||||
if (delta->status == GIT_DELTA_RENAMED || delta->status == GIT_DELTA_COPIED)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
GIT_INLINE(int) flush_file_header(const git_diff_delta *delta, diff_print_info *pi)
|
||||
{
|
||||
if (pi->sent_file_header)
|
||||
return 0;
|
||||
|
||||
pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
|
||||
pi->line.content = git_str_cstr(pi->buf);
|
||||
pi->line.content_len = git_str_len(pi->buf);
|
||||
pi->sent_file_header = 1;
|
||||
|
||||
return pi->print_cb(delta, NULL, &pi->line, pi->payload);
|
||||
}
|
||||
|
||||
static int diff_print_patch_file(
|
||||
const git_diff_delta *delta, float progress, void *data)
|
||||
{
|
||||
@@ -609,15 +634,22 @@ static int diff_print_patch_file(
|
||||
(pi->flags & GIT_DIFF_SHOW_UNTRACKED_CONTENT) == 0))
|
||||
return 0;
|
||||
|
||||
pi->sent_file_header = 0;
|
||||
|
||||
if ((error = git_diff_delta__format_file_header(pi->buf, delta, oldpfx, newpfx,
|
||||
id_strlen, print_index)) < 0)
|
||||
return error;
|
||||
|
||||
pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
|
||||
pi->line.content = git_str_cstr(pi->buf);
|
||||
pi->line.content_len = git_str_len(pi->buf);
|
||||
/*
|
||||
* pi->buf now contains the file header data. Go ahead and send it
|
||||
* if there's useful data in there, like similarity. Otherwise, we
|
||||
* should queue it to send when we see the first hunk. This prevents
|
||||
* us from sending a header when all hunks were ignored.
|
||||
*/
|
||||
if (should_force_header(delta) && (error = flush_file_header(delta, pi)) < 0)
|
||||
return error;
|
||||
|
||||
return pi->print_cb(delta, NULL, &pi->line, pi->payload);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int diff_print_patch_binary(
|
||||
@@ -632,6 +664,9 @@ static int diff_print_patch_binary(
|
||||
pi->new_prefix ? pi->new_prefix : DIFF_NEW_PREFIX_DEFAULT;
|
||||
int error;
|
||||
|
||||
if ((error = flush_file_header(delta, pi)) < 0)
|
||||
return error;
|
||||
|
||||
git_str_clear(pi->buf);
|
||||
|
||||
if ((error = diff_print_patch_file_binary(
|
||||
@@ -651,10 +686,14 @@ static int diff_print_patch_hunk(
|
||||
void *data)
|
||||
{
|
||||
diff_print_info *pi = data;
|
||||
int error;
|
||||
|
||||
if (S_ISDIR(d->new_file.mode))
|
||||
return 0;
|
||||
|
||||
if ((error = flush_file_header(d, pi)) < 0)
|
||||
return error;
|
||||
|
||||
pi->line.origin = GIT_DIFF_LINE_HUNK_HDR;
|
||||
pi->line.content = h->header;
|
||||
pi->line.content_len = h->header_len;
|
||||
@@ -669,10 +708,14 @@ static int diff_print_patch_line(
|
||||
void *data)
|
||||
{
|
||||
diff_print_info *pi = data;
|
||||
int error;
|
||||
|
||||
if (S_ISDIR(delta->new_file.mode))
|
||||
return 0;
|
||||
|
||||
if ((error = flush_file_header(delta, pi)) < 0)
|
||||
return error;
|
||||
|
||||
return pi->print_cb(delta, hunk, line, pi->payload);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef LIBGIT2_COMMENTS
|
||||
# define LIBGIT2_COMMENTS "For more information visit http://libgit2.github.com/"
|
||||
# define LIBGIT2_COMMENTS "For more information visit https://libgit2.org/"
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
@@ -410,7 +410,9 @@ static const char *loose_parse_symbolic(git_str *file_content)
|
||||
static bool is_per_worktree_ref(const char *ref_name)
|
||||
{
|
||||
return git__prefixcmp(ref_name, "refs/") != 0 ||
|
||||
git__prefixcmp(ref_name, "refs/bisect/") == 0;
|
||||
git__prefixcmp(ref_name, "refs/bisect/") == 0 ||
|
||||
git__prefixcmp(ref_name, "refs/worktree/") == 0 ||
|
||||
git__prefixcmp(ref_name, "refs/rewritten/") == 0;
|
||||
}
|
||||
|
||||
static int loose_lookup(
|
||||
@@ -805,83 +807,149 @@ static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter)
|
||||
git__free(iter);
|
||||
}
|
||||
|
||||
struct iter_load_context {
|
||||
refdb_fs_backend *backend;
|
||||
refdb_fs_iter *iter;
|
||||
|
||||
/*
|
||||
* If we have a glob with a prefix (eg `refs/heads/ *`) then we can
|
||||
* optimize our prefix to avoid walking refs that we know won't
|
||||
* match. This is that prefix.
|
||||
*/
|
||||
const char *ref_prefix;
|
||||
size_t ref_prefix_len;
|
||||
|
||||
/* Temporary variables to avoid unnecessary allocations */
|
||||
git_str ref_name;
|
||||
git_str path;
|
||||
};
|
||||
|
||||
static void iter_load_optimize_prefix(struct iter_load_context *ctx)
|
||||
{
|
||||
const char *pos, *last_sep = NULL;
|
||||
|
||||
if (!ctx->iter->glob)
|
||||
return;
|
||||
|
||||
for (pos = ctx->iter->glob; *pos; pos++) {
|
||||
switch (*pos) {
|
||||
case '?':
|
||||
case '*':
|
||||
case '[':
|
||||
case '\\':
|
||||
break;
|
||||
case '/':
|
||||
last_sep = pos;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (last_sep) {
|
||||
ctx->ref_prefix = ctx->iter->glob;
|
||||
ctx->ref_prefix_len = (last_sep - ctx->ref_prefix) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int iter_load_paths(
|
||||
struct iter_load_context *ctx,
|
||||
const char *root_path,
|
||||
bool worktree)
|
||||
{
|
||||
git_iterator *fsit = NULL;
|
||||
git_iterator_options fsit_opts = GIT_ITERATOR_OPTIONS_INIT;
|
||||
const git_index_entry *entry;
|
||||
int error = 0;
|
||||
|
||||
fsit_opts.flags = ctx->backend->iterator_flags;
|
||||
|
||||
git_str_clear(&ctx->path);
|
||||
git_str_puts(&ctx->path, root_path);
|
||||
git_str_put(&ctx->path, ctx->ref_prefix, ctx->ref_prefix_len);
|
||||
|
||||
fsit_opts.flags = ctx->backend->iterator_flags;
|
||||
fsit_opts.oid_type = ctx->backend->oid_type;
|
||||
|
||||
if ((error = git_iterator_for_filesystem(&fsit, ctx->path.ptr, &fsit_opts)) < 0) {
|
||||
/*
|
||||
* Subdirectories - either glob provided or per-worktree refs - need
|
||||
* not exist.
|
||||
*/
|
||||
if ((worktree || ctx->iter->glob) && error == GIT_ENOTFOUND)
|
||||
error = 0;
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
git_str_clear(&ctx->ref_name);
|
||||
git_str_put(&ctx->ref_name, ctx->ref_prefix, ctx->ref_prefix_len);
|
||||
|
||||
while (git_iterator_advance(&entry, fsit) == 0) {
|
||||
char *ref_dup;
|
||||
|
||||
git_str_truncate(&ctx->ref_name, ctx->ref_prefix_len);
|
||||
git_str_puts(&ctx->ref_name, entry->path);
|
||||
|
||||
if (worktree) {
|
||||
if (!is_per_worktree_ref(ctx->ref_name.ptr))
|
||||
continue;
|
||||
} else {
|
||||
if (git_repository_is_worktree(ctx->backend->repo) &&
|
||||
is_per_worktree_ref(ctx->ref_name.ptr))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (git__suffixcmp(ctx->ref_name.ptr, ".lock") == 0)
|
||||
continue;
|
||||
|
||||
if (ctx->iter->glob && wildmatch(ctx->iter->glob, ctx->ref_name.ptr, 0))
|
||||
continue;
|
||||
|
||||
ref_dup = git_pool_strdup(&ctx->iter->pool, ctx->ref_name.ptr);
|
||||
GIT_ERROR_CHECK_ALLOC(ref_dup);
|
||||
|
||||
if ((error = git_vector_insert(&ctx->iter->loose, ref_dup)) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
git_iterator_free(fsit);
|
||||
return error;
|
||||
}
|
||||
|
||||
#define iter_load_context_init(b, i) { b, i, GIT_REFS_DIR, CONST_STRLEN(GIT_REFS_DIR) }
|
||||
#define iter_load_context_dispose(ctx) do { \
|
||||
git_str_dispose(&((ctx)->path)); \
|
||||
git_str_dispose(&((ctx)->ref_name)); \
|
||||
} while(0)
|
||||
|
||||
static int iter_load_loose_paths(
|
||||
refdb_fs_backend *backend,
|
||||
refdb_fs_iter *iter)
|
||||
{
|
||||
int error = 0;
|
||||
git_str path = GIT_STR_INIT;
|
||||
git_iterator *fsit = NULL;
|
||||
git_iterator_options fsit_opts = GIT_ITERATOR_OPTIONS_INIT;
|
||||
const git_index_entry *entry = NULL;
|
||||
const char *ref_prefix = GIT_REFS_DIR;
|
||||
size_t ref_prefix_len = strlen(ref_prefix);
|
||||
struct iter_load_context ctx = iter_load_context_init(backend, iter);
|
||||
|
||||
if (!backend->commonpath) /* do nothing if no commonpath for loose refs */
|
||||
int error = 0;
|
||||
|
||||
if (!backend->commonpath)
|
||||
return 0;
|
||||
|
||||
fsit_opts.flags = backend->iterator_flags;
|
||||
fsit_opts.oid_type = backend->oid_type;
|
||||
iter_load_optimize_prefix(&ctx);
|
||||
|
||||
if (iter->glob) {
|
||||
const char *last_sep = NULL;
|
||||
const char *pos;
|
||||
for (pos = iter->glob; *pos; ++pos) {
|
||||
switch (*pos) {
|
||||
case '?':
|
||||
case '*':
|
||||
case '[':
|
||||
case '\\':
|
||||
break;
|
||||
case '/':
|
||||
last_sep = pos;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (last_sep) {
|
||||
ref_prefix = iter->glob;
|
||||
ref_prefix_len = (last_sep - ref_prefix) + 1;
|
||||
}
|
||||
if ((error = iter_load_paths(&ctx,
|
||||
backend->commonpath, false)) < 0)
|
||||
goto done;
|
||||
|
||||
if (git_repository_is_worktree(backend->repo)) {
|
||||
if ((error = iter_load_paths(&ctx,
|
||||
backend->gitpath, true)) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((error = git_str_puts(&path, backend->commonpath)) < 0 ||
|
||||
(error = git_str_put(&path, ref_prefix, ref_prefix_len)) < 0) {
|
||||
git_str_dispose(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
if ((error = git_iterator_for_filesystem(&fsit, path.ptr, &fsit_opts)) < 0) {
|
||||
git_str_dispose(&path);
|
||||
return (iter->glob && error == GIT_ENOTFOUND)? 0 : error;
|
||||
}
|
||||
|
||||
error = git_str_sets(&path, ref_prefix);
|
||||
|
||||
while (!error && !git_iterator_advance(&entry, fsit)) {
|
||||
const char *ref_name;
|
||||
char *ref_dup;
|
||||
|
||||
git_str_truncate(&path, ref_prefix_len);
|
||||
git_str_puts(&path, entry->path);
|
||||
ref_name = git_str_cstr(&path);
|
||||
|
||||
if (git__suffixcmp(ref_name, ".lock") == 0 ||
|
||||
(iter->glob && wildmatch(iter->glob, ref_name, 0) != 0))
|
||||
continue;
|
||||
|
||||
ref_dup = git_pool_strdup(&iter->pool, ref_name);
|
||||
if (!ref_dup)
|
||||
error = -1;
|
||||
else
|
||||
error = git_vector_insert(&iter->loose, ref_dup);
|
||||
}
|
||||
|
||||
git_iterator_free(fsit);
|
||||
git_str_dispose(&path);
|
||||
|
||||
done:
|
||||
iter_load_context_dispose(&ctx);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -3281,14 +3281,18 @@ int git_repository_set_workdir(
|
||||
if (git_fs_path_prettify_dir(&path, workdir, NULL) < 0)
|
||||
return -1;
|
||||
|
||||
if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0)
|
||||
if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0) {
|
||||
git_str_dispose(&path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (update_gitlink) {
|
||||
git_config *config;
|
||||
|
||||
if (git_repository_config__weakptr(&config, repo) < 0)
|
||||
if (git_repository_config__weakptr(&config, repo) < 0) {
|
||||
git_str_dispose(&path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
error = repo_write_gitlink(path.ptr, git_repository_path(repo), false);
|
||||
|
||||
@@ -3310,6 +3314,7 @@ int git_repository_set_workdir(
|
||||
|
||||
git__free(old_workdir);
|
||||
}
|
||||
git_str_dispose(&path);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ static void free_submodule_names(git_strmap *names)
|
||||
*/
|
||||
static int load_submodule_names(git_strmap **out, git_repository *repo, git_config *cfg)
|
||||
{
|
||||
const char *key = "submodule\\..*\\.path";
|
||||
const char *key = "^submodule\\..*\\.path$";
|
||||
git_config_iterator *iter = NULL;
|
||||
git_config_entry *entry;
|
||||
git_str buf = GIT_STR_INIT;
|
||||
@@ -332,7 +332,7 @@ int git_submodule__lookup_with_cache(
|
||||
/* If it's not configured or we're looking by path */
|
||||
if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) {
|
||||
git_config_backend *mods;
|
||||
const char *pattern = "submodule\\..*\\.path";
|
||||
const char *pattern = "^submodule\\..*\\.path$";
|
||||
git_str path = GIT_STR_INIT;
|
||||
fbp_data data = { NULL, NULL };
|
||||
|
||||
|
||||
@@ -303,6 +303,11 @@ static int local_negotiate_fetch(
|
||||
|
||||
GIT_UNUSED(wants);
|
||||
|
||||
if (wants->depth) {
|
||||
git_error_set(GIT_ERROR_NET, "shallow fetch is not supported by the local transport");
|
||||
return GIT_ENOTSUPPORTED;
|
||||
}
|
||||
|
||||
/* Fill in the loids */
|
||||
git_vector_foreach(&t->refs, i, rhead) {
|
||||
git_object *obj;
|
||||
|
||||
@@ -335,11 +335,21 @@ int git_worktree_add(git_worktree **out, git_repository *repo,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (git_branch_is_checked_out(wtopts.ref)) {
|
||||
git_error_set(GIT_ERROR_WORKTREE, "reference is already checked out");
|
||||
err = -1;
|
||||
if ((err = git_reference_dup(&ref, wtopts.ref)) < 0)
|
||||
goto out;
|
||||
}
|
||||
} else if (wtopts.checkout_existing && git_branch_lookup(&ref, repo, name, GIT_BRANCH_LOCAL) == 0) {
|
||||
/* Do nothing */
|
||||
} else if ((err = git_repository_head(&head, repo)) < 0 ||
|
||||
(err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0 ||
|
||||
(err = git_branch_create(&ref, repo, name, commit, false)) < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (git_branch_is_checked_out(ref)) {
|
||||
git_error_set(GIT_ERROR_WORKTREE, "reference %s is already checked out",
|
||||
git_reference_name(ref));
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Create gitdir directory ".git/worktrees/<name>" */
|
||||
@@ -392,19 +402,6 @@ int git_worktree_add(git_worktree **out, git_repository *repo,
|
||||
|| (err = write_wtfile(gitdir.ptr, "gitdir", &buf)) < 0)
|
||||
goto out;
|
||||
|
||||
/* Set up worktree reference */
|
||||
if (wtopts.ref) {
|
||||
if ((err = git_reference_dup(&ref, wtopts.ref)) < 0)
|
||||
goto out;
|
||||
} else {
|
||||
if ((err = git_repository_head(&head, repo)) < 0)
|
||||
goto out;
|
||||
if ((err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0)
|
||||
goto out;
|
||||
if ((err = git_branch_create(&ref, repo, name, commit, false)) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set worktree's HEAD */
|
||||
if ((err = git_repository_create_head(gitdir.ptr, git_reference_name(ref))) < 0)
|
||||
goto out;
|
||||
|
||||
@@ -210,3 +210,14 @@ void test_clone_local__git_style_unc_paths(void)
|
||||
cl_git_pass(git_futils_rmdir_r("./clone.git", NULL, GIT_RMDIR_REMOVE_FILES));
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_clone_local__shallow_fails(void)
|
||||
{
|
||||
git_repository *repo;
|
||||
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
|
||||
|
||||
opts.fetch_opts.depth = 4;
|
||||
|
||||
cl_git_fail_with(GIT_ENOTSUPPORTED, git_clone(&repo, cl_fixture("testrepo.git"), "./clone.git", &opts));
|
||||
git_repository_free(repo);
|
||||
}
|
||||
|
||||
@@ -2286,42 +2286,81 @@ void test_diff_workdir__to_index_reversed_content_loads(void)
|
||||
diff_expects exp;
|
||||
int use_iterator;
|
||||
char *pathspec = "new_file";
|
||||
|
||||
|
||||
g_repo = cl_git_sandbox_init("status");
|
||||
|
||||
|
||||
opts.context_lines = 3;
|
||||
opts.interhunk_lines = 1;
|
||||
opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED |
|
||||
GIT_DIFF_SHOW_UNTRACKED_CONTENT | GIT_DIFF_REVERSE;
|
||||
opts.pathspec.strings = &pathspec;
|
||||
opts.pathspec.count = 1;
|
||||
|
||||
|
||||
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
|
||||
|
||||
|
||||
for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
|
||||
memset(&exp, 0, sizeof(exp));
|
||||
|
||||
|
||||
if (use_iterator)
|
||||
cl_git_pass(diff_foreach_via_iterator(
|
||||
diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp));
|
||||
else
|
||||
cl_git_pass(git_diff_foreach(
|
||||
diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp));
|
||||
|
||||
|
||||
cl_assert_equal_i(1, exp.files);
|
||||
cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
|
||||
cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
|
||||
cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]);
|
||||
cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]);
|
||||
|
||||
|
||||
cl_assert_equal_i(1, exp.hunks);
|
||||
|
||||
|
||||
cl_assert_equal_i(1, exp.lines);
|
||||
cl_assert_equal_i(0, exp.line_ctxt);
|
||||
cl_assert_equal_i(0, exp.line_adds);
|
||||
cl_assert_equal_i(1, exp.line_dels);
|
||||
}
|
||||
|
||||
|
||||
git_diff_free(diff);
|
||||
}
|
||||
|
||||
void test_diff_workdir__completely_ignored_shows_empty_diff(void)
|
||||
{
|
||||
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
||||
git_diff *diff;
|
||||
git_patch *patch;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
char *pathspec = "subdir.txt";
|
||||
|
||||
opts.pathspec.strings = &pathspec;
|
||||
opts.pathspec.count = 1;
|
||||
|
||||
g_repo = cl_git_sandbox_init("status");
|
||||
cl_git_rewritefile("status/subdir.txt", "Is it a bird?\n\nIs it a plane?\n");
|
||||
|
||||
/* Perform the diff normally */
|
||||
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
|
||||
cl_git_pass(git_patch_from_diff(&patch, diff, 0));
|
||||
cl_git_pass(git_patch_to_buf(&buf, patch));
|
||||
|
||||
cl_assert_equal_s("diff --git a/subdir.txt b/subdir.txt\nindex e8ee89e..53c8db5 100644\n--- a/subdir.txt\n+++ b/subdir.txt\n@@ -1,2 +1,3 @@\n Is it a bird?\n+\n Is it a plane?\n", buf.ptr);
|
||||
|
||||
git_buf_dispose(&buf);
|
||||
git_patch_free(patch);
|
||||
git_diff_free(diff);
|
||||
|
||||
/* Perform the diff ignoring blank lines */
|
||||
opts.flags |= GIT_DIFF_IGNORE_BLANK_LINES;
|
||||
|
||||
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
|
||||
cl_git_pass(git_patch_from_diff(&patch, diff, 0));
|
||||
cl_git_pass(git_patch_to_buf(&buf, patch));
|
||||
|
||||
cl_assert_equal_s("", buf.ptr);
|
||||
|
||||
git_buf_dispose(&buf);
|
||||
git_patch_free(patch);
|
||||
git_diff_free(diff);
|
||||
}
|
||||
|
||||
@@ -401,6 +401,24 @@ void test_submodule_lookup__prefix_name(void)
|
||||
git_submodule_free(sm);
|
||||
}
|
||||
|
||||
/* ".path" in name of submodule */
|
||||
void test_submodule_lookup__dotpath_in_name(void)
|
||||
{
|
||||
sm_lookup_data data;
|
||||
|
||||
cl_git_rewritefile(
|
||||
"submod2/.gitmodules", "[submodule \"kwb.pathdict\"]\n"
|
||||
" path = kwb.pathdict\n"
|
||||
" url = ../Test_App\n"
|
||||
"[submodule \"fakin.path.app\"]\n"
|
||||
" path = fakin.path.app\n"
|
||||
" url = ../Test_App\n");
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
cl_git_pass(git_submodule_foreach(g_repo, sm_lookup_cb, &data));
|
||||
cl_assert_equal_i(9, data.count);
|
||||
}
|
||||
|
||||
void test_submodule_lookup__renamed(void)
|
||||
{
|
||||
const char *newpath = "sm_actually_changed";
|
||||
|
||||
@@ -32,16 +32,11 @@ void test_trace_trace__cleanup(void)
|
||||
|
||||
void test_trace_trace__sets(void)
|
||||
{
|
||||
#ifdef GIT_TRACE
|
||||
cl_assert(git_trace_level() == GIT_TRACE_INFO);
|
||||
#else
|
||||
cl_skip();
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_trace_trace__can_reset(void)
|
||||
{
|
||||
#ifdef GIT_TRACE
|
||||
cl_assert(git_trace_level() == GIT_TRACE_INFO);
|
||||
cl_git_pass(git_trace_set(GIT_TRACE_ERROR, trace_callback));
|
||||
|
||||
@@ -51,14 +46,10 @@ void test_trace_trace__can_reset(void)
|
||||
|
||||
git_trace(GIT_TRACE_ERROR, "Hello %s!", "world");
|
||||
cl_assert(written == 1);
|
||||
#else
|
||||
cl_skip();
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_trace_trace__can_unset(void)
|
||||
{
|
||||
#ifdef GIT_TRACE
|
||||
cl_assert(git_trace_level() == GIT_TRACE_INFO);
|
||||
cl_git_pass(git_trace_set(GIT_TRACE_NONE, NULL));
|
||||
|
||||
@@ -67,40 +58,25 @@ void test_trace_trace__can_unset(void)
|
||||
cl_assert(written == 0);
|
||||
git_trace(GIT_TRACE_FATAL, "Hello %s!", "world");
|
||||
cl_assert(written == 0);
|
||||
#else
|
||||
cl_skip();
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_trace_trace__skips_higher_level(void)
|
||||
{
|
||||
#ifdef GIT_TRACE
|
||||
cl_assert(written == 0);
|
||||
git_trace(GIT_TRACE_DEBUG, "Hello %s!", "world");
|
||||
cl_assert(written == 0);
|
||||
#else
|
||||
cl_skip();
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_trace_trace__writes(void)
|
||||
{
|
||||
#ifdef GIT_TRACE
|
||||
cl_assert(written == 0);
|
||||
git_trace(GIT_TRACE_INFO, "Hello %s!", "world");
|
||||
cl_assert(written == 1);
|
||||
#else
|
||||
cl_skip();
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_trace_trace__writes_lower_level(void)
|
||||
{
|
||||
#ifdef GIT_TRACE
|
||||
cl_assert(written == 0);
|
||||
git_trace(GIT_TRACE_ERROR, "Hello %s!", "world");
|
||||
cl_assert(written == 1);
|
||||
#else
|
||||
cl_skip();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ void test_worktree_refs__cleanup(void)
|
||||
cleanup_fixture_worktree(&fixture);
|
||||
}
|
||||
|
||||
void test_worktree_refs__list(void)
|
||||
void test_worktree_refs__list_no_difference_in_worktree(void)
|
||||
{
|
||||
git_strarray refs, wtrefs;
|
||||
unsigned i, j;
|
||||
@@ -61,6 +61,66 @@ exit:
|
||||
cl_git_pass(error);
|
||||
}
|
||||
|
||||
void test_worktree_refs__list_worktree_specific(void)
|
||||
{
|
||||
git_strarray refs, wtrefs;
|
||||
git_reference *ref, *new_branch;
|
||||
int error = 0;
|
||||
git_oid oid;
|
||||
|
||||
cl_git_pass(git_reference_name_to_id(&oid, fixture.repo, "refs/heads/dir"));
|
||||
cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(&ref, fixture.repo, "refs/bisect/a-bisect-ref"));
|
||||
cl_git_pass(git_reference_create(
|
||||
&new_branch, fixture.worktree, "refs/bisect/a-bisect-ref", &oid,
|
||||
0, "test"));
|
||||
|
||||
cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(&ref, fixture.repo, "refs/bisect/a-bisect-ref"));
|
||||
cl_git_pass(git_reference_lookup(&ref, fixture.worktree, "refs/bisect/a-bisect-ref"));
|
||||
|
||||
cl_git_pass(git_reference_list(&refs, fixture.repo));
|
||||
cl_git_pass(git_reference_list(&wtrefs, fixture.worktree));
|
||||
|
||||
cl_assert_equal_sz(wtrefs.count, refs.count + 1);
|
||||
|
||||
git_reference_free(ref);
|
||||
git_reference_free(new_branch);
|
||||
git_strarray_dispose(&refs);
|
||||
git_strarray_dispose(&wtrefs);
|
||||
cl_git_pass(error);
|
||||
}
|
||||
|
||||
void test_worktree_refs__list_worktree_specific_hidden_in_main_repo(void)
|
||||
{
|
||||
git_strarray refs, wtrefs;
|
||||
git_reference *ref, *new_branch;
|
||||
int error = 0;
|
||||
git_oid oid;
|
||||
|
||||
cl_git_pass(
|
||||
git_reference_name_to_id(&oid, fixture.repo, "refs/heads/dir"));
|
||||
cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(
|
||||
&ref, fixture.worktree, "refs/bisect/a-bisect-ref"));
|
||||
cl_git_pass(git_reference_create(
|
||||
&new_branch, fixture.repo, "refs/bisect/a-bisect-ref", &oid,
|
||||
0, "test"));
|
||||
|
||||
cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(
|
||||
&ref, fixture.worktree, "refs/bisect/a-bisect-ref"));
|
||||
cl_git_pass(git_reference_lookup(
|
||||
&ref, fixture.repo, "refs/bisect/a-bisect-ref"));
|
||||
|
||||
cl_git_pass(git_reference_list(&refs, fixture.repo));
|
||||
cl_git_pass(git_reference_list(&wtrefs, fixture.worktree));
|
||||
|
||||
cl_assert_equal_sz(refs.count, wtrefs.count + 1);
|
||||
|
||||
git_reference_free(ref);
|
||||
git_reference_free(new_branch);
|
||||
git_strarray_dispose(&refs);
|
||||
git_strarray_dispose(&wtrefs);
|
||||
cl_git_pass(error);
|
||||
}
|
||||
|
||||
void test_worktree_refs__read_head(void)
|
||||
{
|
||||
git_reference *head;
|
||||
|
||||
@@ -217,6 +217,50 @@ void test_worktree_worktree__init(void)
|
||||
git_repository_free(repo);
|
||||
}
|
||||
|
||||
void test_worktree_worktree__add_remove_add(void)
|
||||
{
|
||||
git_worktree_add_options add_opts = GIT_WORKTREE_ADD_OPTIONS_INIT;
|
||||
git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
|
||||
git_str path = GIT_BUF_INIT;
|
||||
git_reference *branch;
|
||||
git_repository *repo;
|
||||
git_worktree *wt;
|
||||
|
||||
/* Add the worktree */
|
||||
cl_git_pass(git_str_joinpath(&path, fixture.repo->workdir, "../worktree-add-remove-add"));
|
||||
cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-add-remove-add", path.ptr, NULL));
|
||||
|
||||
/* Open and verify created repo */
|
||||
cl_git_pass(git_repository_open(&repo, path.ptr));
|
||||
cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-add-remove-add/") == 0);
|
||||
cl_git_pass(git_branch_lookup(&branch, repo, "worktree-add-remove-add", GIT_BRANCH_LOCAL));
|
||||
git_reference_free(branch);
|
||||
git_repository_free(repo);
|
||||
|
||||
/* Prune the worktree */
|
||||
opts.flags = GIT_WORKTREE_PRUNE_VALID|GIT_WORKTREE_PRUNE_WORKING_TREE;
|
||||
cl_git_pass(git_worktree_prune(wt, &opts));
|
||||
cl_assert(!git_fs_path_exists(wt->gitdir_path));
|
||||
cl_assert(!git_fs_path_exists(wt->gitlink_path));
|
||||
git_worktree_free(wt);
|
||||
|
||||
/* Add the worktree back with default options should fail. */
|
||||
cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-add-remove-add", path.ptr, &add_opts));
|
||||
/* If allowing checkout of existing branches, it should succeed. */
|
||||
add_opts.checkout_existing = 1;
|
||||
cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-add-remove-add", path.ptr, &add_opts));
|
||||
|
||||
/* Open and verify created repo */
|
||||
cl_git_pass(git_repository_open(&repo, path.ptr));
|
||||
cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-add-remove-add/") == 0);
|
||||
cl_git_pass(git_branch_lookup(&branch, repo, "worktree-add-remove-add", GIT_BRANCH_LOCAL));
|
||||
git_reference_free(branch);
|
||||
git_repository_free(repo);
|
||||
|
||||
git_str_dispose(&path);
|
||||
git_worktree_free(wt);
|
||||
}
|
||||
|
||||
void test_worktree_worktree__add_locked(void)
|
||||
{
|
||||
git_worktree *wt;
|
||||
@@ -244,6 +288,7 @@ void test_worktree_worktree__add_locked(void)
|
||||
|
||||
void test_worktree_worktree__init_existing_branch(void)
|
||||
{
|
||||
git_worktree_add_options opts = GIT_WORKTREE_ADD_OPTIONS_INIT;
|
||||
git_reference *head, *branch;
|
||||
git_commit *commit;
|
||||
git_worktree *wt;
|
||||
@@ -251,12 +296,18 @@ void test_worktree_worktree__init_existing_branch(void)
|
||||
|
||||
cl_git_pass(git_repository_head(&head, fixture.repo));
|
||||
cl_git_pass(git_commit_lookup(&commit, fixture.repo, &head->target.oid));
|
||||
cl_git_pass(git_branch_create(&branch, fixture.repo, "worktree-new", commit, false));
|
||||
cl_git_pass(git_branch_create(&branch, fixture.repo, "worktree-new-exist", commit, false));
|
||||
|
||||
cl_git_pass(git_str_joinpath(&path, fixture.repo->workdir, "../worktree-new"));
|
||||
cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL));
|
||||
cl_git_pass(git_str_joinpath(&path, fixture.repo->workdir, "../worktree-new-exist"));
|
||||
|
||||
/* Add the worktree back with default options should fail. */
|
||||
cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new-exist", path.ptr, NULL));
|
||||
/* If allowing checkout of existing branches, it should succeed. */
|
||||
opts.checkout_existing = 1;
|
||||
cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-new-exist", path.ptr, &opts));
|
||||
|
||||
git_str_dispose(&path);
|
||||
git_worktree_free(wt);
|
||||
git_commit_free(commit);
|
||||
git_reference_free(head);
|
||||
git_reference_free(branch);
|
||||
|
||||
Reference in New Issue
Block a user