Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ce5e661

Browse files
author
Vicent Marti
committed
Merge pull request libgit2#2407 from libgit2/cmn/remote-rename-more
More remote rename fixes
2 parents 9560203 + 231f350 commit ce5e661

File tree

5 files changed

+191
-115
lines changed

5 files changed

+191
-115
lines changed

include/git2/remote.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,9 @@ GIT_EXTERN(void) git_remote_set_autotag(
572572
*
573573
* A temporary in-memory remote cannot be given a name with this method.
574574
*
575+
* @param problems non-default refspecs cannot be renamed and will be
576+
* stored here for further processing by the caller. Always free this
577+
* strarray on succesful return.
575578
* @param remote the remote to rename
576579
* @param new_name the new name the remote should bear
577580
* @param callback Optional callback to notify the consumer of fetch refspecs
@@ -580,10 +583,9 @@ GIT_EXTERN(void) git_remote_set_autotag(
580583
* @return 0, GIT_EINVALIDSPEC, GIT_EEXISTS or an error code
581584
*/
582585
GIT_EXTERN(int) git_remote_rename(
586+
git_strarray *problems,
583587
git_remote *remote,
584-
const char *new_name,
585-
git_remote_rename_problem_cb callback,
586-
void *payload);
588+
const char *new_name);
587589

588590
/**
589591
* Retrieve the update FETCH_HEAD setting.
@@ -616,8 +618,6 @@ GIT_EXTERN(int) git_remote_is_valid_name(const char *remote_name);
616618
* All remote-tracking branches and configuration settings
617619
* for the remote will be removed.
618620
*
619-
* once deleted, the passed remote object will be freed and invalidated.
620-
*
621621
* @param remote A valid remote
622622
* @return 0 on success, or an error code.
623623
*/

src/remote.c

Lines changed: 80 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,32 +1359,61 @@ static int update_branch_remote_config_entry(
13591359
}
13601360

13611361
static int rename_one_remote_reference(
1362-
git_reference *reference,
1362+
git_reference *reference_in,
13631363
const char *old_remote_name,
13641364
const char *new_remote_name)
13651365
{
13661366
int error;
1367+
git_reference *ref = NULL, *dummy = NULL;
1368+
git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT;
13671369
git_buf new_name = GIT_BUF_INIT;
13681370
git_buf log_message = GIT_BUF_INIT;
1371+
size_t pfx_len;
1372+
const char *target;
13691373

1370-
if ((error = git_buf_printf(
1371-
&new_name,
1372-
GIT_REFS_REMOTES_DIR "%s%s",
1373-
new_remote_name,
1374-
reference->name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name))) < 0)
1374+
if ((error = git_buf_printf(&namespace, GIT_REFS_REMOTES_DIR "%s/", new_remote_name)) < 0)
1375+
return error;
1376+
1377+
pfx_len = strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name) + 1;
1378+
git_buf_puts(&new_name, namespace.ptr);
1379+
if ((error = git_buf_puts(&new_name, git_reference_name(reference_in) + pfx_len)) < 0)
13751380
goto cleanup;
13761381

13771382
if ((error = git_buf_printf(&log_message,
13781383
"renamed remote %s to %s",
13791384
old_remote_name, new_remote_name)) < 0)
13801385
goto cleanup;
13811386

1382-
error = git_reference_rename(
1383-
NULL, reference, git_buf_cstr(&new_name), 1,
1384-
NULL, git_buf_cstr(&log_message));
1385-
git_reference_free(reference);
1387+
if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1,
1388+
NULL, git_buf_cstr(&log_message))) < 0)
1389+
goto cleanup;
1390+
1391+
if (git_reference_type(ref) != GIT_REF_SYMBOLIC)
1392+
goto cleanup;
1393+
1394+
/* Handle refs like origin/HEAD -> origin/master */
1395+
target = git_reference_symbolic_target(ref);
1396+
if ((error = git_buf_printf(&old_namespace, GIT_REFS_REMOTES_DIR "%s/", old_remote_name)) < 0)
1397+
goto cleanup;
1398+
1399+
if (git__prefixcmp(target, old_namespace.ptr))
1400+
goto cleanup;
1401+
1402+
git_buf_clear(&new_name);
1403+
git_buf_puts(&new_name, namespace.ptr);
1404+
if ((error = git_buf_puts(&new_name, target + pfx_len)) < 0)
1405+
goto cleanup;
1406+
1407+
error = git_reference_symbolic_set_target(&dummy, ref, git_buf_cstr(&new_name),
1408+
NULL, git_buf_cstr(&log_message));
1409+
1410+
git_reference_free(dummy);
13861411

13871412
cleanup:
1413+
git_reference_free(reference_in);
1414+
git_reference_free(ref);
1415+
git_buf_free(&namespace);
1416+
git_buf_free(&old_namespace);
13881417
git_buf_free(&new_name);
13891418
git_buf_free(&log_message);
13901419
return error;
@@ -1419,11 +1448,7 @@ static int rename_remote_references(
14191448
return (error == GIT_ITEROVER) ? 0 : error;
14201449
}
14211450

1422-
static int rename_fetch_refspecs(
1423-
git_remote *remote,
1424-
const char *new_name,
1425-
int (*callback)(const char *problematic_refspec, void *payload),
1426-
void *payload)
1451+
static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const char *new_name)
14271452
{
14281453
git_config *config;
14291454
git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
@@ -1434,6 +1459,9 @@ static int rename_fetch_refspecs(
14341459
if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
14351460
return error;
14361461

1462+
if ((error = git_vector_init(problems, 1, NULL)) < 0)
1463+
return error;
1464+
14371465
if ((error = git_buf_printf(
14381466
&base, "+refs/heads/*:refs/remotes/%s/*", remote->name)) < 0)
14391467
return error;
@@ -1442,15 +1470,15 @@ static int rename_fetch_refspecs(
14421470
if (spec->push)
14431471
continue;
14441472

1445-
/* Every refspec is a problem refspec for an anonymous remote, OR */
14461473
/* Does the dst part of the refspec follow the expected format? */
1447-
if (!remote->name ||
1448-
strcmp(git_buf_cstr(&base), spec->string)) {
1474+
if (strcmp(git_buf_cstr(&base), spec->string)) {
1475+
char *dup;
14491476

1450-
if ((error = callback(spec->string, payload)) != 0) {
1451-
giterr_set_after_callback(error);
1477+
dup = git__strdup(spec->string);
1478+
GITERR_CHECK_ALLOC(dup);
1479+
1480+
if ((error = git_vector_insert(problems, dup)) < 0)
14521481
break;
1453-
}
14541482

14551483
continue;
14561484
}
@@ -1476,18 +1504,25 @@ static int rename_fetch_refspecs(
14761504
git_buf_free(&base);
14771505
git_buf_free(&var);
14781506
git_buf_free(&val);
1507+
1508+
if (error < 0) {
1509+
char *str;
1510+
git_vector_foreach(problems, i, str)
1511+
git__free(str);
1512+
1513+
git_vector_free(problems);
1514+
}
1515+
14791516
return error;
14801517
}
14811518

1482-
int git_remote_rename(
1483-
git_remote *remote,
1484-
const char *new_name,
1485-
git_remote_rename_problem_cb callback,
1486-
void *payload)
1519+
int git_remote_rename(git_strarray *out, git_remote *remote, const char *new_name)
14871520
{
14881521
int error;
1522+
git_vector problem_refspecs;
1523+
char *tmp, *dup;
14891524

1490-
assert(remote && new_name);
1525+
assert(out && remote && new_name);
14911526

14921527
if (!remote->name) {
14931528
giterr_set(GITERR_INVALID, "Can't rename an anonymous remote.");
@@ -1497,54 +1532,30 @@ int git_remote_rename(
14971532
if ((error = ensure_remote_name_is_valid(new_name)) < 0)
14981533
return error;
14991534

1500-
if (remote->repo) {
1501-
if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0)
1502-
return error;
1535+
if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0)
1536+
return error;
1537+
1538+
if ((error = rename_remote_config_section(remote->repo, remote->name, new_name)) < 0)
1539+
return error;
15031540

1504-
if (!remote->name) {
1505-
if ((error = rename_fetch_refspecs(
1506-
remote,
1507-
new_name,
1508-
callback,
1509-
payload)) < 0)
1510-
return error;
1541+
if ((error = update_branch_remote_config_entry(remote->repo, remote->name, new_name)) < 0)
1542+
return error;
15111543

1512-
remote->name = git__strdup(new_name);
1513-
GITERR_CHECK_ALLOC(remote->name);
1544+
if ((error = rename_remote_references(remote->repo, remote->name, new_name)) < 0)
1545+
return error;
15141546

1515-
return git_remote_save(remote);
1516-
}
1547+
if ((error = rename_fetch_refspecs(&problem_refspecs, remote, new_name)) < 0)
1548+
return error;
15171549

1518-
if ((error = rename_remote_config_section(
1519-
remote->repo,
1520-
remote->name,
1521-
new_name)) < 0)
1522-
return error;
1523-
1524-
if ((error = update_branch_remote_config_entry(
1525-
remote->repo,
1526-
remote->name,
1527-
new_name)) < 0)
1528-
return error;
1529-
1530-
if ((error = rename_remote_references(
1531-
remote->repo,
1532-
remote->name,
1533-
new_name)) < 0)
1534-
return error;
1535-
1536-
if ((error = rename_fetch_refspecs(
1537-
remote,
1538-
new_name,
1539-
callback,
1540-
payload)) < 0)
1541-
return error;
1542-
}
1550+
out->count = problem_refspecs.length;
1551+
out->strings = (char **) problem_refspecs.contents;
15431552

1544-
git__free(remote->name);
1553+
dup = git__strdup(new_name);
1554+
GITERR_CHECK_ALLOC(dup);
15451555

1546-
remote->name = git__strdup(new_name);
1547-
GITERR_CHECK_ALLOC(remote->name);
1556+
tmp = remote->name;
1557+
remote->name = dup;
1558+
git__free(tmp);
15481559

15491560
return 0;
15501561
}
@@ -1910,8 +1921,6 @@ int git_remote_delete(git_remote *remote)
19101921
repo, git_remote_name(remote), NULL)) < 0)
19111922
return error;
19121923

1913-
git_remote_free(remote);
1914-
19151924
return 0;
19161925
}
19171926

tests/network/remote/delete.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ void test_network_remote_delete__initialize(void)
1515

1616
void test_network_remote_delete__cleanup(void)
1717
{
18+
git_remote_free(_remote);
1819
cl_git_sandbox_cleanup();
1920
}
2021

@@ -27,7 +28,6 @@ void test_network_remote_delete__cannot_delete_an_anonymous_remote(void)
2728
cl_git_fail(git_remote_delete(remote));
2829

2930
git_remote_free(remote);
30-
git_remote_free(_remote);
3131
}
3232

3333
void test_network_remote_delete__remove_remote_tracking_branches(void)

0 commit comments

Comments
 (0)