rugged 0.17.0.b6 → 0.17.0.b7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -3
- data/Rakefile +3 -1
- data/ext/rugged/rugged.c +30 -0
- data/ext/rugged/rugged.h +9 -0
- data/ext/rugged/rugged_branch.c +306 -0
- data/ext/rugged/rugged_config.c +16 -13
- data/ext/rugged/rugged_index.c +25 -0
- data/ext/rugged/rugged_object.c +6 -2
- data/ext/rugged/rugged_reference.c +11 -18
- data/ext/rugged/rugged_revwalk.c +1 -1
- data/lib/rugged.rb +1 -0
- data/lib/rugged/branch.rb +28 -0
- data/lib/rugged/commit.rb +5 -5
- data/lib/rugged/repository.rb +32 -7
- data/lib/rugged/tag.rb +5 -1
- data/lib/rugged/version.rb +1 -1
- data/test/branch_test.rb +227 -0
- data/test/config_test.rb +1 -1
- data/test/fixtures/testrepo.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 +0 -0
- data/test/fixtures/testrepo.git/objects/a3/e05719b428a2d0ed7a55c4ce53dcc5768c6d5e +0 -0
- data/test/index_test.rb +31 -0
- data/test/index_test.rb~ +218 -0
- data/test/lib_test.rb +22 -0
- data/test/reference_test.rb +5 -3
- data/vendor/libgit2/Makefile.embed +1 -1
- data/vendor/libgit2/include/git2.h +1 -0
- data/vendor/libgit2/include/git2/branch.h +17 -13
- data/vendor/libgit2/include/git2/checkout.h +83 -22
- data/vendor/libgit2/include/git2/clone.h +6 -3
- data/vendor/libgit2/include/git2/common.h +1 -8
- data/vendor/libgit2/include/git2/config.h +185 -26
- data/vendor/libgit2/include/git2/diff.h +229 -17
- data/vendor/libgit2/include/git2/errors.h +39 -1
- data/vendor/libgit2/include/git2/ignore.h +6 -3
- data/vendor/libgit2/include/git2/indexer.h +1 -0
- data/vendor/libgit2/include/git2/merge.h +1 -1
- data/vendor/libgit2/include/git2/object.h +7 -4
- data/vendor/libgit2/include/git2/odb.h +4 -2
- data/vendor/libgit2/include/git2/odb_backend.h +6 -0
- data/vendor/libgit2/include/git2/oid.h +2 -0
- data/vendor/libgit2/include/git2/pack.h +89 -0
- data/vendor/libgit2/include/git2/refs.h +88 -0
- data/vendor/libgit2/include/git2/refspec.h +0 -8
- data/vendor/libgit2/include/git2/remote.h +34 -1
- data/vendor/libgit2/include/git2/repository.h +238 -6
- data/vendor/libgit2/include/git2/reset.h +4 -1
- data/vendor/libgit2/include/git2/revwalk.h +1 -1
- data/vendor/libgit2/include/git2/status.h +19 -14
- data/vendor/libgit2/include/git2/strarray.h +54 -0
- data/vendor/libgit2/include/git2/submodule.h +451 -45
- data/vendor/libgit2/include/git2/tag.h +16 -0
- data/vendor/libgit2/include/git2/tree.h +2 -2
- data/vendor/libgit2/include/git2/types.h +4 -0
- data/vendor/libgit2/src/amiga/map.c +4 -7
- data/vendor/libgit2/src/attr.c +21 -13
- data/vendor/libgit2/src/attr.h +3 -1
- data/vendor/libgit2/src/attr_file.c +14 -14
- data/vendor/libgit2/src/attr_file.h +6 -5
- data/vendor/libgit2/src/blob.c +22 -12
- data/vendor/libgit2/src/branch.c +62 -66
- data/vendor/libgit2/src/buffer.c +63 -14
- data/vendor/libgit2/src/buffer.h +4 -0
- data/vendor/libgit2/src/cache.c +5 -4
- data/vendor/libgit2/src/checkout.c +381 -159
- data/vendor/libgit2/src/clone.c +221 -94
- data/vendor/libgit2/src/common.h +13 -3
- data/vendor/libgit2/src/compress.c +53 -0
- data/vendor/libgit2/src/compress.h +16 -0
- data/vendor/libgit2/src/config.c +380 -175
- data/vendor/libgit2/src/config.h +2 -5
- data/vendor/libgit2/src/config_file.c +63 -46
- data/vendor/libgit2/src/config_file.h +16 -4
- data/vendor/libgit2/src/crlf.c +4 -3
- data/vendor/libgit2/src/delta.c +491 -0
- data/vendor/libgit2/src/delta.h +112 -0
- data/vendor/libgit2/src/diff.c +310 -67
- data/vendor/libgit2/src/diff.h +10 -1
- data/vendor/libgit2/src/diff_output.c +1030 -337
- data/vendor/libgit2/src/diff_output.h +86 -0
- data/vendor/libgit2/src/errors.c +10 -1
- data/vendor/libgit2/src/fetch.c +108 -24
- data/vendor/libgit2/src/filebuf.c +8 -2
- data/vendor/libgit2/src/fileops.c +342 -177
- data/vendor/libgit2/src/fileops.h +84 -7
- data/vendor/libgit2/src/filter.c +0 -35
- data/vendor/libgit2/src/filter.h +0 -12
- data/vendor/libgit2/src/{compat/fnmatch.c → fnmatch.c} +16 -4
- data/vendor/libgit2/src/{compat/fnmatch.h → fnmatch.h} +4 -3
- data/vendor/libgit2/src/global.c +4 -0
- data/vendor/libgit2/src/ignore.c +122 -23
- data/vendor/libgit2/src/ignore.h +1 -0
- data/vendor/libgit2/src/index.c +56 -10
- data/vendor/libgit2/src/index.h +2 -0
- data/vendor/libgit2/src/indexer.c +8 -9
- data/vendor/libgit2/src/iterator.c +244 -31
- data/vendor/libgit2/src/iterator.h +30 -1
- data/vendor/libgit2/src/message.c +1 -1
- data/vendor/libgit2/src/netops.c +44 -4
- data/vendor/libgit2/src/object.c +80 -69
- data/vendor/libgit2/src/object.h +39 -0
- data/vendor/libgit2/src/odb.c +79 -15
- data/vendor/libgit2/src/odb.h +20 -5
- data/vendor/libgit2/src/odb_pack.c +65 -33
- data/vendor/libgit2/src/oid.c +0 -3
- data/vendor/libgit2/src/pack-objects.c +1315 -0
- data/vendor/libgit2/src/pack-objects.h +87 -0
- data/vendor/libgit2/src/pack.c +36 -12
- data/vendor/libgit2/src/pack.h +1 -0
- data/vendor/libgit2/src/path.c +42 -9
- data/vendor/libgit2/src/path.h +14 -0
- data/vendor/libgit2/src/pkt.c +52 -2
- data/vendor/libgit2/src/pkt.h +10 -0
- data/vendor/libgit2/src/pool.h +11 -0
- data/vendor/libgit2/src/posix.h +8 -0
- data/vendor/libgit2/src/protocol.c +24 -2
- data/vendor/libgit2/src/protocol.h +4 -0
- data/vendor/libgit2/src/reflog.c +1 -1
- data/vendor/libgit2/src/refs.c +292 -124
- data/vendor/libgit2/src/refs.h +4 -2
- data/vendor/libgit2/src/refspec.c +117 -19
- data/vendor/libgit2/src/refspec.h +19 -0
- data/vendor/libgit2/src/remote.c +152 -48
- data/vendor/libgit2/src/remote.h +4 -1
- data/vendor/libgit2/src/repo_template.h +58 -0
- data/vendor/libgit2/src/repository.c +594 -179
- data/vendor/libgit2/src/repository.h +23 -22
- data/vendor/libgit2/src/reset.c +71 -29
- data/vendor/libgit2/src/revparse.c +26 -17
- data/vendor/libgit2/src/revwalk.c +36 -19
- data/vendor/libgit2/src/sha1.h +7 -0
- data/vendor/libgit2/src/{sha1.c → sha1/sha1.c} +0 -0
- data/vendor/libgit2/src/signature.c +12 -10
- data/vendor/libgit2/src/status.c +52 -6
- data/vendor/libgit2/src/submodule.c +1363 -255
- data/vendor/libgit2/src/submodule.h +102 -0
- data/vendor/libgit2/src/tag.c +42 -26
- data/vendor/libgit2/src/thread-utils.h +7 -7
- data/vendor/libgit2/src/transport.h +15 -1
- data/vendor/libgit2/src/transports/git.c +1 -1
- data/vendor/libgit2/src/transports/http.c +197 -36
- data/vendor/libgit2/src/tree.c +3 -3
- data/vendor/libgit2/src/unix/map.c +2 -0
- data/vendor/libgit2/src/unix/posix.h +1 -8
- data/vendor/libgit2/src/util.c +6 -1
- data/vendor/libgit2/src/util.h +7 -0
- data/vendor/libgit2/src/vector.c +16 -0
- data/vendor/libgit2/src/vector.h +1 -0
- data/vendor/libgit2/src/win32/dir.c +8 -21
- data/vendor/libgit2/src/win32/findfile.c +149 -0
- data/vendor/libgit2/src/win32/findfile.h +23 -0
- data/vendor/libgit2/src/win32/posix.h +3 -7
- data/vendor/libgit2/src/win32/posix_w32.c +44 -102
- data/vendor/libgit2/src/win32/pthread.c +68 -0
- data/vendor/libgit2/src/win32/pthread.h +7 -0
- data/vendor/libgit2/src/win32/utf-conv.c +60 -71
- data/vendor/libgit2/src/win32/utf-conv.h +4 -3
- metadata +70 -71
- data/vendor/libgit2/include/git2/windows.h +0 -59
data/vendor/libgit2/src/buffer.c
CHANGED
@@ -144,31 +144,40 @@ int git_buf_puts(git_buf *buf, const char *string)
|
|
144
144
|
int git_buf_puts_escaped(
|
145
145
|
git_buf *buf, const char *string, const char *esc_chars, const char *esc_with)
|
146
146
|
{
|
147
|
-
const char *scan
|
148
|
-
size_t total = 0,
|
147
|
+
const char *scan;
|
148
|
+
size_t total = 0, esc_len = strlen(esc_with), count;
|
149
149
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
150
|
+
if (!string)
|
151
|
+
return 0;
|
152
|
+
|
153
|
+
for (scan = string; *scan; ) {
|
154
|
+
/* count run of non-escaped characters */
|
155
|
+
count = strcspn(scan, esc_chars);
|
156
|
+
total += count;
|
157
|
+
scan += count;
|
158
|
+
/* count run of escaped characters */
|
159
|
+
count = strspn(scan, esc_chars);
|
160
|
+
total += count * (esc_len + 1);
|
161
|
+
scan += count;
|
154
162
|
}
|
155
163
|
|
156
164
|
ENSURE_SIZE(buf, buf->size + total + 1);
|
157
165
|
|
158
166
|
for (scan = string; *scan; ) {
|
159
|
-
|
167
|
+
count = strcspn(scan, esc_chars);
|
160
168
|
|
161
169
|
memmove(buf->ptr + buf->size, scan, count);
|
162
170
|
scan += count;
|
163
171
|
buf->size += count;
|
164
172
|
|
165
|
-
|
166
|
-
|
167
|
-
buf->size
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
buf->size
|
173
|
+
for (count = strspn(scan, esc_chars); count > 0; --count) {
|
174
|
+
/* copy escape sequence */
|
175
|
+
memmove(buf->ptr + buf->size, esc_with, esc_len);
|
176
|
+
buf->size += esc_len;
|
177
|
+
/* copy character to be escaped */
|
178
|
+
buf->ptr[buf->size] = *scan;
|
179
|
+
buf->size++;
|
180
|
+
scan++;
|
172
181
|
}
|
173
182
|
}
|
174
183
|
|
@@ -177,6 +186,46 @@ int git_buf_puts_escaped(
|
|
177
186
|
return 0;
|
178
187
|
}
|
179
188
|
|
189
|
+
static const char b64str[64] =
|
190
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
191
|
+
|
192
|
+
int git_buf_put_base64(git_buf *buf, const char *data, size_t len)
|
193
|
+
{
|
194
|
+
size_t extra = len % 3;
|
195
|
+
uint8_t *write, a, b, c;
|
196
|
+
const uint8_t *read = (const uint8_t *)data;
|
197
|
+
|
198
|
+
ENSURE_SIZE(buf, buf->size + 4 * ((len / 3) + !!extra) + 1);
|
199
|
+
write = (uint8_t *)&buf->ptr[buf->size];
|
200
|
+
|
201
|
+
/* convert each run of 3 bytes into 4 output bytes */
|
202
|
+
for (len -= extra; len > 0; len -= 3) {
|
203
|
+
a = *read++;
|
204
|
+
b = *read++;
|
205
|
+
c = *read++;
|
206
|
+
|
207
|
+
*write++ = b64str[a >> 2];
|
208
|
+
*write++ = b64str[(a & 0x03) << 4 | b >> 4];
|
209
|
+
*write++ = b64str[(b & 0x0f) << 2 | c >> 6];
|
210
|
+
*write++ = b64str[c & 0x3f];
|
211
|
+
}
|
212
|
+
|
213
|
+
if (extra > 0) {
|
214
|
+
a = *read++;
|
215
|
+
b = (extra > 1) ? *read++ : 0;
|
216
|
+
|
217
|
+
*write++ = b64str[a >> 2];
|
218
|
+
*write++ = b64str[(a & 0x03) << 4 | b >> 4];
|
219
|
+
*write++ = (extra > 1) ? b64str[(b & 0x0f) << 2] : '=';
|
220
|
+
*write++ = '=';
|
221
|
+
}
|
222
|
+
|
223
|
+
buf->size = ((char *)write) - buf->ptr;
|
224
|
+
buf->ptr[buf->size] = '\0';
|
225
|
+
|
226
|
+
return 0;
|
227
|
+
}
|
228
|
+
|
180
229
|
int git_buf_vprintf(git_buf *buf, const char *format, va_list ap)
|
181
230
|
{
|
182
231
|
int len;
|
data/vendor/libgit2/src/buffer.h
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
#define INCLUDE_buffer_h__
|
9
9
|
|
10
10
|
#include "common.h"
|
11
|
+
#include "git2/strarray.h"
|
11
12
|
#include <stdarg.h>
|
12
13
|
|
13
14
|
typedef struct {
|
@@ -154,4 +155,7 @@ bool git_buf_is_binary(const git_buf *buf);
|
|
154
155
|
/* Unescape all characters in a buffer */
|
155
156
|
void git_buf_unescape(git_buf *buf);
|
156
157
|
|
158
|
+
/* Write data as base64 encoded in buffer */
|
159
|
+
int git_buf_put_base64(git_buf *buf, const char *data, size_t len);
|
160
|
+
|
157
161
|
#endif
|
data/vendor/libgit2/src/cache.c
CHANGED
@@ -89,12 +89,13 @@ void *git_cache_try_store(git_cache *cache, void *_entry)
|
|
89
89
|
git_cached_obj_decref(node, cache->free_obj);
|
90
90
|
cache->nodes[hash & cache->size_mask] = entry;
|
91
91
|
}
|
92
|
+
|
93
|
+
/* increase the refcount again, because we are
|
94
|
+
* returning it to the user */
|
95
|
+
git_cached_obj_incref(entry);
|
96
|
+
|
92
97
|
}
|
93
98
|
git_mutex_unlock(&cache->lock);
|
94
99
|
|
95
|
-
/* increase the refcount again, because we are
|
96
|
-
* returning it to the user */
|
97
|
-
git_cached_obj_incref(entry);
|
98
|
-
|
99
100
|
return entry;
|
100
101
|
}
|
@@ -11,9 +11,9 @@
|
|
11
11
|
#include "git2/repository.h"
|
12
12
|
#include "git2/refs.h"
|
13
13
|
#include "git2/tree.h"
|
14
|
-
#include "git2/commit.h"
|
15
14
|
#include "git2/blob.h"
|
16
15
|
#include "git2/config.h"
|
16
|
+
#include "git2/diff.h"
|
17
17
|
|
18
18
|
#include "common.h"
|
19
19
|
#include "refs.h"
|
@@ -22,209 +22,431 @@
|
|
22
22
|
#include "filter.h"
|
23
23
|
#include "blob.h"
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
typedef struct tree_walk_data
|
25
|
+
struct checkout_diff_data
|
29
26
|
{
|
27
|
+
git_buf *path;
|
28
|
+
size_t workdir_len;
|
29
|
+
git_checkout_opts *checkout_opts;
|
30
30
|
git_indexer_stats *stats;
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
bool
|
35
|
-
|
31
|
+
git_repository *owner;
|
32
|
+
bool can_symlink;
|
33
|
+
bool found_submodules;
|
34
|
+
bool create_submodules;
|
35
|
+
int error;
|
36
|
+
};
|
37
|
+
|
38
|
+
static int buffer_to_file(
|
39
|
+
git_buf *buffer,
|
40
|
+
const char *path,
|
41
|
+
mode_t dir_mode,
|
42
|
+
int file_open_flags,
|
43
|
+
mode_t file_mode)
|
44
|
+
{
|
45
|
+
int fd, error, error_close;
|
36
46
|
|
47
|
+
if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
|
48
|
+
return error;
|
37
49
|
|
38
|
-
|
39
|
-
|
40
|
-
{
|
41
|
-
int retcode = GIT_ERROR;
|
42
|
-
git_blob *blob;
|
50
|
+
if ((fd = p_open(path, file_open_flags, file_mode)) < 0)
|
51
|
+
return fd;
|
43
52
|
|
44
|
-
|
45
|
-
if (!(retcode = git_blob_lookup(&blob, data->repo, id))) {
|
46
|
-
git_buf linktarget = GIT_BUF_INIT;
|
47
|
-
if (!(retcode = git_blob__getbuf(&linktarget, blob))) {
|
48
|
-
/* Create the link */
|
49
|
-
const char *new = git_buf_cstr(&linktarget),
|
50
|
-
*old = git_buf_cstr(fnbuf);
|
51
|
-
retcode = data->do_symlinks
|
52
|
-
? p_symlink(new, old)
|
53
|
-
: git_futils_fake_symlink(new, old);
|
54
|
-
}
|
55
|
-
git_buf_free(&linktarget);
|
56
|
-
git_blob_free(blob);
|
57
|
-
}
|
53
|
+
error = p_write(fd, git_buf_cstr(buffer), git_buf_len(buffer));
|
58
54
|
|
59
|
-
|
60
|
-
}
|
55
|
+
error_close = p_close(fd);
|
61
56
|
|
57
|
+
if (!error)
|
58
|
+
error = error_close;
|
62
59
|
|
63
|
-
|
64
|
-
|
60
|
+
if (!error &&
|
61
|
+
(file_mode & 0100) != 0 &&
|
62
|
+
(error = p_chmod(path, file_mode)) < 0)
|
63
|
+
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
|
64
|
+
|
65
|
+
return error;
|
66
|
+
}
|
67
|
+
|
68
|
+
static int blob_content_to_file(
|
69
|
+
git_blob *blob,
|
70
|
+
const char *path,
|
71
|
+
mode_t entry_filemode,
|
72
|
+
git_checkout_opts *opts)
|
65
73
|
{
|
66
|
-
int
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
74
|
+
int error = -1, nb_filters = 0;
|
75
|
+
mode_t file_mode = opts->file_mode;
|
76
|
+
bool dont_free_filtered = false;
|
77
|
+
git_buf unfiltered = GIT_BUF_INIT, filtered = GIT_BUF_INIT;
|
78
|
+
git_vector filters = GIT_VECTOR_INIT;
|
79
|
+
|
80
|
+
if (opts->disable_filters ||
|
81
|
+
(nb_filters = git_filters_load(
|
82
|
+
&filters,
|
83
|
+
git_object_owner((git_object *)blob),
|
84
|
+
path,
|
85
|
+
GIT_FILTER_TO_WORKTREE)) == 0) {
|
86
|
+
|
87
|
+
/* Create a fake git_buf from the blob raw data... */
|
88
|
+
filtered.ptr = blob->odb_object->raw.data;
|
89
|
+
filtered.size = blob->odb_object->raw.len;
|
90
|
+
|
91
|
+
/* ... and make sure it doesn't get unexpectedly freed */
|
92
|
+
dont_free_filtered = true;
|
93
|
+
}
|
94
|
+
|
95
|
+
if (nb_filters < 0)
|
96
|
+
return nb_filters;
|
97
|
+
|
98
|
+
if (nb_filters > 0) {
|
99
|
+
if ((error = git_blob__getbuf(&unfiltered, blob)) < 0)
|
100
|
+
goto cleanup;
|
101
|
+
|
102
|
+
if ((error = git_filters_apply(&filtered, &unfiltered, &filters)) < 0)
|
103
|
+
goto cleanup;
|
86
104
|
}
|
87
|
-
if (retcode < 0) goto bctf_cleanup;
|
88
105
|
|
89
106
|
/* Allow overriding of file mode */
|
90
107
|
if (!file_mode)
|
91
|
-
file_mode =
|
108
|
+
file_mode = entry_filemode;
|
109
|
+
|
110
|
+
error = buffer_to_file(&filtered, path, opts->dir_mode, opts->file_open_flags, file_mode);
|
92
111
|
|
93
|
-
|
94
|
-
|
112
|
+
cleanup:
|
113
|
+
git_filters_free(&filters);
|
114
|
+
git_buf_free(&unfiltered);
|
115
|
+
if (!dont_free_filtered)
|
116
|
+
git_buf_free(&filtered);
|
95
117
|
|
96
|
-
|
97
|
-
|
118
|
+
return error;
|
119
|
+
}
|
98
120
|
|
99
|
-
|
100
|
-
|
121
|
+
static int blob_content_to_link(git_blob *blob, const char *path, bool can_symlink)
|
122
|
+
{
|
123
|
+
git_buf linktarget = GIT_BUF_INIT;
|
124
|
+
int error;
|
125
|
+
|
126
|
+
if ((error = git_blob__getbuf(&linktarget, blob)) < 0)
|
127
|
+
return error;
|
128
|
+
|
129
|
+
if (can_symlink)
|
130
|
+
error = p_symlink(git_buf_cstr(&linktarget), path);
|
101
131
|
else
|
102
|
-
|
103
|
-
|
132
|
+
error = git_futils_fake_symlink(git_buf_cstr(&linktarget), path);
|
133
|
+
|
134
|
+
git_buf_free(&linktarget);
|
104
135
|
|
105
|
-
|
106
|
-
git_buf_free(&contents);
|
107
|
-
return retcode;
|
136
|
+
return error;
|
108
137
|
}
|
109
138
|
|
110
|
-
static int
|
139
|
+
static int checkout_submodule(
|
140
|
+
struct checkout_diff_data *data,
|
141
|
+
const git_diff_file *file)
|
111
142
|
{
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
143
|
+
if (git_futils_mkdir(
|
144
|
+
file->path, git_repository_workdir(data->owner),
|
145
|
+
data->checkout_opts->dir_mode, GIT_MKDIR_PATH) < 0)
|
146
|
+
return -1;
|
147
|
+
|
148
|
+
/* TODO: two cases:
|
149
|
+
* 1 - submodule already checked out, but we need to move the HEAD
|
150
|
+
* to the new OID, or
|
151
|
+
* 2 - submodule not checked out and we should recursively check it out
|
152
|
+
*
|
153
|
+
* Checkout will not execute a pull request on the submodule, but a
|
154
|
+
* clone command should probably be able to. Do we need a submodule
|
155
|
+
* callback option?
|
156
|
+
*/
|
157
|
+
|
158
|
+
return 0;
|
159
|
+
}
|
160
|
+
|
161
|
+
static int checkout_blob(
|
162
|
+
struct checkout_diff_data *data,
|
163
|
+
const git_diff_file *file)
|
164
|
+
{
|
165
|
+
git_blob *blob;
|
166
|
+
int error;
|
167
|
+
|
168
|
+
git_buf_truncate(data->path, data->workdir_len);
|
169
|
+
if (git_buf_joinpath(data->path, git_buf_cstr(data->path), file->path) < 0)
|
170
|
+
return -1;
|
171
|
+
|
172
|
+
if ((error = git_blob_lookup(&blob, data->owner, &file->oid)) < 0)
|
173
|
+
return error;
|
174
|
+
|
175
|
+
if (S_ISLNK(file->mode))
|
176
|
+
error = blob_content_to_link(
|
177
|
+
blob, git_buf_cstr(data->path), data->can_symlink);
|
178
|
+
else
|
179
|
+
error = blob_content_to_file(
|
180
|
+
blob, git_buf_cstr(data->path), file->mode, data->checkout_opts);
|
181
|
+
|
182
|
+
git_blob_free(blob);
|
183
|
+
|
184
|
+
return error;
|
185
|
+
}
|
186
|
+
|
187
|
+
static int checkout_remove_the_old(
|
188
|
+
void *cb_data, const git_diff_delta *delta, float progress)
|
189
|
+
{
|
190
|
+
struct checkout_diff_data *data = cb_data;
|
191
|
+
git_checkout_opts *opts = data->checkout_opts;
|
192
|
+
|
193
|
+
GIT_UNUSED(progress);
|
194
|
+
data->stats->processed++;
|
195
|
+
|
196
|
+
if ((delta->status == GIT_DELTA_UNTRACKED &&
|
197
|
+
(opts->checkout_strategy & GIT_CHECKOUT_REMOVE_UNTRACKED) != 0) ||
|
198
|
+
(delta->status == GIT_DELTA_TYPECHANGE &&
|
199
|
+
(opts->checkout_strategy & GIT_CHECKOUT_OVERWRITE_MODIFIED) != 0))
|
200
|
+
{
|
201
|
+
data->error = git_futils_rmdir_r(
|
202
|
+
delta->new_file.path,
|
203
|
+
git_repository_workdir(data->owner),
|
204
|
+
GIT_DIRREMOVAL_FILES_AND_DIRS);
|
205
|
+
}
|
206
|
+
|
207
|
+
return data->error;
|
208
|
+
}
|
209
|
+
|
210
|
+
static int checkout_create_the_new(
|
211
|
+
void *cb_data, const git_diff_delta *delta, float progress)
|
212
|
+
{
|
213
|
+
int error = 0;
|
214
|
+
struct checkout_diff_data *data = cb_data;
|
215
|
+
git_checkout_opts *opts = data->checkout_opts;
|
216
|
+
bool do_checkout = false, do_notify = false;
|
217
|
+
|
218
|
+
GIT_UNUSED(progress);
|
219
|
+
data->stats->processed++;
|
220
|
+
|
221
|
+
if (delta->status == GIT_DELTA_MODIFIED ||
|
222
|
+
delta->status == GIT_DELTA_TYPECHANGE)
|
122
223
|
{
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
224
|
+
if ((opts->checkout_strategy & GIT_CHECKOUT_OVERWRITE_MODIFIED) != 0)
|
225
|
+
do_checkout = true;
|
226
|
+
else if (opts->skipped_notify_cb != NULL)
|
227
|
+
do_notify = !data->create_submodules;
|
228
|
+
}
|
229
|
+
else if (delta->status == GIT_DELTA_DELETED &&
|
230
|
+
(opts->checkout_strategy & GIT_CHECKOUT_CREATE_MISSING) != 0)
|
231
|
+
do_checkout = true;
|
232
|
+
|
233
|
+
if (do_notify) {
|
234
|
+
if (opts->skipped_notify_cb(
|
235
|
+
delta->old_file.path, &delta->old_file.oid,
|
236
|
+
delta->old_file.mode, opts->notify_payload))
|
237
|
+
{
|
238
|
+
giterr_clear();
|
239
|
+
error = GIT_EUSER;
|
139
240
|
}
|
140
|
-
|
241
|
+
}
|
242
|
+
|
243
|
+
if (do_checkout) {
|
244
|
+
bool is_submodule = S_ISGITLINK(delta->old_file.mode);
|
141
245
|
|
142
|
-
|
143
|
-
|
144
|
-
|
246
|
+
if (is_submodule)
|
247
|
+
data->found_submodules = true;
|
248
|
+
|
249
|
+
if (!is_submodule && !data->create_submodules)
|
250
|
+
error = checkout_blob(data, &delta->old_file);
|
251
|
+
|
252
|
+
else if (is_submodule && data->create_submodules)
|
253
|
+
error = checkout_submodule(data, &delta->old_file);
|
145
254
|
}
|
146
255
|
|
147
|
-
|
148
|
-
|
149
|
-
return retcode;
|
150
|
-
}
|
256
|
+
if (error)
|
257
|
+
data->error = error;
|
151
258
|
|
259
|
+
return error;
|
260
|
+
}
|
152
261
|
|
153
|
-
int
|
262
|
+
static int retrieve_symlink_capabilities(git_repository *repo, bool *can_symlink)
|
154
263
|
{
|
155
|
-
int retcode = GIT_ERROR;
|
156
|
-
git_indexer_stats dummy_stats;
|
157
|
-
git_checkout_opts default_opts = {0};
|
158
|
-
git_tree *tree;
|
159
|
-
tree_walk_data payload;
|
160
264
|
git_config *cfg;
|
265
|
+
int error;
|
161
266
|
|
162
|
-
|
163
|
-
|
164
|
-
|
267
|
+
if (git_repository_config__weakptr(&cfg, repo) < 0)
|
268
|
+
return -1;
|
269
|
+
|
270
|
+
error = git_config_get_bool((int *)can_symlink, cfg, "core.symlinks");
|
271
|
+
|
272
|
+
/*
|
273
|
+
* When no "core.symlinks" entry is found in any of the configuration
|
274
|
+
* store (local, global or system), default value is "true".
|
275
|
+
*/
|
276
|
+
if (error == GIT_ENOTFOUND) {
|
277
|
+
*can_symlink = true;
|
278
|
+
error = 0;
|
279
|
+
}
|
280
|
+
|
281
|
+
return error;
|
282
|
+
}
|
283
|
+
|
284
|
+
static void normalize_options(git_checkout_opts *normalized, git_checkout_opts *proposed)
|
285
|
+
{
|
286
|
+
assert(normalized);
|
287
|
+
|
288
|
+
if (!proposed)
|
289
|
+
memset(normalized, 0, sizeof(git_checkout_opts));
|
290
|
+
else
|
291
|
+
memmove(normalized, proposed, sizeof(git_checkout_opts));
|
165
292
|
|
166
293
|
/* Default options */
|
167
|
-
if (!
|
168
|
-
|
294
|
+
if (!normalized->checkout_strategy)
|
295
|
+
normalized->checkout_strategy = GIT_CHECKOUT_DEFAULT;
|
296
|
+
|
169
297
|
/* opts->disable_filters is false by default */
|
170
|
-
if (!
|
171
|
-
|
172
|
-
opts->file_open_flags = O_CREAT | O_TRUNC | O_WRONLY;
|
298
|
+
if (!normalized->dir_mode)
|
299
|
+
normalized->dir_mode = GIT_DIR_MODE;
|
173
300
|
|
174
|
-
if (
|
175
|
-
|
176
|
-
|
177
|
-
}
|
301
|
+
if (!normalized->file_open_flags)
|
302
|
+
normalized->file_open_flags = O_CREAT | O_TRUNC | O_WRONLY;
|
303
|
+
}
|
178
304
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
}
|
305
|
+
int git_checkout_index(
|
306
|
+
git_repository *repo,
|
307
|
+
git_checkout_opts *opts,
|
308
|
+
git_indexer_stats *stats)
|
309
|
+
{
|
310
|
+
git_diff_list *diff = NULL;
|
311
|
+
git_indexer_stats dummy_stats;
|
187
312
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
313
|
+
git_diff_options diff_opts = {0};
|
314
|
+
git_checkout_opts checkout_opts;
|
315
|
+
|
316
|
+
struct checkout_diff_data data;
|
317
|
+
git_buf workdir = GIT_BUF_INIT;
|
318
|
+
|
319
|
+
int error;
|
320
|
+
|
321
|
+
assert(repo);
|
322
|
+
|
323
|
+
if ((error = git_repository__ensure_not_bare(repo, "checkout")) < 0)
|
324
|
+
return error;
|
325
|
+
|
326
|
+
diff_opts.flags =
|
327
|
+
GIT_DIFF_INCLUDE_UNTRACKED |
|
328
|
+
GIT_DIFF_INCLUDE_TYPECHANGE |
|
329
|
+
GIT_DIFF_SKIP_BINARY_CHECK;
|
330
|
+
|
331
|
+
if (opts && opts->paths.count > 0)
|
332
|
+
diff_opts.pathspec = opts->paths;
|
333
|
+
|
334
|
+
if ((error = git_diff_workdir_to_index(repo, &diff_opts, &diff)) < 0)
|
335
|
+
goto cleanup;
|
336
|
+
|
337
|
+
if ((error = git_buf_puts(&workdir, git_repository_workdir(repo))) < 0)
|
338
|
+
goto cleanup;
|
339
|
+
|
340
|
+
normalize_options(&checkout_opts, opts);
|
341
|
+
|
342
|
+
if (!stats)
|
343
|
+
stats = &dummy_stats;
|
344
|
+
|
345
|
+
stats->processed = 0;
|
346
|
+
/* total based on 3 passes, but it might be 2 if no submodules */
|
347
|
+
stats->total = (unsigned int)git_diff_num_deltas(diff) * 3;
|
348
|
+
|
349
|
+
memset(&data, 0, sizeof(data));
|
350
|
+
|
351
|
+
data.path = &workdir;
|
352
|
+
data.workdir_len = git_buf_len(&workdir);
|
353
|
+
data.checkout_opts = &checkout_opts;
|
354
|
+
data.stats = stats;
|
355
|
+
data.owner = repo;
|
356
|
+
|
357
|
+
if ((error = retrieve_symlink_capabilities(repo, &data.can_symlink)) < 0)
|
358
|
+
goto cleanup;
|
359
|
+
|
360
|
+
/* Checkout is best performed with three passes through the diff.
|
361
|
+
*
|
362
|
+
* 1. First do removes, because we iterate in alphabetical order, thus
|
363
|
+
* a new untracked directory will end up sorted *after* a blob that
|
364
|
+
* should be checked out with the same name.
|
365
|
+
* 2. Then checkout all blobs.
|
366
|
+
* 3. Then checkout all submodules in case a new .gitmodules blob was
|
367
|
+
* checked out during pass #2.
|
368
|
+
*/
|
369
|
+
|
370
|
+
if (!(error = git_diff_foreach(
|
371
|
+
diff, &data, checkout_remove_the_old, NULL, NULL)) &&
|
372
|
+
!(error = git_diff_foreach(
|
373
|
+
diff, &data, checkout_create_the_new, NULL, NULL)) &&
|
374
|
+
data.found_submodules)
|
375
|
+
{
|
376
|
+
data.create_submodules = true;
|
377
|
+
error = git_diff_foreach(
|
378
|
+
diff, &data, checkout_create_the_new, NULL, NULL);
|
204
379
|
}
|
205
380
|
|
206
|
-
|
207
|
-
return retcode;
|
208
|
-
}
|
381
|
+
stats->processed = stats->total;
|
209
382
|
|
383
|
+
cleanup:
|
384
|
+
if (error == GIT_EUSER)
|
385
|
+
error = (data.error != 0) ? data.error : -1;
|
210
386
|
|
211
|
-
|
212
|
-
|
213
|
-
|
387
|
+
git_diff_list_free(diff);
|
388
|
+
git_buf_free(&workdir);
|
389
|
+
|
390
|
+
return error;
|
391
|
+
}
|
392
|
+
|
393
|
+
int git_checkout_tree(
|
394
|
+
git_repository *repo,
|
395
|
+
git_object *treeish,
|
396
|
+
git_checkout_opts *opts,
|
397
|
+
git_indexer_stats *stats)
|
214
398
|
{
|
215
|
-
|
216
|
-
|
217
|
-
int retcode = GIT_ERROR;
|
399
|
+
git_index *index = NULL;
|
400
|
+
git_tree *tree = NULL;
|
218
401
|
|
219
|
-
|
220
|
-
git_reference_name(ref), true)) < 0)
|
221
|
-
return retcode;
|
402
|
+
int error;
|
222
403
|
|
223
|
-
|
404
|
+
assert(repo && treeish);
|
224
405
|
|
225
|
-
|
226
|
-
|
406
|
+
if (git_object_peel((git_object **)&tree, treeish, GIT_OBJ_TREE) < 0) {
|
407
|
+
giterr_set(GITERR_INVALID, "Provided treeish cannot be peeled into a tree.");
|
408
|
+
return GIT_ERROR;
|
409
|
+
}
|
410
|
+
|
411
|
+
if ((error = git_repository_index(&index, repo)) < 0)
|
412
|
+
goto cleanup;
|
413
|
+
|
414
|
+
if ((error = git_index_read_tree(index, tree, NULL)) < 0)
|
415
|
+
goto cleanup;
|
416
|
+
|
417
|
+
if ((error = git_index_write(index)) < 0)
|
418
|
+
goto cleanup;
|
419
|
+
|
420
|
+
error = git_checkout_index(repo, opts, stats);
|
421
|
+
|
422
|
+
cleanup:
|
423
|
+
git_index_free(index);
|
424
|
+
git_tree_free(tree);
|
425
|
+
return error;
|
227
426
|
}
|
228
427
|
|
428
|
+
int git_checkout_head(
|
429
|
+
git_repository *repo,
|
430
|
+
git_checkout_opts *opts,
|
431
|
+
git_indexer_stats *stats)
|
432
|
+
{
|
433
|
+
git_reference *head;
|
434
|
+
int error;
|
435
|
+
git_object *tree = NULL;
|
436
|
+
|
437
|
+
assert(repo);
|
438
|
+
|
439
|
+
if ((error = git_repository_head(&head, repo)) < 0)
|
440
|
+
return error;
|
441
|
+
|
442
|
+
if ((error = git_reference_peel(&tree, head, GIT_OBJ_TREE)) < 0)
|
443
|
+
goto cleanup;
|
444
|
+
|
445
|
+
error = git_checkout_tree(repo, tree, opts, stats);
|
229
446
|
|
230
|
-
|
447
|
+
cleanup:
|
448
|
+
git_reference_free(head);
|
449
|
+
git_object_free(tree);
|
450
|
+
|
451
|
+
return error;
|
452
|
+
}
|