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

[PATCH 2/2] ignorecase: Fix git mv on insensitive filesystems

From
dturner@twopensource.com <dturner@twopensource.com>
Date
May 6, 2014, 22:59 UTC
Message-ID
<1399417144-24864-2-git-send-email-dturner@twopensource.com>
In-Reply-To
<1399417144-24864-1-git-send-email-dturner@twopensource.com>
From: David Turner <dturner@twitter.com>

Make it possible to change the case of a filename on a case-insensitive filesystem using git mv. Change git mv to allow moves where the destination file exists if either the destination file has the same inode as the source file (for Mac) or the same name ignoring case (for Win).

Signed-off-by: David Turner <dturner@twitter.com>
---
 builtin/mv.c                | 18 ++++++++++--------
 t/t6039-merge-ignorecase.sh |  2 +-
 2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/builtin/mv.c b/builtin/mv.c
index 45e57f3..8cead13 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -74,7 +74,7 @@ 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 } *modes;
-	struct stat st;
+	struct stat src_st,dst_st;
 	struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
 
 	gitmodules_config();
@@ -102,8 +102,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 	if (dest_path[0][0] == '\0')
 		/* special case: "." was normalized to "" */
 		destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
-	else if (!lstat(dest_path[0], &st) &&
-			S_ISDIR(st.st_mode)) {
+	else if (!lstat(dest_path[0], &dst_st) &&
+			S_ISDIR(dst_st.st_mode)) {
 		dest_path[0] = add_slash(dest_path[0]);
 		destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
 	} else {
@@ -122,13 +122,13 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 			printf(_("Checking rename of '%s' to '%s'\n"), src, dst);
 
 		length = strlen(src);
-		if (lstat(src, &st) < 0)
+		if (lstat(src, &src_st) < 0)
 			bad = _("bad source");
 		else if (!strncmp(src, dst, length) &&
 				(dst[length] == 0 || dst[length] == '/')) {
 			bad = _("can not move directory into itself");
-		} else if ((src_is_dir = S_ISDIR(st.st_mode))
-				&& lstat(dst, &st) == 0)
+		} else if ((src_is_dir = S_ISDIR(src_st.st_mode))
+				&& lstat(dst, &dst_st) == 0)
 			bad = _("cannot move directory over file");
 		else if (src_is_dir) {
 			int first = cache_name_pos(src, length);
@@ -202,14 +202,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 			}
 		} else if (cache_name_pos(src, length) < 0)
 			bad = _("not under version control");
-		else if (lstat(dst, &st) == 0) {
+		else if (lstat(dst, &dst_st) == 0 &&
+			 (src_st.st_ino != dst_st.st_ino ||
+			  (src_st.st_ino == 0 && strcasecmp(src, dst)))) {
 			bad = _("destination exists");
 			if (force) {
 				/*
 				 * only files can overwrite each other:
 				 * check both source and destination
 				 */
-				if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
+				if (S_ISREG(dst_st.st_mode) || S_ISLNK(dst_st.st_mode)) {
 					if (verbose)
 						warning(_("overwriting '%s'"), dst);
 					bad = NULL;
diff --git a/t/t6039-merge-ignorecase.sh b/t/t6039-merge-ignorecase.sh
index ad06752..28cfb49 100755
--- a/t/t6039-merge-ignorecase.sh
+++ b/t/t6039-merge-ignorecase.sh
@@ -35,7 +35,7 @@ test_expect_success 'merge with case-changing rename on both sides' '
 	git reset --hard baseline &&
 	git branch -D with-camel &&
 	git checkout -b with-camel &&
-	git mv --force TestCase testcase &&
+	git mv TestCase testcase &&
 	git commit -m "recase on branch" &&
 	> foo &&
 	git add foo &&
-- 
2.0.0.rc0.33.g27630aa
Previous: dturner@twopensource.comNext: Johannes Sixt
Message 7 of 24 in “Bug: Case-insensitive filesystems can cause merge and checkout problems”
  1. David TurnerApr 29, 2014
  2. merge-recursive.c: Fix case-changing merge bugDavid Turner, May 2, 2014
  3. Junio C HamanoMay 6, 2014
  4. David TurnerMay 6, 2014
  5. Junio C HamanoMay 6, 2014
  6. 1/2 merge-recursive.c: Fix case-changing merge.dturner@twopensource.com, May 6, 2014
  7. 2/2 ignorecase: Fix git mv on insensitive filesystemsdturner@twopensource.com, May 6, 2014
  8. Johannes SixtMay 7, 2014
  9. David TurnerMay 7, 2014
  10. Junio C HamanoMay 7, 2014
  11. David TurnerMay 7, 2014
  12. Johannes SixtMay 8, 2014
  13. Torsten BögershausenMay 8, 2014
  14. 0/2 Re: ignorecase: Fix git mv on insensitive filesystemsdturner@twopensource.com, May 8, 2014
  15. 1/2 merge-recursive.c: Fix case-changing merge.dturner@twopensource.com, May 8, 2014
  16. Junio C HamanoMay 8, 2014
  17. 2/2 ignorecase: Fix git mv on insensitive filesystemsdturner@twopensource.com, May 8, 2014
  18. Junio C HamanoMay 8, 2014
  19. David TurnerMay 8, 2014
  20. Junio C HamanoMay 8, 2014
  21. brian m. carlsonMay 8, 2014
  22. Junio C HamanoMay 7, 2014
  23. Jonathan NiederMay 7, 2014
  24. Junio C HamanoMay 7, 2014

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.