commit 69de9dd4215502c97f3e9b6c95cd1ce609fba278 from: Stefan Sperling date: Fri Sep 03 09:02:06 2021 UTC limit checks for merge conflicts to files affected by the merge Performance problems reported by naddy commit - 6435d2a6d2c84c4875a0c6f641b06d7cd1796a0c commit + 69de9dd4215502c97f3e9b6c95cd1ce609fba278 blob - 15441d50109add43dd64b4368c57680ec2884d50 blob + ca162036c4a7413a130d54e0e6c5d6e375606b33 --- got/got.1 +++ got/got.1 @@ -1615,7 +1615,7 @@ will refuse to run if certain preconditions are not me If the work tree contains multiple base commits it must first be updated to a single base commit with .Cm got update . -If the work tree already contains files with merge conflicts, these +If any relevant files already contain merge conflicts, these conflicts must be resolved first. .It Cm cy Short alias for @@ -1659,7 +1659,7 @@ will refuse to run if certain preconditions are not me If the work tree contains multiple base commits it must first be updated to a single base commit with .Cm got update . -If the work tree already contains files with merge conflicts, these +If any relevant files already contain merge conflicts, these conflicts must be resolved first. .It Cm bo Short alias for blob - 821074bee10bd2aec44fc5e2732eb33c5b157f6f blob + 43f9d955895f646cd52000b292a11000f9ed15d6 --- lib/worktree.c +++ lib/worktree.c @@ -3118,26 +3118,48 @@ done: return err; } -struct check_merge_ok_arg { +static const struct got_error * +check_mixed_commits(void *arg, struct got_fileindex_entry *ie) +{ + struct got_worktree *worktree = arg; + + /* Reject merges into a work tree with mixed base commits. */ + if (got_fileindex_entry_has_commit(ie) && + memcmp(ie->commit_sha1, worktree->base_commit_id->sha1, + SHA1_DIGEST_LENGTH) != 0) + return got_error(GOT_ERR_MIXED_COMMITS); + + return NULL; +} + +struct check_merge_conflicts_arg { struct got_worktree *worktree; + struct got_fileindex *fileindex; struct got_repository *repo; }; static const struct got_error * -check_merge_ok(void *arg, struct got_fileindex_entry *ie) +check_merge_conflicts(void *arg, struct got_blob_object *blob1, + struct got_blob_object *blob2, struct got_object_id *id1, + struct got_object_id *id2, const char *path1, const char *path2, + mode_t mode1, mode_t mode2, struct got_repository *repo) { const struct got_error *err = NULL; - struct check_merge_ok_arg *a = arg; + struct check_merge_conflicts_arg *a = arg; unsigned char status; struct stat sb; + struct got_fileindex_entry *ie; + const char *path = path2 ? path2 : path1; + struct got_object_id *id = id2 ? id2 : id1; char *ondisk_path; - /* Reject merges into a work tree with mixed base commits. */ - if (got_fileindex_entry_has_commit(ie) && - memcmp(ie->commit_sha1, a->worktree->base_commit_id->sha1, - SHA1_DIGEST_LENGTH)) - return got_error(GOT_ERR_MIXED_COMMITS); + if (id == NULL) + return NULL; + ie = got_fileindex_entry_get(a->fileindex, path, strlen(path)); + if (ie == NULL) + return NULL; + if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, ie->path) == -1) return got_error_from_errno("asprintf"); @@ -3163,6 +3185,7 @@ merge_files(struct got_worktree *worktree, struct got_ const struct got_error *err = NULL, *sync_err; struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; + struct check_merge_conflicts_arg cmc_arg; struct merge_file_cb_arg arg; char *label_orig = NULL; @@ -3201,6 +3224,14 @@ merge_files(struct got_worktree *worktree, struct got_ if (err) goto done; + cmc_arg.worktree = worktree; + cmc_arg.fileindex = fileindex; + cmc_arg.repo = repo; + err = got_diff_tree(tree1, tree2, "", "", repo, + check_merge_conflicts, &cmc_arg, 0); + if (err) + goto done; + arg.worktree = worktree; arg.fileindex = fileindex; arg.progress_cb = progress_cb; @@ -3231,7 +3262,6 @@ got_worktree_merge_files(struct got_worktree *worktree const struct got_error *err, *unlockerr; char *fileindex_path = NULL; struct got_fileindex *fileindex = NULL; - struct check_merge_ok_arg mok_arg; err = lock_worktree(worktree, LOCK_EX); if (err) @@ -3241,10 +3271,8 @@ got_worktree_merge_files(struct got_worktree *worktree if (err) goto done; - mok_arg.worktree = worktree; - mok_arg.repo = repo; - err = got_fileindex_for_each_entry_safe(fileindex, check_merge_ok, - &mok_arg); + err = got_fileindex_for_each_entry_safe(fileindex, check_mixed_commits, + worktree); if (err) goto done;