diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2014-06-06 22:38:26 +0200 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2014-06-06 22:38:26 +0200 |
commit | d15445646440807a082feb54a1e92d54864137d1 (patch) | |
tree | 3fc5056124561ef30278828faf1730b0fd93291f | |
parent | eb6aa791a7c1a311b556398acce69cde3d43e3cd (diff) | |
download | libgit2-d15445646440807a082feb54a1e92d54864137d1.tar.gz |
remote: handle symrefs when renaming
A symref inside the namespace gets renamed, we should make it point to
the target's new name.
This is for the origin/HEAD -> origin/master type of situations.
-rw-r--r-- | src/remote.c | 49 |
1 files changed, 39 insertions, 10 deletions
diff --git a/src/remote.c b/src/remote.c index 4e6f350d5..827c54f9d 100644 --- a/src/remote.c +++ b/src/remote.c @@ -1359,19 +1359,24 @@ static int update_branch_remote_config_entry( } static int rename_one_remote_reference( - git_reference *reference, + git_reference *reference_in, const char *old_remote_name, const char *new_remote_name) { int error; + git_reference *ref = NULL, *dummy = NULL; + git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT; git_buf new_name = GIT_BUF_INIT; git_buf log_message = GIT_BUF_INIT; + size_t pfx_len; + const char *target; - if ((error = git_buf_printf( - &new_name, - GIT_REFS_REMOTES_DIR "%s%s", - new_remote_name, - reference->name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name))) < 0) + if ((error = git_buf_printf(&namespace, GIT_REFS_REMOTES_DIR "%s/", new_remote_name)) < 0) + return error; + + pfx_len = strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name) + 1; + git_buf_puts(&new_name, namespace.ptr); + if ((error = git_buf_puts(&new_name, git_reference_name(reference_in) + pfx_len)) < 0) goto cleanup; if ((error = git_buf_printf(&log_message, @@ -1379,12 +1384,36 @@ static int rename_one_remote_reference( old_remote_name, new_remote_name)) < 0) goto cleanup; - error = git_reference_rename( - NULL, reference, git_buf_cstr(&new_name), 1, - NULL, git_buf_cstr(&log_message)); - git_reference_free(reference); + if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1, + NULL, git_buf_cstr(&log_message))) < 0) + goto cleanup; + + if (git_reference_type(ref) != GIT_REF_SYMBOLIC) + goto cleanup; + + /* Handle refs like origin/HEAD -> origin/master */ + target = git_reference_symbolic_target(ref); + if ((error = git_buf_printf(&old_namespace, GIT_REFS_REMOTES_DIR "%s/", old_remote_name)) < 0) + goto cleanup; + + if (git__prefixcmp(target, old_namespace.ptr)) + goto cleanup; + + git_buf_clear(&new_name); + git_buf_puts(&new_name, namespace.ptr); + if ((error = git_buf_puts(&new_name, target + pfx_len)) < 0) + goto cleanup; + + error = git_reference_symbolic_set_target(&dummy, ref, git_buf_cstr(&new_name), + NULL, git_buf_cstr(&log_message)); + + git_reference_free(dummy); cleanup: + git_reference_free(reference_in); + git_reference_free(ref); + git_buf_free(&namespace); + git_buf_free(&old_namespace); git_buf_free(&new_name); git_buf_free(&log_message); return error; |