예제 #1
0
파일: merge.c 프로젝트: AzinmarErus/seafile
/*
 * Get the list of new blocks that would be checked out after
 * we merge with a branch headed by @remote.
 *
 * This function should be called before downloading any block
 * if the repo is set to not preserving history. In this case,
 * we don't want to download any block that will not be checked
 * out to the worktree (i.e. data from any historical commits).
 *
 * Return 0 if successfully calculate the block list, -1 otherwise.
 * If there is no new block to download, *@bl will be set to NULL;
 * otherwise it's set to the block list.
 */
int
merge_get_new_block_list (SeafRepo *repo, SeafCommit *remote, BlockList **bl)
{
    SeafCommit *common = NULL;
    SeafCommit *head;
    int ret = 0;

    head = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->head->commit_id);
    if (!head) {
        g_warning ("current branch corrupted.\n");
        return -1;
    }

    common = get_merge_base (head, remote);

    if (!common) {
        g_warning ("Cannot find common ancestor\n");
        ret = -1;
        goto free_head;
    }

    if (strcmp(common->commit_id, remote->commit_id) == 0) {
        /* We are already up to date. No new block. */
        *bl = NULL;
    } else if (strcmp(common->commit_id, head->commit_id) == 0) {
        /* Fast forward. */
        ret = get_new_blocks_ff (repo, head, remote, bl);
    } else {
        /* Not up-to-date and ff, we need a real merge. */
        ret = get_new_blocks_merge (repo, head, remote, common, bl);
    }

    seaf_commit_unref (common);
free_head:
    seaf_commit_unref (head);

    return ret;
}
예제 #2
0
VCCompareResult
vc_compare_commits (const char *repo_id, int version,
                    const char *c1, const char *c2)
{
    SeafCommit *commit1, *commit2, *ca;
    VCCompareResult ret;

    /* Treat the same as up-to-date. */
    if (strcmp (c1, c2) == 0)
        return VC_UP_TO_DATE;

    commit1 = seaf_commit_manager_get_commit (seaf->commit_mgr, repo_id, version, c1);
    if (!commit1)
        return VC_INDEPENDENT;

    commit2 = seaf_commit_manager_get_commit (seaf->commit_mgr, repo_id, version, c2);
    if (!commit2) {
        seaf_commit_unref (commit1);
        return VC_INDEPENDENT;
    }

    ca = get_merge_base (commit1, commit2);

    if (!ca)
        ret = VC_INDEPENDENT;
    else if (strcmp(ca->commit_id, commit1->commit_id) == 0)
        ret = VC_UP_TO_DATE;
    else if (strcmp(ca->commit_id, commit2->commit_id) == 0)
        ret = VC_FAST_FORWARD;
    else
        ret = VC_INDEPENDENT;

    if (ca) seaf_commit_unref (ca);
    seaf_commit_unref (commit1);
    seaf_commit_unref (commit2);
    return ret;
}
예제 #3
0
파일: merge.c 프로젝트: AzinmarErus/seafile
int
merge_branches (SeafRepo *repo, SeafBranch *remote_branch, char **error,
                gboolean *real_merge)
{
    SeafCommit *common = NULL;
    SeafCommit *head, *remote;
    int ret = 0;
    SeafRepoMergeInfo minfo;

    g_assert (repo && remote_branch && error);

    *real_merge = FALSE;

    memset (&minfo, 0, sizeof(minfo));
    if (seaf_repo_manager_get_merge_info (repo->manager, repo->id, &minfo) < 0) {
        g_warning ("Failed to get merge status of repo %s.\n", repo->id);
        return -1;
    }

    head = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->head->commit_id);
    if (!head) {
        *error = g_strdup("Internal error: current branch corrupted.\n");
        return -1;
    }

    remote = seaf_commit_manager_get_commit (seaf->commit_mgr, remote_branch->commit_id);
    if (!remote) {
        *error = g_strdup("Invalid remote branch.\n");
        ret = -1;
        goto free_head;
    }

    /* Are we going to recover from the last interrupted merge? */
    if (minfo.in_merge) {
        /* We don't need to recover 2 cases, since the last merge was actually finished.
         * - "master" and "local" are the same;
         * - index is unmerged.
         *
         * The first case is a clean merge; the second case is unclean merge.
         */
        if (strcmp (head->commit_id, remote->commit_id) == 0 ||
            seaf_repo_is_index_unmerged (repo)) {
            seaf_repo_manager_clear_merge (repo->manager, repo->id);
            goto free_head;
        }
    }

    /* We use the same logic for normal merge and recover. */

    /* Set in_merge state. */
    seaf_repo_manager_set_merge (repo->manager, repo->id, remote_branch->commit_id);

    common = get_merge_base (head, remote);

    if (!common) {
        g_warning ("Cannot find common ancestor\n");
        *error = g_strdup ("Cannot find common ancestor\n");
        ret = -1;
        goto free_remote;
    }

    /* printf ("common commit id is %s.\n", common->commit_id); */

    if (strcmp(common->commit_id, remote->commit_id) == 0) {
        /* We are already up to date. */
        g_debug ("Already up to date.\n");
    } else if (strcmp(common->commit_id, head->commit_id) == 0) {
        /* Fast forward. */
        if (seaf_repo_checkout_commit (repo, remote, minfo.in_merge, error) < 0) {
            ret = -1;
            goto out;
        }
        seaf_branch_set_commit (repo->head, remote->commit_id);
        seaf_branch_manager_update_branch (seaf->branch_mgr, repo->head);

        /* Repo info on the client is in memory. */
        g_free (repo->name);
        repo->name = g_strdup(remote->repo_name);
        g_free (repo->desc);
        repo->desc = g_strdup(remote->repo_desc);

        g_debug ("Fast forward.\n");
    } else {
        /* Not up-to-date and ff, we need a real merge. */
        *real_merge = TRUE;
        ret = do_real_merge (repo, 
                             repo->head, head, 
                             remote_branch, remote, common, 
                             minfo.in_merge,
                             error);
    }

out:
    /* Clear in_merge state, no matter clean or not. */
    seaf_repo_manager_clear_merge (repo->manager, repo->id);

    seaf_commit_unref (common);
free_remote:
    seaf_commit_unref (remote);
free_head:
    seaf_commit_unref (head);

    return ret;
}