commit ea7786be381853efad88beae518c19a391d13791 from: Stefan Sperling date: Thu Jul 23 14:22:38 2020 UTC make 'got unstage' work with symlinks commit - b7422a2f5c775615ff397e14c04aa9c9a41504c1 commit + ea7786be381853efad88beae518c19a391d13791 blob - cec70da8d017f316d73c553fe1f13cb015f3d6e8 blob + d94da1d659df18bb44c73bf7b04d0cfb808d6bd4 --- lib/worktree.c +++ lib/worktree.c @@ -1071,13 +1071,20 @@ merge_symlink(struct got_worktree *worktree, goto done; err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path); } else if (have_local_change && have_incoming_change) { - err = install_symlink_conflict(deriv_target, - deriv_base_commit_id, ancestor_target, label_orig, - ondisk_target, ondisk_path); - if (err) - goto done; - err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT, - path); + if (deriv_len == ondisk_len && + memcmp(deriv_target, ondisk_target, deriv_len) == 0) { + /* Both sides made the same change. */ + err = (*progress_cb)(progress_arg, GOT_STATUS_MERGE, + path); + } else { + err = install_symlink_conflict(deriv_target, + deriv_base_commit_id, ancestor_target, label_orig, + ondisk_target, ondisk_path); + if (err) + goto done; + err = (*progress_cb)(progress_arg, GOT_STATUS_CONFLICT, + path); + } } done: @@ -4578,7 +4585,6 @@ collect_commitables(void *arg, unsigned char status, ct->mode = S_IFLNK; break; default: - fprintf(stderr, "got: ie mode is 0x%x\n", ie->mode); err = got_error_path(path, GOT_ERR_BAD_FILETYPE); goto done; } @@ -7540,11 +7546,26 @@ unstage_path(void *arg, unsigned char status, staged_blob_id, 8192); if (err) break; - err = merge_blob(&local_changes_subsumed, a->worktree, - blob_base, ondisk_path, relpath, - got_fileindex_perms_to_st(ie), label_orig, blob_staged, - commit_id ? commit_id : a->worktree->base_commit_id, - a->repo, a->progress_cb, a->progress_arg); + switch (got_fileindex_entry_staged_filetype_get(ie)) { + case GOT_FILEIDX_MODE_BAD_SYMLINK: + case GOT_FILEIDX_MODE_REGULAR_FILE: + err = merge_blob(&local_changes_subsumed, a->worktree, + blob_base, ondisk_path, relpath, + got_fileindex_perms_to_st(ie), label_orig, + blob_staged, commit_id ? commit_id : + a->worktree->base_commit_id, a->repo, + a->progress_cb, a->progress_arg); + break; + case GOT_FILEIDX_MODE_SYMLINK: + err = merge_symlink(a->worktree, blob_base, ondisk_path, + relpath, got_fileindex_perms_to_st(ie), label_orig, + blob_staged, a->worktree->base_commit_id, a->repo, + a->progress_cb, a->progress_arg); + break; + default: + err = got_error_path(relpath, GOT_ERR_BAD_FILETYPE); + break; + } if (err == NULL) got_fileindex_entry_stage_set(ie, GOT_FILEIDX_STAGE_NONE); blob - ef2a91d696b6b381bc506f6ed946a1bfa9412d17 blob + 90b33b415f9ac6e50f34f0abf71c068ca2f81efb --- regress/cmdline/unstage.sh +++ regress/cmdline/unstage.sh @@ -952,7 +952,189 @@ EOF fi test_done "$testroot" "$ret" } + +function test_unstage_symlink { + local testroot=`test_init unstage_symlink` + + (cd $testroot/repo && ln -s alpha alpha.link) + (cd $testroot/repo && ln -s epsilon epsilon.link) + (cd $testroot/repo && ln -s /etc/passwd passwd.link) + (cd $testroot/repo && ln -s ../beta epsilon/beta.link) + (cd $testroot/repo && ln -s nonexistent nonexistent.link) + (cd $testroot/repo && git add .) + git_commit $testroot/repo -m "add symlinks" + local head_commit=`git_show_head $testroot/repo` + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/wt && ln -sf beta alpha.link) + (cd $testroot/wt && ln -sfh gamma epsilon.link) + (cd $testroot/wt && ln -sf ../gamma/delta epsilon/beta.link) + echo 'this is regular file foo' > $testroot/wt/dotgotfoo.link + (cd $testroot/wt && got add dotgotfoo.link > /dev/null) + (cd $testroot/wt && ln -sf .got/bar dotgotbar.link) + (cd $testroot/wt && got add dotgotbar.link > /dev/null) + (cd $testroot/wt && got rm nonexistent.link > /dev/null) + (cd $testroot/wt && ln -sf gamma/delta zeta.link) + (cd $testroot/wt && got add zeta.link > /dev/null) + + (cd $testroot/wt && got stage > /dev/null) + + (cd $testroot/wt && got status > $testroot/stdout) + cat > $testroot/stdout.expected < $testroot/stdout) + ret="$?" + if [ "$ret" != "0" ]; then + echo "got unstage command failed unexpectedly" >&2 + test_done "$testroot" "1" + return 1 + fi + + cat > $testroot/stdout.expected < $testroot/stdout + echo "beta" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + if [ ! -h $testroot/wt/epsilon.link ]; then + echo "epsilon.link is not a symlink" + test_done "$testroot" "1" + return 1 + fi + + readlink $testroot/wt/epsilon.link > $testroot/stdout + echo "gamma" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + if [ ! -h $testroot/wt/epsilon/beta.link ]; then + echo "epsilon/beta.link is not a symlink" + test_done "$testroot" "1" + return 1 + fi + + readlink $testroot/wt/epsilon/beta.link > $testroot/stdout + echo "../gamma/delta" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + if [ ! -f $testroot/wt/dotgotfoo.link ]; then + echo "dotgotfoo.link is a symlink" + test_done "$testroot" "1" + return 1 + fi + + echo "this is regular file foo" > $testroot/content.expected + cp $testroot/wt/dotgotfoo.link $testroot/content + cmp -s $testroot/content.expected $testroot/content + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/content.expected $testroot/content + test_done "$testroot" "$ret" + return 1 + fi + + # bad symlinks are allowed as-is for commit and stage/unstage + if [ ! -h $testroot/wt/dotgotbar.link ]; then + echo "dotgotbar.link is not a symlink" + test_done "$testroot" "1" + return 1 + fi + + readlink $testroot/wt/dotgotbar.link > $testroot/stdout + echo ".got/bar" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + if [ -e $testroot/wt/nonexistent.link ]; then + echo "nonexistent.link exists on disk" + test_done "$testroot" "1" + return 1 + fi + + if [ ! -h $testroot/wt/zeta.link ]; then + echo "zeta.link is not a symlink" + test_done "$testroot" "1" + return 1 + fi + + readlink $testroot/wt/zeta.link > $testroot/stdout + echo "gamma/delta" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + test_done "$testroot" "0" +} + run_test test_unstage_basic run_test test_unstage_unversioned run_test test_unstage_nonexistent @@ -960,3 +1142,4 @@ run_test test_unstage_patch run_test test_unstage_patch_added run_test test_unstage_patch_removed run_test test_unstage_patch_quit +run_test test_unstage_symlink