Commit a4827a5b by Ben Straub

Merge remote-tracking branch 'upstream/development' into test-merge

parents 15445f9e 31637cd5
...@@ -6,8 +6,10 @@ language: erlang ...@@ -6,8 +6,10 @@ language: erlang
# Settings to try # Settings to try
env: env:
- OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release" - CC=gcc OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release"
- OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=ON" - CC=clang OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release"
- CC=gcc OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=ON"
- CC=clang OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=ON"
- CC=i586-mingw32msvc-gcc OPTIONS="-DBUILD_CLAR=OFF -DWIN32=ON -DMINGW=ON" - CC=i586-mingw32msvc-gcc OPTIONS="-DBUILD_CLAR=OFF -DWIN32=ON -DMINGW=ON"
# Make sure CMake is installed # Make sure CMake is installed
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <pthread.h> #include <pthread.h>
#include <unistd.h>
struct dl_data { struct dl_data {
git_remote *remote; git_remote *remote;
...@@ -39,7 +40,7 @@ exit: ...@@ -39,7 +40,7 @@ exit:
pthread_exit(&data->ret); pthread_exit(&data->ret);
} }
int update_cb(const char *refname, const git_oid *a, const git_oid *b) int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data)
{ {
const char *action; const char *action;
char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1]; char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1];
...@@ -65,6 +66,7 @@ int fetch(git_repository *repo, int argc, char **argv) ...@@ -65,6 +66,7 @@ int fetch(git_repository *repo, int argc, char **argv)
git_indexer_stats stats; git_indexer_stats stats;
pthread_t worker; pthread_t worker;
struct dl_data data; struct dl_data data;
git_remote_callbacks callbacks;
// Figure out whether it's a named remote or a URL // Figure out whether it's a named remote or a URL
printf("Fetching %s\n", argv[1]); printf("Fetching %s\n", argv[1]);
...@@ -73,6 +75,11 @@ int fetch(git_repository *repo, int argc, char **argv) ...@@ -73,6 +75,11 @@ int fetch(git_repository *repo, int argc, char **argv)
return -1; return -1;
} }
// Set up the callbacks (only update_tips for now)
memset(&callbacks, 0, sizeof(callbacks));
callbacks.update_tips = &update_cb;
git_remote_set_callbacks(remote, &callbacks);
// Set up the information for the background worker thread // Set up the information for the background worker thread
data.remote = remote; data.remote = remote;
data.bytes = &bytes; data.bytes = &bytes;
...@@ -101,7 +108,7 @@ int fetch(git_repository *repo, int argc, char **argv) ...@@ -101,7 +108,7 @@ int fetch(git_repository *repo, int argc, char **argv)
// right commits. This may be needed even if there was no packfile // right commits. This may be needed even if there was no packfile
// to download, which can happen e.g. when the branches have been // to download, which can happen e.g. when the branches have been
// changed but all the neede objects are available locally. // changed but all the neede objects are available locally.
if (git_remote_update_tips(remote, update_cb) < 0) if (git_remote_update_tips(remote) < 0)
return -1; return -1;
git_remote_free(remote); git_remote_free(remote);
......
...@@ -26,9 +26,9 @@ GIT_BEGIN_DECL ...@@ -26,9 +26,9 @@ GIT_BEGIN_DECL
* this target commit. If `force` is true and a reference * this target commit. If `force` is true and a reference
* already exists with the given name, it'll be replaced. * already exists with the given name, it'll be replaced.
* *
* @param oid_out Pointer where to store the OID of the target commit. * The returned reference must be freed by the user.
* *
* @param repo Repository where to store the branch. * @param branch_out Pointer where to store the underlying reference.
* *
* @param branch_name Name for the branch; this name is * @param branch_name Name for the branch; this name is
* validated for consistency. It should also not conflict with * validated for consistency. It should also not conflict with
...@@ -46,7 +46,7 @@ GIT_BEGIN_DECL ...@@ -46,7 +46,7 @@ GIT_BEGIN_DECL
* pointing to the provided target commit. * pointing to the provided target commit.
*/ */
GIT_EXTERN(int) git_branch_create( GIT_EXTERN(int) git_branch_create(
git_oid *oid_out, git_reference **branch_out,
git_repository *repo, git_repository *repo,
const char *branch_name, const char *branch_name,
const git_object *target, const git_object *target,
...@@ -97,27 +97,62 @@ GIT_EXTERN(int) git_branch_foreach( ...@@ -97,27 +97,62 @@ GIT_EXTERN(int) git_branch_foreach(
); );
/** /**
* Move/rename an existing branch reference. * Move/rename an existing local branch reference.
* *
* @param repo Repository where lives the branch. * @param branch Current underlying reference of the branch.
*
* @param old_branch_name Current name of the branch to be moved;
* this name is validated for consistency.
* *
* @param new_branch_name Target name of the branch once the move * @param new_branch_name Target name of the branch once the move
* is performed; this name is validated for consistency. * is performed; this name is validated for consistency.
* *
* @param force Overwrite existing branch. * @param force Overwrite existing branch.
* *
* @return 0 on success, GIT_ENOTFOUND if the branch * @return 0 on success, or an error code.
* doesn't exist or an error code.
*/ */
GIT_EXTERN(int) git_branch_move( GIT_EXTERN(int) git_branch_move(
git_repository *repo, git_reference *branch,
const char *old_branch_name,
const char *new_branch_name, const char *new_branch_name,
int force); int force);
/**
* Lookup a branch by its name in a repository.
*
* The generated reference must be freed by the user.
*
* @param branch_out pointer to the looked-up branch reference
*
* @param repo the repository to look up the branch
*
* @param branch_name Name of the branch to be looked-up;
* this name is validated for consistency.
*
* @param branch_type Type of the considered branch. This should
* be valued with either GIT_BRANCH_LOCAL or GIT_BRANCH_REMOTE.
*
* @return 0 on success; GIT_ENOTFOUND when no matching branch
* exists, otherwise an error code.
*/
GIT_EXTERN(int) git_branch_lookup(
git_reference **branch_out,
git_repository *repo,
const char *branch_name,
git_branch_t branch_type);
/**
* Return the reference supporting the remote tracking branch,
* given a local branch reference.
*
* @param tracking_out Pointer where to store the retrieved
* reference.
*
* @param branch Current underlying reference of the branch.
*
* @return 0 on success; GIT_ENOTFOUND when no remote tracking
* reference exists, otherwise an error code.
*/
GIT_EXTERN(int) git_branch_tracking(
git_reference **tracking_out,
git_reference *branch);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif
...@@ -46,6 +46,7 @@ enum { ...@@ -46,6 +46,7 @@ enum {
GIT_DIFF_INCLUDE_UNTRACKED = (1 << 8), GIT_DIFF_INCLUDE_UNTRACKED = (1 << 8),
GIT_DIFF_INCLUDE_UNMODIFIED = (1 << 9), GIT_DIFF_INCLUDE_UNMODIFIED = (1 << 9),
GIT_DIFF_RECURSE_UNTRACKED_DIRS = (1 << 10), GIT_DIFF_RECURSE_UNTRACKED_DIRS = (1 << 10),
GIT_DIFF_DISABLE_PATHSPEC_MATCH = (1 << 11),
}; };
/** /**
......
...@@ -167,6 +167,23 @@ GIT_EXTERN(int) git_object_typeisloose(git_otype type); ...@@ -167,6 +167,23 @@ GIT_EXTERN(int) git_object_typeisloose(git_otype type);
*/ */
GIT_EXTERN(size_t) git_object__size(git_otype type); GIT_EXTERN(size_t) git_object__size(git_otype type);
/**
* Recursively peel an object until an object of the specified
* type is met
*
* The retrieved `peeled` object is owned by the repository
* and should be closed with the `git_object_free` method.
*
* @param peeled Pointer to the peeled git_object
* @param object The object to be processed
* @param target_type The type of the requested object
* @return 0 or an error code
*/
GIT_EXTERN(int) git_object_peel(
git_object **peeled,
git_object *object,
git_otype target_type);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -23,6 +23,10 @@ GIT_BEGIN_DECL ...@@ -23,6 +23,10 @@ GIT_BEGIN_DECL
/** /**
* Read the reflog for the given reference * Read the reflog for the given reference
* *
* If there is no reflog file for the given
* reference yet, an empty reflog object will
* be returned.
*
* The reflog must be freed manually by using * The reflog must be freed manually by using
* git_reflog_free(). * git_reflog_free().
* *
...@@ -33,22 +37,26 @@ GIT_BEGIN_DECL ...@@ -33,22 +37,26 @@ GIT_BEGIN_DECL
GIT_EXTERN(int) git_reflog_read(git_reflog **reflog, git_reference *ref); GIT_EXTERN(int) git_reflog_read(git_reflog **reflog, git_reference *ref);
/** /**
* Write a new reflog for the given reference * Write an existing in-memory reflog object back to disk
* * using an atomic file lock.
* If there is no reflog file for the given
* reference yet, it will be created.
* *
* `oid_old` may be NULL in case it's a new reference. * @param reflog an existing reflog object
* @return 0 or an error code
*/
GIT_EXTERN(int) git_reflog_write(git_reflog *reflog);
/**
* Add a new entry to the reflog.
* *
* `msg` is optional and can be NULL. * `msg` is optional and can be NULL.
* *
* @param ref the changed reference * @param reflog an existing reflog object
* @param oid_old the OID the reference was pointing to * @param new_oid the OID the reference is now pointing to
* @param committer the signature of the committer * @param committer the signature of the committer
* @param msg the reflog message * @param msg the reflog message
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_reflog_write(git_reference *ref, const git_oid *oid_old, const git_signature *committer, const char *msg); GIT_EXTERN(int) git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_signature *committer, const char *msg);
/** /**
* Rename the reflog for the given reference * Rename the reflog for the given reference
...@@ -87,6 +95,26 @@ GIT_EXTERN(unsigned int) git_reflog_entrycount(git_reflog *reflog); ...@@ -87,6 +95,26 @@ GIT_EXTERN(unsigned int) git_reflog_entrycount(git_reflog *reflog);
GIT_EXTERN(const git_reflog_entry *) git_reflog_entry_byindex(git_reflog *reflog, unsigned int idx); GIT_EXTERN(const git_reflog_entry *) git_reflog_entry_byindex(git_reflog *reflog, unsigned int idx);
/** /**
* Remove an entry from the reflog by its index
*
* To ensure there's no gap in the log history, set the `rewrite_previosu_entry` to 1.
* When deleting entry `n`, member old_oid of entry `n-1` (if any) will be updated with
* the value of memeber new_oid of entry `n+1`.
*
* @param reflog a previously loaded reflog.
*
* @param idx the position of the entry to remove.
*
* @param rewrite_previous_entry 1 to rewrite the history; 0 otherwise.
*
* @return 0 on success or an error code.
*/
GIT_EXTERN(int) git_reflog_drop(
git_reflog *reflog,
unsigned int idx,
int rewrite_previous_entry);
/**
* Get the old oid * Get the old oid
* *
* @param entry a reflog entry * @param entry a reflog entry
......
...@@ -363,26 +363,15 @@ GIT_EXTERN(int) git_reference_foreach_glob( ...@@ -363,26 +363,15 @@ GIT_EXTERN(int) git_reference_foreach_glob(
*/ */
GIT_EXTERN(int) git_reference_has_log(git_reference *ref); GIT_EXTERN(int) git_reference_has_log(git_reference *ref);
/** /**
* Return the reference supporting the remote tracking branch, * Check if a reference is a local branch.
* given a reference branch.
*
* The input reference has to be located in the `refs/heads`
* namespace.
*
* @param tracking_ref Pointer where to store the retrieved
* reference.
* *
* @param branch_ref A git local branch reference. * @param ref A git reference
* *
* @return 0 on success; GIT_ENOTFOUND when no remote tracking * @return 1 when the reference lives in the refs/heads
* reference exists, otherwise an error code. * namespace; 0 otherwise.
*/ */
GIT_EXTERN(int) git_reference_remote_tracking_from_branch( GIT_EXTERN(int) git_reference_is_branch(git_reference *ref);
git_reference **tracking_ref,
git_reference *branch_ref
);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -80,6 +80,36 @@ GIT_EXTERN(const char *) git_remote_name(git_remote *remote); ...@@ -80,6 +80,36 @@ GIT_EXTERN(const char *) git_remote_name(git_remote *remote);
GIT_EXTERN(const char *) git_remote_url(git_remote *remote); GIT_EXTERN(const char *) git_remote_url(git_remote *remote);
/** /**
* Get the remote's url for pushing
*
* @param remote the remote
* @return a pointer to the url or NULL if no special url for pushing is set
*/
GIT_EXTERN(const char *) git_remote_pushurl(git_remote *remote);
/**
* Set the remote's url
*
* Existing connections will not be updated.
*
* @param remote the remote
* @param url the url to set
* @return 0 or an error value
*/
GIT_EXTERN(int) git_remote_set_url(git_remote *remote, const char* url);
/**
* Set the remote's url for pushing
*
* Existing connections will not be updated.
*
* @param remote the remote
* @param url the url to set or NULL to clear the pushurl
* @return 0 or an error value
*/
GIT_EXTERN(int) git_remote_set_pushurl(git_remote *remote, const char* url);
/**
* Set the remote's fetch refspec * Set the remote's fetch refspec
* *
* @param remote the remote * @param remote the remote
...@@ -190,7 +220,7 @@ GIT_EXTERN(void) git_remote_free(git_remote *remote); ...@@ -190,7 +220,7 @@ GIT_EXTERN(void) git_remote_free(git_remote *remote);
* @param remote the remote to update * @param remote the remote to update
* @param cb callback to run on each ref update. 'a' is the old value, 'b' is then new value * @param cb callback to run on each ref update. 'a' is the old value, 'b' is then new value
*/ */
GIT_EXTERN(int) git_remote_update_tips(git_remote *remote, int (*cb)(const char *refname, const git_oid *a, const git_oid *b)); GIT_EXTERN(int) git_remote_update_tips(git_remote *remote);
/** /**
* Return whether a string is a valid remote URL * Return whether a string is a valid remote URL
...@@ -238,6 +268,39 @@ GIT_EXTERN(int) git_remote_add(git_remote **out, git_repository *repo, const cha ...@@ -238,6 +268,39 @@ GIT_EXTERN(int) git_remote_add(git_remote **out, git_repository *repo, const cha
GIT_EXTERN(void) git_remote_check_cert(git_remote *remote, int check); GIT_EXTERN(void) git_remote_check_cert(git_remote *remote, int check);
/**
* Argument to the completion callback which tells it which operation
* finished.
*/
typedef enum git_remote_completion_type {
GIT_REMOTE_COMPLETION_DOWNLOAD,
GIT_REMOTE_COMPLETION_INDEXING,
GIT_REMOTE_COMPLETION_ERROR,
} git_remote_completion_type;
/**
* The callback settings structure
*
* Set the calbacks to be called by the remote.
*/
struct git_remote_callbacks {
int (*progress)(const char *str, void *data);
int (*completion)(git_remote_completion_type type, void *data);
int (*update_tips)(const char *refname, const git_oid *a, const git_oid *b, void *data);
void *data;
};
/**
* Set the callbacks for a remote
*
* Note that the remote keeps its own copy of the data and you need to
* call this function again if you want to change the callbacks.
*
* @param remote the remote to configure
* @param callbacks a pointer to the user's callback settings
*/
GIT_EXTERN(void) git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif
...@@ -96,6 +96,8 @@ typedef enum { ...@@ -96,6 +96,8 @@ typedef enum {
* the top-level directory will be included (with a trailing * the top-level directory will be included (with a trailing
* slash on the entry name). Given this flag, the directory * slash on the entry name). Given this flag, the directory
* itself will not be included, but all the files in it will. * itself will not be included, but all the files in it will.
* - GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH indicates that the given
* path will be treated as a literal path, and not as a pathspec.
*/ */
enum { enum {
...@@ -104,6 +106,7 @@ enum { ...@@ -104,6 +106,7 @@ enum {
GIT_STATUS_OPT_INCLUDE_UNMODIFIED = (1 << 2), GIT_STATUS_OPT_INCLUDE_UNMODIFIED = (1 << 2),
GIT_STATUS_OPT_EXCLUDE_SUBMODULES = (1 << 3), GIT_STATUS_OPT_EXCLUDE_SUBMODULES = (1 << 3),
GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS = (1 << 4), GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS = (1 << 4),
GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH = (1 << 5),
}; };
/** /**
......
...@@ -179,6 +179,7 @@ typedef struct git_refspec git_refspec; ...@@ -179,6 +179,7 @@ typedef struct git_refspec git_refspec;
typedef struct git_remote git_remote; typedef struct git_remote git_remote;
typedef struct git_remote_head git_remote_head; typedef struct git_remote_head git_remote_head;
typedef struct git_remote_callbacks git_remote_callbacks;
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -426,17 +426,7 @@ int git_attr_fnmatch__parse( ...@@ -426,17 +426,7 @@ int git_attr_fnmatch__parse(
return -1; return -1;
} else { } else {
/* strip '\' that might have be used for internal whitespace */ /* strip '\' that might have be used for internal whitespace */
char *to = spec->pattern; spec->length = git__unescape(spec->pattern);
for (scan = spec->pattern; *scan; to++, scan++) {
if (*scan == '\\')
scan++; /* skip '\' but include next char */
if (to != scan)
*to = *scan;
}
if (to != scan) {
*to = '\0';
spec->length = (to - spec->pattern);
}
} }
return 0; return 0;
......
...@@ -7,8 +7,11 @@ ...@@ -7,8 +7,11 @@
#include "common.h" #include "common.h"
#include "commit.h" #include "commit.h"
#include "branch.h"
#include "tag.h" #include "tag.h"
#include "config.h"
#include "refspec.h"
#include "git2/branch.h"
static int retrieve_branch_reference( static int retrieve_branch_reference(
git_reference **branch_reference_out, git_reference **branch_reference_out,
...@@ -48,8 +51,8 @@ static int create_error_invalid(const char *msg) ...@@ -48,8 +51,8 @@ static int create_error_invalid(const char *msg)
} }
int git_branch_create( int git_branch_create(
git_oid *oid_out, git_reference **ref_out,
git_repository *repo, git_repository *repository,
const char *branch_name, const char *branch_name,
const git_object *target, const git_object *target,
int force) int force)
...@@ -60,10 +63,8 @@ int git_branch_create( ...@@ -60,10 +63,8 @@ int git_branch_create(
git_buf canonical_branch_name = GIT_BUF_INIT; git_buf canonical_branch_name = GIT_BUF_INIT;
int error = -1; int error = -1;
assert(repo && branch_name && target && oid_out); assert(branch_name && target && ref_out);
assert(git_object_owner(target) == repository);
if (git_object_owner(target) != repo)
return create_error_invalid("The given target does not belong to this repository");
target_type = git_object_type(target); target_type = git_object_type(target);
...@@ -90,17 +91,17 @@ int git_branch_create( ...@@ -90,17 +91,17 @@ int git_branch_create(
if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0) if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
goto cleanup; goto cleanup;
if (git_reference_create_oid(&branch, repo, git_buf_cstr(&canonical_branch_name), git_object_id(commit), force) < 0) if (git_reference_create_oid(&branch, repository,
git_buf_cstr(&canonical_branch_name), git_object_id(commit), force) < 0)
goto cleanup; goto cleanup;
git_oid_cpy(oid_out, git_reference_oid(branch)); *ref_out = branch;
error = 0; error = 0;
cleanup: cleanup:
if (target_type == GIT_OBJ_TAG) if (target_type == GIT_OBJ_TAG)
git_object_free(commit); git_object_free(commit);
git_reference_free(branch);
git_buf_free(&canonical_branch_name); git_buf_free(&canonical_branch_name);
return error; return error;
} }
...@@ -111,6 +112,7 @@ int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_ ...@@ -111,6 +112,7 @@ int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_
git_reference *head = NULL; git_reference *head = NULL;
int error; int error;
assert(repo && branch_name);
assert((branch_type == GIT_BRANCH_LOCAL) || (branch_type == GIT_BRANCH_REMOTE)); assert((branch_type == GIT_BRANCH_LOCAL) || (branch_type == GIT_BRANCH_REMOTE));
if ((error = retrieve_branch_reference(&branch, repo, branch_name, branch_type == GIT_BRANCH_REMOTE)) < 0) if ((error = retrieve_branch_reference(&branch, repo, branch_name, branch_type == GIT_BRANCH_REMOTE)) < 0)
...@@ -183,28 +185,110 @@ int git_branch_foreach( ...@@ -183,28 +185,110 @@ int git_branch_foreach(
return git_reference_foreach(repo, GIT_REF_LISTALL, &branch_foreach_cb, (void *)&filter); return git_reference_foreach(repo, GIT_REF_LISTALL, &branch_foreach_cb, (void *)&filter);
} }
int git_branch_move(git_repository *repo, const char *old_branch_name, const char *new_branch_name, int force) static int not_a_local_branch(git_reference *ref)
{
giterr_set(GITERR_INVALID, "Reference '%s' is not a local branch.", git_reference_name(ref));
return -1;
}
int git_branch_move(
git_reference *branch,
const char *new_branch_name,
int force)
{ {
git_reference *reference = NULL; git_buf new_reference_name = GIT_BUF_INIT;
git_buf old_reference_name = GIT_BUF_INIT, new_reference_name = GIT_BUF_INIT; int error;
int error = 0;
if ((error = git_buf_joinpath(&old_reference_name, GIT_REFS_HEADS_DIR, old_branch_name)) < 0) assert(branch && new_branch_name);
goto cleanup;
/* We need to be able to return GIT_ENOTFOUND */ if (!git_reference_is_branch(branch))
if ((error = git_reference_lookup(&reference, repo, git_buf_cstr(&old_reference_name))) < 0) return not_a_local_branch(branch);
goto cleanup;
if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0) if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0)
goto cleanup; goto cleanup;
error = git_reference_rename(reference, git_buf_cstr(&new_reference_name), force); error = git_reference_rename(branch, git_buf_cstr(&new_reference_name), force);
cleanup: cleanup:
git_reference_free(reference);
git_buf_free(&old_reference_name);
git_buf_free(&new_reference_name); git_buf_free(&new_reference_name);
return error; return error;
} }
int git_branch_lookup(
git_reference **ref_out,
git_repository *repo,
const char *branch_name,
git_branch_t branch_type)
{
assert(ref_out && repo && branch_name);
return retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE);
}
static int retrieve_tracking_configuration(
const char **out, git_reference *branch, const char *format)
{
git_config *config;
git_buf buf = GIT_BUF_INIT;
int error;
if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0)
return -1;
if (git_buf_printf(&buf, format,
git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
return -1;
error = git_config_get_string(out, config, git_buf_cstr(&buf));
git_buf_free(&buf);
return error;
}
int git_branch_tracking(
git_reference **tracking_out,
git_reference *branch)
{
const char *remote_name, *merge_name;
git_buf buf = GIT_BUF_INIT;
int error = -1;
git_remote *remote = NULL;
const git_refspec *refspec;
assert(tracking_out && branch);
if (!git_reference_is_branch(branch))
return not_a_local_branch(branch);
if ((error = retrieve_tracking_configuration(&remote_name, branch, "branch.%s.remote")) < 0)
goto cleanup;
if ((error = retrieve_tracking_configuration(&merge_name, branch, "branch.%s.merge")) < 0)
goto cleanup;
if (strcmp(".", remote_name) != 0) {
if ((error = git_remote_load(&remote, git_reference_owner(branch), remote_name)) < 0)
goto cleanup;
refspec = git_remote_fetchspec(remote);
if (refspec == NULL) {
error = GIT_ENOTFOUND;
goto cleanup;
}
if (git_refspec_transform_r(&buf, refspec, merge_name) < 0)
goto cleanup;
} else
if (git_buf_sets(&buf, merge_name) < 0)
goto cleanup;
error = git_reference_lookup(
tracking_out,
git_reference_owner(branch),
git_buf_cstr(&buf));
cleanup:
git_remote_free(remote);
git_buf_free(&buf);
return error;
}
/*
* Copyright (C) 2009-2012 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_branch_h__
#define INCLUDE_branch_h__
#include "git2/branch.h"
struct git_branch {
char *remote; /* TODO: Make this a git_remote */
char *merge;
};
#endif
...@@ -496,3 +496,7 @@ bool git_buf_is_binary(const git_buf *buf) ...@@ -496,3 +496,7 @@ bool git_buf_is_binary(const git_buf *buf)
return ((printable >> 7) < nonprintable); return ((printable >> 7) < nonprintable);
} }
void git_buf_unescape(git_buf *buf)
{
buf->size = git__unescape(buf->ptr);
}
...@@ -151,4 +151,7 @@ int git_buf_common_prefix(git_buf *buf, const git_strarray *strings); ...@@ -151,4 +151,7 @@ int git_buf_common_prefix(git_buf *buf, const git_strarray *strings);
/* Check if buffer looks like it contains binary data */ /* Check if buffer looks like it contains binary data */
bool git_buf_is_binary(const git_buf *buf); bool git_buf_is_binary(const git_buf *buf);
/* Unescape all characters in a buffer */
void git_buf_unescape(git_buf *buf);
#endif #endif
...@@ -49,15 +49,6 @@ ...@@ -49,15 +49,6 @@
#include <regex.h> #include <regex.h>
extern void git___throw(const char *, ...) GIT_FORMAT_PRINTF(1, 2);
#define git__throw(error, ...) \
(git___throw(__VA_ARGS__), error)
extern void git___rethrow(const char *, ...) GIT_FORMAT_PRINTF(1, 2);
#define git__rethrow(error, ...) \
(git___rethrow(__VA_ARGS__), error)
#define GITERR_CHECK_ALLOC(ptr) if (ptr == NULL) { return -1; } #define GITERR_CHECK_ALLOC(ptr) if (ptr == NULL) { return -1; }
void giterr_set_oom(void); void giterr_set_oom(void);
...@@ -68,5 +59,4 @@ void giterr_set_regex(const regex_t *regex, int error_code); ...@@ -68,5 +59,4 @@ void giterr_set_regex(const regex_t *regex, int error_code);
#include "util.h" #include "util.h"
#endif /* INCLUDE_common_h__ */ #endif /* INCLUDE_common_h__ */
...@@ -983,9 +983,12 @@ static int write_section(git_filebuf *file, const char *key) ...@@ -983,9 +983,12 @@ static int write_section(git_filebuf *file, const char *key)
if (dot == NULL) { if (dot == NULL) {
git_buf_puts(&buf, key); git_buf_puts(&buf, key);
} else { } else {
char *escaped;
git_buf_put(&buf, key, dot - key); git_buf_put(&buf, key, dot - key);
/* TODO: escape */ escaped = escape_value(dot + 1);
git_buf_printf(&buf, " \"%s\"", dot + 1); GITERR_CHECK_ALLOC(escaped);
git_buf_printf(&buf, " \"%s\"", escaped);
git__free(escaped);
} }
git_buf_puts(&buf, "]\n"); git_buf_puts(&buf, "]\n");
......
...@@ -20,14 +20,21 @@ static char *diff_prefix_from_pathspec(const git_strarray *pathspec) ...@@ -20,14 +20,21 @@ static char *diff_prefix_from_pathspec(const git_strarray *pathspec)
return NULL; return NULL;
/* diff prefix will only be leading non-wildcards */ /* diff prefix will only be leading non-wildcards */
for (scan = prefix.ptr; *scan && !git__iswildcard(*scan); ++scan); for (scan = prefix.ptr; *scan; ++scan) {
if (git__iswildcard(*scan) &&
(scan == prefix.ptr || (*(scan - 1) != '\\')))
break;
}
git_buf_truncate(&prefix, scan - prefix.ptr); git_buf_truncate(&prefix, scan - prefix.ptr);
if (prefix.size > 0) if (prefix.size <= 0) {
return git_buf_detach(&prefix); git_buf_free(&prefix);
return NULL;
}
git_buf_free(&prefix); git_buf_unescape(&prefix);
return NULL;
return git_buf_detach(&prefix);
} }
static bool diff_pathspec_is_interesting(const git_strarray *pathspec) static bool diff_pathspec_is_interesting(const git_strarray *pathspec)
...@@ -54,7 +61,11 @@ static bool diff_path_matches_pathspec(git_diff_list *diff, const char *path) ...@@ -54,7 +61,11 @@ static bool diff_path_matches_pathspec(git_diff_list *diff, const char *path)
return true; return true;
git_vector_foreach(&diff->pathspec, i, match) { git_vector_foreach(&diff->pathspec, i, match) {
int result = p_fnmatch(match->pattern, path, 0); int result = strcmp(match->pattern, path) ? FNM_NOMATCH : 0;
if (((diff->opts.flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH) == 0) &&
result == FNM_NOMATCH)
result = p_fnmatch(match->pattern, path, 0);
/* if we didn't match, look for exact dirname prefix match */ /* if we didn't match, look for exact dirname prefix match */
if (result == FNM_NOMATCH && if (result == FNM_NOMATCH &&
...@@ -814,9 +825,9 @@ int git_diff_merge( ...@@ -814,9 +825,9 @@ int git_diff_merge(
/* prefix strings also come from old pool, so recreate those.*/ /* prefix strings also come from old pool, so recreate those.*/
onto->opts.old_prefix = onto->opts.old_prefix =
git_pool_strdup(&onto->pool, onto->opts.old_prefix); git_pool_strdup_safe(&onto->pool, onto->opts.old_prefix);
onto->opts.new_prefix = onto->opts.new_prefix =
git_pool_strdup(&onto->pool, onto->opts.new_prefix); git_pool_strdup_safe(&onto->pool, onto->opts.new_prefix);
} }
git_vector_foreach(&onto_new, i, delta) git_vector_foreach(&onto_new, i, delta)
...@@ -826,4 +837,3 @@ int git_diff_merge( ...@@ -826,4 +837,3 @@ int git_diff_merge(
return error; return error;
} }
...@@ -10,10 +10,6 @@ ...@@ -10,10 +10,6 @@
#include "mwindow.h" #include "mwindow.h"
typedef struct { typedef struct {
struct {
char last[1024];
} error;
git_error *last_error; git_error *last_error;
git_error error_t; git_error error_t;
......
...@@ -333,3 +333,72 @@ int git_object__resolve_to_type(git_object **obj, git_otype type) ...@@ -333,3 +333,72 @@ int git_object__resolve_to_type(git_object **obj, git_otype type)
*obj = scan; *obj = scan;
return error; return error;
} }
static int dereference_object(git_object **dereferenced, git_object *obj)
{
git_otype type = git_object_type(obj);
switch (type) {
case GIT_OBJ_COMMIT:
return git_commit_tree((git_tree **)dereferenced, (git_commit*)obj);
break;
case GIT_OBJ_TAG:
return git_tag_target(dereferenced, (git_tag*)obj);
break;
default:
return GIT_ENOTFOUND;
break;
}
}
static int peel_error(int error, const char* msg)
{
giterr_set(GITERR_INVALID, "The given object cannot be peeled - %s", msg);
return error;
}
int git_object_peel(
git_object **peeled,
git_object *object,
git_otype target_type)
{
git_object *source, *deref = NULL;
assert(object);
if (git_object_type(object) == target_type)
return git_object__dup(peeled, object);
if (target_type == GIT_OBJ_BLOB
|| target_type == GIT_OBJ_ANY)
return peel_error(GIT_EAMBIGUOUS, "Ambiguous target type");
if (git_object_type(object) == GIT_OBJ_BLOB)
return peel_error(GIT_ERROR, "A blob cannot be dereferenced");
source = object;
while (true) {
if (dereference_object(&deref, source) < 0)
goto cleanup;
if (source != object)
git_object_free(source);
if (git_object_type(deref) == target_type) {
*peeled = deref;
return 0;
}
source = deref;
deref = NULL;
}
cleanup:
if (source != object)
git_object_free(source);
git_object_free(deref);
return -1;
}
...@@ -206,6 +206,11 @@ char *git_pool_strdup(git_pool *pool, const char *str) ...@@ -206,6 +206,11 @@ char *git_pool_strdup(git_pool *pool, const char *str)
return git_pool_strndup(pool, str, strlen(str)); return git_pool_strndup(pool, str, strlen(str));
} }
char *git_pool_strdup_safe(git_pool *pool, const char *str)
{
return str ? git_pool_strdup(pool, str) : NULL;
}
char *git_pool_strcat(git_pool *pool, const char *a, const char *b) char *git_pool_strcat(git_pool *pool, const char *a, const char *b)
{ {
void *ptr; void *ptr;
......
...@@ -90,6 +90,13 @@ extern char *git_pool_strndup(git_pool *pool, const char *str, size_t n); ...@@ -90,6 +90,13 @@ extern char *git_pool_strndup(git_pool *pool, const char *str, size_t n);
extern char *git_pool_strdup(git_pool *pool, const char *str); extern char *git_pool_strdup(git_pool *pool, const char *str);
/** /**
* Allocate space and duplicate a string into it, NULL is no error.
*
* This is allowed only for pools with item_size == sizeof(char)
*/
extern char *git_pool_strdup_safe(git_pool *pool, const char *str);
/**
* Allocate space for the concatenation of two strings. * Allocate space for the concatenation of two strings.
* *
* This is allowed only for pools with item_size == sizeof(char) * This is allowed only for pools with item_size == sizeof(char)
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#define GIT_REFLOG_SIZE_MIN (2*GIT_OID_HEXSZ+2+17) #define GIT_REFLOG_SIZE_MIN (2*GIT_OID_HEXSZ+2+17)
#define GIT_OID_HEX_ZERO "0000000000000000000000000000000000000000"
struct git_reflog_entry { struct git_reflog_entry {
git_oid oid_old; git_oid oid_old;
git_oid oid_cur; git_oid oid_cur;
...@@ -28,6 +30,7 @@ struct git_reflog_entry { ...@@ -28,6 +30,7 @@ struct git_reflog_entry {
struct git_reflog { struct git_reflog {
char *ref_name; char *ref_name;
git_repository *owner;
git_vector entries; git_vector entries;
}; };
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "fileops.h" #include "fileops.h"
#include "pack.h" #include "pack.h"
#include "reflog.h" #include "reflog.h"
#include "config.h"
#include <git2/tag.h> #include <git2/tag.h>
#include <git2/object.h> #include <git2/object.h>
...@@ -1816,75 +1815,9 @@ int git_reference_has_log( ...@@ -1816,75 +1815,9 @@ int git_reference_has_log(
return result; return result;
} }
//TODO: How about also taking care of local tracking branches? int git_reference_is_branch(git_reference *ref)
//cf. http://alblue.bandlem.com/2011/07/git-tip-of-week-tracking-branches.html
int git_reference_remote_tracking_from_branch(
git_reference **tracking_ref,
git_reference *branch_ref)
{ {
git_config *config = NULL; assert(ref);
const char *name, *remote, *merge;
git_buf buf = GIT_BUF_INIT;
int error = -1;
assert(tracking_ref && branch_ref);
name = git_reference_name(branch_ref);
if (git__prefixcmp(name, GIT_REFS_HEADS_DIR)) {
giterr_set(
GITERR_INVALID,
"Failed to retrieve tracking reference - '%s' is not a branch.",
name);
return -1;
}
if (git_repository_config(&config, branch_ref->owner) < 0)
return -1;
if (git_buf_printf(
&buf,
"branch.%s.remote",
name + strlen(GIT_REFS_HEADS_DIR)) < 0)
goto cleanup;
if ((error = git_config_get_string(&remote, config, git_buf_cstr(&buf))) < 0)
goto cleanup;
error = -1;
git_buf_clear(&buf);
//TODO: Is it ok to fail when no merge target is found?
if (git_buf_printf(
&buf,
"branch.%s.merge",
name + strlen(GIT_REFS_HEADS_DIR)) < 0)
goto cleanup;
if (git_config_get_string(&merge, config, git_buf_cstr(&buf)) < 0)
goto cleanup;
//TODO: Should we test this?
if (git__prefixcmp(merge, GIT_REFS_HEADS_DIR))
goto cleanup;
git_buf_clear(&buf);
if (git_buf_printf(
&buf,
"refs/remotes/%s/%s",
remote,
merge + strlen(GIT_REFS_HEADS_DIR)) < 0)
goto cleanup;
error = git_reference_lookup(
tracking_ref,
branch_ref->owner,
git_buf_cstr(&buf));
cleanup: return git__prefixcmp(ref->name, GIT_REFS_HEADS_DIR) == 0;
git_config_free(config);
git_buf_free(&buf);
return error;
} }
...@@ -131,6 +131,26 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) ...@@ -131,6 +131,26 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
GITERR_CHECK_ALLOC(remote->url); GITERR_CHECK_ALLOC(remote->url);
git_buf_clear(&buf); git_buf_clear(&buf);
if (git_buf_printf(&buf, "remote.%s.pushurl", name) < 0) {
error = -1;
goto cleanup;
}
error = git_config_get_string(&val, config, git_buf_cstr(&buf));
if (error == GIT_ENOTFOUND)
error = 0;
if (error < 0) {
error = -1;
goto cleanup;
}
if (val) {
remote->pushurl = git__strdup(val);
GITERR_CHECK_ALLOC(remote->pushurl);
}
git_buf_clear(&buf);
if (git_buf_printf(&buf, "remote.%s.fetch", name) < 0) { if (git_buf_printf(&buf, "remote.%s.fetch", name) < 0) {
error = -1; error = -1;
goto cleanup; goto cleanup;
...@@ -179,7 +199,7 @@ int git_remote_save(const git_remote *remote) ...@@ -179,7 +199,7 @@ int git_remote_save(const git_remote *remote)
if (git_repository_config__weakptr(&config, remote->repo) < 0) if (git_repository_config__weakptr(&config, remote->repo) < 0)
return -1; return -1;
if (git_buf_printf(&buf, "remote.%s.%s", remote->name, "url") < 0) if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0)
return -1; return -1;
if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) { if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
...@@ -187,6 +207,26 @@ int git_remote_save(const git_remote *remote) ...@@ -187,6 +207,26 @@ int git_remote_save(const git_remote *remote)
return -1; return -1;
} }
git_buf_clear(&buf);
if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0)
return -1;
if (remote->pushurl) {
if (git_config_set_string(config, git_buf_cstr(&buf), remote->pushurl) < 0) {
git_buf_free(&buf);
return -1;
}
} else {
int error = git_config_delete(config, git_buf_cstr(&buf));
if (error == GIT_ENOTFOUND) {
error = 0;
}
if (error < 0) {
git_buf_free(&buf);
return -1;
}
}
if (remote->fetch.src != NULL && remote->fetch.dst != NULL) { if (remote->fetch.src != NULL && remote->fetch.dst != NULL) {
git_buf_clear(&buf); git_buf_clear(&buf);
git_buf_clear(&value); git_buf_clear(&value);
...@@ -238,6 +278,38 @@ const char *git_remote_url(git_remote *remote) ...@@ -238,6 +278,38 @@ const char *git_remote_url(git_remote *remote)
return remote->url; return remote->url;
} }
int git_remote_set_url(git_remote *remote, const char* url)
{
assert(remote);
assert(url);
git__free(remote->url);
remote->url = git__strdup(url);
GITERR_CHECK_ALLOC(remote->url);
return 0;
}
const char *git_remote_pushurl(git_remote *remote)
{
assert(remote);
return remote->pushurl;
}
int git_remote_set_pushurl(git_remote *remote, const char* url)
{
assert(remote);
git__free(remote->pushurl);
if (url) {
remote->pushurl = git__strdup(url);
GITERR_CHECK_ALLOC(remote->pushurl);
} else {
remote->pushurl = NULL;
}
return 0;
}
int git_remote_set_fetchspec(git_remote *remote, const char *spec) int git_remote_set_fetchspec(git_remote *remote, const char *spec)
{ {
git_refspec refspec; git_refspec refspec;
...@@ -284,13 +356,33 @@ const git_refspec *git_remote_pushspec(git_remote *remote) ...@@ -284,13 +356,33 @@ const git_refspec *git_remote_pushspec(git_remote *remote)
return &remote->push; return &remote->push;
} }
const char* git_remote__urlfordirection(git_remote *remote, int direction)
{
assert(remote);
if (direction == GIT_DIR_FETCH) {
return remote->url;
}
if (direction == GIT_DIR_PUSH) {
return remote->pushurl ? remote->pushurl : remote->url;
}
return NULL;
}
int git_remote_connect(git_remote *remote, int direction) int git_remote_connect(git_remote *remote, int direction)
{ {
git_transport *t; git_transport *t;
const char *url;
assert(remote); assert(remote);
if (git_transport_new(&t, remote->url) < 0) url = git_remote__urlfordirection(remote, direction);
if (url == NULL )
return -1;
if (git_transport_new(&t, url) < 0)
return -1; return -1;
t->check_cert = remote->check_cert; t->check_cert = remote->check_cert;
...@@ -331,7 +423,7 @@ int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats ...@@ -331,7 +423,7 @@ int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats
return git_fetch_download_pack(remote, bytes, stats); return git_fetch_download_pack(remote, bytes, stats);
} }
int git_remote_update_tips(git_remote *remote, int (*cb)(const char *refname, const git_oid *a, const git_oid *b)) int git_remote_update_tips(git_remote *remote)
{ {
int error = 0; int error = 0;
unsigned int i = 0; unsigned int i = 0;
...@@ -377,12 +469,12 @@ int git_remote_update_tips(git_remote *remote, int (*cb)(const char *refname, co ...@@ -377,12 +469,12 @@ int git_remote_update_tips(git_remote *remote, int (*cb)(const char *refname, co
continue; continue;
if (git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, 1) < 0) if (git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, 1) < 0)
break; goto on_error;
git_reference_free(ref); git_reference_free(ref);
if (cb != NULL) { if (remote->callbacks.update_tips != NULL) {
if (cb(refname.ptr, &old, &head->oid) < 0) if (remote->callbacks.update_tips(refname.ptr, &old, &head->oid, remote->callbacks.data) < 0)
goto on_error; goto on_error;
} }
} }
...@@ -429,6 +521,7 @@ void git_remote_free(git_remote *remote) ...@@ -429,6 +521,7 @@ void git_remote_free(git_remote *remote)
git__free(remote->push.src); git__free(remote->push.src);
git__free(remote->push.dst); git__free(remote->push.dst);
git__free(remote->url); git__free(remote->url);
git__free(remote->pushurl);
git__free(remote->name); git__free(remote->name);
git__free(remote); git__free(remote);
} }
...@@ -525,3 +618,10 @@ void git_remote_check_cert(git_remote *remote, int check) ...@@ -525,3 +618,10 @@ void git_remote_check_cert(git_remote *remote, int check)
remote->check_cert = check; remote->check_cert = check;
} }
void git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks)
{
assert(remote && callbacks);
memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks));
}
...@@ -14,13 +14,17 @@ ...@@ -14,13 +14,17 @@
struct git_remote { struct git_remote {
char *name; char *name;
char *url; char *url;
char *pushurl;
git_vector refs; git_vector refs;
struct git_refspec fetch; struct git_refspec fetch;
struct git_refspec push; struct git_refspec push;
git_transport *transport; git_transport *transport;
git_repository *repo; git_repository *repo;
git_remote_callbacks callbacks;
unsigned int need_pack:1, unsigned int need_pack:1,
check_cert; check_cert;
}; };
const char* git_remote__urlfordirection(struct git_remote *remote, int direction);
#endif #endif
...@@ -98,6 +98,13 @@ struct git_repository { ...@@ -98,6 +98,13 @@ struct git_repository {
* export */ * export */
void git_object__free(void *object); void git_object__free(void *object);
GIT_INLINE(int) git_object__dup(git_object **dest, git_object *source)
{
git_cached_obj_incref(source);
*dest = source;
return 0;
}
int git_object__resolve_to_type(git_object **obj, git_otype type); int git_object__resolve_to_type(git_object **obj, git_otype type);
int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header); int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header);
......
...@@ -99,6 +99,8 @@ int git_status_foreach_ext( ...@@ -99,6 +99,8 @@ int git_status_foreach_ext(
diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNMODIFIED; diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNMODIFIED;
if ((opts->flags & GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS) != 0) if ((opts->flags & GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS) != 0)
diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS; diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS;
if ((opts->flags & GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH) != 0)
diffopt.flags = diffopt.flags | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
/* TODO: support EXCLUDE_SUBMODULES flag */ /* TODO: support EXCLUDE_SUBMODULES flag */
if (show != GIT_STATUS_SHOW_WORKDIR_ONLY && if (show != GIT_STATUS_SHOW_WORKDIR_ONLY &&
...@@ -176,10 +178,12 @@ static int get_one_status(const char *path, unsigned int status, void *data) ...@@ -176,10 +178,12 @@ static int get_one_status(const char *path, unsigned int status, void *data)
sfi->count++; sfi->count++;
sfi->status = status; sfi->status = status;
if (sfi->count > 1 || strcmp(sfi->expected, path) != 0) { if (sfi->count > 1 ||
(strcmp(sfi->expected, path) != 0 &&
p_fnmatch(sfi->expected, path, 0) != 0)) {
giterr_set(GITERR_INVALID, giterr_set(GITERR_INVALID,
"Ambiguous path '%s' given to git_status_file", sfi->expected); "Ambiguous path '%s' given to git_status_file", sfi->expected);
return -1; return GIT_EAMBIGUOUS;
} }
return 0; return 0;
......
...@@ -759,11 +759,12 @@ int git_tree_entry_bypath( ...@@ -759,11 +759,12 @@ int git_tree_entry_bypath(
return error; return error;
} }
static int tree_walk_post( static int tree_walk(
git_tree *tree, git_tree *tree,
git_treewalk_cb callback, git_treewalk_cb callback,
git_buf *path, git_buf *path,
void *payload) void *payload,
bool preorder)
{ {
int error = 0; int error = 0;
unsigned int i; unsigned int i;
...@@ -771,8 +772,8 @@ static int tree_walk_post( ...@@ -771,8 +772,8 @@ static int tree_walk_post(
for (i = 0; i < tree->entries.length; ++i) { for (i = 0; i < tree->entries.length; ++i) {
git_tree_entry *entry = tree->entries.contents[i]; git_tree_entry *entry = tree->entries.contents[i];
if (callback(path->ptr, entry, payload) < 0) if (preorder && callback(path->ptr, entry, payload) < 0)
continue; return -1;
if (git_tree_entry__is_tree(entry)) { if (git_tree_entry__is_tree(entry)) {
git_tree *subtree; git_tree *subtree;
...@@ -789,12 +790,15 @@ static int tree_walk_post( ...@@ -789,12 +790,15 @@ static int tree_walk_post(
if (git_buf_oom(path)) if (git_buf_oom(path))
return -1; return -1;
if (tree_walk_post(subtree, callback, path, payload) < 0) if (tree_walk(subtree, callback, path, payload, preorder) < 0)
return -1; return -1;
git_buf_truncate(path, path_len); git_buf_truncate(path, path_len);
git_tree_free(subtree); git_tree_free(subtree);
} }
if (!preorder && callback(path->ptr, entry, payload) < 0)
return -1;
} }
return 0; return 0;
...@@ -807,12 +811,12 @@ int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payl ...@@ -807,12 +811,12 @@ int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payl
switch (mode) { switch (mode) {
case GIT_TREEWALK_POST: case GIT_TREEWALK_POST:
error = tree_walk_post(tree, callback, &root_path, payload); error = tree_walk(tree, callback, &root_path, payload, false);
break; break;
case GIT_TREEWALK_PRE: case GIT_TREEWALK_PRE:
tree_error("Preorder tree walking is still not implemented"); error = tree_walk(tree, callback, &root_path, payload, true);
return -1; break;
default: default:
giterr_set(GITERR_INVALID, "Invalid walking mode for tree walk"); giterr_set(GITERR_INVALID, "Invalid walking mode for tree walk");
......
...@@ -435,3 +435,21 @@ int git__parse_bool(int *out, const char *value) ...@@ -435,3 +435,21 @@ int git__parse_bool(int *out, const char *value)
return -1; return -1;
} }
size_t git__unescape(char *str)
{
char *scan, *pos = str;
for (scan = str; *scan; pos++, scan++) {
if (*scan == '\\' && *(scan + 1) != '\0')
scan++; /* skip '\' but include next char */
if (pos != scan)
*pos = *scan;
}
if (pos != scan) {
*pos = '\0';
}
return (pos - str);
}
...@@ -238,4 +238,13 @@ extern int git__parse_bool(int *out, const char *value); ...@@ -238,4 +238,13 @@ extern int git__parse_bool(int *out, const char *value);
*/ */
int git__date_parse(git_time_t *out, const char *date); int git__date_parse(git_time_t *out, const char *date);
/*
* Unescapes a string in-place.
*
* Edge cases behavior:
* - "jackie\" -> "jacky\"
* - "chan\\" -> "chan\"
*/
extern size_t git__unescape(char *str);
#endif /* INCLUDE_util_h__ */ #endif /* INCLUDE_util_h__ */
...@@ -59,3 +59,26 @@ void test_config_stress__comments(void) ...@@ -59,3 +59,26 @@ void test_config_stress__comments(void)
git_config_free(config); git_config_free(config);
} }
void test_config_stress__escape_subsection_names(void)
{
struct git_config_file *file;
git_config *config;
const char *str;
cl_assert(git_path_exists("git-test-config"));
cl_git_pass(git_config_file__ondisk(&file, "git-test-config"));
cl_git_pass(git_config_new(&config));
cl_git_pass(git_config_add_file(config, file, 0));
cl_git_pass(git_config_set_string(config, "some.sec\\tion.other", "foo"));
git_config_free(config);
cl_git_pass(git_config_file__ondisk(&file, "git-test-config"));
cl_git_pass(git_config_new(&config));
cl_git_pass(git_config_add_file(config, file, 0));
cl_git_pass(git_config_get_string(&str, config, "some.sec\\tion.other"));
cl_assert(!strcmp("foo", str));
git_config_free(config);
}
...@@ -658,3 +658,23 @@ void test_core_buffer__puts_escaped(void) ...@@ -658,3 +658,23 @@ void test_core_buffer__puts_escaped(void)
git_buf_free(&a); git_buf_free(&a);
} }
static void assert_unescape(char *expected, char *to_unescape) {
git_buf buf = GIT_BUF_INIT;
cl_git_pass(git_buf_sets(&buf, to_unescape));
git_buf_unescape(&buf);
cl_assert_equal_s(expected, buf.ptr);
cl_assert_equal_i(strlen(expected), buf.size);
git_buf_free(&buf);
}
void test_core_buffer__unescape(void)
{
assert_unescape("Escaped\\", "Es\\ca\\ped\\");
assert_unescape("Es\\caped\\", "Es\\\\ca\\ped\\\\");
assert_unescape("\\", "\\");
assert_unescape("\\", "\\\\");
assert_unescape("", "");
}
...@@ -208,3 +208,51 @@ void test_diff_tree__bare(void) ...@@ -208,3 +208,51 @@ void test_diff_tree__bare(void)
git_tree_free(a); git_tree_free(a);
git_tree_free(b); git_tree_free(b);
} }
void test_diff_tree__merge(void)
{
/* grabbed a couple of commit oids from the history of the attr repo */
const char *a_commit = "605812a";
const char *b_commit = "370fe9ec22";
const char *c_commit = "f5b0af1fb4f5c";
git_tree *a, *b, *c;
git_diff_list *diff1 = NULL, *diff2 = NULL;
diff_expects exp;
g_repo = cl_git_sandbox_init("attr");
cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
cl_assert((c = resolve_commit_oid_to_tree(g_repo, c_commit)) != NULL);
cl_git_pass(git_diff_tree_to_tree(g_repo, NULL, a, b, &diff1));
cl_git_pass(git_diff_tree_to_tree(g_repo, NULL, c, b, &diff2));
git_tree_free(a);
git_tree_free(b);
git_tree_free(c);
cl_git_pass(git_diff_merge(diff1, diff2));
git_diff_list_free(diff2);
memset(&exp, 0, sizeof(exp));
cl_git_pass(git_diff_foreach(
diff1, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
cl_assert(exp.files == 6);
cl_assert(exp.file_adds == 2);
cl_assert(exp.file_dels == 1);
cl_assert(exp.file_mods == 3);
cl_assert(exp.hunks == 6);
cl_assert(exp.lines == 59);
cl_assert(exp.line_ctxt == 1);
cl_assert(exp.line_adds == 36);
cl_assert(exp.line_dels == 22);
git_diff_list_free(diff1);
}
...@@ -107,7 +107,7 @@ void test_network_remotelocal__retrieve_advertised_references(void) ...@@ -107,7 +107,7 @@ void test_network_remotelocal__retrieve_advertised_references(void)
cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs)); cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs));
cl_assert_equal_i(how_many_refs, 22); cl_assert_equal_i(how_many_refs, 23);
} }
void test_network_remotelocal__retrieve_advertised_references_from_spaced_repository(void) void test_network_remotelocal__retrieve_advertised_references_from_spaced_repository(void)
...@@ -121,7 +121,7 @@ void test_network_remotelocal__retrieve_advertised_references_from_spaced_reposi ...@@ -121,7 +121,7 @@ void test_network_remotelocal__retrieve_advertised_references_from_spaced_reposi
cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs)); cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs));
cl_assert_equal_i(how_many_refs, 22); cl_assert_equal_i(how_many_refs, 23);
git_remote_free(remote); /* Disconnect from the "spaced repo" before the cleanup */ git_remote_free(remote); /* Disconnect from the "spaced repo" before the cleanup */
remote = NULL; remote = NULL;
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include "buffer.h" #include "buffer.h"
#include "refspec.h" #include "refspec.h"
#include "transport.h" #include "transport.h"
#include "remote.h"
static git_remote *_remote; static git_remote *_remote;
static git_repository *_repo; static git_repository *_repo;
...@@ -27,8 +28,37 @@ void test_network_remotes__cleanup(void) ...@@ -27,8 +28,37 @@ void test_network_remotes__cleanup(void)
void test_network_remotes__parsing(void) void test_network_remotes__parsing(void)
{ {
git_remote *_remote2 = NULL;
cl_assert_equal_s(git_remote_name(_remote), "test"); cl_assert_equal_s(git_remote_name(_remote), "test");
cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2"); cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2");
cl_assert(git_remote_pushurl(_remote) == NULL);
cl_assert_equal_s(git_remote__urlfordirection(_remote, GIT_DIR_FETCH),
"git://github.com/libgit2/libgit2");
cl_assert_equal_s(git_remote__urlfordirection(_remote, GIT_DIR_PUSH),
"git://github.com/libgit2/libgit2");
cl_git_pass(git_remote_load(&_remote2, _repo, "test_with_pushurl"));
cl_assert_equal_s(git_remote_name(_remote2), "test_with_pushurl");
cl_assert_equal_s(git_remote_url(_remote2), "git://github.com/libgit2/fetchlibgit2");
cl_assert_equal_s(git_remote_pushurl(_remote2), "git://github.com/libgit2/pushlibgit2");
cl_assert_equal_s(git_remote__urlfordirection(_remote2, GIT_DIR_FETCH),
"git://github.com/libgit2/fetchlibgit2");
cl_assert_equal_s(git_remote__urlfordirection(_remote2, GIT_DIR_PUSH),
"git://github.com/libgit2/pushlibgit2");
git_remote_free(_remote2);
}
void test_network_remotes__pushurl(void)
{
cl_git_pass(git_remote_set_pushurl(_remote, "git://github.com/libgit2/notlibgit2"));
cl_assert_equal_s(git_remote_pushurl(_remote), "git://github.com/libgit2/notlibgit2");
cl_git_pass(git_remote_set_pushurl(_remote, NULL));
cl_assert(git_remote_pushurl(_remote) == NULL);
} }
void test_network_remotes__parsing_ssh_remote(void) void test_network_remotes__parsing_ssh_remote(void)
...@@ -81,6 +111,7 @@ void test_network_remotes__save(void) ...@@ -81,6 +111,7 @@ void test_network_remotes__save(void)
cl_git_pass(git_remote_new(&_remote, _repo, "upstream", "git://github.com/libgit2/libgit2", NULL)); cl_git_pass(git_remote_new(&_remote, _repo, "upstream", "git://github.com/libgit2/libgit2", NULL));
cl_git_pass(git_remote_set_fetchspec(_remote, "refs/heads/*:refs/remotes/upstream/*")); cl_git_pass(git_remote_set_fetchspec(_remote, "refs/heads/*:refs/remotes/upstream/*"));
cl_git_pass(git_remote_set_pushspec(_remote, "refs/heads/*:refs/heads/*")); cl_git_pass(git_remote_set_pushspec(_remote, "refs/heads/*:refs/heads/*"));
cl_git_pass(git_remote_set_pushurl(_remote, "git://github.com/libgit2/libgit2_push"));
cl_git_pass(git_remote_save(_remote)); cl_git_pass(git_remote_save(_remote));
git_remote_free(_remote); git_remote_free(_remote);
_remote = NULL; _remote = NULL;
...@@ -98,6 +129,18 @@ void test_network_remotes__save(void) ...@@ -98,6 +129,18 @@ void test_network_remotes__save(void)
cl_assert(_refspec != NULL); cl_assert(_refspec != NULL);
cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*"); cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*");
cl_assert_equal_s(git_refspec_dst(_refspec), "refs/heads/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/heads/*");
cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2");
cl_assert_equal_s(git_remote_pushurl(_remote), "git://github.com/libgit2/libgit2_push");
/* remove the pushurl again and see if we can save that too */
cl_git_pass(git_remote_set_pushurl(_remote, NULL));
cl_git_pass(git_remote_save(_remote));
git_remote_free(_remote);
_remote = NULL;
cl_git_pass(git_remote_load(&_remote, _repo, "upstream"));
cl_assert(git_remote_pushurl(_remote) == NULL);
} }
void test_network_remotes__fnmatch(void) void test_network_remotes__fnmatch(void)
...@@ -143,13 +186,13 @@ void test_network_remotes__list(void) ...@@ -143,13 +186,13 @@ void test_network_remotes__list(void)
git_config *cfg; git_config *cfg;
cl_git_pass(git_remote_list(&list, _repo)); cl_git_pass(git_remote_list(&list, _repo));
cl_assert(list.count == 1); cl_assert(list.count == 2);
git_strarray_free(&list); git_strarray_free(&list);
cl_git_pass(git_repository_config(&cfg, _repo)); cl_git_pass(git_repository_config(&cfg, _repo));
cl_git_pass(git_config_set_string(cfg, "remote.specless.url", "http://example.com")); cl_git_pass(git_config_set_string(cfg, "remote.specless.url", "http://example.com"));
cl_git_pass(git_remote_list(&list, _repo)); cl_git_pass(git_remote_list(&list, _repo));
cl_assert(list.count == 2); cl_assert(list.count == 3);
git_strarray_free(&list); git_strarray_free(&list);
git_config_free(cfg); git_config_free(cfg);
...@@ -180,4 +223,5 @@ void test_network_remotes__add(void) ...@@ -180,4 +223,5 @@ void test_network_remotes__add(void)
cl_assert(!strcmp(git_refspec_src(_refspec), "refs/heads/*")); cl_assert(!strcmp(git_refspec_src(_refspec), "refs/heads/*"));
cl_assert(git_refspec_force(_refspec) == 1); cl_assert(git_refspec_force(_refspec) == 1);
cl_assert(!strcmp(git_refspec_dst(_refspec), "refs/remotes/addtest/*")); cl_assert(!strcmp(git_refspec_dst(_refspec), "refs/remotes/addtest/*"));
cl_assert_equal_s(git_remote_url(_remote), "http://github.com/libgit2/libgit2");
} }
#include "clar_libgit2.h"
static git_repository *g_repo;
void test_object_peel__initialize(void)
{
cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
}
void test_object_peel__cleanup(void)
{
git_repository_free(g_repo);
}
static void assert_peel(const char* expected_sha, const char *sha, git_otype requested_type)
{
git_oid oid, expected_oid;
git_object *obj;
git_object *peeled;
cl_git_pass(git_oid_fromstr(&oid, sha));
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
cl_git_pass(git_object_peel(&peeled, obj, requested_type));
cl_git_pass(git_oid_fromstr(&expected_oid, expected_sha));
cl_assert_equal_i(0, git_oid_cmp(&expected_oid, git_object_id(peeled)));
git_object_free(peeled);
git_object_free(obj);
}
static void assert_peel_error(int error, const char *sha, git_otype requested_type)
{
git_oid oid;
git_object *obj;
git_object *peeled;
cl_git_pass(git_oid_fromstr(&oid, sha));
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
cl_assert_equal_i(error, git_object_peel(&peeled, obj, requested_type));
git_object_free(obj);
}
void test_object_peel__peeling_an_object_into_its_own_type_returns_another_instance_of_it(void)
{
assert_peel("e90810b8df3e80c413d903f631643c716887138d", "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_COMMIT);
assert_peel("7b4384978d2493e851f9cca7858815fac9b10980", "7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_TAG);
assert_peel("53fc32d17276939fc79ed05badaef2db09990016", "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_TREE);
assert_peel("0266163a49e280c4f5ed1e08facd36a2bd716bcf", "0266163a49e280c4f5ed1e08facd36a2bd716bcf", GIT_OBJ_BLOB);
}
void test_object_peel__can_peel_a_tag(void)
{
assert_peel("e90810b8df3e80c413d903f631643c716887138d", "7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_COMMIT);
assert_peel("53fc32d17276939fc79ed05badaef2db09990016", "7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_TREE);
}
void test_object_peel__can_peel_a_commit(void)
{
assert_peel("53fc32d17276939fc79ed05badaef2db09990016", "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_TREE);
}
void test_object_peel__cannot_peel_a_tree(void)
{
assert_peel_error(GIT_EAMBIGUOUS, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_BLOB);
}
void test_object_peel__cannot_peel_a_blob(void)
{
assert_peel_error(GIT_ERROR, "0266163a49e280c4f5ed1e08facd36a2bd716bcf", GIT_OBJ_COMMIT);
}
void test_object_peel__cannot_target_any_object(void)
{
assert_peel_error(GIT_EAMBIGUOUS, "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_ANY);
}
...@@ -29,8 +29,18 @@ static int foreach_cb(git_oid *oid, void *data) ...@@ -29,8 +29,18 @@ static int foreach_cb(git_oid *oid, void *data)
return 0; return 0;
} }
/*
* $ git --git-dir tests-clar/resources/testrepo.git count-objects --verbose
* count: 43
* size: 3
* in-pack: 1640
* packs: 3
* size-pack: 425
* prune-packable: 0
* garbage: 0
*/
void test_odb_foreach__foreach(void) void test_odb_foreach__foreach(void)
{ {
cl_git_pass(git_odb_foreach(_odb, foreach_cb, NULL)); cl_git_pass(git_odb_foreach(_odb, foreach_cb, NULL));
cl_assert(nobj == 1683); cl_assert_equal_i(43 + 1640, nobj); /* count + in-pack */
} }
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "refs.h" #include "refs.h"
#include "branch.h"
static git_repository *repo; static git_repository *repo;
static git_oid branch_target_oid;
static git_object *target; static git_object *target;
static git_reference *branch;
void test_refs_branches_create__initialize(void) void test_refs_branches_create__initialize(void)
{ {
cl_fixture_sandbox("testrepo.git"); cl_fixture_sandbox("testrepo.git");
cl_git_pass(git_repository_open(&repo, "testrepo.git")); cl_git_pass(git_repository_open(&repo, "testrepo.git"));
branch = NULL;
} }
void test_refs_branches_create__cleanup(void) void test_refs_branches_create__cleanup(void)
{ {
git_reference_free(branch);
git_object_free(target); git_object_free(target);
git_repository_free(repo); git_repository_free(repo);
...@@ -39,54 +42,24 @@ void test_refs_branches_create__can_create_a_local_branch(void) ...@@ -39,54 +42,24 @@ void test_refs_branches_create__can_create_a_local_branch(void)
{ {
retrieve_known_commit(&target, repo); retrieve_known_commit(&target, repo);
cl_git_pass(git_branch_create(&branch_target_oid, repo, NEW_BRANCH_NAME, target, 0)); cl_git_pass(git_branch_create(&branch, repo, NEW_BRANCH_NAME, target, 0));
cl_git_pass(git_oid_cmp(&branch_target_oid, git_object_id(target))); cl_git_pass(git_oid_cmp(git_reference_oid(branch), git_object_id(target)));
}
void test_refs_branches_create__creating_a_local_branch_triggers_the_creation_of_a_new_direct_reference(void)
{
git_reference *branch;
retrieve_known_commit(&target, repo);
cl_git_fail(git_reference_lookup(&branch, repo, GIT_REFS_HEADS_DIR NEW_BRANCH_NAME));
cl_git_pass(git_branch_create(&branch_target_oid, repo, NEW_BRANCH_NAME, target, 0));
cl_git_pass(git_reference_lookup(&branch, repo, GIT_REFS_HEADS_DIR NEW_BRANCH_NAME));
cl_assert(git_reference_type(branch) == GIT_REF_OID);
git_reference_free(branch);
} }
void test_refs_branches_create__can_not_create_a_branch_if_its_name_collide_with_an_existing_one(void) void test_refs_branches_create__can_not_create_a_branch_if_its_name_collide_with_an_existing_one(void)
{ {
retrieve_known_commit(&target, repo); retrieve_known_commit(&target, repo);
cl_git_fail(git_branch_create(&branch_target_oid, repo, "br2", target, 0)); cl_git_fail(git_branch_create(&branch, repo, "br2", target, 0));
} }
void test_refs_branches_create__can_force_create_over_an_existing_branch(void) void test_refs_branches_create__can_force_create_over_an_existing_branch(void)
{ {
retrieve_known_commit(&target, repo); retrieve_known_commit(&target, repo);
cl_git_pass(git_branch_create(&branch_target_oid, repo, "br2", target, 1)); cl_git_pass(git_branch_create(&branch, repo, "br2", target, 1));
cl_git_pass(git_oid_cmp(&branch_target_oid, git_object_id(target))); cl_git_pass(git_oid_cmp(git_reference_oid(branch), git_object_id(target)));
} cl_assert_equal_s("refs/heads/br2", git_reference_name(branch));
void test_refs_branches_create__can_not_create_a_branch_pointing_at_an_object_unknown_from_the_repository(void)
{
git_repository *repo2;
/* Open another instance of the same repository */
cl_git_pass(git_repository_open(&repo2, cl_fixture("testrepo.git")));
/* Retrieve a commit object from this different repository */
retrieve_known_commit(&target, repo2);
cl_git_fail(git_branch_create(&branch_target_oid, repo, NEW_BRANCH_NAME, target, 0));
git_repository_free(repo2);
} }
void test_refs_branches_create__creating_a_branch_targeting_a_tag_dereferences_it_to_its_commit(void) void test_refs_branches_create__creating_a_branch_targeting_a_tag_dereferences_it_to_its_commit(void)
...@@ -94,8 +67,8 @@ void test_refs_branches_create__creating_a_branch_targeting_a_tag_dereferences_i ...@@ -94,8 +67,8 @@ void test_refs_branches_create__creating_a_branch_targeting_a_tag_dereferences_i
/* b25fa35 is a tag, pointing to another tag which points to a commit */ /* b25fa35 is a tag, pointing to another tag which points to a commit */
retrieve_target_from_oid(&target, repo, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); retrieve_target_from_oid(&target, repo, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1");
cl_git_pass(git_branch_create(&branch_target_oid, repo, NEW_BRANCH_NAME, target, 0)); cl_git_pass(git_branch_create(&branch, repo, NEW_BRANCH_NAME, target, 0));
cl_git_pass(git_oid_streq(&branch_target_oid, "e90810b8df3e80c413d903f631643c716887138d")); cl_git_pass(git_oid_streq(git_reference_oid(branch), "e90810b8df3e80c413d903f631643c716887138d"));
} }
void test_refs_branches_create__can_not_create_a_branch_pointing_to_a_non_commit_object(void) void test_refs_branches_create__can_not_create_a_branch_pointing_to_a_non_commit_object(void)
...@@ -103,11 +76,11 @@ void test_refs_branches_create__can_not_create_a_branch_pointing_to_a_non_commit ...@@ -103,11 +76,11 @@ void test_refs_branches_create__can_not_create_a_branch_pointing_to_a_non_commit
/* 53fc32d is the tree of commit e90810b */ /* 53fc32d is the tree of commit e90810b */
retrieve_target_from_oid(&target, repo, "53fc32d17276939fc79ed05badaef2db09990016"); retrieve_target_from_oid(&target, repo, "53fc32d17276939fc79ed05badaef2db09990016");
cl_git_fail(git_branch_create(&branch_target_oid, repo, NEW_BRANCH_NAME, target, 0)); cl_git_fail(git_branch_create(&branch, repo, NEW_BRANCH_NAME, target, 0));
git_object_free(target); git_object_free(target);
/* 521d87c is an annotated tag pointing to a blob */ /* 521d87c is an annotated tag pointing to a blob */
retrieve_target_from_oid(&target, repo, "521d87c1ec3aef9824daf6d96cc0ae3710766d91"); retrieve_target_from_oid(&target, repo, "521d87c1ec3aef9824daf6d96cc0ae3710766d91");
cl_git_fail(git_branch_create(&branch_target_oid, repo, NEW_BRANCH_NAME, target, 0)); cl_git_fail(git_branch_create(&branch, repo, NEW_BRANCH_NAME, target, 0));
} }
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "refs.h" #include "refs.h"
#include "branch.h"
static git_repository *repo; static git_repository *repo;
static git_reference *fake_remote; static git_reference *fake_remote;
......
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "refs.h" #include "refs.h"
#include "branch.h"
static git_repository *repo; static git_repository *repo;
static git_reference *fake_remote; static git_reference *fake_remote;
...@@ -48,7 +47,7 @@ static void assert_retrieval(unsigned int flags, unsigned int expected_count) ...@@ -48,7 +47,7 @@ static void assert_retrieval(unsigned int flags, unsigned int expected_count)
void test_refs_branches_foreach__retrieve_all_branches(void) void test_refs_branches_foreach__retrieve_all_branches(void)
{ {
assert_retrieval(GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, 10); assert_retrieval(GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, 11);
} }
void test_refs_branches_foreach__retrieve_remote_branches(void) void test_refs_branches_foreach__retrieve_remote_branches(void)
...@@ -58,7 +57,7 @@ void test_refs_branches_foreach__retrieve_remote_branches(void) ...@@ -58,7 +57,7 @@ void test_refs_branches_foreach__retrieve_remote_branches(void)
void test_refs_branches_foreach__retrieve_local_branches(void) void test_refs_branches_foreach__retrieve_local_branches(void)
{ {
assert_retrieval(GIT_BRANCH_LOCAL, 8); assert_retrieval(GIT_BRANCH_LOCAL, 9);
} }
struct expectations { struct expectations {
......
#include "clar_libgit2.h"
#include "refs.h"
static git_repository *repo;
static git_reference *branch;
void test_refs_branches_lookup__initialize(void)
{
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
branch = NULL;
}
void test_refs_branches_lookup__cleanup(void)
{
git_reference_free(branch);
git_repository_free(repo);
}
void test_refs_branches_lookup__can_retrieve_a_local_branch(void)
{
cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
}
void test_refs_branches_lookup__can_retrieve_a_remote_tracking_branch(void)
{
cl_git_pass(git_branch_lookup(&branch, repo, "test/master", GIT_BRANCH_REMOTE));
}
void test_refs_branches_lookup__trying_to_retrieve_an_unknown_branch_returns_ENOTFOUND(void)
{
cl_assert_equal_i(GIT_ENOTFOUND, git_branch_lookup(&branch, repo, "where/are/you", GIT_BRANCH_LOCAL));
cl_assert_equal_i(GIT_ENOTFOUND, git_branch_lookup(&branch, repo, "over/here", GIT_BRANCH_REMOTE));
}
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "branch.h" #include "refs.h"
static git_repository *repo; static git_repository *repo;
static git_reference *ref;
void test_refs_branches_move__initialize(void) void test_refs_branches_move__initialize(void)
{ {
cl_fixture_sandbox("testrepo.git"); repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_repository_open(&repo, "testrepo.git"));
cl_git_pass(git_reference_lookup(&ref, repo, "refs/heads/br2"));
} }
void test_refs_branches_move__cleanup(void) void test_refs_branches_move__cleanup(void)
{ {
git_repository_free(repo); git_reference_free(ref);
cl_git_sandbox_cleanup();
cl_fixture_cleanup("testrepo.git");
} }
#define NEW_BRANCH_NAME "new-branch-on-the-block" #define NEW_BRANCH_NAME "new-branch-on-the-block"
void test_refs_branches_move__can_move_a_local_branch(void) void test_refs_branches_move__can_move_a_local_branch(void)
{ {
cl_git_pass(git_branch_move(repo, "br2", NEW_BRANCH_NAME, 0)); cl_git_pass(git_branch_move(ref, NEW_BRANCH_NAME, 0));
cl_assert_equal_s(GIT_REFS_HEADS_DIR NEW_BRANCH_NAME, git_reference_name(ref));
} }
void test_refs_branches_move__can_move_a_local_branch_to_a_different_namespace(void) void test_refs_branches_move__can_move_a_local_branch_to_a_different_namespace(void)
{ {
/* Downward */ /* Downward */
cl_git_pass(git_branch_move(repo, "br2", "somewhere/" NEW_BRANCH_NAME, 0)); cl_git_pass(git_branch_move(ref, "somewhere/" NEW_BRANCH_NAME, 0));
/* Upward */ /* Upward */
cl_git_pass(git_branch_move(repo, "somewhere/" NEW_BRANCH_NAME, "br2", 0)); cl_git_pass(git_branch_move(ref, "br2", 0));
} }
void test_refs_branches_move__can_move_a_local_branch_to_a_partially_colliding_namespace(void) void test_refs_branches_move__can_move_a_local_branch_to_a_partially_colliding_namespace(void)
{ {
/* Downward */ /* Downward */
cl_git_pass(git_branch_move(repo, "br2", "br2/" NEW_BRANCH_NAME, 0)); cl_git_pass(git_branch_move(ref, "br2/" NEW_BRANCH_NAME, 0));
/* Upward */ /* Upward */
cl_git_pass(git_branch_move(repo, "br2/" NEW_BRANCH_NAME, "br2", 0)); cl_git_pass(git_branch_move(ref, "br2", 0));
} }
void test_refs_branches_move__can_not_move_a_branch_if_its_destination_name_collide_with_an_existing_one(void) void test_refs_branches_move__can_not_move_a_branch_if_its_destination_name_collide_with_an_existing_one(void)
{ {
cl_git_fail(git_branch_move(repo, "br2", "master", 0)); cl_git_fail(git_branch_move(ref, "master", 0));
} }
void test_refs_branches_move__can_not_move_a_non_existing_branch(void) void test_refs_branches_move__can_not_move_a_non_branch(void)
{ {
cl_git_fail(git_branch_move(repo, "i-am-no-branch", NEW_BRANCH_NAME, 0)); git_reference *tag;
}
void test_refs_branches_move__can_force_move_over_an_existing_branch(void) cl_git_pass(git_reference_lookup(&tag, repo, "refs/tags/e90810b"));
{ cl_git_fail(git_branch_move(tag, NEW_BRANCH_NAME, 0));
cl_git_pass(git_branch_move(repo, "br2", "master", 1));
}
void test_refs_branches_move__can_not_move_a_branch_through_its_canonical_name(void) git_reference_free(tag);
{
cl_git_fail(git_branch_move(repo, "refs/heads/br2", NEW_BRANCH_NAME, 1));
} }
void test_refs_branches_move__moving_a_non_exisiting_branch_returns_ENOTFOUND(void) void test_refs_branches_move__can_force_move_over_an_existing_branch(void)
{ {
int error; cl_git_pass(git_branch_move(ref, "master", 1));
error = git_branch_move(repo, "where/am/I", NEW_BRANCH_NAME, 0);
cl_git_fail(error);
cl_assert_equal_i(GIT_ENOTFOUND, error);
} }
#include "clar_libgit2.h"
#include "refs.h"
static git_repository *repo;
static git_reference *branch;
void test_refs_branches_tracking__initialize(void)
{
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
branch = NULL;
}
void test_refs_branches_tracking__cleanup(void)
{
git_reference_free(branch);
git_repository_free(repo);
}
void test_refs_branches_tracking__can_retrieve_the_remote_tracking_reference_of_a_local_branch(void)
{
git_reference *branch, *tracking;
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master"));
cl_git_pass(git_branch_tracking(&tracking, branch));
cl_assert_equal_s("refs/remotes/test/master", git_reference_name(tracking));
git_reference_free(branch);
git_reference_free(tracking);
}
void test_refs_branches_tracking__can_retrieve_the_local_tracking_reference_of_a_local_branch(void)
{
git_reference *branch, *tracking;
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/track-local"));
cl_git_pass(git_branch_tracking(&tracking, branch));
cl_assert_equal_s("refs/heads/master", git_reference_name(tracking));
git_reference_free(branch);
git_reference_free(tracking);
}
void test_refs_branches_tracking__cannot_retrieve_a_remote_tracking_reference_from_a_non_branch(void)
{
git_reference *branch, *tracking;
cl_git_pass(git_reference_lookup(&branch, repo, "refs/tags/e90810b"));
cl_git_fail(git_branch_tracking(&tracking, branch));
git_reference_free(branch);
}
void test_refs_branches_tracking__trying_to_retrieve_a_remote_tracking_reference_from_a_plain_local_branch_returns_GIT_ENOTFOUND(void)
{
git_reference *branch, *tracking;
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/subtrees"));
cl_assert_equal_i(GIT_ENOTFOUND, git_branch_tracking(&tracking, branch));
git_reference_free(branch);
}
...@@ -46,7 +46,7 @@ static void assert_retrieval(const char *glob, unsigned int flags, int expected_ ...@@ -46,7 +46,7 @@ static void assert_retrieval(const char *glob, unsigned int flags, int expected_
void test_refs_foreachglob__retrieve_all_refs(void) void test_refs_foreachglob__retrieve_all_refs(void)
{ {
/* 7 heads (including one packed head) + 1 note + 2 remotes + 6 tags */ /* 7 heads (including one packed head) + 1 note + 2 remotes + 6 tags */
assert_retrieval("*", GIT_REF_LISTALL, 17); assert_retrieval("*", GIT_REF_LISTALL, 18);
} }
void test_refs_foreachglob__retrieve_remote_branches(void) void test_refs_foreachglob__retrieve_remote_branches(void)
...@@ -56,7 +56,7 @@ void test_refs_foreachglob__retrieve_remote_branches(void) ...@@ -56,7 +56,7 @@ void test_refs_foreachglob__retrieve_remote_branches(void)
void test_refs_foreachglob__retrieve_local_branches(void) void test_refs_foreachglob__retrieve_local_branches(void)
{ {
assert_retrieval("refs/heads/*", GIT_REF_LISTALL, 8); assert_retrieval("refs/heads/*", GIT_REF_LISTALL, 9);
} }
void test_refs_foreachglob__retrieve_partially_named_references(void) void test_refs_foreachglob__retrieve_partially_named_references(void)
......
...@@ -202,3 +202,19 @@ void test_refs_read__unfound_return_ENOTFOUND(void) ...@@ -202,3 +202,19 @@ void test_refs_read__unfound_return_ENOTFOUND(void)
cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/tags/test/master")); cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/tags/test/master"));
cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/tags/test/farther/master")); cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/tags/test/farther/master"));
} }
static void assert_is_branch(const char *name, bool expected_branchness)
{
git_reference *reference;
cl_git_pass(git_reference_lookup(&reference, g_repo, name));
cl_assert_equal_i(expected_branchness, git_reference_is_branch(reference));
git_reference_free(reference);
}
void test_refs_read__can_determine_if_a_reference_is_a_local_branch(void)
{
assert_is_branch("refs/heads/master", true);
assert_is_branch("refs/heads/packed", true);
assert_is_branch("refs/remotes/test/master", false);
assert_is_branch("refs/tags/e90810b", false);
}
#include "clar_libgit2.h"
#include "reflog.h"
static git_repository *g_repo;
static git_reflog *g_reflog;
static unsigned int entrycount;
void test_refs_reflog_drop__initialize(void)
{
git_reference *ref;
g_repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
git_reflog_read(&g_reflog, ref);
entrycount = git_reflog_entrycount(g_reflog);
git_reference_free(ref);
}
void test_refs_reflog_drop__cleanup(void)
{
git_reflog_free(g_reflog);
cl_git_sandbox_cleanup();
}
void test_refs_reflog_drop__dropping_a_non_exisiting_entry_from_the_log_returns_ENOTFOUND(void)
{
cl_assert_equal_i(GIT_ENOTFOUND, git_reflog_drop(g_reflog, entrycount, 0));
cl_assert_equal_i(entrycount, git_reflog_entrycount(g_reflog));
}
void test_refs_reflog_drop__can_drop_an_entry(void)
{
cl_assert(entrycount > 4);
cl_git_pass(git_reflog_drop(g_reflog, 2, 0));
cl_assert_equal_i(entrycount - 1, git_reflog_entrycount(g_reflog));
}
void test_refs_reflog_drop__can_drop_an_entry_and_rewrite_the_log_history(void)
{
const git_reflog_entry *before_previous, *before_next;
const git_reflog_entry *after_next;
git_oid before_next_old_oid;
cl_assert(entrycount > 4);
before_previous = git_reflog_entry_byindex(g_reflog, 3);
before_next = git_reflog_entry_byindex(g_reflog, 1);
git_oid_cpy(&before_next_old_oid, &before_next->oid_old);
cl_git_pass(git_reflog_drop(g_reflog, 2, 1));
cl_assert_equal_i(entrycount - 1, git_reflog_entrycount(g_reflog));
after_next = git_reflog_entry_byindex(g_reflog, 1);
cl_assert_equal_i(0, git_oid_cmp(&before_next->oid_cur, &after_next->oid_cur));
cl_assert(git_oid_cmp(&before_next_old_oid, &after_next->oid_old) != 0);
cl_assert_equal_i(0, git_oid_cmp(&before_previous->oid_cur, &after_next->oid_old));
}
void test_refs_reflog_drop__can_drop_the_first_entry(void)
{
cl_assert(entrycount > 2);
cl_git_pass(git_reflog_drop(g_reflog, 0, 0));
cl_assert_equal_i(entrycount - 1, git_reflog_entrycount(g_reflog));
}
void test_refs_reflog_drop__can_drop_the_last_entry(void)
{
const git_reflog_entry *entry;
cl_assert(entrycount > 2);
cl_git_pass(git_reflog_drop(g_reflog, entrycount - 1, 0));
cl_assert_equal_i(entrycount - 1, git_reflog_entrycount(g_reflog));
entry = git_reflog_entry_byindex(g_reflog, entrycount - 2);
cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) != 0);
}
void test_refs_reflog_drop__can_drop_the_last_entry_and_rewrite_the_log_history(void)
{
const git_reflog_entry *entry;
cl_assert(entrycount > 2);
cl_git_pass(git_reflog_drop(g_reflog, entrycount - 1, 1));
cl_assert_equal_i(entrycount - 1, git_reflog_entrycount(g_reflog));
entry = git_reflog_entry_byindex(g_reflog, entrycount - 2);
cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) == 0);
}
void test_refs_reflog_drop__can_drop_all_the_entries(void)
{
cl_assert(--entrycount > 0);
do {
cl_git_pass(git_reflog_drop(g_reflog, --entrycount, 1));
} while (entrycount > 0);
cl_git_pass(git_reflog_drop(g_reflog, 0, 1));
cl_assert_equal_i(0, git_reflog_entrycount(g_reflog));
}
void test_refs_reflog_drop__can_persist_deletion_on_disk(void)
{
git_reference *ref;
cl_assert(entrycount > 2);
cl_git_pass(git_reference_lookup(&ref, g_repo, g_reflog->ref_name));
cl_git_pass(git_reflog_drop(g_reflog, entrycount - 1, 1));
cl_assert_equal_i(entrycount - 1, git_reflog_entrycount(g_reflog));
cl_git_pass(git_reflog_write(g_reflog));
git_reflog_free(g_reflog);
git_reflog_read(&g_reflog, ref);
git_reference_free(ref);
cl_assert_equal_i(entrycount - 1, git_reflog_entrycount(g_reflog));
}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
static const char *new_ref = "refs/heads/test-reflog"; static const char *new_ref = "refs/heads/test-reflog";
static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"; static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750";
static const char *commit_msg = "commit: bla bla"; #define commit_msg "commit: bla bla"
static git_repository *g_repo; static git_repository *g_repo;
...@@ -24,66 +24,60 @@ static void assert_signature(git_signature *expected, git_signature *actual) ...@@ -24,66 +24,60 @@ static void assert_signature(git_signature *expected, git_signature *actual)
// Fixture setup and teardown // Fixture setup and teardown
void test_refs_reflog__initialize(void) void test_refs_reflog_reflog__initialize(void)
{ {
g_repo = cl_git_sandbox_init("testrepo.git"); g_repo = cl_git_sandbox_init("testrepo.git");
} }
void test_refs_reflog__cleanup(void) void test_refs_reflog_reflog__cleanup(void)
{ {
cl_git_sandbox_cleanup(); cl_git_sandbox_cleanup();
} }
void test_refs_reflog_reflog__append_then_read(void)
void test_refs_reflog__write_then_read(void)
{ {
// write a reflog for a given reference and ensure it can be read back // write a reflog for a given reference and ensure it can be read back
git_repository *repo2; git_repository *repo2;
git_reference *ref, *lookedup_ref; git_reference *ref, *lookedup_ref;
git_oid oid; git_oid oid;
git_signature *committer; git_signature *committer;
git_reflog *reflog; git_reflog *reflog;
git_reflog_entry *entry; const git_reflog_entry *entry;
char oid_str[GIT_OID_HEXSZ+1];
/* Create a new branch pointing at the HEAD */ /* Create a new branch pointing at the HEAD */
git_oid_fromstr(&oid, current_master_tip); git_oid_fromstr(&oid, current_master_tip);
cl_git_pass(git_reference_create_oid(&ref, g_repo, new_ref, &oid, 0)); cl_git_pass(git_reference_create_oid(&ref, g_repo, new_ref, &oid, 0));
git_reference_free(ref);
cl_git_pass(git_reference_lookup(&ref, g_repo, new_ref));
cl_git_pass(git_signature_now(&committer, "foo", "foo@bar")); cl_git_pass(git_signature_now(&committer, "foo", "foo@bar"));
cl_git_pass(git_reflog_write(ref, NULL, committer, NULL)); cl_git_pass(git_reflog_read(&reflog, ref));
cl_git_fail(git_reflog_write(ref, NULL, committer, "no ancestor NULL for an existing reflog"));
cl_git_fail(git_reflog_write(ref, NULL, committer, "no\nnewline")); cl_git_fail(git_reflog_append(reflog, &oid, committer, "no inner\nnewline"));
cl_git_pass(git_reflog_write(ref, &oid, committer, commit_msg)); cl_git_pass(git_reflog_append(reflog, &oid, committer, NULL));
cl_git_pass(git_reflog_append(reflog, &oid, committer, commit_msg "\n"));
cl_git_pass(git_reflog_write(reflog));
git_reflog_free(reflog);
/* Reopen a new instance of the repository */ /* Reopen a new instance of the repository */
cl_git_pass(git_repository_open(&repo2, "testrepo.git")); cl_git_pass(git_repository_open(&repo2, "testrepo.git"));
/* Lookup the preivously created branch */ /* Lookup the previously created branch */
cl_git_pass(git_reference_lookup(&lookedup_ref, repo2, new_ref)); cl_git_pass(git_reference_lookup(&lookedup_ref, repo2, new_ref));
/* Read and parse the reflog for this branch */ /* Read and parse the reflog for this branch */
cl_git_pass(git_reflog_read(&reflog, lookedup_ref)); cl_git_pass(git_reflog_read(&reflog, lookedup_ref));
cl_assert(reflog->entries.length == 2); cl_assert_equal_i(2, git_reflog_entrycount(reflog));
entry = (git_reflog_entry *)git_vector_get(&reflog->entries, 0); entry = git_reflog_entry_byindex(reflog, 0);
assert_signature(committer, entry->committer); assert_signature(committer, entry->committer);
git_oid_tostr(oid_str, GIT_OID_HEXSZ+1, &entry->oid_old); cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) == 0);
cl_assert_equal_s("0000000000000000000000000000000000000000", oid_str); cl_assert(git_oid_cmp(&oid, &entry->oid_cur) == 0);
git_oid_tostr(oid_str, GIT_OID_HEXSZ+1, &entry->oid_cur);
cl_assert_equal_s(current_master_tip, oid_str);
cl_assert(entry->msg == NULL); cl_assert(entry->msg == NULL);
entry = (git_reflog_entry *)git_vector_get(&reflog->entries, 1); entry = git_reflog_entry_byindex(reflog, 1);
assert_signature(committer, entry->committer); assert_signature(committer, entry->committer);
git_oid_tostr(oid_str, GIT_OID_HEXSZ+1, &entry->oid_old); cl_assert(git_oid_cmp(&oid, &entry->oid_old) == 0);
cl_assert_equal_s(current_master_tip, oid_str); cl_assert(git_oid_cmp(&oid, &entry->oid_cur) == 0);
git_oid_tostr(oid_str, GIT_OID_HEXSZ+1, &entry->oid_cur);
cl_assert_equal_s(current_master_tip, oid_str);
cl_assert_equal_s(commit_msg, entry->msg); cl_assert_equal_s(commit_msg, entry->msg);
git_signature_free(committer); git_signature_free(committer);
...@@ -94,35 +88,7 @@ void test_refs_reflog__write_then_read(void) ...@@ -94,35 +88,7 @@ void test_refs_reflog__write_then_read(void)
git_reference_free(lookedup_ref); git_reference_free(lookedup_ref);
} }
void test_refs_reflog__dont_write_bad(void) void test_refs_reflog_reflog__renaming_the_reference_moves_the_reflog(void)
{
// avoid writing an obviously wrong reflog
git_reference *ref;
git_oid oid;
git_signature *committer;
/* Create a new branch pointing at the HEAD */
git_oid_fromstr(&oid, current_master_tip);
cl_git_pass(git_reference_create_oid(&ref, g_repo, new_ref, &oid, 0));
git_reference_free(ref);
cl_git_pass(git_reference_lookup(&ref, g_repo, new_ref));
cl_git_pass(git_signature_now(&committer, "foo", "foo@bar"));
/* Write the reflog for the new branch */
cl_git_pass(git_reflog_write(ref, NULL, committer, NULL));
/* Try to update the reflog with wrong information:
* It's no new reference, so the ancestor OID cannot
* be NULL. */
cl_git_fail(git_reflog_write(ref, NULL, committer, NULL));
git_signature_free(committer);
git_reference_free(ref);
}
void test_refs_reflog__renaming_the_reference_moves_the_reflog(void)
{ {
git_reference *master; git_reference *master;
git_buf master_log_path = GIT_BUF_INIT, moved_log_path = GIT_BUF_INIT; git_buf master_log_path = GIT_BUF_INIT, moved_log_path = GIT_BUF_INIT;
...@@ -145,6 +111,7 @@ void test_refs_reflog__renaming_the_reference_moves_the_reflog(void) ...@@ -145,6 +111,7 @@ void test_refs_reflog__renaming_the_reference_moves_the_reflog(void)
git_buf_free(&moved_log_path); git_buf_free(&moved_log_path);
git_buf_free(&master_log_path); git_buf_free(&master_log_path);
} }
static void assert_has_reflog(bool expected_result, const char *name) static void assert_has_reflog(bool expected_result, const char *name)
{ {
git_reference *ref; git_reference *ref;
...@@ -156,9 +123,50 @@ static void assert_has_reflog(bool expected_result, const char *name) ...@@ -156,9 +123,50 @@ static void assert_has_reflog(bool expected_result, const char *name)
git_reference_free(ref); git_reference_free(ref);
} }
void test_refs_reflog__reference_has_reflog(void) void test_refs_reflog_reflog__reference_has_reflog(void)
{ {
assert_has_reflog(true, "HEAD"); assert_has_reflog(true, "HEAD");
assert_has_reflog(true, "refs/heads/master"); assert_has_reflog(true, "refs/heads/master");
assert_has_reflog(false, "refs/heads/subtrees"); assert_has_reflog(false, "refs/heads/subtrees");
} }
void test_refs_reflog_reflog__reading_the_reflog_from_a_reference_with_no_log_returns_an_empty_one(void)
{
git_reference *subtrees;
git_reflog *reflog;
git_buf subtrees_log_path = GIT_BUF_INIT;
cl_git_pass(git_reference_lookup(&subtrees, g_repo, "refs/heads/subtrees"));
git_buf_join_n(&subtrees_log_path, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, git_reference_name(subtrees));
cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&subtrees_log_path)));
cl_git_pass(git_reflog_read(&reflog, subtrees));
cl_assert_equal_i(0, git_reflog_entrycount(reflog));
git_reflog_free(reflog);
git_reference_free(subtrees);
git_buf_free(&subtrees_log_path);
}
void test_refs_reflog_reflog__cannot_write_a_moved_reflog(void)
{
git_reference *master;
git_buf master_log_path = GIT_BUF_INIT, moved_log_path = GIT_BUF_INIT;
git_reflog *reflog;
cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master"));
cl_git_pass(git_reflog_read(&reflog, master));
cl_git_pass(git_reflog_write(reflog));
cl_git_pass(git_reference_rename(master, "refs/moved", 0));
cl_git_fail(git_reflog_write(reflog));
git_reflog_free(reflog);
git_reference_free(master);
git_buf_free(&moved_log_path);
git_buf_free(&master_log_path);
}
#include "clar_libgit2.h"
static git_repository *g_repo;
void test_refs_remotetracking__initialize(void)
{
cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
}
void test_refs_remotetracking__cleanup(void)
{
git_repository_free(g_repo);
}
void test_refs_remotetracking__unfound_returns_GIT_ENOTFOUND(void)
{
git_reference *branch, *tracking;
cl_git_pass(git_reference_lookup(&branch, g_repo, "refs/heads/subtrees"));
cl_assert_equal_i(GIT_ENOTFOUND, git_reference_remote_tracking_from_branch(&tracking, branch));
git_reference_free(branch);
}
void test_refs_remotetracking__retrieving_from_a_non_head_fails(void)
{
git_reference *branch, *tracking;
cl_git_pass(git_reference_lookup(&branch, g_repo, "refs/tags/e90810b"));
cl_git_fail(git_reference_remote_tracking_from_branch(&tracking, branch));
git_reference_free(branch);
}
void test_refs_remotetracking__can_retrieve_a_remote_tracking_branch_reference(void)
{
git_reference *branch, *tracking;
cl_git_pass(git_reference_lookup(&branch, g_repo, "refs/heads/master"));
cl_git_pass(git_reference_remote_tracking_from_branch(&tracking, branch));
cl_assert_equal_s("refs/remotes/test/master", git_reference_name(tracking));
git_reference_free(branch);
git_reference_free(tracking);
}
...@@ -64,6 +64,8 @@ void test_refs_revparse__invalid_reference_name(void) ...@@ -64,6 +64,8 @@ void test_refs_revparse__invalid_reference_name(void)
cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't make sense")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't make sense"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't make sense^1")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't make sense^1"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't make sense~2")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't make sense~2"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, ""));
} }
void test_refs_revparse__shas(void) void test_refs_revparse__shas(void)
...@@ -75,6 +77,9 @@ void test_refs_revparse__shas(void) ...@@ -75,6 +77,9 @@ void test_refs_revparse__shas(void)
void test_refs_revparse__head(void) void test_refs_revparse__head(void)
{ {
test_object("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("HEAD^0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("HEAD~0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("master", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
} }
void test_refs_revparse__full_refs(void) void test_refs_revparse__full_refs(void)
...@@ -99,12 +104,18 @@ void test_refs_revparse__describe_output(void) ...@@ -99,12 +104,18 @@ void test_refs_revparse__describe_output(void)
void test_refs_revparse__nth_parent(void) void test_refs_revparse__nth_parent(void)
{ {
cl_git_fail(git_revparse_single(&g_obj, g_repo, "be3563a^-1"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "^"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "be3563a^{tree}^"));
test_object("be3563a^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("be3563a^1", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("be3563a^", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("be3563a^", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("be3563a^2", "c47800c7266a2be04c571c04d5a6614691ea99bd"); test_object("be3563a^2", "c47800c7266a2be04c571c04d5a6614691ea99bd");
test_object("be3563a^1^1", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); test_object("be3563a^1^1", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045");
test_object("be3563a^^", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045");
test_object("be3563a^2^1", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); test_object("be3563a^2^1", "5b5b025afb0b4c913b4c338a42934a3863bf3644");
test_object("be3563a^0", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("be3563a^0", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("be3563a^{commit}^", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("be3563a^42", NULL); test_object("be3563a^42", NULL);
} }
...@@ -113,34 +124,56 @@ void test_refs_revparse__not_tag(void) ...@@ -113,34 +124,56 @@ void test_refs_revparse__not_tag(void)
{ {
test_object("point_to_blob^{}", "1385f264afb75a56a5bec74243be9b367ba4ca08"); test_object("point_to_blob^{}", "1385f264afb75a56a5bec74243be9b367ba4ca08");
test_object("wrapped_tag^{}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("wrapped_tag^{}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("master^{}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("master^{tree}^{}", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162");
test_object("e90810b^{}", "e90810b8df3e80c413d903f631643c716887138d");
test_object("tags/e90810b^{}", "e90810b8df3e80c413d903f631643c716887138d");
test_object("e908^{}", "e90810b8df3e80c413d903f631643c716887138d");
} }
void test_refs_revparse__to_type(void) void test_refs_revparse__to_type(void)
{ {
cl_git_fail(git_revparse_single(&g_obj, g_repo, "wrapped_tag^{blob}"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "wrapped_tag^{trip}"));
test_object("wrapped_tag^{commit}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("wrapped_tag^{commit}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("wrapped_tag^{tree}", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); test_object("wrapped_tag^{tree}", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162");
test_object("point_to_blob^{blob}", "1385f264afb75a56a5bec74243be9b367ba4ca08"); test_object("point_to_blob^{blob}", "1385f264afb75a56a5bec74243be9b367ba4ca08");
test_object("master^{commit}^{commit}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
cl_git_fail(git_revparse_single(&g_obj, g_repo, "wrapped_tag^{blob}"));
} }
void test_refs_revparse__linear_history(void) void test_refs_revparse__linear_history(void)
{ {
cl_git_fail(git_revparse_single(&g_obj, g_repo, "~"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "foo~bar")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "foo~bar"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "master~bar")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "master~bar"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "master~-1"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "master~0bar"));
test_object("master~0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("master~0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
test_object("master~1", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("master~1", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("master~2", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("master~2", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("master~1~1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("master~1~1", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("master~~", "9fd738e8f7967c078dceed8190330fc8648ee56a");
} }
void test_refs_revparse__chaining(void) void test_refs_revparse__chaining(void)
{ {
cl_git_fail(git_revparse_single(&g_obj, g_repo, "master@{0}@{0}"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{u}@{-1}"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-1}@{-1}"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-3}@{0}"));
test_object("master@{0}~1^1", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("@{u}@{0}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("@{-1}@{0}", "a4a7dce85cf63874e984719f4fdd239f5145052f");
test_object("@{-4}@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
test_object("master~1^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("master~1^1", "9fd738e8f7967c078dceed8190330fc8648ee56a");
test_object("master~1^2", "c47800c7266a2be04c571c04d5a6614691ea99bd"); test_object("master~1^2", "c47800c7266a2be04c571c04d5a6614691ea99bd");
test_object("master^1^2~1", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); test_object("master^1^2~1", "5b5b025afb0b4c913b4c338a42934a3863bf3644");
test_object("master^^2^", "5b5b025afb0b4c913b4c338a42934a3863bf3644");
test_object("master^1^1^1^1^1", "8496071c1b46c854b31185ea97743be6a8774479"); test_object("master^1^1^1^1^1", "8496071c1b46c854b31185ea97743be6a8774479");
test_object("master^^1^2^1", NULL);
} }
void test_refs_revparse__upstream(void) void test_refs_revparse__upstream(void)
...@@ -158,6 +191,10 @@ void test_refs_revparse__upstream(void) ...@@ -158,6 +191,10 @@ void test_refs_revparse__upstream(void)
void test_refs_revparse__ordinal(void) void test_refs_revparse__ordinal(void)
{ {
cl_git_fail(git_revparse_single(&g_obj, g_repo, "master@{-2}")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "master@{-2}"));
/* TODO: make the test below actually fail
* cl_git_fail(git_revparse_single(&g_obj, g_repo, "master@{1a}"));
*/
test_object("nope@{0}", NULL); test_object("nope@{0}", NULL);
test_object("master@{31415}", NULL); test_object("master@{31415}", NULL);
...@@ -177,6 +214,7 @@ void test_refs_revparse__previous_head(void) ...@@ -177,6 +214,7 @@ void test_refs_revparse__previous_head(void)
{ {
cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-xyz}")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-xyz}"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-0}")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-0}"));
cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-1b}"));
test_object("@{-42}", NULL); test_object("@{-42}", NULL);
...@@ -353,6 +391,7 @@ void test_refs_revparse__colon(void) ...@@ -353,6 +391,7 @@ void test_refs_revparse__colon(void)
test_object(":/one", "c47800c7266a2be04c571c04d5a6614691ea99bd"); test_object(":/one", "c47800c7266a2be04c571c04d5a6614691ea99bd");
test_object(":/packed commit t", "41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9"); test_object(":/packed commit t", "41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9");
test_object("test/master^2:branch_file.txt", "45b983be36b73c0788dc9cbcb76cbb80fc7bb057"); test_object("test/master^2:branch_file.txt", "45b983be36b73c0788dc9cbcb76cbb80fc7bb057");
test_object("test/master@{1}:branch_file.txt", "3697d64be941a53d4ae8f6a271e4e3fa56b022cc");
} }
void test_refs_revparse__disambiguation(void) void test_refs_revparse__disambiguation(void)
......
...@@ -7,6 +7,14 @@ ...@@ -7,6 +7,14 @@
url = git://github.com/libgit2/libgit2 url = git://github.com/libgit2/libgit2
fetch = +refs/heads/*:refs/remotes/test/* fetch = +refs/heads/*:refs/remotes/test/*
[remote "test_with_pushurl"]
url = git://github.com/libgit2/fetchlibgit2
pushurl = git://github.com/libgit2/pushlibgit2
fetch = +refs/heads/*:refs/remotes/test_with_pushurl/*
[branch "master"] [branch "master"]
remote = test remote = test
merge = refs/heads/master merge = refs/heads/master
[branch "track-local"]
remote = .
merge = refs/heads/master
0000000000000000000000000000000000000000 be3563ae3f795b2b4353bcce3a527ad0a4f7f644 Ben Straub <bstraub@github.com> 1335806563 -0700 clone: from /Users/ben/src/libgit2/tests/resources/testrepo.git 0000000000000000000000000000000000000000 be3563ae3f795b2b4353bcce3a527ad0a4f7f644 Ben Straub <bstraub@github.com> 1335806563 -0700 clone: from /Users/ben/src/libgit2/tests/resources/testrepo.git
be3563ae3f795b2b4353bcce3a527ad0a4f7f644 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Ben Straub <bstraub@github.com> 1335806603 -0900 commit: be3563ae3f795b2b4353bcce3a527ad0a4f7f644 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Ben Straub <bstraub@github.com> 1335806603 -0900 commit:
a65fedf39aefe402d3bb6e24df4d4f5fe4547750 5b5b025afb0b4c913b4c338a42934a3863bf3644 Ben Straub <bstraub@github.com> 1335806604 -0900 checkout: moving from master to 5b5b025
5b5b025afb0b4c913b4c338a42934a3863bf3644 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Ben Straub <bstraub@github.com> 1335806605 -0900 checkout: moving from 5b5b025 to master
a65fedf39aefe402d3bb6e24df4d4f5fe4547750 c47800c7266a2be04c571c04d5a6614691ea99bd Ben Straub <bstraub@github.com> 1335806608 -0900 checkout: moving from master to br2 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 c47800c7266a2be04c571c04d5a6614691ea99bd Ben Straub <bstraub@github.com> 1335806608 -0900 checkout: moving from master to br2
c47800c7266a2be04c571c04d5a6614691ea99bd a4a7dce85cf63874e984719f4fdd239f5145052f Ben Straub <bstraub@github.com> 1335806617 -0900 commit: checking in c47800c7266a2be04c571c04d5a6614691ea99bd a4a7dce85cf63874e984719f4fdd239f5145052f Ben Straub <bstraub@github.com> 1335806617 -0900 commit: checking in
a4a7dce85cf63874e984719f4fdd239f5145052f a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Ben Straub <bstraub@github.com> 1335806621 -0900 checkout: moving from br2 to master a4a7dce85cf63874e984719f4fdd239f5145052f a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Ben Straub <bstraub@github.com> 1335806621 -0900 checkout: moving from br2 to master
0000000000000000000000000000000000000000 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Ben Straub <bstraub@github.com> 1335806565 -0800 update by push
a65fedf39aefe402d3bb6e24df4d4f5fe4547750 be3563ae3f795b2b4353bcce3a527ad0a4f7f644 Ben Straub <bstraub@github.com> 1335806688 -0800 update by push
9fd738e8f7967c078dceed8190330fc8648ee56a
...@@ -517,6 +517,85 @@ void test_status_worktree__status_file_with_clean_index_and_empty_workdir(void) ...@@ -517,6 +517,85 @@ void test_status_worktree__status_file_with_clean_index_and_empty_workdir(void)
cl_git_pass(p_unlink("my-index")); cl_git_pass(p_unlink("my-index"));
} }
void test_status_worktree__bracket_in_filename(void)
{
git_repository *repo;
git_index *index;
status_entry_single result;
unsigned int status_flags;
int error;
#define FILE_WITH_BRACKET "LICENSE[1].md"
#define FILE_WITHOUT_BRACKET "LICENSE1.md"
cl_git_pass(git_repository_init(&repo, "with_bracket", 0));
cl_git_mkfile("with_bracket/" FILE_WITH_BRACKET, "I have a bracket in my name\n");
/* file is new to working directory */
memset(&result, 0, sizeof(result));
cl_git_pass(git_status_foreach(repo, cb_status__single, &result));
cl_assert_equal_i(1, result.count);
cl_assert(result.status == GIT_STATUS_WT_NEW);
cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_BRACKET));
cl_assert(status_flags == GIT_STATUS_WT_NEW);
/* ignore the file */
cl_git_rewritefile("with_bracket/.gitignore", "*.md\n.gitignore\n");
memset(&result, 0, sizeof(result));
cl_git_pass(git_status_foreach(repo, cb_status__single, &result));
cl_assert_equal_i(2, result.count);
cl_assert(result.status == GIT_STATUS_IGNORED);
cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_BRACKET));
cl_assert(status_flags == GIT_STATUS_IGNORED);
/* don't ignore the file */
cl_git_rewritefile("with_bracket/.gitignore", ".gitignore\n");
memset(&result, 0, sizeof(result));
cl_git_pass(git_status_foreach(repo, cb_status__single, &result));
cl_assert_equal_i(2, result.count);
cl_assert(result.status == GIT_STATUS_WT_NEW);
cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_BRACKET));
cl_assert(status_flags == GIT_STATUS_WT_NEW);
/* add the file to the index */
cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_index_add(index, FILE_WITH_BRACKET, 0));
cl_git_pass(git_index_write(index));
memset(&result, 0, sizeof(result));
cl_git_pass(git_status_foreach(repo, cb_status__single, &result));
cl_assert_equal_i(2, result.count);
cl_assert(result.status == GIT_STATUS_INDEX_NEW);
cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_BRACKET));
cl_assert(status_flags == GIT_STATUS_INDEX_NEW);
/* Create file without bracket */
cl_git_mkfile("with_bracket/" FILE_WITHOUT_BRACKET, "I have no bracket in my name!\n");
cl_git_pass(git_status_file(&status_flags, repo, FILE_WITHOUT_BRACKET));
cl_assert(status_flags == GIT_STATUS_WT_NEW);
cl_git_pass(git_status_file(&status_flags, repo, "LICENSE\\[1\\].md"));
cl_assert(status_flags == GIT_STATUS_INDEX_NEW);
error = git_status_file(&status_flags, repo, FILE_WITH_BRACKET);
cl_git_fail(error);
cl_assert(error == GIT_EAMBIGUOUS);
git_index_free(index);
git_repository_free(repo);
}
void test_status_worktree__space_in_filename(void) void test_status_worktree__space_in_filename(void)
{ {
...@@ -647,3 +726,49 @@ void test_status_worktree__filemode_changes(void) ...@@ -647,3 +726,49 @@ void test_status_worktree__filemode_changes(void)
git_config_free(cfg); git_config_free(cfg);
} }
static int cb_status__expected_path(const char *p, unsigned int s, void *payload)
{
const char *expected_path = (const char *)payload;
GIT_UNUSED(s);
if (payload == NULL)
cl_fail("Unexpected path");
cl_assert_equal_s(expected_path, p);
return 0;
}
void test_status_worktree__disable_pathspec_match(void)
{
git_repository *repo;
git_status_options opts;
char *file_with_bracket = "LICENSE[1].md",
*imaginary_file_with_bracket = "LICENSE[1-2].md";
cl_git_pass(git_repository_init(&repo, "pathspec", 0));
cl_git_mkfile("pathspec/LICENSE[1].md", "screaming bracket\n");
cl_git_mkfile("pathspec/LICENSE1.md", "no bracket\n");
memset(&opts, 0, sizeof(opts));
opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH;
opts.pathspec.count = 1;
opts.pathspec.strings = &file_with_bracket;
cl_git_pass(
git_status_foreach_ext(repo, &opts, cb_status__expected_path,
file_with_bracket)
);
/* Test passing a pathspec matching files in the workdir. */
/* Must not match because pathspecs are disabled. */
opts.pathspec.strings = &imaginary_file_with_bracket;
cl_git_pass(
git_status_foreach_ext(repo, &opts, cb_status__expected_path, NULL)
);
git_repository_free(repo);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment