예제 #1
0
static int check_remote_status(git_repository *repo, git_remote *origin, const char *branch, enum remote_transport rt)
{
	int error = 0;

	git_reference *local_ref, *remote_ref;

	if (git_branch_lookup(&local_ref, repo, branch, GIT_BRANCH_LOCAL))
		return report_error("Git cache branch %s no longer exists", branch);

	if (git_branch_upstream(&remote_ref, local_ref)) {
		/* so there is no upstream branch for our branch; that's a problem.
		 * let's push our branch */
		git_strarray refspec;
		git_reference_list(&refspec, repo);
#if USE_LIBGIT23_API
		git_push_options opts = GIT_PUSH_OPTIONS_INIT;
		if (rt == RT_SSH)
			opts.callbacks.credentials = credential_ssh_cb;
		else if (rt == RT_HTTPS)
			opts.callbacks.credentials = credential_https_cb;
		opts.callbacks.certificate_check = certificate_check_cb;
		error = git_remote_push(origin, &refspec, &opts);
#else
		error = git_remote_push(origin, &refspec, NULL);
#endif
	} else {
		error = try_to_update(repo, origin, local_ref, remote_ref, rt);
		git_reference_free(remote_ref);
	}
	git_reference_free(local_ref);
	return error;
}
예제 #2
0
파일: local.c 프로젝트: rlugojr/libgit2
void test_network_remote_local__update_tips_for_new_remote(void) {
    git_repository *src_repo;
    git_repository *dst_repo;
    git_remote *new_remote;
    git_reference* branch;

    /* Copy test repo */
    cl_fixture_sandbox("testrepo.git");
    cl_git_pass(git_repository_open(&src_repo, "testrepo.git"));

    /* Set up an empty bare repo to push into */
    cl_git_pass(git_repository_init(&dst_repo, "./localbare.git", 1));

    /* Push to bare repo */
    cl_git_pass(git_remote_create(&new_remote, src_repo, "bare", "./localbare.git"));
    cl_git_pass(git_remote_push(new_remote, &push_array, NULL));
    /* Make sure remote branch has been created */
    cl_git_pass(git_branch_lookup(&branch, src_repo, "bare/master", GIT_BRANCH_REMOTE));

    git_reference_free(branch);
    git_remote_free(new_remote);
    git_repository_free(dst_repo);
    cl_fixture_cleanup("localbare.git");
    git_repository_free(src_repo);
    cl_fixture_cleanup("testrepo.git");
}
예제 #3
0
파일: delete.c 프로젝트: 1336/libgit2
void test_refs_branches_delete__can_delete_a_remote_branch(void)
{
	git_reference *branch;
	cl_git_pass(git_branch_lookup(&branch, repo, "nulltoken/master", GIT_BRANCH_REMOTE));
	cl_git_pass(git_branch_delete(branch));
	git_reference_free(branch);
}
예제 #4
0
파일: delete.c 프로젝트: 1336/libgit2
void test_refs_branches_delete__can_delete_a_local_branch(void)
{
	git_reference *branch;
	cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
	cl_git_pass(git_branch_delete(branch));
	git_reference_free(branch);
}
예제 #5
0
void test_refs_branches_create__cannot_force_create_over_current_branch(void)
{
	const git_oid *oid;
	git_reference *branch2;
	retrieve_known_commit(&target, repo);

	cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL));
	cl_assert_equal_s("refs/heads/master", git_reference_name(branch2));
	cl_assert_equal_i(true, git_branch_is_head(branch2));
	oid = git_reference_target(branch2);

	cl_git_fail_with(-1, git_branch_create(&branch, repo, "master", target, 1, NULL, NULL));
	branch = NULL;
	cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
	cl_assert_equal_s("refs/heads/master", git_reference_name(branch));
	cl_git_pass(git_oid_cmp(git_reference_target(branch), oid));
	git_reference_free(branch2);
}
예제 #6
0
파일: delete.c 프로젝트: 1336/libgit2
void test_refs_branches_delete__can_delete_a_branch_when_HEAD_is_unborn(void)
{
	git_reference *branch;

	make_head_unborn(repo, NON_EXISTING_HEAD);

	cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
	cl_git_pass(git_branch_delete(branch));
	git_reference_free(branch);
}
예제 #7
0
파일: branch.c 프로젝트: Angeldude/sonic-pi
static int create_branch(
	git_reference **ref_out,
	git_repository *repository,
	const char *branch_name,
	const git_commit *commit,
	const char *from,
	int force)
{
	int is_unmovable_head = 0;
	git_reference *branch = NULL;
	git_buf canonical_branch_name = GIT_BUF_INIT,
			  log_message = GIT_BUF_INIT;
	int error = -1;
	int bare = git_repository_is_bare(repository);

	assert(branch_name && commit && ref_out);
	assert(git_object_owner((const git_object *)commit) == repository);

	if (force && !bare && git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) {
		error = git_branch_is_head(branch);
		git_reference_free(branch);
		branch = NULL;

		if (error < 0)
			goto cleanup;

		is_unmovable_head = error;
	}

	if (is_unmovable_head && force) {
		giterr_set(GITERR_REFERENCE, "Cannot force update branch '%s' as it is "
			"the current HEAD of the repository.", branch_name);
		error = -1;
		goto cleanup;
	}

	if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
		goto cleanup;

	if (git_buf_printf(&log_message, "branch: Created from %s", from) < 0)
		goto cleanup;

	error = git_reference_create(&branch, repository,
		git_buf_cstr(&canonical_branch_name), git_commit_id(commit), force,
		git_buf_cstr(&log_message));

	if (!error)
		*ref_out = branch;

cleanup:
	git_buf_free(&canonical_branch_name);
	git_buf_free(&log_message);
	return error;
}
예제 #8
0
파일: delete.c 프로젝트: 1336/libgit2
void test_refs_branches_delete__can_delete_a_branch_even_if_HEAD_is_missing(void)
{
	git_reference *head;
	git_reference *branch;

	cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE));
	git_reference_delete(head);
	git_reference_free(head);

	cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
	cl_git_pass(git_branch_delete(branch));
	git_reference_free(branch);
}
예제 #9
0
void test_online_fetchhead__empty_dst_refspec_creates_no_branch(void)
{
	git_reference *ref;
	int refs;

	fetchhead_test_clone();
	refs = count_references();

	fetchhead_test_fetch("refs/heads/first-merge", FETCH_HEAD_EXPLICIT_DATA);
	cl_git_fail(git_branch_lookup(&ref, g_repo, "first-merge", GIT_BRANCH_ALL));

	cl_assert_equal_i(refs, count_references());
}
예제 #10
0
파일: delete.c 프로젝트: 1336/libgit2
void test_refs_branches_delete__can_not_delete_a_branch_pointed_at_by_HEAD(void)
{
	git_reference *head;
	git_reference *branch;

	/* Ensure HEAD targets the local master branch */
	cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE));
	cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head));
	git_reference_free(head);

	cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
	cl_git_fail(git_branch_delete(branch));
	git_reference_free(branch);
}
예제 #11
0
파일: delete.c 프로젝트: 1336/libgit2
void test_refs_branches_delete__deleting_a_branch_removes_related_configuration_data(void)
{
	git_reference *branch;

	assert_config_entry_existence(repo, "branch.track-local.remote", true);
	assert_config_entry_existence(repo, "branch.track-local.merge", true);

	cl_git_pass(git_branch_lookup(&branch, repo, "track-local", GIT_BRANCH_LOCAL));
	cl_git_pass(git_branch_delete(branch));
	git_reference_free(branch);

	assert_config_entry_existence(repo, "branch.track-local.remote", false);
	assert_config_entry_existence(repo, "branch.track-local.merge", false);
}
예제 #12
0
void test_online_fetchhead__explicit_dst_refspec_creates_branch(void)
{
	git_reference *ref;
	int refs;

	fetchhead_test_clone();
	refs = count_references();
	fetchhead_test_fetch("refs/heads/first-merge:refs/heads/explicit-refspec", FETCH_HEAD_EXPLICIT_DATA);

	cl_git_pass(git_branch_lookup(&ref, g_repo, "explicit-refspec", GIT_BRANCH_ALL));
	cl_assert_equal_i(refs + 1, count_references());

	git_reference_free(ref);
}
예제 #13
0
// Helper method to normalize branch lookups.
static inline int rugged_branch_lookup(git_reference **branch, git_repository *repo, VALUE rb_name_or_branch)
{
	if (rb_obj_is_kind_of(rb_name_or_branch, rb_cRuggedBranch)) {
		rb_name_or_branch = rb_funcall(rb_name_or_branch, rb_intern("canonical_name"), 0);

		if (TYPE(rb_name_or_branch) != T_STRING)
			rb_raise(rb_eTypeError, "Expected #canonical_name to return a String");

		return git_reference_lookup(branch, repo, StringValueCStr(rb_name_or_branch));
	} else if (TYPE(rb_name_or_branch) == T_STRING) {
		char *branch_name = StringValueCStr(rb_name_or_branch), *ref_name;
		int error;

		if (strncmp(branch_name, "refs/heads/", strlen("refs/heads/")) == 0 ||
		    strncmp(branch_name, "refs/remotes/", strlen("refs/remotes/")) == 0)
			return git_reference_lookup(branch, repo, branch_name);

		if ((error = git_branch_lookup(branch, repo, branch_name, GIT_BRANCH_LOCAL)) == GIT_OK ||
		    error != GIT_ENOTFOUND)
			return error;

		if ((error = git_branch_lookup(branch, repo, branch_name, GIT_BRANCH_REMOTE)) == GIT_OK ||
		    error != GIT_ENOTFOUND)
			return error;

		ref_name = xmalloc((strlen(branch_name) + strlen("refs/") + 1)  * sizeof(char));
		strcpy(ref_name, "refs/");
		strcat(ref_name, branch_name);

		error = git_reference_lookup(branch, repo, ref_name);
		xfree(ref_name);

		return error;
	} else {
		rb_raise(rb_eTypeError, "Expecting a String or Rugged::Branch instance");
	}
}
예제 #14
0
static void do_prune(git_repository *repo, const char *name)
{
	git_reference *branch;
	int err;

	err = git_branch_lookup(&branch, repo, name, GIT_BRANCH_LOCAL);
	if (err != 0) {
		gbr_perror("git_branch_lookup()");
		return;
	}

	if (git_branch_delete(branch) != 0) {
		gbr_perror("git_branch_delete()");
		git_reference_free(branch);
	}
}
예제 #15
0
파일: delete.c 프로젝트: 1336/libgit2
void test_refs_branches_delete__can_delete_a_branch_pointed_at_by_detached_HEAD(void)
{
	git_reference *head, *branch;

	cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE));
	cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head));
	cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head));
	git_reference_free(head);

	/* Detach HEAD and make it target the commit that "master" points to */
	git_repository_detach_head(repo);

	cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
	cl_git_pass(git_branch_delete(branch));
	git_reference_free(branch);
}
예제 #16
0
static void assert_branch_matches_name(
	const char *expected, const char *lookup_as)
{
	git_reference *ref;
	git_buf b = GIT_BUF_INIT;

	cl_git_pass(git_branch_lookup(&ref, repo, lookup_as, GIT_BRANCH_LOCAL));

	cl_git_pass(git_buf_sets(&b, "refs/heads/"));
	cl_git_pass(git_buf_puts(&b, expected));
	cl_assert_equal_s(b.ptr, git_reference_name(ref));

	cl_git_pass(
		git_oid_cmp(git_reference_target(ref), git_commit_id(target)));

	git_reference_free(ref);
	git_buf_free(&b);
}
예제 #17
0
PyObject *
Repository_lookup_branch(Repository *self, PyObject *args)
{
    git_reference *c_reference;
    const char *c_name;
    git_branch_t branch_type = GIT_BRANCH_LOCAL;
    int err;

    if (!PyArg_ParseTuple(args, "s|I", &c_name, &branch_type))
        return NULL;

    err = git_branch_lookup(&c_reference, self->repo, c_name, branch_type);
    if (err == 0)
        return wrap_branch(c_reference, self);

    if (err == GIT_ENOTFOUND)
        Py_RETURN_NONE;

    return Error_set(err);
}
예제 #18
0
static int check_remote_status(git_repository *repo, git_remote *origin, const char *remote, const char *branch, enum remote_transport rt)
{
	int error = 0;

	git_reference *local_ref, *remote_ref;

	if (verbose)
		fprintf(stderr, "git storage: check remote status\n");

	if (git_branch_lookup(&local_ref, repo, branch, GIT_BRANCH_LOCAL)) {
		if (is_subsurface_cloud)
			return cleanup_local_cache(remote, branch);
		else
			return report_error("Git cache branch %s no longer exists", branch);
	}
	if (git_branch_upstream(&remote_ref, local_ref)) {
		/* so there is no upstream branch for our branch; that's a problem.
		 * let's push our branch */
		git_strarray refspec;
		git_reference_list(&refspec, repo);
		git_push_options opts = GIT_PUSH_OPTIONS_INIT;
		opts.callbacks.transfer_progress = &transfer_progress_cb;
		auth_attempt = 0;
		if (rt == RT_SSH)
			opts.callbacks.credentials = credential_ssh_cb;
		else if (rt == RT_HTTPS)
			opts.callbacks.credentials = credential_https_cb;
		opts.callbacks.certificate_check = certificate_check_cb;
		git_storage_update_progress(translate("gettextFromC", "Store data into cloud storage"));
		error = git_remote_push(origin, &refspec, &opts);
	} else {
		error = try_to_update(repo, origin, local_ref, remote_ref, remote, branch, rt);
		git_reference_free(remote_ref);
	}
	git_reference_free(local_ref);
	return error;
}
예제 #19
0
파일: delete.c 프로젝트: 1336/libgit2
void test_refs_branches_delete__removes_reflog(void)
{
	git_reference *branch;
	git_reflog *log;
	git_oid oidzero = {{0}};
	git_signature *sig;

	/* Ensure the reflog has at least one entry */
	cl_git_pass(git_signature_now(&sig, "Me", "*****@*****.**"));
	cl_git_pass(git_reflog_read(&log, repo, "refs/heads/track-local"));
	cl_git_pass(git_reflog_append(log, &oidzero, sig, "message"));
	cl_assert(git_reflog_entrycount(log) > 0);
	git_signature_free(sig);
	git_reflog_free(log);

	cl_git_pass(git_branch_lookup(&branch, repo, "track-local", GIT_BRANCH_LOCAL));
	cl_git_pass(git_branch_delete(branch));
	git_reference_free(branch);

	/* Reading a nonexistant reflog creates it, but it should be empty */
	cl_git_pass(git_reflog_read(&log, repo, "refs/heads/track-local"));
	cl_assert_equal_i(0, git_reflog_entrycount(log));
	git_reflog_free(log);
}
예제 #20
0
void GitRepository::branch(const QString& name)
{
    git_repository* repo = repository();
    git_auto<git_reference> branch;

    int err = git_branch_lookup(&branch, repo, name.toLatin1(), GIT_BRANCH_LOCAL);
    if (err == GIT_ENOTFOUND){
        git_oid parent_id;
        git_auto<git_commit> parent;

        git_eval(git_reference_name_to_id(&parent_id, repo, "HEAD"));
        git_eval(git_commit_lookup(&parent, repo, &parent_id));
        git_eval(git_branch_create(&branch, repo, name.toLocal8Bit(), parent, 1));
    }else{
        git_eval(err);
    }

    git_eval(git_repository_set_head(repo, git_reference_name(branch)));

    git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
    opts.checkout_strategy = GIT_CHECKOUT_FORCE;

    git_eval(git_checkout_head(repo, &opts));
}
예제 #21
0
파일: branch.c 프로젝트: Angeldude/sonic-pi
int git_branch_set_upstream(git_reference *branch, const char *upstream_name)
{
	git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT;
	git_reference *upstream;
	git_repository *repo;
	git_remote *remote = NULL;
	git_config *config;
	const char *name, *shortname;
	int local, error;
	const git_refspec *fetchspec;

	name = git_reference_name(branch);
	if (!git_reference__is_branch(name))
		return not_a_local_branch(name);

	if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0)
		return -1;

	shortname = name + strlen(GIT_REFS_HEADS_DIR);

	if (upstream_name == NULL)
		return unset_upstream(config, shortname);

	repo = git_reference_owner(branch);

	/* First we need to figure out whether it's a branch or remote-tracking */
	if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0)
		local = 1;
	else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0)
		local = 0;
	else {
		giterr_set(GITERR_REFERENCE,
			"Cannot set upstream for branch '%s'", shortname);
		return GIT_ENOTFOUND;
	}

	/*
	 * If it's local, the remote is "." and the branch name is
	 * simply the refname. Otherwise we need to figure out what
	 * the remote-tracking branch's name on the remote is and use
	 * that.
	 */
	if (local)
		error = git_buf_puts(&value, ".");
	else
		error = git_branch_remote_name(&value, repo, git_reference_name(upstream));

	if (error < 0)
		goto on_error;

	if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0)
		goto on_error;

	if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0)
		goto on_error;

	if (local) {
		git_buf_clear(&value);
		if (git_buf_puts(&value, git_reference_name(upstream)) < 0)
			goto on_error;
	} else {
		/* Get the remoe-tracking branch's refname in its repo */
		if (git_remote_lookup(&remote, repo, git_buf_cstr(&value)) < 0)
			goto on_error;

		fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream));
		git_buf_clear(&value);
		if (!fetchspec || git_refspec_rtransform(&value, fetchspec, git_reference_name(upstream)) < 0)
			goto on_error;

		git_remote_free(remote);
		remote = NULL;
	}

	git_buf_clear(&key);
	if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0)
		goto on_error;

	if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0)
		goto on_error;

	git_reference_free(upstream);
	git_buf_free(&key);
	git_buf_free(&value);

	return 0;

on_error:
	git_reference_free(upstream);
	git_buf_free(&key);
	git_buf_free(&value);
	git_remote_free(remote);

	return -1;
}
예제 #22
0
int cmd_checkout(git_repository *repo, int argc, char **argv)
{
	int i, err, rc;
	char *branch;
	git_reference *branch_ref;
	git_checkout_options checkout_opts;

	branch = NULL;
	rc = EXIT_FAILURE;

	for (i=1;i<argc;i++)
	{
		if (argv[i][0] != '-')
		{
			if (!branch) branch = argv[i];
		} else
		{
		}
	}

	if (!branch)
	{
		fprintf (stderr, "USAGE: %s <branch>\n", argv[0]);
		return -1;
	}

	/* Try local branch */
	if (git_branch_lookup(&branch_ref,repo,branch,GIT_BRANCH_LOCAL) != 0)
	{
		/* No, try remote branch */
		git_reference *remote_branch_ref;
		char remote_buf[256];
		snprintf(remote_buf,sizeof(remote_buf),"%s/%s","origin",branch);
		if (git_branch_lookup(&remote_branch_ref, repo, remote_buf, GIT_BRANCH_REMOTE) == 0)
		{
			/* Exists, now try to create a local one from that reference */
			if ((err = git2_create_branch_from_ref(&branch_ref,remote_branch_ref,repo,branch)) != 0)
			{
				fprintf(stderr,"Error code %d\n",err);
				libgit_error();
				goto out;
			}
			git_reference_free(remote_branch_ref);
		} else
		{
			branch_ref = NULL;
		}
	}

	printf("Checking out %s\n",branch_ref?git_reference_name(branch_ref):branch);
	if ((err = git_repository_set_head(repo,branch_ref?git_reference_name(branch_ref):branch)) != 0)
	{
		fprintf(stderr,"Error code %d\n",err);
		libgit_error();
		goto out;
	}

	/* Default options. Note by default we perform a dry checkout */
	memset(&checkout_opts,0,sizeof(checkout_opts));
	checkout_opts.version = GIT_CHECKOUT_OPTIONS_VERSION;
	checkout_opts.notify_cb = notify_cb;

	checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE|GIT_CHECKOUT_REMOVE_UNTRACKED;//GIT_CHECKOUT_SAFE|GIT_CHECKOUT_UPDATE_UNTRACKED;
	if (git_checkout_head(repo,&checkout_opts) != 0)
	{
		libgit_error();
		goto out;
	}

	rc = EXIT_SUCCESS;
out:
	if (branch_ref)
		git_reference_free(branch_ref);

	return rc;
}
예제 #23
0
파일: git2r_merge.c 프로젝트: krlmlr/git2r
/**
 * Merge branch into HEAD
 *
 * @param branch S4 class git_branch to merge into HEAD.
 * @param merger Who is performing the merge
 * @param commit_on_success Commit merge commit, if one was created
 * during a normal merge
 * @return S4 class git_merge_result
 */
SEXP git2r_merge_branch(SEXP branch, SEXP merger, SEXP commit_on_success)
{
    int err;
    SEXP result = R_NilValue;
    const char *name;
    git_buf buf = GIT_BUF_INIT;
    git_branch_t type;
    git_annotated_commit **merge_heads = NULL;
    git_reference *reference = NULL;
    git_repository *repository = NULL;
    git_signature *who = NULL;

    if (git2r_arg_check_branch(branch))
        git2r_error(__func__, NULL, "'branch'", git2r_err_branch_arg);
    if (git2r_arg_check_logical(commit_on_success))
        git2r_error(__func__, NULL, "'commit_on_success'", git2r_err_logical_arg);
    if (git2r_arg_check_signature(merger))
        git2r_error(__func__, NULL, "'merger'", git2r_err_signature_arg);

    err = git2r_signature_from_arg(&who, merger);
    if (err)
        goto cleanup;

    repository = git2r_repository_open(GET_SLOT(branch, Rf_install("repo")));
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    name = CHAR(STRING_ELT(GET_SLOT(branch, Rf_install("name")), 0));
    type = INTEGER(GET_SLOT(branch, Rf_install("type")))[0];
    err = git_branch_lookup(&reference, repository, name, type);
    if (err)
        goto cleanup;

    merge_heads = calloc(1, sizeof(git_annotated_commit*));
    if (NULL == merge_heads) {
        giterr_set_str(GITERR_NONE, git2r_err_alloc_memory_buffer);
        goto cleanup;
    }

    err = git_annotated_commit_from_ref(
        &(merge_heads[0]),
        repository,
        reference);
    if (err)
        goto cleanup;

    err = git_buf_printf(&buf, "merge %s", name);
    if (err)
        goto cleanup;

    PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_merge_result")));
    err = git2r_merge(
        result,
        repository,
        (const git_annotated_commit **)merge_heads,
        1,
        GIT_MERGE_PREFERENCE_NONE,
        buf.ptr,
        who,
        LOGICAL(commit_on_success)[0]);

cleanup:
    git_buf_free(&buf);

    if (who)
        git_signature_free(who);

    if (merge_heads)
        git2r_merge_heads_free(merge_heads, 1);

    if (reference)
        git_reference_free(reference);

    if (repository)
        git_repository_free(repository);

    if (R_NilValue != result)
        UNPROTECT(1);

    if (err)
        git2r_error(__func__, giterr_last(), NULL, NULL);

    return result;
}
예제 #24
0
bool Masterlist::Update(const boost::filesystem::path& path, const std::string& repoUrl, const std::string& repoBranch) {
  GitHelper git;
  fs::path repoPath = path.parent_path();
  string filename = path.filename().string();

  if (repoUrl.empty() || repoBranch.empty())
    throw std::invalid_argument("Repository URL and branch must not be empty.");

// Initialise checkout options.
  BOOST_LOG_TRIVIAL(debug) << "Setting up checkout options.";
  char * paths = new char[filename.length() + 1];
  strcpy(paths, filename.c_str());
  git.GetData().checkout_options.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_DONT_REMOVE_EXISTING;
  git.GetData().checkout_options.paths.strings = &paths;
  git.GetData().checkout_options.paths.count = 1;

  // Initialise clone options.
  git.GetData().clone_options.checkout_opts = git.GetData().checkout_options;
  git.GetData().clone_options.bare = 0;
  git.GetData().clone_options.checkout_branch = repoBranch.c_str();

  // Now try to access the repository if it exists, or clone one if it doesn't.
  BOOST_LOG_TRIVIAL(trace) << "Attempting to open the Git repository at: " << repoPath;
  if (!git.IsRepository(repoPath))
    git.Clone(repoPath, repoUrl);
  else {
      // Repository exists: check settings are correct, then pull updates.
    git.SetErrorMessage((boost::format(translate("An error occurred while trying to access the local masterlist repository. If this error happens again, try deleting the \".git\" folder in %1%.")) % repoPath.string()).str());

    // Open the repository.
    BOOST_LOG_TRIVIAL(info) << "Existing repository found, attempting to open it.";
    git.Call(git_repository_open(&git.GetData().repo, repoPath.string().c_str()));

    // Set the remote URL.
    BOOST_LOG_TRIVIAL(info) << "Using remote URL: " << repoUrl;
    git.Call(git_remote_set_url(git.GetData().repo, "origin", repoUrl.c_str()));

    // Now fetch updates from the remote.
    git.Fetch("origin");

    // Check that a local branch with the correct name exists.
    git.SetErrorMessage((boost::format(translate("An error occurred while trying to access the local masterlist repository. If this error happens again, try deleting the \".git\" folder in %1%.")) % repoPath.string()).str());
    int ret = git_branch_lookup(&git.GetData().reference, git.GetData().repo, repoBranch.c_str(), GIT_BRANCH_LOCAL);
    if (ret == GIT_ENOTFOUND)
        // Branch doesn't exist. Create a new branch using the remote branch's latest commit.
      git.CheckoutNewBranch("origin", repoBranch);
    else {
        // The local branch exists. Need to merge the remote branch
        // into it.
      git.Call(ret);  // Handle other errors from preceding branch lookup.

      // Check if HEAD points to the desired branch and set it to if not.
      if (!git_branch_is_head(git.GetData().reference)) {
        BOOST_LOG_TRIVIAL(trace) << "Setting HEAD to follow branch: " << repoBranch;
        git.Call(git_repository_set_head(git.GetData().repo, (string("refs/heads/") + repoBranch).c_str()));
      }

      // Get remote branch reference.
      git.Call(git_branch_upstream(&git.GetData().reference2, git.GetData().reference));

      BOOST_LOG_TRIVIAL(trace) << "Checking HEAD and remote branch's mergeability.";
      git_merge_analysis_t analysis;
      git_merge_preference_t pref;
      git.Call(git_annotated_commit_from_ref(&git.GetData().annotated_commit, git.GetData().repo, git.GetData().reference2));
      git.Call(git_merge_analysis(&analysis, &pref, git.GetData().repo, (const git_annotated_commit **)&git.GetData().annotated_commit, 1));

      if ((analysis & GIT_MERGE_ANALYSIS_FASTFORWARD) == 0 && (analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) == 0) {
          // The local branch can't be easily merged. Best just to delete and recreate it.
        BOOST_LOG_TRIVIAL(trace) << "Local branch cannot be easily merged with remote branch.";

        BOOST_LOG_TRIVIAL(trace) << "Deleting the local branch.";
        git.Call(git_branch_delete(git.GetData().reference));

        // Need to free ref before calling git.CheckoutNewBranch()
        git_reference_free(git.GetData().reference);
        git.GetData().reference = nullptr;
        git_reference_free(git.GetData().reference2);
        git.GetData().reference2 = nullptr;

        git.CheckoutNewBranch("origin", repoBranch);
      } else {
          // Get remote branch commit ID.
        git.Call(git_reference_peel(&git.GetData().object, git.GetData().reference2, GIT_OBJ_COMMIT));
        const git_oid * remote_commit_id = git_object_id(git.GetData().object);

        git_object_free(git.GetData().object);
        git.GetData().object = nullptr;
        git_reference_free(git.GetData().reference2);
        git.GetData().reference2 = nullptr;

        bool updateBranchHead = true;
        if ((analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) != 0) {
            // No merge is required, but HEAD might be ahead of the remote branch. Check
            // to see if that's the case, and move HEAD back to match the remote branch
            // if so.
          BOOST_LOG_TRIVIAL(trace) << "Local branch is up-to-date with remote branch.";
          BOOST_LOG_TRIVIAL(trace) << "Checking to see if local and remote branch heads are equal.";

          // Get local branch commit ID.
          git.Call(git_reference_peel(&git.GetData().object, git.GetData().reference, GIT_OBJ_COMMIT));
          const git_oid * local_commit_id = git_object_id(git.GetData().object);

          git_object_free(git.GetData().object);
          git.GetData().object = nullptr;

          updateBranchHead = local_commit_id->id != remote_commit_id->id;

          // If the masterlist in
          // HEAD also matches the masterlist file, no further
          // action needs to be taken. Otherwise, a checkout
          // must be performed and the checked-out file parsed.
          if (!updateBranchHead) {
            BOOST_LOG_TRIVIAL(trace) << "Local and remote branch heads are equal.";
            if (!GitHelper::IsFileDifferent(repoPath, filename)) {
              BOOST_LOG_TRIVIAL(info) << "Local branch and masterlist file are already up to date.";
              return false;
            }
          } else
            BOOST_LOG_TRIVIAL(trace) << "Local branch heads is ahead of remote branch head.";
        } else
          BOOST_LOG_TRIVIAL(trace) << "Local branch can be fast-forwarded to remote branch.";

        if (updateBranchHead) {
            // The remote branch reference points to a particular
            // commit. Update the local branch reference to point
            // to the same commit.
          BOOST_LOG_TRIVIAL(trace) << "Syncing local branch head with remote branch head.";
          git.Call(git_reference_set_target(&git.GetData().reference2, git.GetData().reference, remote_commit_id, "Setting branch reference."));

          git_reference_free(git.GetData().reference2);
          git.GetData().reference2 = nullptr;
        }

        git_reference_free(git.GetData().reference);
        git.GetData().reference = nullptr;

        BOOST_LOG_TRIVIAL(trace) << "Performing a Git checkout of HEAD.";
        git.Call(git_checkout_head(git.GetData().repo, &git.GetData().checkout_options));
      }
    }
  }

  // Now whether the repository was cloned or updated, the working directory contains
  // the latest masterlist. Try parsing it: on failure, detach the HEAD back one commit
  // and try again.

  bool parsingFailed = false;
  std::string parsingError;
  git.SetErrorMessage((boost::format(translate("An error occurred while trying to read information on the updated masterlist. If this error happens again, try deleting the \".git\" folder in %1%.")) % repoPath.string()).str());
  do {
      // Get the HEAD revision's short ID.
    string revision = git.GetHeadShortId();

    //Now try parsing the masterlist.
    BOOST_LOG_TRIVIAL(debug) << "Testing masterlist parsing.";
    try {
      this->Load(path);

      parsingFailed = false;
    } catch (std::exception& e) {
      parsingFailed = true;
      if (parsingError.empty())
        parsingError = boost::locale::translate("Masterlist revision").str() +
        " " + string(revision) +
        ": " + e.what() +
        ". " +
        boost::locale::translate("The latest masterlist revision contains a syntax error, LOOT is using the most recent valid revision instead. Syntax errors are usually minor and fixed within hours.").str();

    //There was an error, roll back one revision.
      BOOST_LOG_TRIVIAL(error) << "Masterlist parsing failed. Masterlist revision " + string(revision) + ": " + e.what();
      git.CheckoutRevision("HEAD^");
    }
  } while (parsingFailed);

  if (!parsingError.empty())
    AppendMessage(Message(MessageType::error, parsingError));

  return true;
}
예제 #25
0
int main()
{
    git_libgit2_init();

    git_repository* rep = nullptr;

    git_rebase* prebase = nullptr;
    git_rebase_options rebase_opt = GIT_REBASE_OPTIONS_INIT;

    git_reference* onto_branch = nullptr;
    git_annotated_commit* onto = nullptr;

    git_rebase_operation* operation = nullptr;

    size_t entrycount;
    size_t current;

    git_signature* me = nullptr;

    git_index* index = nullptr;
    git_oid new_commit;

    int error = 0;

    // git open
    git_repository_open(&rep, path);

    error = git_rebase_open(&prebase, rep, &rebase_opt);
    // There is no rebase in progress
    if (error == GIT_ENOTFOUND)
    {
        git_branch_lookup(&onto_branch, rep, "new", GIT_BRANCH_LOCAL);
        git_annotated_commit_from_ref(&onto, rep, onto_branch);
        git_rebase_init(&prebase, rep, nullptr /* current branch */, nullptr /* upstream */
                , onto /* branch to rebase onto */, &rebase_opt);
    }
    else if (error < 0)
    {
        const git_error *e = giterr_last();
        std::cout << "Error: " << error << " / " << e->klass << " : " << e->message << std::endl;
        goto SHUTDOWN;
    }

    entrycount = git_rebase_operation_entrycount(prebase);
    std::cout<< "rebase entry count: " << entrycount << "\n";

    while (git_rebase_next(&operation, prebase) != GIT_ITEROVER)
    {

        current = git_rebase_operation_current(prebase); // (called `init` but not yet `next`) then this returns `GIT_REBASE_NO_OPERATION`
        std::cout<< "rebase current index: " << current << "\n";
        if (GIT_REBASE_NO_OPERATION == current)
        {
            std::cout<< "rebase no operation" << "\n";
        }
        operation = git_rebase_operation_byindex(prebase, 0);
    }

    // reslove conflicts
    git_repository_index(&index, rep);
    if (git_index_has_conflicts(index))
    {
        // git checkout --theirs
        git_checkout_options opt = GIT_CHECKOUT_OPTIONS_INIT;
        opt.checkout_strategy |= GIT_CHECKOUT_USE_THEIRS;
        git_checkout_index(rep, index, &opt);
    }

    // add
    git_index_update_all(index, nullptr, nullptr, nullptr);
    git_index_write(index);

    // commit
    git_signature_now(&me, "XiaochenFTX", "*****@*****.**");
    git_rebase_commit(&new_commit, prebase, me, me, "UTF-8", "new rebase");

    error = git_rebase_finish(prebase, me);
    if (error < 0)
    {
        const git_error *e = giterr_last();
        std::cout << "Error: " << error << " / " << e->klass << " : " << e->message << std::endl;
        goto SHUTDOWN;
    }

//    git_rebase_abort(prebase);

    git_rebase_free(prebase);

SHUTDOWN:
    git_repository_free(rep);
    git_libgit2_shutdown();
    return 0;
}