summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVicent Martí <vicent@github.com>2012-06-07 12:30:20 -0700
committerVicent Martí <vicent@github.com>2012-06-07 12:30:20 -0700
commit6c08e69fd92028822cb98368e564c5cb7964c072 (patch)
treee34d67219a554d58faa17e77fd13f5e568414938 /src
parentb9ebcc59e7d13507d4f8faf86d68dd3ac1a4b627 (diff)
parentedebceffef1d661d073b9961d13042007325832d (diff)
downloadlibgit2-6c08e69fd92028822cb98368e564c5cb7964c072.tar.gz
Merge pull request #669 from nulltoken/topic/reset
Add git_reset()
Diffstat (limited to 'src')
-rw-r--r--src/commit.c62
-rw-r--r--src/refs.c59
-rw-r--r--src/refs.h1
-rw-r--r--src/reset.c103
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;
+}