[client] Fix a bug in merge.

Reproduce sequence (only for version 0 repo):
1. Both client and server change the same file;
2. Client syncs and do a real merge and fails with conflict;
3. The 30-second auto syncing timer kicks in, sync state [initializing] -> [merging];
4. Merge returns "Already up to date".
5. Afterwards, every sync of this repo will stuck in "Already up to date".
This commit is contained in:
Jiaqiang Xu 2014-05-12 16:20:09 +08:00
parent c0bf9494a9
commit 8b04dc0dac
4 changed files with 20 additions and 10 deletions

View File

@ -149,7 +149,7 @@ get_common_ancestor_commit (const char *repo_id, int version)
int
merge_branches (SeafRepo *repo, SeafBranch *remote_branch, char **error,
gboolean *real_merge)
int *merge_status)
{
SeafCommit *common = NULL;
SeafCommit *head = NULL, *remote = NULL;
@ -160,7 +160,7 @@ merge_branches (SeafRepo *repo, SeafBranch *remote_branch, char **error,
g_return_val_if_fail (repo && remote_branch && error, -1);
*real_merge = FALSE;
*merge_status = MERGE_STATUS_UNKNOWN;
#if 0
memset (&minfo, 0, sizeof(minfo));
@ -230,7 +230,10 @@ merge_branches (SeafRepo *repo, SeafBranch *remote_branch, char **error,
if (strcmp(common->commit_id, remote->commit_id) == 0) {
/* We are already up to date. */
g_debug ("Already up to date.\n");
*merge_status = MERGE_STATUS_UPTODATE;
} else if (strcmp(common->commit_id, head->commit_id) == 0) {
*merge_status = MERGE_STATUS_FAST_FORWARD;
/* Fast forward. */
if (seaf_repo_checkout_commit (repo, remote, FALSE, error) < 0) {
ret = -1;
@ -248,7 +251,7 @@ merge_branches (SeafRepo *repo, SeafBranch *remote_branch, char **error,
g_debug ("Fast forward.\n");
} else {
/* Not up-to-date and ff, we need a real merge. */
*real_merge = TRUE;
*merge_status = MERGE_STATUS_REAL_MERGE;
ret = do_real_merge (repo,
repo->head, head,
remote_branch, remote, common,

View File

@ -1235,7 +1235,7 @@ error:
int
seaf_repo_merge (SeafRepo *repo, const char *branch, char **error,
gboolean *real_merge)
int *merge_status)
{
SeafBranch *remote_branch;
int ret = 0;
@ -1257,7 +1257,7 @@ seaf_repo_merge (SeafRepo *repo, const char *branch, char **error,
goto error;
}
ret = merge_branches (repo, remote_branch, error, real_merge);
ret = merge_branches (repo, remote_branch, error, merge_status);
seaf_branch_unref (remote_branch);
return ret;

View File

@ -149,9 +149,16 @@ int
seaf_repo_checkout_commit (SeafRepo *repo, SeafCommit *commit, gboolean recover_merge,
char **error);
enum {
MERGE_STATUS_UNKNOWN = 0,
MERGE_STATUS_UPTODATE,
MERGE_STATUS_FAST_FORWARD,
MERGE_STATUS_REAL_MERGE,
};
int
seaf_repo_merge (SeafRepo *repo, const char *branch, char **error,
gboolean *real_merge);
int *merge_status);
GList *
seaf_repo_diff (SeafRepo *repo, const char *arg1, const char *arg2, char **error);

View File

@ -609,7 +609,7 @@ start_fetch_if_necessary (SyncTask *task)
struct MergeResult {
SyncTask *task;
gboolean success;
gboolean real_merge;
int merge_status;
gboolean worktree_dirty;
};
@ -674,7 +674,7 @@ merge_job (void *vtask)
* For 2 and 4, the errors are ignored by the merge routine (return 0).
* For 3, just wait another merge retry.
* */
if (seaf_repo_merge (repo, "master", &err_msg, &res->real_merge) < 0) {
if (seaf_repo_merge (repo, "master", &err_msg, &res->merge_status) < 0) {
seaf_message ("[Sync mgr] Merge of repo %s(%.8s) is not clean.\n",
repo->name, repo->id);
res->success = FALSE;
@ -728,7 +728,7 @@ merge_job_done (void *vresult)
seaf_branch_unref (master);
/* If it's a ff merge, also update REPO_LOCAL_HEAD. */
if (!res->real_merge) {
if (res->merge_status == MERGE_STATUS_FAST_FORWARD) {
SeafBranch *local = seaf_branch_manager_get_branch (seaf->branch_mgr,
repo->id,
"local");
@ -747,7 +747,7 @@ merge_job_done (void *vresult)
}
if (res->success && res->real_merge)
if (res->success && res->merge_status == MERGE_STATUS_REAL_MERGE)
start_upload_if_necessary (res->task);
else if (res->success)
transition_sync_state (res->task, SYNC_STATE_DONE);