2 * Copyright (C) 2009-2012 the libgit2 contributors
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
12 #include "git2/reset.h"
13 #include "git2/checkout.h"
14 #include "git2/merge.h"
16 #define ERROR_MSG "Cannot perform reset"
18 static int update_head(git_repository
*repo
, git_object
*commit
)
21 git_reference
*head
= NULL
, *target
= NULL
;
23 error
= git_repository_head(&head
, repo
);
25 if (error
< 0 && error
!= GIT_EORPHANEDHEAD
)
28 if (error
== GIT_EORPHANEDHEAD
) {
32 * TODO: This is a bit weak as this doesn't support chained
33 * symbolic references. yet.
35 if ((error
= git_reference_lookup(&head
, repo
, GIT_HEAD_FILE
)) < 0)
38 if ((error
= git_reference_create(
41 git_reference_symbolic_target(head
),
42 git_object_id(commit
), 0)) < 0)
45 if ((error
= git_reference_set_target(head
, git_object_id(commit
))) < 0)
52 git_reference_free(head
);
53 git_reference_free(target
);
60 git_reset_t reset_type
)
62 git_object
*commit
= NULL
;
63 git_index
*index
= NULL
;
64 git_tree
*tree
= NULL
;
66 git_checkout_opts opts
= GIT_CHECKOUT_OPTS_INIT
;
68 assert(repo
&& target
);
70 if (git_object_owner(target
) != repo
) {
71 giterr_set(GITERR_OBJECT
,
72 "%s - The given target does not belong to this repository.", ERROR_MSG
);
76 if (reset_type
!= GIT_RESET_SOFT
&&
77 (error
= git_repository__ensure_not_bare(repo
,
78 reset_type
== GIT_RESET_MIXED
? "reset mixed" : "reset hard")) < 0)
81 if ((error
= git_object_peel(&commit
, target
, GIT_OBJ_COMMIT
)) < 0 ||
82 (error
= git_repository_index(&index
, repo
)) < 0 ||
83 (error
= git_commit_tree(&tree
, (git_commit
*)commit
)) < 0)
86 if (reset_type
== GIT_RESET_SOFT
&&
87 (git_repository_state(repo
) == GIT_REPOSITORY_STATE_MERGE
||
88 git_index_has_conflicts(index
)))
90 giterr_set(GITERR_OBJECT
, "%s (soft) in the middle of a merge.", ERROR_MSG
);
91 error
= GIT_EUNMERGED
;
95 /* move HEAD to the new target */
96 if ((error
= update_head(repo
, commit
)) < 0)
99 if (reset_type
== GIT_RESET_HARD
) {
100 /* overwrite working directory with HEAD */
101 opts
.checkout_strategy
= GIT_CHECKOUT_FORCE
;
103 if ((error
= git_checkout_tree(repo
, (git_object
*)tree
, &opts
)) < 0)
107 if (reset_type
> GIT_RESET_SOFT
) {
108 /* reset index to the target content */
110 if ((error
= git_index_read_tree(index
, tree
)) < 0 ||
111 (error
= git_index_write(index
)) < 0)
114 if ((error
= git_repository_merge_cleanup(repo
)) < 0) {
115 giterr_set(GITERR_INDEX
, "%s - failed to clean up merge data", ERROR_MSG
);
121 git_object_free(commit
);
122 git_index_free(index
);