rugged 0.22.0b5 → 0.22.1b1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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;
|