Skip to content

Commit

Permalink
Merge pull request #925 from nulltoken/topic/moving-branch-updates-co…
Browse files Browse the repository at this point in the history
…nfig

Updates config upon moving and deletion of branches
  • Loading branch information
arrbee committed Oct 25, 2012
2 parents 505f37b + fcccf30 commit 1b93468
Show file tree
Hide file tree
Showing 16 changed files with 970 additions and 35 deletions.
18 changes: 18 additions & 0 deletions include/git2/remote.h
Expand Up @@ -347,6 +347,24 @@ GIT_EXTERN(int) git_remote_autotag(git_remote *remote);
*/
GIT_EXTERN(void) git_remote_set_autotag(git_remote *remote, int value);

/**
* Give the remote a new name
*
* All remote-tracking branches and configuration settings
* for the remote are updated.
*
* @param remote the remote to rename
* @param new_name the new name the remote should bear
* @param callback Optional callback to notify the consumer of fetch refspecs
* that haven't been automatically updated and need potential manual tweaking.
* @param payload Additional data to pass to the callback
* @return 0 or an error code
*/
GIT_EXTERN(int) git_remote_rename(
git_remote *remote,
const char *new_name,
int (*callback)(const char *problematic_refspec, void *payload),
void *payload);

/** @} */
GIT_END_DECL
Expand Down
44 changes: 41 additions & 3 deletions src/branch.c
Expand Up @@ -92,6 +92,8 @@ int git_branch_create(
int git_branch_delete(git_reference *branch)
{
int is_head;
git_buf config_section = GIT_BUF_INIT;
int error = -1;

assert(branch);

Expand All @@ -110,7 +112,23 @@ int git_branch_delete(git_reference *branch)
return -1;
}

return git_reference_delete(branch);
if (git_buf_printf(&config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
goto on_error;

if (git_config_rename_section(
git_reference_owner(branch),
git_buf_cstr(&config_section),
NULL) < 0)
goto on_error;

if (git_reference_delete(branch) < 0)
goto on_error;

error = 0;

on_error:
git_buf_free(&config_section);
return error;
}

typedef struct {
Expand Down Expand Up @@ -161,7 +179,9 @@ int git_branch_move(
const char *new_branch_name,
int force)
{
git_buf new_reference_name = GIT_BUF_INIT;
git_buf new_reference_name = GIT_BUF_INIT,
old_config_section = GIT_BUF_INIT,
new_config_section = GIT_BUF_INIT;
int error;

assert(branch && new_branch_name);
Expand All @@ -172,10 +192,28 @@ int git_branch_move(
if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0)
goto cleanup;

error = git_reference_rename(branch, git_buf_cstr(&new_reference_name), force);
if (git_buf_printf(
&old_config_section,
"branch.%s",
git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
goto cleanup;

if ((error = git_reference_rename(branch, git_buf_cstr(&new_reference_name), force)) < 0)
goto cleanup;

if (git_buf_printf(&new_config_section, "branch.%s", new_branch_name) < 0)
goto cleanup;

if ((error = git_config_rename_section(
git_reference_owner(branch),
git_buf_cstr(&old_config_section),
git_buf_cstr(&new_config_section))) < 0)
goto cleanup;

cleanup:
git_buf_free(&new_reference_name);
git_buf_free(&old_config_section);
git_buf_free(&new_config_section);

return error;
}
Expand Down
28 changes: 28 additions & 0 deletions src/buffer.c
Expand Up @@ -549,3 +549,31 @@ void git_buf_unescape(git_buf *buf)
{
buf->size = git__unescape(buf->ptr);
}

int git_buf_splice(
git_buf *buf,
size_t where,
size_t nb_to_remove,
const char *data,
size_t nb_to_insert)
{
assert(buf &&
where <= git_buf_len(buf) &&
where + nb_to_remove <= git_buf_len(buf));

/* Ported from git.git
* https://github.com/git/git/blob/16eed7c/strbuf.c#L159-176
*/
if (git_buf_grow(buf, git_buf_len(buf) + nb_to_insert - nb_to_remove) < 0)
return -1;

memmove(buf->ptr + where + nb_to_insert,
buf->ptr + where + nb_to_remove,
buf->size - where - nb_to_remove);

memcpy(buf->ptr + where, data, nb_to_insert);

buf->size = buf->size + nb_to_insert - nb_to_remove;
buf->ptr[buf->size] = '\0';
return 0;
}
25 changes: 25 additions & 0 deletions src/buffer.h
Expand Up @@ -158,4 +158,29 @@ void git_buf_unescape(git_buf *buf);
/* Write data as base64 encoded in buffer */
int git_buf_put_base64(git_buf *buf, const char *data, size_t len);

/*
* Insert, remove or replace a portion of the buffer.
*
* @param buf The buffer to work with
*
* @param where The location in the buffer where the transformation
* should be applied.
*
* @param nb_to_remove The number of chars to be removed. 0 to not
* remove any character in the buffer.
*
* @param data A pointer to the data which should be inserted.
*
* @param nb_to_insert The number of chars to be inserted. 0 to not
* insert any character from the buffer.
*
* @return 0 or an error code.
*/
int git_buf_splice(
git_buf *buf,
size_t where,
size_t nb_to_remove,
const char *data,
size_t nb_to_insert);

#endif
78 changes: 78 additions & 0 deletions src/config.c
Expand Up @@ -720,3 +720,81 @@ int git_config_parse_int32(int32_t *out, const char *value)
giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a 32-bit integer", value);
return -1;
}

struct rename_data
{
git_config *config;
const char *old_name;
const char *new_name;
};

static int rename_config_entries_cb(
const git_config_entry *entry,
void *payload)
{
struct rename_data *data = (struct rename_data *)payload;

if (data->new_name != NULL) {
git_buf name = GIT_BUF_INIT;
int error;

if (git_buf_printf(
&name,
"%s.%s",
data->new_name,
entry->name + strlen(data->old_name) + 1) < 0)
return -1;

error = git_config_set_string(
data->config,
git_buf_cstr(&name),
entry->value);

git_buf_free(&name);

if (error)
return error;
}

return git_config_delete(data->config, entry->name);
}

int git_config_rename_section(
git_repository *repo,
const char *old_section_name,
const char *new_section_name)
{
git_config *config;
git_buf pattern = GIT_BUF_INIT;
int error = -1;
struct rename_data data;

git_buf_puts_escape_regex(&pattern, old_section_name);
git_buf_puts(&pattern, "\\..+");
if (git_buf_oom(&pattern))
goto cleanup;

if (git_repository_config__weakptr(&config, repo) < 0)
goto cleanup;

data.config = config;
data.old_name = old_section_name;
data.new_name = new_section_name;

if ((error = git_config_foreach_match(
config,
git_buf_cstr(&pattern),
rename_config_entries_cb, &data)) < 0) {
giterr_set(GITERR_CONFIG,
"Cannot rename config section '%s' to '%s'",
old_section_name,
new_section_name);
goto cleanup;
}

error = 0;

cleanup:
git_buf_free(&pattern);
return error;
}
5 changes: 5 additions & 0 deletions src/config.h
Expand Up @@ -27,4 +27,9 @@ extern int git_config_find_global_r(git_buf *global_config_path);
extern int git_config_find_xdg_r(git_buf *system_config_path);
extern int git_config_find_system_r(git_buf *system_config_path);

extern int git_config_rename_section(
git_repository *repo,
const char *old_section_name, /* eg "branch.dummy" */
const char *new_section_name); /* NULL to drop the old section */

#endif
11 changes: 11 additions & 0 deletions src/refspec.c
Expand Up @@ -225,3 +225,14 @@ int git_refspec_transform_l(git_buf *out, const git_refspec *spec, const char *n
return refspec_transform(out, spec->dst, spec->src, name);
}

int git_refspec__serialize(git_buf *out, const git_refspec *refspec)
{
if (refspec->force)
git_buf_putc(out, '+');

git_buf_printf(out, "%s:%s",
refspec->src != NULL ? refspec->src : "",
refspec->dst != NULL ? refspec->dst : "");

return git_buf_oom(out) == false;
}
2 changes: 2 additions & 0 deletions src/refspec.h
Expand Up @@ -51,4 +51,6 @@ int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *n
*/
int git_refspec_transform_l(git_buf *out, const git_refspec *spec, const char *name);

int git_refspec__serialize(git_buf *out, const git_refspec *refspec);

#endif

0 comments on commit 1b93468

Please sign in to comment.