diff options
Diffstat (limited to 'src/refs.c')
| -rw-r--r-- | src/refs.c | 142 | 
1 files changed, 133 insertions, 9 deletions
diff --git a/src/refs.c b/src/refs.c index 104685793..b3c140bec 100644 --- a/src/refs.c +++ b/src/refs.c @@ -11,6 +11,7 @@  #include "fileops.h"  #include "pack.h"  #include "reflog.h" +#include "config.h"  #include <git2/tag.h>  #include <git2/object.h> @@ -1396,6 +1397,9 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)  	head_target = git_reference_target(head);  	if (head_target && !strcmp(head_target, ref->name)) { +		git_reference_free(head); +		head = NULL; +  		if (git_reference_create_symbolic(&head, ref->owner, "HEAD", new_name, 1) < 0) {  			giterr_set(GITERR_REFERENCE,  				"Failed to update HEAD after renaming reference"); @@ -1404,18 +1408,11 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)  	}  	/* -	 * Rename the reflog file. +	 * Rename the reflog file, if it exists.  	 */ -	if (git_buf_join_n(&aux_path, '/', 3, ref->owner->path_repository, GIT_REFLOG_DIR, ref->name) < 0) +	if ((git_reference_has_log(ref)) && (git_reflog_rename(ref, new_name) < 0))  		goto cleanup; -	if (git_path_exists(aux_path.ptr) == true) { -		if (git_reflog_rename(ref, new_name) < 0) -			goto cleanup; -	} else { -		giterr_clear(); -	} -  	/*  	 * Change the name of the reference given by the user.  	 */ @@ -1764,3 +1761,130 @@ int git_reference__update(git_repository *repo, const git_oid *oid, const char *  	git_reference_free(ref);  	return res;  } + +struct glob_cb_data { +	const char *glob; +	int (*callback)(const char *, void *); +	void *payload; +}; + +static int fromglob_cb(const char *reference_name, void *payload) +{ +	struct glob_cb_data *data = (struct glob_cb_data *)payload; + +	if (!p_fnmatch(data->glob, reference_name, 0)) +		return data->callback(reference_name, data->payload); + +	return 0; +} + +int git_reference_foreach_glob( +	git_repository *repo, +	const char *glob, +	unsigned int list_flags, +	int (*callback)( +		const char *reference_name, +		void *payload), +	void *payload) +{ +	struct glob_cb_data data; + +	assert(repo && glob && callback); + +	data.glob = glob; +	data.callback = callback; +	data.payload = payload; + +	return git_reference_foreach( +			repo, list_flags, fromglob_cb, &data); +} + +int git_reference_has_log( +	git_reference *ref) +{ +	git_buf path = GIT_BUF_INIT; +	int result; + +	assert(ref); + +	if (git_buf_join_n(&path, '/', 3, ref->owner->path_repository, GIT_REFLOG_DIR, ref->name) < 0) +		return -1; + +	result = git_path_isfile(git_buf_cstr(&path)); +	git_buf_free(&path); + +	return result; +} + +//TODO: How about also taking care of local tracking branches? +//cf. http://alblue.bandlem.com/2011/07/git-tip-of-week-tracking-branches.html +int git_reference_remote_tracking_from_branch( +	git_reference **tracking_ref, +	git_reference *branch_ref) +{ +	git_config *config = NULL; +	const char *name, *remote, *merge; +	git_buf buf = GIT_BUF_INIT; +	int error = -1; + +	assert(tracking_ref && branch_ref); + +	name = git_reference_name(branch_ref); + +	if (git__prefixcmp(name, GIT_REFS_HEADS_DIR)) { +		giterr_set( +			GITERR_INVALID, +			"Failed to retrieve tracking reference - '%s' is not a branch.", +			name); +		return -1; +	} + +	if (git_repository_config(&config, branch_ref->owner) < 0) +		return -1; + +	if (git_buf_printf( +		&buf, +		"branch.%s.remote", +		name + strlen(GIT_REFS_HEADS_DIR)) < 0) +			goto cleanup; + +	if ((error = git_config_get_string(&remote, config, git_buf_cstr(&buf))) < 0) +		goto cleanup; + +	error = -1; + +	git_buf_clear(&buf); + +	//TODO: Is it ok to fail when no merge target is found? +	if (git_buf_printf( +		&buf, +		"branch.%s.merge", +		name + strlen(GIT_REFS_HEADS_DIR)) < 0) +			goto cleanup; + +	if (git_config_get_string(&merge, config, git_buf_cstr(&buf)) < 0) +		goto cleanup; + +	//TODO: Should we test this? +	if (git__prefixcmp(merge, GIT_REFS_HEADS_DIR)) +		goto cleanup; + +	git_buf_clear(&buf); + +	if (git_buf_printf( +		&buf, +		"refs/remotes/%s/%s", +		remote, +		merge + strlen(GIT_REFS_HEADS_DIR)) < 0) +			goto cleanup; + +	error = git_reference_lookup( +		tracking_ref, +		branch_ref->owner, +		git_buf_cstr(&buf)); + +cleanup: +	git_config_free(config); +	git_buf_free(&buf); +	return error; +}  | 
