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