Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
3 - *
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.
6 - */
7 -
8 - #include "common.h"
9 -
10 - #include "commit.h"
11 - #include "tag.h"
12 - #include "merge.h"
13 - #include "diff.h"
14 - #include "annotated_commit.h"
15 - #include "git2/reset.h"
16 - #include "git2/checkout.h"
17 - #include "git2/merge.h"
18 - #include "git2/refs.h"
19 -
20 - #define ERROR_MSG "Cannot perform reset"
21 -
22 5 2 int git_reset_default(
23 - git_repository *repo,
24 - const git_object *target,
25 - const git_strarray* pathspecs)
26 - {
27 5 2 git_object *commit = NULL;
28 5 2 git_tree *tree = NULL;
29 5 2 git_diff *diff = NULL;
30 5 2 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
31 - size_t i, max_i;
32 - git_index_entry entry;
33 - int error;
34 5 2 git_index *index = NULL;
35 -
36 5 2-4 assert(pathspecs != NULL && pathspecs->count > 0);
37 -
38 5 5 memset(&entry, 0, sizeof(git_index_entry));
39 -
40 5 5,6 if ((error = git_repository_index(&index, repo)) < 0)
41 ##### 7 goto cleanup;
42 -
43 5 8 if (target) {
44 4 9,10 if (git_object_owner(target) != repo) {
45 ##### 11 git_error_set(GIT_ERROR_OBJECT,
46 - "%s_default - The given target does not belong to this repository.", ERROR_MSG);
47 ##### 12 return -1;
48 - }
49 -
50 4 13-16 if ((error = git_object_peel(&commit, target, GIT_OBJECT_COMMIT)) < 0 ||
51 4 15 (error = git_commit_tree(&tree, (git_commit *)commit)) < 0)
52 - goto cleanup;
53 - }
54 -
55 5 17 opts.pathspec = *pathspecs;
56 5 17 opts.flags = GIT_DIFF_REVERSE;
57 -
58 5 17,18 if ((error = git_diff_tree_to_index(
59 - &diff, repo, tree, index, &opts)) < 0)
60 ##### 19 goto cleanup;
61 -
62 11 20,40,41 for (i = 0, max_i = git_diff_num_deltas(diff); i < max_i; ++i) {
63 6 21 const git_diff_delta *delta = git_diff_get_delta(diff, i);
64 -
65 6 22-26 assert(delta->status == GIT_DELTA_ADDED ||
66 - delta->status == GIT_DELTA_MODIFIED ||
67 - delta->status == GIT_DELTA_CONFLICTED ||
68 - delta->status == GIT_DELTA_DELETED);
69 -
70 6 27 error = git_index_conflict_remove(index, delta->old_file.path);
71 6 28 if (error < 0) {
72 1 29,30 if (delta->status == GIT_DELTA_ADDED && error == GIT_ENOTFOUND)
73 1 31 git_error_clear();
74 - else
75 - goto cleanup;
76 - }
77 -
78 6 32 if (delta->status == GIT_DELTA_DELETED) {
79 2 33,34 if ((error = git_index_remove(index, delta->old_file.path, 0)) < 0)
80 ##### 35 goto cleanup;
81 - } else {
82 4 36 entry.mode = delta->new_file.mode;
83 4 36 git_oid_cpy(&entry.id, &delta->new_file.id);
84 4 37 entry.path = (char *)delta->new_file.path;
85 -
86 4 37,38 if ((error = git_index_add(index, &entry)) < 0)
87 ##### 39 goto cleanup;
88 - }
89 - }
90 -
91 5 42 error = git_index_write(index);
92 -
93 - cleanup:
94 5 43 git_object_free(commit);
95 5 44 git_tree_free(tree);
96 5 45 git_index_free(index);
97 5 46 git_diff_free(diff);
98 -
99 5 47 return error;
100 - }
101 -
102 196 2 static int reset(
103 - git_repository *repo,
104 - const git_object *target,
105 - const char *to,
106 - git_reset_t reset_type,
107 - const git_checkout_options *checkout_opts)
108 - {
109 196 2 git_object *commit = NULL;
110 196 2 git_index *index = NULL;
111 196 2 git_tree *tree = NULL;
112 196 2 int error = 0;
113 196 2 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
114 196 2 git_buf log_message = GIT_BUF_INIT;
115 -
116 196 2-4 assert(repo && target);
117 -
118 196 5 if (checkout_opts)
119 11 6 opts = *checkout_opts;
120 -
121 196 7,8 if (git_object_owner(target) != repo) {
122 ##### 9 git_error_set(GIT_ERROR_OBJECT,
123 - "%s - The given target does not belong to this repository.", ERROR_MSG);
124 ##### 10 return -1;
125 - }
126 -
127 196 11,15,16 if (reset_type != GIT_RESET_SOFT &&
128 183 12-14 (error = git_repository__ensure_not_bare(repo,
129 - reset_type == GIT_RESET_MIXED ? "reset mixed" : "reset hard")) < 0)
130 2 17 return error;
131 -
132 194 18-21 if ((error = git_object_peel(&commit, target, GIT_OBJECT_COMMIT)) < 0 ||
133 192 22,23 (error = git_repository_index(&index, repo)) < 0 ||
134 192 22 (error = git_commit_tree(&tree, (git_commit *)commit)) < 0)
135 - goto cleanup;
136 -
137 192 24,26 if (reset_type == GIT_RESET_SOFT &&
138 11 25,28 (git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE ||
139 10 27 git_index_has_conflicts(index)))
140 - {
141 2 29 git_error_set(GIT_ERROR_OBJECT, "%s (soft) in the middle of a merge", ERROR_MSG);
142 2 30 error = GIT_EUNMERGED;
143 2 30 goto cleanup;
144 - }
145 -
146 190 31,32 if ((error = git_buf_printf(&log_message, "reset: moving to %s", to)) < 0)
147 ##### 33 return error;
148 -
149 190 34 if (reset_type == GIT_RESET_HARD) {
150 - /* overwrite working directory with the new tree */
151 175 35 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
152 -
153 175 35,36 if ((error = git_checkout_tree(repo, (git_object *)tree, &opts)) < 0)
154 ##### 37 goto cleanup;
155 - }
156 -
157 - /* move HEAD to the new target */
158 190 38-41 if ((error = git_reference__update_terminal(repo, GIT_HEAD_FILE,
159 - git_object_id(commit), NULL, git_buf_cstr(&log_message))) < 0)
160 ##### 42 goto cleanup;
161 -
162 190 43 if (reset_type > GIT_RESET_SOFT) {
163 - /* reset index to the target content */
164 -
165 181 44-47 if ((error = git_index_read_tree(index, tree)) < 0 ||
166 181 46 (error = git_index_write(index)) < 0)
167 - goto cleanup;
168 -
169 181 48,49 if ((error = git_repository_state_cleanup(repo)) < 0) {
170 ##### 50 git_error_set(GIT_ERROR_INDEX, "%s - failed to clean up merge data", ERROR_MSG);
171 ##### 51 goto cleanup;
172 - }
173 - }
174 -
175 - cleanup:
176 194 52 git_object_free(commit);
177 194 53 git_index_free(index);
178 194 54 git_tree_free(tree);
179 194 55 git_buf_dispose(&log_message);
180 -
181 194 56 return error;
182 - }
183 -
184 193 2 int git_reset(
185 - git_repository *repo,
186 - const git_object *target,
187 - git_reset_t reset_type,
188 - const git_checkout_options *checkout_opts)
189 - {
190 193 2 return reset(repo, target, git_oid_tostr_s(git_object_id(target)), reset_type, checkout_opts);
191 - }
192 -
193 3 2 int git_reset_from_annotated(
194 - git_repository *repo,
195 - const git_annotated_commit *commit,
196 - git_reset_t reset_type,
197 - const git_checkout_options *checkout_opts)
198 - {
199 3 2 return reset(repo, (git_object *) commit->commit, commit->description, reset_type, checkout_opts);
200 - }