| 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
|
|
|
|
|
assert(pathspecs != NULL && 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
|
|
|
|
|
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_buf log_message = GIT_BUF_INIT; |
|
115
|
|
|
|
|
|
|
|
|
116
|
2
|
50
|
|
|
|
|
assert(repo && target); |
|
|
|
50
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
|
|
118
|
2
|
100
|
|
|
|
|
if (checkout_opts) |
|
119
|
1
|
|
|
|
|
|
opts = *checkout_opts; |
|
120
|
|
|
|
|
|
|
|
|
121
|
2
|
50
|
|
|
|
|
if (git_object_owner(target) != repo) { |
|
122
|
0
|
|
|
|
|
|
git_error_set(GIT_ERROR_OBJECT, |
|
123
|
|
|
|
|
|
|
"%s - The given target does not belong to this repository.", ERROR_MSG); |
|
124
|
0
|
|
|
|
|
|
return -1; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
4
|
50
|
|
|
|
|
if (reset_type != GIT_RESET_SOFT && |
|
|
|
50
|
|
|
|
|
|
|
128
|
2
|
50
|
|
|
|
|
(error = git_repository__ensure_not_bare(repo, |
|
129
|
|
|
|
|
|
|
reset_type == GIT_RESET_MIXED ? "reset mixed" : "reset hard")) < 0) |
|
130
|
0
|
|
|
|
|
|
return error; |
|
131
|
|
|
|
|
|
|
|
|
132
|
2
|
50
|
|
|
|
|
if ((error = git_object_peel(&commit, target, GIT_OBJECT_COMMIT)) < 0 || |
|
|
|
50
|
|
|
|
|
|
|
133
|
2
|
50
|
|
|
|
|
(error = git_repository_index(&index, repo)) < 0 || |
|
134
|
2
|
|
|
|
|
|
(error = git_commit_tree(&tree, (git_commit *)commit)) < 0) |
|
135
|
|
|
|
|
|
|
goto cleanup; |
|
136
|
|
|
|
|
|
|
|
|
137
|
2
|
|
|
|
|
|
if (reset_type == GIT_RESET_SOFT && |
|
138
|
0
|
0
|
|
|
|
|
(git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE || |
|
139
|
0
|
|
|
|
|
|
git_index_has_conflicts(index))) |
|
140
|
|
|
|
|
|
|
{ |
|
141
|
0
|
|
|
|
|
|
git_error_set(GIT_ERROR_OBJECT, "%s (soft) in the middle of a merge", ERROR_MSG); |
|
142
|
0
|
|
|
|
|
|
error = GIT_EUNMERGED; |
|
143
|
0
|
|
|
|
|
|
goto cleanup; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
2
|
50
|
|
|
|
|
if ((error = git_buf_printf(&log_message, "reset: moving to %s", to)) < 0) |
|
147
|
0
|
|
|
|
|
|
return error; |
|
148
|
|
|
|
|
|
|
|
|
149
|
2
|
50
|
|
|
|
|
if (reset_type == GIT_RESET_HARD) { |
|
150
|
|
|
|
|
|
|
/* overwrite working directory with the new tree */ |
|
151
|
2
|
|
|
|
|
|
opts.checkout_strategy = GIT_CHECKOUT_FORCE; |
|
152
|
|
|
|
|
|
|
|
|
153
|
2
|
50
|
|
|
|
|
if ((error = git_checkout_tree(repo, (git_object *)tree, &opts)) < 0) |
|
154
|
0
|
|
|
|
|
|
goto cleanup; |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
/* move HEAD to the new target */ |
|
158
|
2
|
50
|
|
|
|
|
if ((error = git_reference__update_terminal(repo, GIT_HEAD_FILE, |
|
159
|
|
|
|
|
|
|
git_object_id(commit), NULL, git_buf_cstr(&log_message))) < 0) |
|
160
|
0
|
|
|
|
|
|
goto cleanup; |
|
161
|
|
|
|
|
|
|
|
|
162
|
2
|
50
|
|
|
|
|
if (reset_type > GIT_RESET_SOFT) { |
|
163
|
|
|
|
|
|
|
/* reset index to the target content */ |
|
164
|
|
|
|
|
|
|
|
|
165
|
2
|
50
|
|
|
|
|
if ((error = git_index_read_tree(index, tree)) < 0 || |
|
|
|
50
|
|
|
|
|
|
|
166
|
2
|
|
|
|
|
|
(error = git_index_write(index)) < 0) |
|
167
|
|
|
|
|
|
|
goto cleanup; |
|
168
|
|
|
|
|
|
|
|
|
169
|
2
|
50
|
|
|
|
|
if ((error = git_repository_state_cleanup(repo)) < 0) { |
|
170
|
0
|
|
|
|
|
|
git_error_set(GIT_ERROR_INDEX, "%s - failed to clean up merge data", ERROR_MSG); |
|
171
|
0
|
|
|
|
|
|
goto cleanup; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
cleanup: |
|
176
|
2
|
|
|
|
|
|
git_object_free(commit); |
|
177
|
2
|
|
|
|
|
|
git_index_free(index); |
|
178
|
2
|
|
|
|
|
|
git_tree_free(tree); |
|
179
|
2
|
|
|
|
|
|
git_buf_dispose(&log_message); |
|
180
|
|
|
|
|
|
|
|
|
181
|
2
|
|
|
|
|
|
return error; |
|
182
|
|
|
|
|
|
|
} |
|
183
|
|
|
|
|
|
|
|
|
184
|
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
|
2
|
|
|
|
|
|
return reset(repo, target, git_oid_tostr_s(git_object_id(target)), reset_type, checkout_opts); |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
|
|
193
|
0
|
|
|
|
|
|
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
|
0
|
|
|
|
|
|
return reset(repo, (git_object *) commit->commit, commit->description, reset_type, checkout_opts); |
|
200
|
|
|
|
|
|
|
} |