From c5203bdf66531c848a2b6cd74f3c02cb18286c55 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Date: Fri, 18 Aug 2006 12:42:39 +0200
Subject: [PATCH 1/3] git-mv: special case destination "."

Since the normalized basename of "." is "", the check for directory
failed erroneously.

Noticed by Fredrik Kuivinen.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 builtin-mv.c  | 5 ++++-
 t/t7001-mv.sh | 4 ++++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/builtin-mv.c b/builtin-mv.c
index c0c8764f7fa..b2ecc26f238 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -114,7 +114,10 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 	modes = xcalloc(count, sizeof(enum update_mode));
 	dest_path = copy_pathspec(prefix, argv + argc - 1, 1, 0);
 
-	if (!lstat(dest_path[0], &st) &&
+	if (dest_path[0][0] == '\0')
+		/* special case: "." was normalized to "" */
+		destination = copy_pathspec(dest_path[0], argv + i, count, 1);
+	else if (!lstat(dest_path[0], &st) &&
 			S_ISDIR(st.st_mode)) {
 		dest_path[0] = add_slash(dest_path[0]);
 		destination = copy_pathspec(dest_path[0], argv + i, count, 1);
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index e5e0bb9d513..b7fcdb390c5 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -82,4 +82,8 @@ test_expect_failure \
     'do not move directory over existing directory' \
     'mkdir path0 && mkdir path0/path2 && git-mv path2 path0'
 
+test_expect_success \
+    'move into "."' \
+    'git-mv path1/path2/ .'
+
 test_done

From 6e17886d376ee8480cc9a8b9bc5046f2d721565f Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Date: Mon, 21 Aug 2006 22:22:25 +0200
Subject: [PATCH 2/3] git-mv: fix off-by-one error

Embarassing.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 builtin-mv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin-mv.c b/builtin-mv.c
index b2ecc26f238..e3bc7a86bb0 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -26,7 +26,7 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
 		if (length > 0 && result[i][length - 1] == '/') {
 			char *without_slash = xmalloc(length);
 			memcpy(without_slash, result[i], length - 1);
-			without_slash[length] = '\0';
+			without_slash[length - 1] = '\0';
 			result[i] = without_slash;
 		}
 		if (base_name) {

From 60a6bf5f53635005f4f68d8b8a33172309193623 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Date: Sat, 19 Aug 2006 16:52:21 +0200
Subject: [PATCH 3/3] builtin-mv: readability patch

The old version was not liked at all. This is hopefully better. Oh, and it
gets rid of the goto.

Note that it does not change any functionality.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 builtin-mv.c | 102 ++++++++++++++++++++++-----------------------------
 1 file changed, 43 insertions(+), 59 deletions(-)

diff --git a/builtin-mv.c b/builtin-mv.c
index e3bc7a86bb0..ff882bec474 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -129,48 +129,43 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 
 	/* Checking */
 	for (i = 0; i < count; i++) {
-		int length;
+		const char *src = source[i], *dst = destination[i];
+		int length, src_is_dir;
 		const char *bad = NULL;
 
 		if (show_only)
-			printf("Checking rename of '%s' to '%s'\n",
-				source[i], destination[i]);
+			printf("Checking rename of '%s' to '%s'\n", src, dst);
 
-		if (lstat(source[i], &st) < 0)
+		length = strlen(src);
+		if (lstat(src, &st) < 0)
 			bad = "bad source";
-
-		if (!bad &&
-		    (length = strlen(source[i])) >= 0 &&
-		    !strncmp(destination[i], source[i], length) &&
-		    (destination[i][length] == 0 || destination[i][length] == '/'))
+		else if (!strncmp(src, dst, length) &&
+				(dst[length] == 0 || dst[length] == '/')) {
 			bad = "can not move directory into itself";
-
-		if (S_ISDIR(st.st_mode)) {
-			const char *dir = source[i], *dest_dir = destination[i];
-			int first, last, len = strlen(dir);
-
-			if (lstat(dest_dir, &st) == 0) {
-				bad = "cannot move directory over file";
-				goto next;
-			}
+		} else if ((src_is_dir = S_ISDIR(st.st_mode))
+				&& lstat(dst, &st) == 0)
+			bad = "cannot move directory over file";
+		else if (src_is_dir) {
+			int first, last;
 
 			modes[i] = WORKING_DIRECTORY;
 
-			first = cache_name_pos(source[i], len);
+			first = cache_name_pos(src, length);
 			if (first >= 0)
-				die ("Huh? %s/ is in index?", dir);
+				die ("Huh? %s/ is in index?", src);
 
 			first = -1 - first;
 			for (last = first; last < active_nr; last++) {
 				const char *path = active_cache[last]->name;
-				if (strncmp(path, dir, len) || path[len] != '/')
+				if (strncmp(path, src, length)
+						|| path[length] != '/')
 					break;
 			}
 
 			if (last - first < 1)
 				bad = "source directory is empty";
-			else if (!bad) {
-				int j, dst_len = strlen(dest_dir);
+			else {
+				int j, dst_len;
 
 				if (last - first > 0) {
 					source = realloc(source,
@@ -184,24 +179,21 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 							* sizeof(enum update_mode));
 				}
 
-				dest_dir = add_slash(dest_dir);
+				dst = add_slash(dst);
+				dst_len = strlen(dst) - 1;
 
 				for (j = 0; j < last - first; j++) {
 					const char *path =
 						active_cache[first + j]->name;
 					source[count + j] = path;
 					destination[count + j] =
-						prefix_path(dest_dir, dst_len,
-							path + len);
+						prefix_path(dst, dst_len,
+							path + length);
 					modes[count + j] = INDEX;
 				}
 				count += last - first;
 			}
-
-			goto next;
-		}
-
-		if (!bad && lstat(destination[i], &st) == 0) {
+		} else if (lstat(dst, &st) == 0) {
 			bad = "destination exists";
 			if (force) {
 				/*
@@ -213,24 +205,17 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 							" will overwrite!\n",
 							bad);
 					bad = NULL;
-					path_list_insert(destination[i],
-							&overwritten);
+					path_list_insert(dst, &overwritten);
 				} else
 					bad = "Cannot overwrite";
 			}
-		}
-
-		if (!bad && cache_name_pos(source[i], strlen(source[i])) < 0)
+		} else if (cache_name_pos(src, length) < 0)
 			bad = "not under version control";
+		else if (path_list_has_path(&src_for_dst, dst))
+			bad = "multiple sources for the same target";
+		else
+			path_list_insert(dst, &src_for_dst);
 
-		if (!bad) {
-			if (path_list_has_path(&src_for_dst, destination[i]))
-				bad = "multiple sources for the same target";
-			else
-				path_list_insert(destination[i], &src_for_dst);
-		}
-
-next:
 		if (bad) {
 			if (ignore_errors) {
 				if (--count > 0) {
@@ -242,33 +227,32 @@ next:
 				}
 			} else
 				die ("%s, source=%s, destination=%s",
-				     bad, source[i], destination[i]);
+				     bad, src, dst);
 		}
 	}
 
 	for (i = 0; i < count; i++) {
+		const char *src = source[i], *dst = destination[i];
+		enum update_mode mode = modes[i];
 		if (show_only || verbose)
-			printf("Renaming %s to %s\n",
-			       source[i], destination[i]);
-		if (!show_only && modes[i] != INDEX &&
-		    rename(source[i], destination[i]) < 0 &&
-		    !ignore_errors)
-			die ("renaming %s failed: %s",
-			     source[i], strerror(errno));
+			printf("Renaming %s to %s\n", src, dst);
+		if (!show_only && mode != INDEX &&
+				rename(src, dst) < 0 && !ignore_errors)
+			die ("renaming %s failed: %s", src, strerror(errno));
 
-		if (modes[i] == WORKING_DIRECTORY)
+		if (mode == WORKING_DIRECTORY)
 			continue;
 
-		if (cache_name_pos(source[i], strlen(source[i])) >= 0) {
-			path_list_insert(source[i], &deleted);
+		if (cache_name_pos(src, strlen(src)) >= 0) {
+			path_list_insert(src, &deleted);
 
 			/* destination can be a directory with 1 file inside */
-			if (path_list_has_path(&overwritten, destination[i]))
-				path_list_insert(destination[i], &changed);
+			if (path_list_has_path(&overwritten, dst))
+				path_list_insert(dst, &changed);
 			else
-				path_list_insert(destination[i], &added);
+				path_list_insert(dst, &added);
 		} else
-			path_list_insert(destination[i], &added);
+			path_list_insert(dst, &added);
 	}
 
         if (show_only) {