commit 9a298e5c10f6c68afbaca853454de2787a312c81 from: Stefan Sperling date: Fri Mar 10 09:40:21 2023 UTC support histedit fold operations which delete a file and then add it again problem found by naddy@ ok op@ commit - 8d98a775225f31c6c2c71c5d40f1d323a6f552bd commit + 9a298e5c10f6c68afbaca853454de2787a312c81 blob - f391c9b29f69de0b5abb466e2cd2bd6e65ae9dde blob + 19b8418d8d3b6252476d3f2048056a0c997b1377 --- lib/fileindex.c +++ lib/fileindex.c @@ -128,7 +128,7 @@ got_fileindex_entry_update(struct got_fileindex_entry } if (blob_sha1) { - memcpy(ie->blob_sha1, blob_sha1, SHA1_DIGEST_LENGTH); + memmove(ie->blob_sha1, blob_sha1, SHA1_DIGEST_LENGTH); ie->flags &= ~GOT_FILEIDX_F_NO_BLOB; } else ie->flags |= GOT_FILEIDX_F_NO_BLOB; blob - d7bd842e2f1e138573c94334a50105954443372d blob + ce1ab2adbfadcbf6d57d031d9390a6d8a3940fb8 --- lib/worktree.c +++ lib/worktree.c @@ -2853,6 +2853,66 @@ done: return err; } +static const struct got_error * +add_file(struct got_worktree *worktree, struct got_fileindex *fileindex, + struct got_fileindex_entry *ie, const char *ondisk_path, + const char *path2, struct got_blob_object *blob2, mode_t mode2, + int restoring_missing_file, int reverting_versioned_file, + int path_is_unversioned, int allow_bad_symlinks, + struct got_repository *repo, + got_worktree_checkout_cb progress_cb, void *progress_arg) +{ + const struct got_error *err = NULL; + int is_bad_symlink = 0; + + if (S_ISLNK(mode2)) { + err = install_symlink(&is_bad_symlink, + worktree, ondisk_path, path2, blob2, + restoring_missing_file, + reverting_versioned_file, + path_is_unversioned, allow_bad_symlinks, + repo, progress_cb, progress_arg); + } else { + err = install_blob(worktree, ondisk_path, path2, + mode2, GOT_DEFAULT_FILE_MODE, blob2, + restoring_missing_file, reverting_versioned_file, 0, + path_is_unversioned, repo, progress_cb, progress_arg); + } + if (err) + return err; + if (ie == NULL) { + /* Adding an unversioned file. */ + err = got_fileindex_entry_alloc(&ie, path2); + if (err) + return err; + err = got_fileindex_entry_update(ie, + worktree->root_fd, path2, NULL, NULL, 1); + if (err) { + got_fileindex_entry_free(ie); + return err; + } + err = got_fileindex_entry_add(fileindex, ie); + if (err) { + got_fileindex_entry_free(ie); + return err; + } + } else { + /* Re-adding a locally deleted file. */ + err = got_fileindex_entry_update(ie, + worktree->root_fd, path2, ie->blob_sha1, + worktree->base_commit_id->sha1, 0); + if (err) + return err; + } + + if (is_bad_symlink) { + got_fileindex_entry_filetype_set(ie, + GOT_FILEIDX_MODE_BAD_SYMLINK); + } + + return NULL; +} + struct merge_file_cb_arg { struct got_worktree *worktree; struct got_fileindex *fileindex; @@ -3070,7 +3130,8 @@ merge_file_cb(void *arg, struct got_blob_object *blob1 if (status != GOT_STATUS_NO_CHANGE && status != GOT_STATUS_MODIFY && status != GOT_STATUS_CONFLICT && - status != GOT_STATUS_ADD) { + status != GOT_STATUS_ADD && + status != GOT_STATUS_DELETE) { err = (*a->progress_cb)(a->progress_arg, status, path2); goto done; @@ -3092,52 +3153,28 @@ merge_file_cb(void *arg, struct got_blob_object *blob1 sb.st_mode, a->label_orig, blob2, a->commit_id2, repo, a->progress_cb, a->progress_arg); - } else { + } else if (status != GOT_STATUS_DELETE) { err = got_error_path(ondisk_path, GOT_ERR_FILE_OBSTRUCTED); } if (err) goto done; if (status == GOT_STATUS_DELETE) { - err = got_fileindex_entry_update(ie, - a->worktree->root_fd, path2, blob2->id.sha1, - a->worktree->base_commit_id->sha1, 0); + /* Re-add file with content from new blob. */ + err = add_file(a->worktree, a->fileindex, ie, + ondisk_path, path2, blob2, mode2, + 0, 0, 0, a->allow_bad_symlinks, + repo, a->progress_cb, a->progress_arg); if (err) goto done; } } else { - int is_bad_symlink = 0; - sb.st_mode = GOT_DEFAULT_FILE_MODE; - if (S_ISLNK(mode2)) { - err = install_symlink(&is_bad_symlink, - a->worktree, ondisk_path, path2, blob2, 0, - 0, 1, a->allow_bad_symlinks, repo, - a->progress_cb, a->progress_arg); - } else { - err = install_blob(a->worktree, ondisk_path, path2, - mode2, sb.st_mode, blob2, 0, 0, 0, 1, repo, - a->progress_cb, a->progress_arg); - } + err = add_file(a->worktree, a->fileindex, NULL, + ondisk_path, path2, blob2, mode2, + 0, 0, 1, a->allow_bad_symlinks, + repo, a->progress_cb, a->progress_arg); if (err) - goto done; - err = got_fileindex_entry_alloc(&ie, path2); - if (err) - goto done; - err = got_fileindex_entry_update(ie, - a->worktree->root_fd, path2, NULL, NULL, 1); - if (err) { - got_fileindex_entry_free(ie); - goto done; - } - err = got_fileindex_entry_add(a->fileindex, ie); - if (err) { - got_fileindex_entry_free(ie); goto done; - } - if (is_bad_symlink) { - got_fileindex_entry_filetype_set(ie, - GOT_FILEIDX_MODE_BAD_SYMLINK); - } } } done: blob - b4517778fe90cf2ff3cb089a57a6fc0b911217dc blob + 4837661a3f1d3724a4c7b8a235329ae2d6330c0f --- regress/cmdline/histedit.sh +++ regress/cmdline/histedit.sh @@ -1590,18 +1590,20 @@ test_histedit_fold_delete_add() { echo "Switching work tree to refs/heads/master" \ >> $testroot/stdout.expected - #cmp -s $testroot/stdout.expected $testroot/stdout - #ret=$? - #if [ $ret -ne 0 ]; then - # diff -u $testroot/stdout.expected $testroot/stdout - # test_done "$testroot" "$ret" - # return 1 - #fi + cmp -s $testroot/stdout.expected $testroot/stdout + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi if [ ! -e $testroot/wt/alpha ]; then - ret="xfail fold deleted and added file" + echo "file alpha is missing on disk" >&2 + test_done "$testroot" "1" + return 1 fi - test_done "$testroot" "$ret" + test_done "$testroot" "0" } test_histedit_fold_only() {