git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[WIP v2 0/5] mv: fix out-of-cone file/directory move logic

From
Shaoxuan Yuan <shaoxuan.yuan02@gmail.com>
Date
May 27, 2022, 10:07 UTC
Message-ID
<20220527100804.209890-1-shaoxuan.yuan02@gmail.com>
In-Reply-To
<20220331091755.385961-1-shaoxuan.yuan02@gmail.com>
## Changes since WIP v1 ##
1. Move t7002 tests to the front and turn corresponding tests to 
   test_expect_success along with corresponding commits.
2. Add two tests to t7002.
3. Update check_dir_in_index() and added corresponding documentation.
4. Turn update_mode into enum flags.
5. Use update_sparsity() to replace advise*() function after touching
   sparse contents (this change is INCOMPLETE, NEED FIX).
6. Fix some format issues.
## Limitations ##

This series has not considered moving file from in-cone area to out-of-cone area *yet*. Moving from in-cone to out-of-cone has not been covered/tested. The plan is to add the "in-cone to out-of-cone" functionality later, since this series is WIP for now.

Shaoxuan Yuan (5):
  t7002: add tests for moving out-of-cone file/directory
  mv: check if out-of-cone file exists in index with SKIP_WORKTREE bit
  mv: check if <destination> exists in index to handle overwriting
  mv: add check_dir_in_index() and solve general dir check issue
  mv: use update_sparsity() after touching sparse contents
 builtin/mv.c                  | 104 +++++++++++++++++++++++++++++--
 t/t7002-mv-sparse-checkout.sh | 114 ++++++++++++++++++++++++++++++++++
 2 files changed, 212 insertions(+), 6 deletions(-)
Range-diff against v1:
4:  1dd2fcb234 ! 1:  485d1e9102 t7002: add tests for moving out-of-cone file/directory
    @@ Commit message
         * 'can move out-of-cone directory with --sparse'
         * 'refuse to move out-of-cone file without --sparse'
         * 'can move out-of-cone file with --sparse'
    +    * 'refuse to move sparse file to existing destination'
    +    * 'move sparse file to existing destination with --force and --sparse'
     
         Signed-off-by: Shaoxuan Yuan <shaoxuan.yuan02@gmail.com>
     
    @@ t/t7002-mv-sparse-checkout.sh: test_expect_success 'refuse to move file to non-s
      	test_cmp expect stderr
      '
      
    -+test_expect_success 'refuse to move out-of-cone directory without --sparse' '
    ++test_expect_failure 'refuse to move out-of-cone directory without --sparse' '
     +	git sparse-checkout disable &&
     +	git reset --hard &&
     +	mkdir folder1 &&
    @@ t/t7002-mv-sparse-checkout.sh: test_expect_success 'refuse to move file to non-s
     +	test_cmp expect stderr
     +'
     +
    -+test_expect_success 'can move out-of-cone directory with --sparse' '
    ++test_expect_failure 'can move out-of-cone directory with --sparse' '
     +	git sparse-checkout disable &&
     +	git reset --hard &&
     +	mkdir folder1 &&
    @@ t/t7002-mv-sparse-checkout.sh: test_expect_success 'refuse to move file to non-s
     +
     +	git mv --sparse folder1 sub 1>actual 2>stderr &&
     +	test_must_be_empty stderr &&
    -+	echo "Please use \"git sparse-checkout reapply\" to reapply the sparsity."\
    -+	>expect &&
    -+	test_cmp actual expect &&
     +
     +	git sparse-checkout reapply &&
     +	test_path_is_dir sub/folder1 &&
     +	test_path_is_file sub/folder1/file1
     +'
     +
    -+test_expect_success 'refuse to move out-of-cone file without --sparse' '
    ++test_expect_failure 'refuse to move out-of-cone file without --sparse' '
     +	git sparse-checkout disable &&
     +	git reset --hard &&
     +	mkdir folder1 &&
    @@ t/t7002-mv-sparse-checkout.sh: test_expect_success 'refuse to move file to non-s
     +	test_cmp expect stderr
     +'
     +
    -+test_expect_success 'can move out-of-cone file with --sparse' '
    ++test_expect_failure 'can move out-of-cone file with --sparse' '
     +	git sparse-checkout disable &&
     +	git reset --hard &&
     +	mkdir folder1 &&
    @@ t/t7002-mv-sparse-checkout.sh: test_expect_success 'refuse to move file to non-s
     +
     +	git mv --sparse folder1/file1 sub 1>actual 2>stderr &&
     +	test_must_be_empty stderr &&
    -+	echo "Please use \"git sparse-checkout reapply\" to reapply the sparsity."\
    -+	>expect &&
    -+	test_cmp actual expect &&
     +
     +	git sparse-checkout reapply &&
     +	! test_path_is_dir sub/folder1 &&
     +	test_path_is_file sub/file1
     +'
    ++
    ++test_expect_failure 'refuse to move sparse file to existing destination' '
    ++	git sparse-checkout disable &&
    ++	git reset --hard &&
    ++	mkdir folder1 &&
    ++	touch folder1/file1 &&
    ++	touch sub/file1 &&
    ++	git add folder1 sub/file1 &&
    ++	git sparse-checkout init --cone &&
    ++	git sparse-checkout set sub &&
    ++
    ++	test_must_fail git mv --sparse folder1/file1 sub 2>stderr &&
    ++	echo "fatal: destination exists, source=folder1/file1, destination=sub/file1" >expect &&
    ++	test_cmp expect stderr
    ++'
    ++
    ++test_expect_failure 'move sparse file to existing destination with --force and --sparse' '
    ++	git sparse-checkout disable &&
    ++	git reset --hard &&
    ++	mkdir folder1 &&
    ++	touch folder1/file1 &&
    ++	touch sub/file1 &&
    ++	echo "overwrite" >folder1/file1 &&
    ++	git add folder1 sub/file1 &&
    ++	git sparse-checkout init --cone &&
    ++	git sparse-checkout set sub &&
    ++
    ++	git mv --sparse --force folder1/file1 sub 2>stderr &&
    ++	test_must_be_empty stderr &&
    ++	echo "overwrite" >expect &&
    ++	test_cmp expect sub/file1
    ++'
     +
      test_done
1:  5cf6b860e3 ! 2:  c99df4fc1a mv: check if out-of-cone file exists in index with SKIP_WORKTREE bit
    @@ builtin/mv.c: int cmd_mv(int argc, const char **argv, const char *prefix)
      				bad = _("bad source");
      		} else if (!strncmp(src, dst, length) &&
      				(dst[length] == 0 || dst[length] == '/')) {
    +
    + ## t/t7002-mv-sparse-checkout.sh ##
    +@@ t/t7002-mv-sparse-checkout.sh: test_expect_failure 'can move out-of-cone directory with --sparse' '
    + 	test_path_is_file sub/folder1/file1
    + '
    + 
    +-test_expect_failure 'refuse to move out-of-cone file without --sparse' '
    ++test_expect_success 'refuse to move out-of-cone file without --sparse' '
    + 	git sparse-checkout disable &&
    + 	git reset --hard &&
    + 	mkdir folder1 &&
    +@@ t/t7002-mv-sparse-checkout.sh: test_expect_failure 'refuse to move out-of-cone file without --sparse' '
    + 	test_cmp expect stderr
    + '
    + 
    +-test_expect_failure 'can move out-of-cone file with --sparse' '
    ++test_expect_success 'can move out-of-cone file with --sparse' '
    + 	git sparse-checkout disable &&
    + 	git reset --hard &&
    + 	mkdir folder1 &&
-:  ---------- > 3:  8f1193188b mv: check if <destination> exists in index to handle overwriting
2:  7b3c931f3f ! 4:  e195bfbc73 mv: add check_dir_in_index() and solve general dir check issue
    @@ Commit message
         errors out with "bad source".
     
         Add a helper check_dir_in_index() function to see if a directory
    -    name exists in the index. Also add a SPARSE_DIRECTORY bit to mark
    +    name exists in the index. Also add a SKIP_WORKTREE_DIR bit to mark
         such directories.
     
         Change the checking logic, so that such <source> directory makes
    @@ Commit message
         instead of "bad source"; also user now can supply a "--sparse" flag so
         this operation can be carried out successfully.
     
    +    Also, as suggested by Derrick [1],
    +    move the in-line definition of "enum update_mode" to the top
    +    of the file and make it use "flags" mode (each state is a different
    +    bit in the word).
    +
    +    [1] https://lore.kernel.org/git/22aadea2-9330-aa9e-7b6a-834585189144@github.com/
    +
         Signed-off-by: Shaoxuan Yuan <shaoxuan.yuan02@gmail.com>
     
      ## builtin/mv.c ##
    +@@ builtin/mv.c: static const char * const builtin_mv_usage[] = {
    + 	NULL
    + };
    + 
    ++enum update_mode {
    ++	BOTH = 0,
    ++	WORKING_DIRECTORY = (1 << 1),
    ++	INDEX = (1 << 2),
    ++	SPARSE = (1 << 3),
    ++	SKIP_WORKTREE_DIR = (1 << 4),
    ++};
    ++
    + #define DUP_BASENAME 1
    + #define KEEP_TRAILING_SLASH 2
    + 
     @@ builtin/mv.c: static int index_range_of_same_dir(const char *src, int length,
      	return last - first;
      }
      
    -+static int check_dir_in_index(const char *dir)
    ++/*
    ++ * Check if an out-of-cone directory should be in the index. Imagine this case
    ++ * that all the files under a directory are marked with 'CE_SKIP_WORKTREE' bit
    ++ * and thus the directory is sparsified.
    ++ *
    ++ * Return 0 if such directory exist (i.e. with any of its contained files not
    ++ * marked with CE_SKIP_WORKTREE, the directory would be present in working tree).
    ++ * Return 1 otherwise.
    ++ */
    ++static int check_dir_in_index(const char *name, int namelen)
     +{
    -+	int ret = 0;
    -+	int length = sizeof(dir) + 1;
    -+	char *substr = malloc(length);
    ++	int ret = 1;
    ++	const char *with_slash = add_slash(name);
    ++	int length = namelen + 1;
     +
    -+	for (int i = 0; i < the_index.cache_nr; i++) {
    -+		memcpy(substr, the_index.cache[i]->name, length);
    -+		memset(substr + length - 1, 0, 1);
    ++	int pos = cache_name_pos(with_slash, length);
    ++	const struct cache_entry *ce;
     +
    -+		if (strcmp(dir, substr) == 0) {
    -+			ret = 1;
    ++	if (pos < 0) {
    ++		pos = -pos - 1;
    ++		if (pos >= the_index.cache_nr)
     +			return ret;
    -+		}
    ++		ce = active_cache[pos];
    ++		if (strncmp(with_slash, ce->name, length))
    ++			return ret;
    ++		if (ce_skip_worktree(ce))
    ++			return ret = 0;
     +	}
    -+	free(substr);
     +	return ret;
     +}
     +
    @@ builtin/mv.c: int cmd_mv(int argc, const char **argv, const char *prefix)
      	};
      	const char **source, **destination, **dest_path, **submodule_gitfile;
     -	enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX, SPARSE } *modes;
    -+	enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX, SPARSE,
    -+	SPARSE_DIRECTORY } *modes;
    ++	enum update_mode *modes;
      	struct stat st;
      	struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
      	struct lock_file lock_file = LOCK_INIT;
     @@ builtin/mv.c: int cmd_mv(int argc, const char **argv, const char *prefix)
    - 			 */
    + 		if (lstat(src, &st) < 0) {
      
      			int pos = cache_name_pos(src, length);
     +			const char *src_w_slash = add_slash(src);
    @@ builtin/mv.c: int cmd_mv(int argc, const char **argv, const char *prefix)
      				else
      					bad = _("bad source");
      			}
    -+			else if (check_dir_in_index(src_w_slash) &&
    -+			!path_in_sparse_checkout(src_w_slash, &the_index)) {
    -+				modes[i] = SPARSE_DIRECTORY;
    ++			else if (!check_dir_in_index(src, length) &&
    ++					 !path_in_sparse_checkout(src_w_slash, &the_index)) {
    ++				modes[i] = SKIP_WORKTREE_DIR;
     +				goto dir_check;
     +			}
      			/* only error if existence is expected. */
    @@ builtin/mv.c: int cmd_mv(int argc, const char **argv, const char *prefix)
      
     -				modes[i] = WORKING_DIRECTORY;
     +				if (!modes[i])
    -+					modes[i] = WORKING_DIRECTORY;
    ++					modes[i] |= WORKING_DIRECTORY;
      				n = argc + last - first;
      				REALLOC_ARRAY(source, n);
      				REALLOC_ARRAY(destination, n);
    @@ builtin/mv.c: int cmd_mv(int argc, const char **argv, const char *prefix)
      		if (show_only)
      			continue;
     -		if (mode != INDEX && mode != SPARSE && rename(src, dst) < 0) {
    -+		if (mode != INDEX && mode != SPARSE && mode != SPARSE_DIRECTORY &&
    -+		 rename(src, dst) < 0) {
    ++		if (!(mode & (INDEX | SPARSE | SKIP_WORKTREE_DIR)) &&
    ++		 	rename(src, dst) < 0) {
      			if (ignore_errors)
      				continue;
      			die_errno(_("renaming '%s' failed"), src);
    @@ builtin/mv.c: int cmd_mv(int argc, const char **argv, const char *prefix)
      		}
      
     -		if (mode == WORKING_DIRECTORY)
    -+		if (mode == WORKING_DIRECTORY || mode == SPARSE_DIRECTORY)
    ++		if (mode & (WORKING_DIRECTORY | SKIP_WORKTREE_DIR))
      			continue;
      
      		pos = cache_name_pos(src, strlen(src));
    +
    + ## t/t7002-mv-sparse-checkout.sh ##
    +@@ t/t7002-mv-sparse-checkout.sh: test_expect_success 'refuse to move file to non-skip-worktree sparse path' '
    + 	test_cmp expect stderr
    + '
    + 
    +-test_expect_failure 'refuse to move out-of-cone directory without --sparse' '
    ++test_expect_success 'refuse to move out-of-cone directory without --sparse' '
    + 	git sparse-checkout disable &&
    + 	git reset --hard &&
    + 	mkdir folder1 &&
    +@@ t/t7002-mv-sparse-checkout.sh: test_expect_failure 'refuse to move out-of-cone directory without --sparse' '
    + 	test_cmp expect stderr
    + '
    + 
    +-test_expect_failure 'can move out-of-cone directory with --sparse' '
    ++test_expect_success 'can move out-of-cone directory with --sparse' '
    + 	git sparse-checkout disable &&
    + 	git reset --hard &&
    + 	mkdir folder1 &&
3:  4be4c4f34d < -:  ---------- mv: add advise_to_reapply hint for moving file into cone
-:  ---------- > 5:  aa82ba56b0 mv: use update_sparsity() after touching sparse contents
-- 
2.35.1
Previous: Shaoxuan YuanNext: Shaoxuan Yuan
Message 28 of 95 in “[WIP v1 0/4] mv: fix out-of-cone file/directory move logic”
  1. Shaoxuan YuanMar 31, 2022
  2. 1/4 mv: check if out-of-cone file exists in index with SKIP_WORKTREE bitShaoxuan Yuan, Mar 31, 2022
  3. Victoria DyeMar 31, 2022
  4. Derrick StoleeApr 1, 2022
  5. 2/4 mv: add check_dir_in_index() and solve general dir check issueShaoxuan Yuan, Mar 31, 2022
  6. Ævar Arnfjörð BjarmasonMar 31, 2022
  7. Shaoxuan YuanApr 1, 2022
  8. Victoria DyeMar 31, 2022
  9. Shaoxuan YuanApr 1, 2022
  10. Derrick StoleeApr 1, 2022
  11. Shaoxuan YuanApr 4, 2022
  12. Shaoxuan YuanApr 4, 2022
  13. Derrick StoleeApr 4, 2022
  14. 3/4 mv: add advise_to_reapply hint for moving file into coneShaoxuan Yuan, Mar 31, 2022
  15. Ævar Arnfjörð BjarmasonMar 31, 2022
  16. Shaoxuan YuanApr 1, 2022
  17. Ævar Arnfjörð BjarmasonApr 1, 2022
  18. Eric SunshineApr 3, 2022
  19. Victoria DyeMar 31, 2022
  20. Derrick StoleeApr 1, 2022
  21. 4/4 t7002: add tests for moving out-of-cone file/directoryShaoxuan Yuan, Mar 31, 2022
  22. Ævar Arnfjörð BjarmasonMar 31, 2022
  23. Victoria DyeMar 31, 2022
  24. Shaoxuan YuanMar 31, 2022
  25. Victoria DyeMar 31, 2022
  26. Shaoxuan YuanApr 1, 2022
  27. Shaoxuan YuanApr 8, 2022
  28. 0/5 mv: fix out-of-cone file/directory move logicShaoxuan Yuan, May 27, 2022
  29. 1/5 t7002: add tests for moving out-of-cone file/directoryShaoxuan Yuan, May 27, 2022
  30. Ævar Arnfjörð BjarmasonMay 27, 2022
  31. Derrick StoleeMay 27, 2022
  32. Victoria DyeMay 27, 2022
  33. 2/5 mv: check if out-of-cone file exists in index with SKIP_WORKTREE bitShaoxuan Yuan, May 27, 2022
  34. Derrick StoleeMay 27, 2022
  35. Victoria DyeMay 27, 2022
  36. Shaoxuan YuanMay 31, 2022
  37. 3/5 mv: check if <destination> exists in index to handle overwritingShaoxuan Yuan, May 27, 2022
  38. Victoria DyeMay 27, 2022
  39. 4/5 mv: add check_dir_in_index() and solve general dir check issueShaoxuan Yuan, May 27, 2022
  40. Derrick StoleeMay 27, 2022
  41. Shaoxuan YuanMay 31, 2022
  42. Derrick StoleeMay 31, 2022
  43. 5/5 mv: use update_sparsity() after touching sparse contentsShaoxuan Yuan, May 27, 2022
  44. Ævar Arnfjörð BjarmasonMay 27, 2022
  45. Victoria DyeMay 27, 2022
  46. Junio C HamanoMay 27, 2022
  47. Victoria DyeMay 27, 2022
  48. Shaoxuan YuanJun 16, 2022
  49. Victoria DyeJun 16, 2022
  50. Shaoxuan YuanJun 17, 2022
  51. 0/7 mv: fix out-of-cone file/directory move logicShaoxuan Yuan, Jun 19, 2022
  52. 1/7 t7002: add tests for moving out-of-cone file/directoryShaoxuan Yuan, Jun 19, 2022
  53. Victoria DyeJun 21, 2022
  54. 2/7 mv: decouple if/else-if checks using gotoShaoxuan Yuan, Jun 19, 2022
  55. 3/7 mv: check if out-of-cone file exists in index with SKIP_WORKTREE bitShaoxuan Yuan, Jun 19, 2022
  56. 4/7 mv: check if <destination> exists in index to handle overwritingShaoxuan Yuan, Jun 19, 2022
  57. 5/7 mv: use flags mode for update_modeShaoxuan Yuan, Jun 19, 2022
  58. Victoria DyeJun 21, 2022
  59. Shaoxuan YuanJun 22, 2022
  60. 6/7 mv: add check_dir_in_index() and solve general dir check issueShaoxuan Yuan, Jun 19, 2022
  61. Victoria DyeJun 21, 2022
  62. 7/7 mv: update sparsity after moving from out-of-cone to in-coneShaoxuan Yuan, Jun 19, 2022
  63. Victoria DyeJun 21, 2022
  64. Victoria DyeJun 21, 2022
  65. Derrick StoleeJun 23, 2022
  66. Junio C HamanoJun 23, 2022
  67. Shaoxuan YuanJun 24, 2022
  68. 0/7 mv: fix out-of-cone file/directory move logicShaoxuan Yuan, Jun 23, 2022
  69. 1/7 t7002: add tests for moving out-of-cone file/directoryShaoxuan Yuan, Jun 23, 2022
  70. 2/7 mv: update sparsity after moving from out-of-cone to in-coneShaoxuan Yuan, Jun 23, 2022
  71. Derrick StoleeJun 23, 2022
  72. Shaoxuan YuanJun 24, 2022
  73. Derrick StoleeJun 27, 2022
  74. 3/7 mv: decouple if/else-if checks using gotoShaoxuan Yuan, Jun 23, 2022
  75. 4/7 mv: check if out-of-cone file exists in index with SKIP_WORKTREE bitShaoxuan Yuan, Jun 23, 2022
  76. 5/7 mv: check if <destination> exists in index to handle overwritingShaoxuan Yuan, Jun 23, 2022
  77. 6/7 mv: use flags mode for update_modeShaoxuan Yuan, Jun 23, 2022
  78. Derrick StoleeJun 23, 2022
  79. 7/7 mv: add check_dir_in_index() and solve general dir check issueShaoxuan Yuan, Jun 23, 2022
  80. Derrick StoleeJun 23, 2022
  81. Shaoxuan YuanJun 24, 2022
  82. Derrick StoleeJun 27, 2022
  83. Derrick StoleeJun 23, 2022
  84. Junio C HamanoJun 23, 2022
  85. 0/8 mv: fix out-of-cone file/directory move logicShaoxuan Yuan, Jun 30, 2022
  86. 1/8 t7002: add tests for moving out-of-cone file/directoryShaoxuan Yuan, Jun 30, 2022
  87. 2/8 t1092: mv directory from out-of-cone to in-coneShaoxuan Yuan, Jun 30, 2022
  88. 3/8 mv: update sparsity after moving from out-of-cone to in-coneShaoxuan Yuan, Jun 30, 2022
  89. 4/8 mv: decouple if/else-if checks using gotoShaoxuan Yuan, Jun 30, 2022
  90. 5/8 mv: check if out-of-cone file exists in index with SKIP_WORKTREE bitShaoxuan Yuan, Jun 30, 2022
  91. 6/8 mv: check if <destination> exists in index to handle overwritingShaoxuan Yuan, Jun 30, 2022
  92. 7/8 mv: use flags mode for update_modeShaoxuan Yuan, Jun 30, 2022
  93. 8/8 mv: add check_dir_in_index() and solve general dir check issueShaoxuan Yuan, Jun 30, 2022
  94. Derrick StoleeJul 1, 2022
  95. Junio C HamanoJul 1, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.