示例#1
0
文件: merge.c 项目: mikeando/agb
	//TODO: Use a real error?
	assert(core);
	assert(core->repository);

	/* TODO: FIX THIS */
	const char * local_branch_name = core->local_branch_name;
	const char * remote_branch_name = core->remote_branch_name;
	assert(local_branch_name);
	assert(remote_branch_name);
	git_repository * repo = core->repository;
	int ok;

	git_reference_name_to_id(&local_oid, repo, local_branch_name);
	git_reference_name_to_id(&remote_oid, repo, remote_branch_name);

	ok = git_merge_base(&base_oid, repo, &local_oid, &remote_oid);

	commit_oid_to_tree(&local_tree, repo, &local_oid);
	commit_oid_to_tree(&remote_tree, repo, &remote_oid);
	commit_oid_to_tree(&base_tree, repo, &base_oid);


	return agb_merge__create_iterator(local_tree, remote_tree, base_tree, agb_merge_iterator_options_NONE);
}

const git_oid * agb_merge_iterator_tree_id( const AGBMergeIterator * it, enum AGBMergeIndex i) {
	return git_tree_id(it->trees[i]);
}

const char * agb_merge_entry_name( const AGBMergeEntry * entry) {
       return entry->name;
示例#2
0
static int try_to_update(git_repository *repo, git_remote *origin, git_reference *local, git_reference *remote,
			 const char *remote_url, const char *branch, enum remote_transport rt)
{
	git_oid base;
	const git_oid *local_id, *remote_id;
	int ret = 0;

	if (verbose)
		fprintf(stderr, "git storage: try to update\n");
	git_storage_update_progress(false, "try to update");
	if (!git_reference_cmp(local, remote))
		return 0;

	// Dirty modified state in the working tree? We're not going
	// to update either way
	if (git_status_foreach(repo, check_clean, NULL)) {
		if (is_subsurface_cloud)
			goto cloud_data_error;
		else
			return report_error("local cached copy is dirty, skipping update");
	}
	local_id = git_reference_target(local);
	remote_id = git_reference_target(remote);

	if (!local_id || !remote_id) {
		if (is_subsurface_cloud)
			goto cloud_data_error;
		else
			return report_error("Unable to get local or remote SHA1");
	}
	if (git_merge_base(&base, repo, local_id, remote_id)) {
		if (is_subsurface_cloud)
			goto cloud_data_error;
		else
			return report_error("Unable to find common commit of local and remote branches");
	}
	/* Is the remote strictly newer? Use it */
	if (git_oid_equal(&base, local_id)) {
		git_storage_update_progress(false, "fast forward to remote");
		return reset_to_remote(repo, local, remote_id);
	}

	/* Is the local repo the more recent one? See if we can update upstream */
	if (git_oid_equal(&base, remote_id)) {
		if (verbose)
			fprintf(stderr, "local is newer than remote, update remote\n");
		git_storage_update_progress(false, "git_update_remote, local was newer");
		return update_remote(repo, origin, local, remote, rt);
	}
	/* Merging a bare repository always needs user action */
	if (git_repository_is_bare(repo)) {
		if (is_subsurface_cloud)
			goto cloud_data_error;
		else
			return report_error("Local and remote have diverged, merge of bare branch needed");
	}
	/* Merging will definitely need the head branch too */
	if (git_branch_is_head(local) != 1) {
		if (is_subsurface_cloud)
			goto cloud_data_error;
		else
			return report_error("Local and remote do not match, local branch not HEAD - cannot update");
	}
	/* Ok, let's try to merge these */
	git_storage_update_progress(false, "try to merge");
	ret = try_to_git_merge(repo, &local, remote, &base, local_id, remote_id);
	if (ret == 0)
		return update_remote(repo, origin, local, remote, rt);
	else
		return ret;

cloud_data_error:
	// since we are working with Subsurface cloud storage we want to make the user interaction
	// as painless as possible. So if something went wrong with the local cache, tell the user
	// about it an move it away
	return cleanup_local_cache(remote_url, branch);
}
示例#3
0
/**
 * Updates the master branch with the latest changes, including local
 * changes and changes from the remote repository.
 */
int sync_master(git_repository *repo,
                int *files_changed,
                int *need_push)
{
    int e = 0;
    git_oid master_id = {{0}};
    git_oid remote_id = {{0}};
    git_oid base_id = {{0}};
    int master_dirty = 0;
    int remote_dirty = 0;
    int local_dirty = 0;

    // Find the relevant commit objects:
    git_check(sync_lookup_soft(&master_id, repo, SYNC_REF_MASTER));
    git_check(sync_lookup_soft(&remote_id, repo, SYNC_REF_REMOTE));
    if (!git_oid_iszero(&remote_id) && !git_oid_iszero(&master_id))
    {
        e = git_merge_base(&base_id, repo, &master_id, &remote_id);
        if (e < 0 && e != GIT_ENOTFOUND)
        {
            goto exit;
        }
    }

    // Figure out what needs syncing:
    master_dirty = git_oid_cmp(&master_id, &base_id);
    remote_dirty = git_oid_cmp(&remote_id, &base_id);
    git_check(sync_local_dirty(&local_dirty, repo, &master_id));

    if (remote_dirty)
    {
        if (master_dirty || local_dirty)
        {
            // 3-way merge:
            git_oid local_tree;
            git_oid base_tree;
            git_oid remote_tree;
            if (local_dirty)
            {
                git_check(sync_workdir_tree(&local_tree, repo));
            }
            else
            {
                git_check(sync_get_tree(&local_tree, repo, &master_id));
            }
            git_check(sync_get_tree(&remote_tree, repo, &remote_id));
            git_check(sync_get_tree(&base_tree, repo, &base_id));

            // Do merge:
            git_oid merged_tree;
            git_check(sync_merge_trees(&merged_tree, repo, &base_tree, &remote_tree, &local_tree));

            // Commit to master:
            char const *message =
                local_dirty ? "merge local changes" : "merge";
            if (git_oid_iszero(&master_id))
            {
                const git_oid *parents[] = {&remote_id};
                git_check(sync_commit_master(repo, message, &merged_tree, 1, parents));
            }
            else
            {
                const git_oid *parents[] = {&master_id, &remote_id};
                git_check(sync_commit_master(repo, message, &merged_tree, 2, parents));
            }
        }
        else
        {
            // Fast-forward to remote:
            git_check(sync_fast_forward(repo, SYNC_REF_MASTER, &remote_id));
        }
        if (!git_repository_is_bare(repo))
        {
            git_check(sync_checkout(repo, SYNC_REF_MASTER));
        }
    }
    else if (local_dirty)
    {
        // Commit local changes:
        git_oid local_tree;
        git_check(sync_workdir_tree(&local_tree, repo));
        if (git_oid_iszero(&master_id))
        {
            const git_oid *parents[] = {NULL};
            git_check(sync_commit_master(repo, "first commit", &local_tree, 0, parents));
        }
        else
        {
            const git_oid *parents[] = {&master_id};
            git_check(sync_commit_master(repo, "commit local changes", &local_tree, 1, parents));
        }
    }

    // Report the outcome:
    *files_changed = !!remote_dirty;
    *need_push = local_dirty || master_dirty;

exit:
    return e;
}