rugged 0.22.0b5 → 0.22.1b1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -3
- data/ext/rugged/extconf.rb +21 -5
- data/ext/rugged/rugged.c +1 -0
- data/ext/rugged/rugged.h +8 -0
- data/ext/rugged/rugged_backend.c +34 -0
- data/ext/rugged/rugged_branch_collection.c +1 -0
- data/ext/rugged/rugged_remote.c +37 -86
- data/ext/rugged/rugged_remote_collection.c +2 -1
- data/ext/rugged/rugged_repo.c +149 -24
- data/ext/rugged/rugged_revwalk.c +1 -2
- data/ext/rugged/rugged_submodule.c +1 -1
- data/ext/rugged/rugged_tree.c +69 -5
- data/lib/rugged/version.rb +1 -1
- data/vendor/libgit2/CMakeLists.txt +2 -1
- data/vendor/libgit2/include/git2.h +0 -1
- data/vendor/libgit2/include/git2/checkout.h +8 -0
- data/vendor/libgit2/include/git2/merge.h +8 -0
- data/vendor/libgit2/include/git2/push.h +0 -110
- data/vendor/libgit2/include/git2/remote.h +30 -1
- data/vendor/libgit2/include/git2/revert.h +1 -1
- data/vendor/libgit2/include/git2/submodule.h +80 -1
- data/vendor/libgit2/include/git2/sys/index.h +2 -2
- data/vendor/libgit2/include/git2/{threads.h → sys/openssl.h} +10 -12
- data/vendor/libgit2/include/git2/sys/refs.h +11 -0
- data/vendor/libgit2/include/git2/tree.h +1 -1
- data/vendor/libgit2/include/git2/version.h +3 -3
- data/vendor/libgit2/src/attr_file.c +3 -1
- data/vendor/libgit2/src/buffer.c +2 -1
- data/vendor/libgit2/src/checkout.c +135 -39
- data/vendor/libgit2/src/checkout.h +7 -0
- data/vendor/libgit2/src/config_file.c +5 -7
- data/vendor/libgit2/src/crlf.c +2 -0
- data/vendor/libgit2/src/describe.c +6 -2
- data/vendor/libgit2/src/diff.c +1 -0
- data/vendor/libgit2/src/fileops.c +87 -19
- data/vendor/libgit2/src/fileops.h +18 -0
- data/vendor/libgit2/src/global.c +1 -1
- data/vendor/libgit2/src/ident.c +2 -0
- data/vendor/libgit2/src/index.c +4 -4
- data/vendor/libgit2/src/merge.c +3 -1
- data/vendor/libgit2/src/notes.c +1 -1
- data/vendor/libgit2/src/pack.c +1 -0
- data/vendor/libgit2/src/path.c +17 -12
- data/vendor/libgit2/src/path.h +17 -3
- data/vendor/libgit2/src/push.h +110 -0
- data/vendor/libgit2/src/rebase.c +4 -2
- data/vendor/libgit2/src/remote.c +237 -16
- data/vendor/libgit2/src/remote.h +2 -0
- data/vendor/libgit2/src/repository.c +7 -3
- data/vendor/libgit2/src/submodule.c +229 -18
- data/vendor/libgit2/src/transports/local.c +61 -2
- data/vendor/libgit2/src/transports/smart_protocol.c +5 -3
- data/vendor/libgit2/src/tree.c +2 -2
- data/vendor/libgit2/src/util.h +13 -2
- data/vendor/libgit2/src/win32/mingw-compat.h +2 -0
- data/vendor/libgit2/src/win32/path_w32.h +2 -0
- metadata +4 -4
- data/vendor/libgit2/cmake/Modules/FindLIBSSH2.cmake +0 -44
data/vendor/libgit2/src/rebase.c
CHANGED
@@ -246,7 +246,8 @@ int git_rebase_open(git_rebase **out, git_repository *repo)
|
|
246
246
|
|
247
247
|
if (rebase->type == GIT_REBASE_TYPE_NONE) {
|
248
248
|
giterr_set(GITERR_REBASE, "There is no rebase in progress");
|
249
|
-
|
249
|
+
error = GIT_ENOTFOUND;
|
250
|
+
goto done;
|
250
251
|
}
|
251
252
|
|
252
253
|
if ((error = git_buf_puts(&path, rebase->state_path)) < 0)
|
@@ -591,7 +592,8 @@ static int rebase_init(
|
|
591
592
|
git_buf state_path = GIT_BUF_INIT;
|
592
593
|
int error;
|
593
594
|
|
594
|
-
git_buf_joinpath(&state_path, repo->path_repository, REBASE_MERGE_DIR)
|
595
|
+
if ((error = git_buf_joinpath(&state_path, repo->path_repository, REBASE_MERGE_DIR)) < 0)
|
596
|
+
return error;
|
595
597
|
|
596
598
|
rebase->repo = repo;
|
597
599
|
rebase->type = GIT_REBASE_TYPE_MERGE;
|
data/vendor/libgit2/src/remote.c
CHANGED
@@ -18,8 +18,10 @@
|
|
18
18
|
#include "refs.h"
|
19
19
|
#include "refspec.h"
|
20
20
|
#include "fetchhead.h"
|
21
|
+
#include "push.h"
|
21
22
|
|
22
23
|
static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs);
|
24
|
+
static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name);
|
23
25
|
|
24
26
|
static int add_refspec_to(git_vector *vector, const char *string, bool is_fetch)
|
25
27
|
{
|
@@ -137,6 +139,7 @@ static int canonicalize_url(git_buf *out, const char *in)
|
|
137
139
|
static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
|
138
140
|
{
|
139
141
|
git_remote *remote;
|
142
|
+
git_config *config = NULL;
|
140
143
|
git_buf canonical_url = GIT_BUF_INIT, fetchbuf = GIT_BUF_INIT;
|
141
144
|
int error = -1;
|
142
145
|
|
@@ -164,6 +167,12 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
|
|
164
167
|
if (add_refspec(remote, fetch, true) < 0)
|
165
168
|
goto on_error;
|
166
169
|
|
170
|
+
if ((error = git_repository_config_snapshot(&config, repo)) < 0)
|
171
|
+
goto on_error;
|
172
|
+
|
173
|
+
if (lookup_remote_prune_config(remote, config, name) < 0)
|
174
|
+
goto on_error;
|
175
|
+
|
167
176
|
/* Move the data over to where the matching functions can find them */
|
168
177
|
if (dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs) < 0)
|
169
178
|
goto on_error;
|
@@ -174,12 +183,13 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
|
|
174
183
|
remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
|
175
184
|
|
176
185
|
*out = remote;
|
177
|
-
|
178
|
-
git_buf_free(&canonical_url);
|
179
|
-
return 0;
|
186
|
+
error = 0;
|
180
187
|
|
181
188
|
on_error:
|
182
|
-
|
189
|
+
if (error)
|
190
|
+
git_remote_free(remote);
|
191
|
+
|
192
|
+
git_config_free(config);
|
183
193
|
git_buf_free(&fetchbuf);
|
184
194
|
git_buf_free(&canonical_url);
|
185
195
|
return error;
|
@@ -287,6 +297,7 @@ int git_remote_dup(git_remote **dest, git_remote *source)
|
|
287
297
|
remote->repo = source->repo;
|
288
298
|
remote->download_tags = source->download_tags;
|
289
299
|
remote->update_fetchhead = source->update_fetchhead;
|
300
|
+
remote->prune_refs = source->prune_refs;
|
290
301
|
|
291
302
|
if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
|
292
303
|
git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
|
@@ -442,6 +453,9 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
|
|
442
453
|
if (download_tags_value(remote, config) < 0)
|
443
454
|
goto cleanup;
|
444
455
|
|
456
|
+
if ((error = lookup_remote_prune_config(remote, config, name)) < 0)
|
457
|
+
goto cleanup;
|
458
|
+
|
445
459
|
/* Move the data over to where the matching functions can find them */
|
446
460
|
if (dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs) < 0)
|
447
461
|
goto cleanup;
|
@@ -458,6 +472,30 @@ cleanup:
|
|
458
472
|
return error;
|
459
473
|
}
|
460
474
|
|
475
|
+
static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name)
|
476
|
+
{
|
477
|
+
git_buf buf = GIT_BUF_INIT;
|
478
|
+
int error = 0;
|
479
|
+
|
480
|
+
git_buf_printf(&buf, "remote.%s.prune", name);
|
481
|
+
|
482
|
+
if ((error = git_config_get_bool(&remote->prune_refs, config, git_buf_cstr(&buf))) < 0) {
|
483
|
+
if (error == GIT_ENOTFOUND) {
|
484
|
+
giterr_clear();
|
485
|
+
|
486
|
+
if ((error = git_config_get_bool(&remote->prune_refs, config, "fetch.prune")) < 0) {
|
487
|
+
if (error == GIT_ENOTFOUND) {
|
488
|
+
giterr_clear();
|
489
|
+
error = 0;
|
490
|
+
}
|
491
|
+
}
|
492
|
+
}
|
493
|
+
}
|
494
|
+
|
495
|
+
git_buf_free(&buf);
|
496
|
+
return error;
|
497
|
+
}
|
498
|
+
|
461
499
|
static int update_config_refspec(const git_remote *remote, git_config *config, int direction)
|
462
500
|
{
|
463
501
|
git_buf name = GIT_BUF_INIT;
|
@@ -867,6 +905,11 @@ int git_remote_download(git_remote *remote, const git_strarray *refspecs)
|
|
867
905
|
if (error < 0)
|
868
906
|
return error;
|
869
907
|
|
908
|
+
if (remote->push) {
|
909
|
+
git_push_free(remote->push);
|
910
|
+
remote->push = NULL;
|
911
|
+
}
|
912
|
+
|
870
913
|
if ((error = git_fetch_negotiate(remote)) < 0)
|
871
914
|
return error;
|
872
915
|
|
@@ -912,6 +955,12 @@ int git_remote_fetch(
|
|
912
955
|
/* Create "remote/foo" branches for all remote branches */
|
913
956
|
error = git_remote_update_tips(remote, signature, git_buf_cstr(&reflog_msg_buf));
|
914
957
|
git_buf_free(&reflog_msg_buf);
|
958
|
+
if (error < 0)
|
959
|
+
return error;
|
960
|
+
|
961
|
+
if (remote->prune_refs)
|
962
|
+
error = git_remote_prune(remote);
|
963
|
+
|
915
964
|
return error;
|
916
965
|
}
|
917
966
|
|
@@ -1066,6 +1115,145 @@ cleanup:
|
|
1066
1115
|
return error;
|
1067
1116
|
}
|
1068
1117
|
|
1118
|
+
/**
|
1119
|
+
* Generate a list of candidates for pruning by getting a list of
|
1120
|
+
* references which match the rhs of an active refspec.
|
1121
|
+
*/
|
1122
|
+
static int prune_candidates(git_vector *candidates, git_remote *remote)
|
1123
|
+
{
|
1124
|
+
git_strarray arr = { 0 };
|
1125
|
+
size_t i;
|
1126
|
+
int error;
|
1127
|
+
|
1128
|
+
if ((error = git_reference_list(&arr, remote->repo)) < 0)
|
1129
|
+
return error;
|
1130
|
+
|
1131
|
+
for (i = 0; i < arr.count; i++) {
|
1132
|
+
const char *refname = arr.strings[i];
|
1133
|
+
char *refname_dup;
|
1134
|
+
|
1135
|
+
if (!git_remote__matching_dst_refspec(remote, refname))
|
1136
|
+
continue;
|
1137
|
+
|
1138
|
+
refname_dup = git__strdup(refname);
|
1139
|
+
GITERR_CHECK_ALLOC(refname_dup);
|
1140
|
+
|
1141
|
+
if ((error = git_vector_insert(candidates, refname_dup)) < 0)
|
1142
|
+
goto out;
|
1143
|
+
}
|
1144
|
+
|
1145
|
+
out:
|
1146
|
+
git_strarray_free(&arr);
|
1147
|
+
return error;
|
1148
|
+
}
|
1149
|
+
|
1150
|
+
static int find_head(const void *_a, const void *_b)
|
1151
|
+
{
|
1152
|
+
git_remote_head *a = (git_remote_head *) _a;
|
1153
|
+
git_remote_head *b = (git_remote_head *) _b;
|
1154
|
+
|
1155
|
+
return strcmp(a->name, b->name);
|
1156
|
+
}
|
1157
|
+
|
1158
|
+
int git_remote_prune(git_remote *remote)
|
1159
|
+
{
|
1160
|
+
size_t i, j;
|
1161
|
+
git_vector remote_refs = GIT_VECTOR_INIT;
|
1162
|
+
git_vector candidates = GIT_VECTOR_INIT;
|
1163
|
+
const git_refspec *spec;
|
1164
|
+
const char *refname;
|
1165
|
+
int error;
|
1166
|
+
git_oid zero_id = {{ 0 }};
|
1167
|
+
|
1168
|
+
if ((error = ls_to_vector(&remote_refs, remote)) < 0)
|
1169
|
+
goto cleanup;
|
1170
|
+
|
1171
|
+
git_vector_set_cmp(&remote_refs, find_head);
|
1172
|
+
|
1173
|
+
if ((error = prune_candidates(&candidates, remote)) < 0)
|
1174
|
+
goto cleanup;
|
1175
|
+
|
1176
|
+
/*
|
1177
|
+
* Remove those entries from the candidate list for which we
|
1178
|
+
* can find a remote reference in at least one refspec.
|
1179
|
+
*/
|
1180
|
+
git_vector_foreach(&candidates, i, refname) {
|
1181
|
+
git_vector_foreach(&remote->active_refspecs, j, spec) {
|
1182
|
+
git_buf buf = GIT_BUF_INIT;
|
1183
|
+
size_t pos;
|
1184
|
+
char *src_name;
|
1185
|
+
git_remote_head key = {0};
|
1186
|
+
|
1187
|
+
if (!git_refspec_dst_matches(spec, refname))
|
1188
|
+
continue;
|
1189
|
+
|
1190
|
+
if ((error = git_refspec_rtransform(&buf, spec, refname)) < 0)
|
1191
|
+
goto cleanup;
|
1192
|
+
|
1193
|
+
key.name = (char *) git_buf_cstr(&buf);
|
1194
|
+
error = git_vector_search(&pos, &remote_refs, &key);
|
1195
|
+
git_buf_free(&buf);
|
1196
|
+
|
1197
|
+
if (error < 0 && error != GIT_ENOTFOUND)
|
1198
|
+
goto cleanup;
|
1199
|
+
|
1200
|
+
if (error == GIT_ENOTFOUND)
|
1201
|
+
continue;
|
1202
|
+
|
1203
|
+
/* if we did find a source, remove it from the candiates */
|
1204
|
+
if ((error = git_vector_set((void **) &src_name, &candidates, i, NULL)) < 0)
|
1205
|
+
goto cleanup;
|
1206
|
+
|
1207
|
+
git__free(src_name);
|
1208
|
+
break;
|
1209
|
+
}
|
1210
|
+
}
|
1211
|
+
|
1212
|
+
/*
|
1213
|
+
* For those candidates still left in the list, we need to
|
1214
|
+
* remove them. We do not remove symrefs, as those are for
|
1215
|
+
* stuff like origin/HEAD which will never match, but we do
|
1216
|
+
* not want to remove them.
|
1217
|
+
*/
|
1218
|
+
git_vector_foreach(&candidates, i, refname) {
|
1219
|
+
git_reference *ref;
|
1220
|
+
git_oid id;
|
1221
|
+
|
1222
|
+
if (refname == NULL)
|
1223
|
+
continue;
|
1224
|
+
|
1225
|
+
error = git_reference_lookup(&ref, remote->repo, refname);
|
1226
|
+
/* as we want it gone, let's not consider this an error */
|
1227
|
+
if (error == GIT_ENOTFOUND)
|
1228
|
+
continue;
|
1229
|
+
|
1230
|
+
if (error < 0)
|
1231
|
+
goto cleanup;
|
1232
|
+
|
1233
|
+
if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
|
1234
|
+
git_reference_free(ref);
|
1235
|
+
continue;
|
1236
|
+
}
|
1237
|
+
|
1238
|
+
git_oid_cpy(&id, git_reference_target(ref));
|
1239
|
+
error = git_reference_delete(ref);
|
1240
|
+
git_reference_free(ref);
|
1241
|
+
if (error < 0)
|
1242
|
+
goto cleanup;
|
1243
|
+
|
1244
|
+
if (remote->callbacks.update_tips)
|
1245
|
+
error = remote->callbacks.update_tips(refname, &id, &zero_id, remote->callbacks.payload);
|
1246
|
+
|
1247
|
+
if (error < 0)
|
1248
|
+
goto cleanup;
|
1249
|
+
}
|
1250
|
+
|
1251
|
+
cleanup:
|
1252
|
+
git_vector_free(&remote_refs);
|
1253
|
+
git_vector_free_deep(&candidates);
|
1254
|
+
return error;
|
1255
|
+
}
|
1256
|
+
|
1069
1257
|
static int update_tips_for_spec(
|
1070
1258
|
git_remote *remote,
|
1071
1259
|
git_refspec *spec,
|
@@ -1275,6 +1463,11 @@ int git_remote_update_tips(
|
|
1275
1463
|
int error;
|
1276
1464
|
size_t i;
|
1277
1465
|
|
1466
|
+
/* push has its own logic hidden away in the push object */
|
1467
|
+
if (remote->push) {
|
1468
|
+
return git_push_update_tips(remote->push, signature, reflog_message);
|
1469
|
+
}
|
1470
|
+
|
1278
1471
|
if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
|
1279
1472
|
return -1;
|
1280
1473
|
|
@@ -1355,6 +1548,7 @@ void git_remote_free(git_remote *remote)
|
|
1355
1548
|
free_refspecs(&remote->passive_refspecs);
|
1356
1549
|
git_vector_free(&remote->passive_refspecs);
|
1357
1550
|
|
1551
|
+
git_push_free(remote->push);
|
1358
1552
|
git__free(remote->url);
|
1359
1553
|
git__free(remote->pushurl);
|
1360
1554
|
git__free(remote->name);
|
@@ -1465,6 +1659,11 @@ void git_remote_set_autotag(git_remote *remote, git_remote_autotag_option_t valu
|
|
1465
1659
|
remote->download_tags = value;
|
1466
1660
|
}
|
1467
1661
|
|
1662
|
+
int git_remote_prune_refs(const git_remote *remote)
|
1663
|
+
{
|
1664
|
+
return remote->prune_refs;
|
1665
|
+
}
|
1666
|
+
|
1468
1667
|
static int rename_remote_config_section(
|
1469
1668
|
git_repository *repo,
|
1470
1669
|
const char *old_name,
|
@@ -2117,22 +2316,29 @@ int git_remote_default_branch(git_buf *out, git_remote *remote)
|
|
2117
2316
|
return git_buf_puts(out, guess->name);
|
2118
2317
|
}
|
2119
2318
|
|
2120
|
-
int
|
2121
|
-
const git_signature *signature, const char *reflog_message)
|
2319
|
+
int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
|
2122
2320
|
{
|
2123
|
-
int error;
|
2124
2321
|
size_t i;
|
2125
|
-
|
2126
|
-
|
2322
|
+
int error;
|
2323
|
+
git_push *push;
|
2127
2324
|
git_refspec *spec;
|
2325
|
+
git_remote_callbacks *cbs;
|
2128
2326
|
|
2129
|
-
assert(remote
|
2327
|
+
assert(remote);
|
2130
2328
|
|
2131
|
-
if ((
|
2329
|
+
if (!git_remote_connected(remote) &&
|
2330
|
+
(error = git_remote_connect(remote, GIT_DIRECTION_PUSH)) < 0)
|
2331
|
+
goto cleanup;
|
2332
|
+
|
2333
|
+
if (remote->push) {
|
2334
|
+
git_push_free(remote->push);
|
2335
|
+
remote->push = NULL;
|
2336
|
+
}
|
2337
|
+
|
2338
|
+
if ((error = git_push_new(&remote->push, remote)) < 0)
|
2132
2339
|
return error;
|
2133
2340
|
|
2134
|
-
|
2135
|
-
goto cleanup;
|
2341
|
+
push = remote->push;
|
2136
2342
|
|
2137
2343
|
if (opts && (error = git_push_set_options(push, opts)) < 0)
|
2138
2344
|
goto cleanup;
|
@@ -2164,10 +2370,25 @@ int git_remote_push(git_remote *remote, git_strarray *refspecs, const git_push_o
|
|
2164
2370
|
(error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
|
2165
2371
|
goto cleanup;
|
2166
2372
|
|
2167
|
-
error = git_push_update_tips(push, signature, reflog_message);
|
2168
|
-
|
2169
2373
|
cleanup:
|
2374
|
+
return error;
|
2375
|
+
}
|
2376
|
+
|
2377
|
+
int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts,
|
2378
|
+
const git_signature *signature, const char *reflog_message)
|
2379
|
+
{
|
2380
|
+
int error;
|
2381
|
+
|
2382
|
+
assert(remote && refspecs);
|
2383
|
+
|
2384
|
+
if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH)) < 0)
|
2385
|
+
return error;
|
2386
|
+
|
2387
|
+
if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
|
2388
|
+
return error;
|
2389
|
+
|
2390
|
+
error = git_remote_update_tips(remote, signature, reflog_message);
|
2391
|
+
|
2170
2392
|
git_remote_disconnect(remote);
|
2171
|
-
git_push_free(push);
|
2172
2393
|
return error;
|
2173
2394
|
}
|
data/vendor/libgit2/src/remote.h
CHANGED
@@ -28,11 +28,13 @@ struct git_remote {
|
|
28
28
|
void *transport_cb_payload;
|
29
29
|
git_transport *transport;
|
30
30
|
git_repository *repo;
|
31
|
+
git_push *push;
|
31
32
|
git_remote_callbacks callbacks;
|
32
33
|
git_transfer_progress stats;
|
33
34
|
unsigned int need_pack;
|
34
35
|
git_remote_autotag_option_t download_tags;
|
35
36
|
int update_fetchhead;
|
37
|
+
int prune_refs;
|
36
38
|
int passed_refspecs;
|
37
39
|
};
|
38
40
|
|
@@ -656,7 +656,8 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
|
|
656
656
|
git_buf odb_path = GIT_BUF_INIT;
|
657
657
|
git_odb *odb;
|
658
658
|
|
659
|
-
git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR)
|
659
|
+
if ((error = git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR)) < 0)
|
660
|
+
return error;
|
660
661
|
|
661
662
|
error = git_odb_open(&odb, odb_path.ptr);
|
662
663
|
if (!error) {
|
@@ -741,7 +742,8 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo)
|
|
741
742
|
git_buf index_path = GIT_BUF_INIT;
|
742
743
|
git_index *index;
|
743
744
|
|
744
|
-
git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE)
|
745
|
+
if ((error = git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE)) < 0)
|
746
|
+
return error;
|
745
747
|
|
746
748
|
error = git_index_open(&index, index_path.ptr);
|
747
749
|
if (!error) {
|
@@ -2068,7 +2070,9 @@ int git_repository_is_shallow(git_repository *repo)
|
|
2068
2070
|
struct stat st;
|
2069
2071
|
int error;
|
2070
2072
|
|
2071
|
-
git_buf_joinpath(&path, repo->path_repository, "shallow")
|
2073
|
+
if ((error = git_buf_joinpath(&path, repo->path_repository, "shallow")) < 0)
|
2074
|
+
return error;
|
2075
|
+
|
2072
2076
|
error = git_path_lstat(path.ptr, &st);
|
2073
2077
|
git_buf_free(&path);
|
2074
2078
|
|
@@ -381,10 +381,6 @@ int git_submodule_add_setup(
|
|
381
381
|
return GIT_EEXISTS;
|
382
382
|
}
|
383
383
|
|
384
|
-
/* resolve parameters */
|
385
|
-
if ((error = git_submodule_resolve_url(&real_url, repo, url)) < 0)
|
386
|
-
goto cleanup;
|
387
|
-
|
388
384
|
/* validate and normalize path */
|
389
385
|
|
390
386
|
if (git__prefixcmp(path, git_repository_workdir(repo)) == 0)
|
@@ -409,7 +405,7 @@ int git_submodule_add_setup(
|
|
409
405
|
goto cleanup;
|
410
406
|
|
411
407
|
if ((error = submodule_config_key_trunc_puts(&name, "url")) < 0 ||
|
412
|
-
(error = git_config_file_set_string(mods, name.ptr,
|
408
|
+
(error = git_config_file_set_string(mods, name.ptr, url)) < 0)
|
413
409
|
goto cleanup;
|
414
410
|
|
415
411
|
git_buf_clear(&name);
|
@@ -425,7 +421,12 @@ int git_submodule_add_setup(
|
|
425
421
|
*/
|
426
422
|
if (!(git_path_exists(name.ptr) &&
|
427
423
|
git_path_contains(&name, DOT_GIT))) {
|
428
|
-
|
424
|
+
|
425
|
+
/* resolve the actual URL to use */
|
426
|
+
if ((error = git_submodule_resolve_url(&real_url, repo, url)) < 0)
|
427
|
+
goto cleanup;
|
428
|
+
|
429
|
+
if ((error = submodule_repo_init(&subrepo, repo, path, real_url.ptr, use_gitlink)) < 0)
|
429
430
|
goto cleanup;
|
430
431
|
}
|
431
432
|
|
@@ -466,13 +467,24 @@ int git_submodule_repo_init(
|
|
466
467
|
{
|
467
468
|
int error;
|
468
469
|
git_repository *sub_repo = NULL;
|
470
|
+
const char *configured_url;
|
471
|
+
git_config *cfg = NULL;
|
472
|
+
git_buf buf = GIT_BUF_INIT;
|
469
473
|
|
470
474
|
assert(out && sm);
|
471
475
|
|
472
|
-
|
476
|
+
/* get the configured remote url of the submodule */
|
477
|
+
if ((error = git_buf_printf(&buf, "submodule.%s.url", sm->name)) < 0 ||
|
478
|
+
(error = git_repository_config_snapshot(&cfg, sm->repo)) < 0 ||
|
479
|
+
(error = git_config_get_string(&configured_url, cfg, buf.ptr)) < 0 ||
|
480
|
+
(error = submodule_repo_init(&sub_repo, sm->repo, sm->path, configured_url, use_gitlink)) < 0)
|
481
|
+
goto done;
|
473
482
|
|
474
483
|
*out = sub_repo;
|
475
484
|
|
485
|
+
done:
|
486
|
+
git_config_free(cfg);
|
487
|
+
git_buf_free(&buf);
|
476
488
|
return error;
|
477
489
|
}
|
478
490
|
|
@@ -778,7 +790,7 @@ git_submodule_ignore_t git_submodule_set_ignore(
|
|
778
790
|
return old;
|
779
791
|
}
|
780
792
|
|
781
|
-
git_submodule_update_t
|
793
|
+
git_submodule_update_t git_submodule_update_strategy(git_submodule *submodule)
|
782
794
|
{
|
783
795
|
assert(submodule);
|
784
796
|
return (submodule->update < GIT_SUBMODULE_UPDATE_CHECKOUT) ?
|
@@ -823,11 +835,193 @@ git_submodule_recurse_t git_submodule_set_fetch_recurse_submodules(
|
|
823
835
|
return old;
|
824
836
|
}
|
825
837
|
|
838
|
+
static int submodule_repo_create(
|
839
|
+
git_repository **out,
|
840
|
+
git_repository *parent_repo,
|
841
|
+
const char *path)
|
842
|
+
{
|
843
|
+
int error = 0;
|
844
|
+
git_buf workdir = GIT_BUF_INIT, repodir = GIT_BUF_INIT;
|
845
|
+
git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
|
846
|
+
git_repository *subrepo = NULL;
|
847
|
+
|
848
|
+
initopt.flags =
|
849
|
+
GIT_REPOSITORY_INIT_MKPATH |
|
850
|
+
GIT_REPOSITORY_INIT_NO_REINIT |
|
851
|
+
GIT_REPOSITORY_INIT_NO_DOTGIT_DIR |
|
852
|
+
GIT_REPOSITORY_INIT_RELATIVE_GITLINK;
|
853
|
+
|
854
|
+
/* Workdir: path to sub-repo working directory */
|
855
|
+
error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
|
856
|
+
if (error < 0)
|
857
|
+
goto cleanup;
|
858
|
+
|
859
|
+
initopt.workdir_path = workdir.ptr;
|
860
|
+
|
861
|
+
/**
|
862
|
+
* Repodir: path to the sub-repo. sub-repo goes in:
|
863
|
+
* <repo-dir>/modules/<name>/ with a gitlink in the
|
864
|
+
* sub-repo workdir directory to that repository.
|
865
|
+
*/
|
866
|
+
error = git_buf_join3(
|
867
|
+
&repodir, '/', git_repository_path(parent_repo), "modules", path);
|
868
|
+
if (error < 0)
|
869
|
+
goto cleanup;
|
870
|
+
|
871
|
+
error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
|
872
|
+
|
873
|
+
cleanup:
|
874
|
+
git_buf_free(&workdir);
|
875
|
+
git_buf_free(&repodir);
|
876
|
+
|
877
|
+
*out = subrepo;
|
878
|
+
|
879
|
+
return error;
|
880
|
+
}
|
881
|
+
|
882
|
+
/**
|
883
|
+
* Callback to override sub-repository creation when
|
884
|
+
* cloning a sub-repository.
|
885
|
+
*/
|
886
|
+
static int git_submodule_update_repo_init_cb(
|
887
|
+
git_repository **out,
|
888
|
+
const char *path,
|
889
|
+
int bare,
|
890
|
+
void *payload)
|
891
|
+
{
|
892
|
+
git_submodule *sm;
|
893
|
+
|
894
|
+
GIT_UNUSED(bare);
|
895
|
+
|
896
|
+
sm = payload;
|
897
|
+
|
898
|
+
return submodule_repo_create(out, sm->repo, path);
|
899
|
+
}
|
900
|
+
|
901
|
+
int git_submodule_update_init_options(git_submodule_update_options *opts, unsigned int version)
|
902
|
+
{
|
903
|
+
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
|
904
|
+
opts, version, git_submodule_update_options, GIT_SUBMODULE_UPDATE_OPTIONS_INIT);
|
905
|
+
return 0;
|
906
|
+
}
|
907
|
+
|
908
|
+
int git_submodule_update(git_submodule *sm, int init, git_submodule_update_options *_update_options)
|
909
|
+
{
|
910
|
+
int error;
|
911
|
+
unsigned int submodule_status;
|
912
|
+
git_config *config = NULL;
|
913
|
+
const char *submodule_url;
|
914
|
+
git_repository *sub_repo = NULL;
|
915
|
+
git_remote *remote = NULL;
|
916
|
+
git_object *target_commit = NULL;
|
917
|
+
git_buf buf = GIT_BUF_INIT;
|
918
|
+
git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
|
919
|
+
git_clone_options clone_options = GIT_CLONE_OPTIONS_INIT;
|
920
|
+
|
921
|
+
assert(sm);
|
922
|
+
|
923
|
+
if (_update_options)
|
924
|
+
memcpy(&update_options, _update_options, sizeof(git_submodule_update_options));
|
925
|
+
|
926
|
+
GITERR_CHECK_VERSION(&update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");
|
927
|
+
|
928
|
+
/* Copy over the remote callbacks */
|
929
|
+
clone_options.remote_callbacks = update_options.remote_callbacks;
|
930
|
+
clone_options.signature = update_options.signature;
|
931
|
+
|
932
|
+
/* Get the status of the submodule to determine if it is already initialized */
|
933
|
+
if ((error = git_submodule_status(&submodule_status, sm)) < 0)
|
934
|
+
goto done;
|
935
|
+
|
936
|
+
/*
|
937
|
+
* If submodule work dir is not already initialized, check to see
|
938
|
+
* what we need to do (initialize, clone, return error...)
|
939
|
+
*/
|
940
|
+
if (submodule_status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) {
|
941
|
+
/*
|
942
|
+
* Work dir is not initialized, check to see if the submodule
|
943
|
+
* info has been copied into .git/config
|
944
|
+
*/
|
945
|
+
if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
|
946
|
+
(error = git_buf_printf(&buf, "submodule.%s.url", git_submodule_name(sm))) < 0)
|
947
|
+
goto done;
|
948
|
+
|
949
|
+
if ((error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0) {
|
950
|
+
/*
|
951
|
+
* If the error is not "not found" or if it is "not found" and we are not
|
952
|
+
* initializing the submodule, then return error.
|
953
|
+
*/
|
954
|
+
if (error != GIT_ENOTFOUND)
|
955
|
+
goto done;
|
956
|
+
|
957
|
+
if (error == GIT_ENOTFOUND && !init) {
|
958
|
+
giterr_set(GITERR_SUBMODULE, "Submodule is not initialized.");
|
959
|
+
error = GIT_ERROR;
|
960
|
+
goto done;
|
961
|
+
}
|
962
|
+
|
963
|
+
/* The submodule has not been initialized yet - initialize it now.*/
|
964
|
+
if ((error = git_submodule_init(sm, 0)) < 0)
|
965
|
+
goto done;
|
966
|
+
|
967
|
+
git_config_free(config);
|
968
|
+
config = NULL;
|
969
|
+
|
970
|
+
if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
|
971
|
+
(error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0)
|
972
|
+
goto done;
|
973
|
+
}
|
974
|
+
|
975
|
+
/** submodule is initialized - now clone it **/
|
976
|
+
/* override repo creation */
|
977
|
+
clone_options.repository_cb = git_submodule_update_repo_init_cb;
|
978
|
+
clone_options.repository_cb_payload = sm;
|
979
|
+
|
980
|
+
/*
|
981
|
+
* Do not perform checkout as part of clone, instead we
|
982
|
+
* will checkout the specific commit manually.
|
983
|
+
*/
|
984
|
+
clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
|
985
|
+
update_options.checkout_opts.checkout_strategy = update_options.clone_checkout_strategy;
|
986
|
+
|
987
|
+
if ((error = git_clone(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 ||
|
988
|
+
(error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm), update_options.signature, NULL)) < 0 ||
|
989
|
+
(error = git_checkout_head(sub_repo, &update_options.checkout_opts)) != 0)
|
990
|
+
goto done;
|
991
|
+
} else {
|
992
|
+
/**
|
993
|
+
* Work dir is initialized - look up the commit in the parent repository's index,
|
994
|
+
* update the workdir contents of the subrepository, and set the subrepository's
|
995
|
+
* head to the new commit.
|
996
|
+
*/
|
997
|
+
if ((error = git_submodule_open(&sub_repo, sm)) < 0 ||
|
998
|
+
(error = git_object_lookup(&target_commit, sub_repo, git_submodule_index_id(sm), GIT_OBJ_COMMIT)) < 0 ||
|
999
|
+
(error = git_checkout_tree(sub_repo, target_commit, &update_options.checkout_opts)) != 0 ||
|
1000
|
+
(error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm), update_options.signature, NULL)) < 0)
|
1001
|
+
goto done;
|
1002
|
+
|
1003
|
+
/* Invalidate the wd flags as the workdir has been updated. */
|
1004
|
+
sm->flags = sm->flags &
|
1005
|
+
~(GIT_SUBMODULE_STATUS_IN_WD |
|
1006
|
+
GIT_SUBMODULE_STATUS__WD_OID_VALID |
|
1007
|
+
GIT_SUBMODULE_STATUS__WD_SCANNED);
|
1008
|
+
}
|
1009
|
+
|
1010
|
+
done:
|
1011
|
+
git_buf_free(&buf);
|
1012
|
+
git_config_free(config);
|
1013
|
+
git_object_free(target_commit);
|
1014
|
+
git_remote_free(remote);
|
1015
|
+
git_repository_free(sub_repo);
|
1016
|
+
|
1017
|
+
return error;
|
1018
|
+
}
|
1019
|
+
|
826
1020
|
int git_submodule_init(git_submodule *sm, int overwrite)
|
827
1021
|
{
|
828
1022
|
int error;
|
829
1023
|
const char *val;
|
830
|
-
git_buf key = GIT_BUF_INIT;
|
1024
|
+
git_buf key = GIT_BUF_INIT, effective_submodule_url = GIT_BUF_INIT;
|
831
1025
|
git_config *cfg = NULL;
|
832
1026
|
|
833
1027
|
if (!sm->url) {
|
@@ -841,9 +1035,10 @@ int git_submodule_init(git_submodule *sm, int overwrite)
|
|
841
1035
|
|
842
1036
|
/* write "submodule.NAME.url" */
|
843
1037
|
|
844
|
-
if ((error =
|
1038
|
+
if ((error = git_submodule_resolve_url(&effective_submodule_url, sm->repo, sm->url)) < 0 ||
|
1039
|
+
(error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
|
845
1040
|
(error = git_config__update_entry(
|
846
|
-
cfg, key.ptr,
|
1041
|
+
cfg, key.ptr, effective_submodule_url.ptr, overwrite != 0, false)) < 0)
|
847
1042
|
goto cleanup;
|
848
1043
|
|
849
1044
|
/* write "submodule.NAME.update" if not default */
|
@@ -861,6 +1056,7 @@ int git_submodule_init(git_submodule *sm, int overwrite)
|
|
861
1056
|
cleanup:
|
862
1057
|
git_config_free(cfg);
|
863
1058
|
git_buf_free(&key);
|
1059
|
+
git_buf_free(&effective_submodule_url);
|
864
1060
|
|
865
1061
|
return error;
|
866
1062
|
}
|
@@ -1853,16 +2049,31 @@ static int lookup_head_remote_key(git_buf *remote_name, git_repository *repo)
|
|
1853
2049
|
if ((error = git_repository_head(&head, repo)) < 0)
|
1854
2050
|
return error;
|
1855
2051
|
|
2052
|
+
/**
|
2053
|
+
* If head does not refer to a branch, then return
|
2054
|
+
* GIT_ENOTFOUND to indicate that we could not find
|
2055
|
+
* a remote key for the local tracking branch HEAD points to.
|
2056
|
+
**/
|
2057
|
+
if (!git_reference_is_branch(head)) {
|
2058
|
+
giterr_set(GITERR_INVALID,
|
2059
|
+
"HEAD does not refer to a branch.");
|
2060
|
+
error = GIT_ENOTFOUND;
|
2061
|
+
goto done;
|
2062
|
+
}
|
2063
|
+
|
1856
2064
|
/* lookup remote tracking branch of HEAD */
|
1857
|
-
if (
|
1858
|
-
|
1859
|
-
|
1860
|
-
|
1861
|
-
|
2065
|
+
if ((error = git_branch_upstream_name(
|
2066
|
+
&upstream_name,
|
2067
|
+
repo,
|
2068
|
+
git_reference_name(head))) < 0)
|
2069
|
+
goto done;
|
1862
2070
|
|
1863
|
-
|
1864
|
-
|
2071
|
+
/* lookup remote of remote tracking branch */
|
2072
|
+
if ((error = git_branch_remote_name(remote_name, repo, upstream_name.ptr)) < 0)
|
2073
|
+
goto done;
|
1865
2074
|
|
2075
|
+
done:
|
2076
|
+
git_buf_free(&upstream_name);
|
1866
2077
|
git_reference_free(head);
|
1867
2078
|
|
1868
2079
|
return error;
|