commit - 016a88dd43b7cb2c25db43168377a501de53b1d9
commit + b416585cf047654c6eb266874b5465a6f67861a7
blob - 37547bfa3b92c8e142fb8293c30bb06a1e202a95
blob + 204c0b97c37f8f8c73bf17fbfc12436c416b62a3
--- include/got_worktree.h
+++ include/got_worktree.h
unsigned char status;
struct got_object_id *blob_id;
struct got_object_id *base_blob_id;
+ struct got_object_id *base_commit_id;
mode_t mode;
};
blob - 562647c3bd8bf993798cedfc890acb049eeb70c3
blob + c6e5bb6cbe9b53419ce886ccea0a6899b78ca368
--- lib/worktree.c
+++ lib/worktree.c
free(ct->ondisk_path);
free(ct->blob_id);
free(ct->base_blob_id);
+ free(ct->base_commit_id);
free(ct);
}
if (ct->status != GOT_STATUS_ADD) {
ct->base_blob_id = got_object_id_dup(blob_id);
if (ct->base_blob_id == NULL) {
+ err = got_error_from_errno("got_object_id_dup");
+ goto done;
+ }
+ ct->base_commit_id = got_object_id_dup(commit_id);
+ if (ct->base_commit_id == NULL) {
err = got_error_from_errno("got_object_id_dup");
goto done;
}
if (err)
goto done;
}
- err = report_ct_status(ct, status_cb, status_arg);
+ err = report_ct_status(ct, status_cb,
+ status_arg);
if (err)
goto done;
} else {
struct got_object_id *id_in_head;
/*
- * XXX This should probably be checking each commit from
- * worktree's base_commit -> head and verify that the
- * same blob exists in each of these commits.
- * Removals+additions within this line of history could mean
- * that renames have occured in which case we should really
- * be forcing the user to run an update...
- */
- err = got_object_id_by_path(&id_in_head, repo,
- head_commit_id, ct->in_repo_path);
- if (err) {
- if (err->code != GOT_ERR_NO_TREE_ENTRY)
- return err;
- if (ct->status != GOT_STATUS_ADD)
- return got_error(GOT_ERR_COMMIT_OUT_OF_DATE);
- err = NULL;
- id_in_head = NULL;
+ * Require that modified/deleted files are based on the branch head.
+ * This requirement could be relaxed to force less update operations
+ * on users but, for now, we want to play it safe and see how it goes.
+ *
+ * If this check is relaxed, it must still ensure that no modifications
+ * were made to files *and their parents* in commits between the file's
+ * base commit and the branch head. Otherwise, tree conflicts will not
+ * be detected reliably.
+ */
+ if (ct->status != GOT_STATUS_ADD) {
+ if (got_object_id_cmp(ct->base_commit_id, head_commit_id) != 0)
+ return got_error(GOT_ERR_COMMIT_OUT_OF_DATE);
+ return NULL;
}
- if (id_in_head && got_object_id_cmp(id_in_head, ct->base_blob_id) != 0)
- err = got_error(GOT_ERR_COMMIT_OUT_OF_DATE);
+ /* Require that added files don't exist in the branch head. */
+ err = got_object_id_by_path(&id_in_head, repo, head_commit_id,
+ ct->in_repo_path);
+ if (err && err->code != GOT_ERR_NO_TREE_ENTRY)
+ return err;
+ if (id_in_head) {
+ free(id_in_head);
+ return got_error(GOT_ERR_COMMIT_OUT_OF_DATE);
+ }
free(id_in_head);
- return err;
+ return NULL;
}
const struct got_error *