diff options
author | Vicent Martà <vicent@github.com> | 2012-06-07 12:30:20 -0700 |
---|---|---|
committer | Vicent Martà <vicent@github.com> | 2012-06-07 12:30:20 -0700 |
commit | 6c08e69fd92028822cb98368e564c5cb7964c072 (patch) | |
tree | e34d67219a554d58faa17e77fd13f5e568414938 /src | |
parent | b9ebcc59e7d13507d4f8faf86d68dd3ac1a4b627 (diff) | |
parent | edebceffef1d661d073b9961d13042007325832d (diff) | |
download | libgit2-6c08e69fd92028822cb98368e564c5cb7964c072.tar.gz |
Merge pull request #669 from nulltoken/topic/reset
Add git_reset()
Diffstat (limited to 'src')
-rw-r--r-- | src/commit.c | 62 | ||||
-rw-r--r-- | src/refs.c | 59 | ||||
-rw-r--r-- | src/refs.h | 1 | ||||
-rw-r--r-- | src/reset.c | 103 |
4 files changed, 164 insertions, 61 deletions
diff --git a/src/commit.c b/src/commit.c index 2f40dc67d..57eafaa2e 100644 --- a/src/commit.c +++ b/src/commit.c @@ -81,66 +81,6 @@ int git_commit_create_v( return res; } -/* Update the reference named `ref_name` so it points to `oid` */ -static int update_reference(git_repository *repo, git_oid *oid, const char *ref_name) -{ - git_reference *ref; - int res; - - res = git_reference_lookup(&ref, repo, ref_name); - - /* If we haven't found the reference at all, we assume we need to create - * a new reference and that's it */ - if (res == GIT_ENOTFOUND) { - giterr_clear(); - return git_reference_create_oid(NULL, repo, ref_name, oid, 1); - } - - if (res < 0) - return -1; - - /* If we have found a reference, but it's symbolic, we need to update - * the direct reference it points to */ - if (git_reference_type(ref) == GIT_REF_SYMBOLIC) { - git_reference *aux; - const char *sym_target; - - /* The target pointed at by this reference */ - sym_target = git_reference_target(ref); - - /* resolve the reference to the target it points to */ - res = git_reference_resolve(&aux, ref); - - /* - * if the symbolic reference pointed to an inexisting ref, - * this is means we're creating a new branch, for example. - * We need to create a new direct reference with that name - */ - if (res == GIT_ENOTFOUND) { - giterr_clear(); - res = git_reference_create_oid(NULL, repo, sym_target, oid, 1); - git_reference_free(ref); - return res; - } - - /* free the original symbolic reference now; not before because - * we're using the `sym_target` pointer */ - git_reference_free(ref); - - if (res < 0) - return -1; - - /* store the newly found direct reference in its place */ - ref = aux; - } - - /* ref is made to point to `oid`: ref is either the original reference, - * or the target of the symbolic reference we've looked up */ - res = git_reference_set_oid(ref, oid); - git_reference_free(ref); - return res; -} - int git_commit_create( git_oid *oid, git_repository *repo, @@ -192,7 +132,7 @@ int git_commit_create( git_buf_free(&commit); if (update_ref != NULL) - return update_reference(repo, oid, update_ref); + return git_reference__update(repo, oid, update_ref); return 0; diff --git a/src/refs.c b/src/refs.c index 1ef3e13a4..104685793 100644 --- a/src/refs.c +++ b/src/refs.c @@ -1705,3 +1705,62 @@ int git_reference_cmp(git_reference *ref1, git_reference *ref2) return git_oid_cmp(&ref1->target.oid, &ref2->target.oid); } +/* Update the reference named `ref_name` so it points to `oid` */ +int git_reference__update(git_repository *repo, const git_oid *oid, const char *ref_name) +{ + git_reference *ref; + int res; + + res = git_reference_lookup(&ref, repo, ref_name); + + /* If we haven't found the reference at all, we assume we need to create + * a new reference and that's it */ + if (res == GIT_ENOTFOUND) { + giterr_clear(); + return git_reference_create_oid(NULL, repo, ref_name, oid, 1); + } + + if (res < 0) + return -1; + + /* If we have found a reference, but it's symbolic, we need to update + * the direct reference it points to */ + if (git_reference_type(ref) == GIT_REF_SYMBOLIC) { + git_reference *aux; + const char *sym_target; + + /* The target pointed at by this reference */ + sym_target = git_reference_target(ref); + + /* resolve the reference to the target it points to */ + res = git_reference_resolve(&aux, ref); + + /* + * if the symbolic reference pointed to an inexisting ref, + * this is means we're creating a new branch, for example. + * We need to create a new direct reference with that name + */ + if (res == GIT_ENOTFOUND) { + giterr_clear(); + res = git_reference_create_oid(NULL, repo, sym_target, oid, 1); + git_reference_free(ref); + return res; + } + + /* free the original symbolic reference now; not before because + * we're using the `sym_target` pointer */ + git_reference_free(ref); + + if (res < 0) + return -1; + + /* store the newly found direct reference in its place */ + ref = aux; + } + + /* ref is made to point to `oid`: ref is either the original reference, + * or the target of the symbolic reference we've looked up */ + res = git_reference_set_oid(ref, oid); + git_reference_free(ref); + return res; +} diff --git a/src/refs.h b/src/refs.h index 369e91e1c..082350278 100644 --- a/src/refs.h +++ b/src/refs.h @@ -54,6 +54,7 @@ void git_repository__refcache_free(git_refcache *refs); int git_reference__normalize_name(char *buffer_out, size_t out_size, const char *name); int git_reference__normalize_name_oid(char *buffer_out, size_t out_size, const char *name); +int git_reference__update(git_repository *repo, const git_oid *oid, const char *ref_name); /** * Lookup a reference by name and try to resolve to an OID. diff --git a/src/reset.c b/src/reset.c new file mode 100644 index 000000000..14f7a236a --- /dev/null +++ b/src/reset.c @@ -0,0 +1,103 @@ +/* + * 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. + */ + +#include "common.h" +#include "commit.h" +#include "tag.h" +#include "git2/reset.h" + +#define ERROR_MSG "Cannot perform reset" + +static int reset_error_invalid(const char *msg) +{ + giterr_set(GITERR_INVALID, "%s - %s", ERROR_MSG, msg); + return -1; +} + +int git_reset( + git_repository *repo, + const git_object *target, + git_reset_type reset_type) +{ + git_otype target_type = GIT_OBJ_BAD; + git_object *commit = NULL; + git_index *index = NULL; + git_tree *tree = NULL; + int error = -1; + + assert(repo && target); + assert(reset_type == GIT_RESET_SOFT || reset_type == GIT_RESET_MIXED); + + if (git_object_owner(target) != repo) + return reset_error_invalid("The given target does not belong to this repository."); + + if (reset_type == GIT_RESET_MIXED && git_repository_is_bare(repo)) + return reset_error_invalid("Mixed reset is not allowed in a bare repository."); + + target_type = git_object_type(target); + + switch (target_type) + { + case GIT_OBJ_TAG: + if (git_tag_peel(&commit, (git_tag *)target) < 0) + goto cleanup; + + if (git_object_type(commit) != GIT_OBJ_COMMIT) { + reset_error_invalid("The given target does not resolve to a commit."); + goto cleanup; + } + break; + + case GIT_OBJ_COMMIT: + commit = (git_object *)target; + break; + + default: + return reset_error_invalid("Only git_tag and git_commit objects are valid targets."); + } + + //TODO: Check for unmerged entries + + if (git_reference__update(repo, git_object_id(commit), GIT_HEAD_FILE) < 0) + goto cleanup; + + if (reset_type == GIT_RESET_SOFT) { + error = 0; + goto cleanup; + } + + if (git_commit_tree(&tree, (git_commit *)commit) < 0) { + giterr_set(GITERR_OBJECT, "%s - Failed to retrieve the commit tree.", ERROR_MSG); + goto cleanup; + } + + if (git_repository_index(&index, repo) < 0) { + giterr_set(GITERR_OBJECT, "%s - Failed to retrieve the index.", ERROR_MSG); + goto cleanup; + } + + if (git_index_read_tree(index, tree) < 0) { + giterr_set(GITERR_INDEX, "%s - Failed to update the index.", ERROR_MSG); + goto cleanup; + } + + if (git_index_write(index) < 0) { + giterr_set(GITERR_INDEX, "%s - Failed to write the index.", ERROR_MSG); + goto cleanup; + } + + error = 0; + +cleanup: + if (target_type == GIT_OBJ_TAG) + git_object_free(commit); + + git_index_free(index); + git_tree_free(tree); + + return error; +} |