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

Re: Git clone behaviour change in 1.5.6 (vs 1.5.5.1)

From
Jeff King <peff@peff.net>
Date
Jun 23, 2008, 20:38 UTC
Message-ID
<20080623203835.GA8105@sigill.intra.peff.net>
In-Reply-To
<alpine.LNX.1.00.0806231554380.19665@iabervon.org>
On Mon, Jun 23, 2008 at 03:56:41PM -0400, Daniel Barkalow wrote:
Show 12 quoted lines
> > Switching to the 1.5.6 release from 1.5.5.1, I found out that the
> > rewritten git-clone command changed its behaviour wrt cloning to a
> > non-existing destination directory structure. In the shell version the
> > destination (work tree) is created with 'mkdir -p' but in the C
> > version with just the mkdir() call which doesn't create the parent
> > directories.
> > 
> > I can't find any indication that this would be intended in the repo
> > history nor in the mailing list, so I'm left thinking that this is an
> > unwanted regression. Could someone confirm this?
> 
> It wasn't an intentional change, anyway.

Here is a partial fix. For --bare repo creation, we follow a different codepath, and I think the fix is likely to be a bit tricky. We actually fail in make_absolute_path, before we try creating the directory. But I suspect we can't just create the directory ourselves because init_db expects it not to exist.

-- >8 -- clone: create intermediate directories of repo destination

The shell version used to use "mkdir -p" to create the repo
path, but the C version just calls "mkdir". Let's replicate
the old behavior.
---
 builtin-clone.c  |   40 +++++++++++++++++++++++++++++++++++++++-
 t/t5601-clone.sh |   14 ++++++++++++++
 2 files changed, 53 insertions(+), 1 deletions(-)
diff --git a/builtin-clone.c b/builtin-clone.c
index 5c5acb4..758d02c 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -168,6 +168,44 @@ static void setup_reference(const char *repo)
 	free(ref_git_copy);
 }
 
+static int mkdirp_recurse(char *path, int mode)
+{
+	int n;
+	char tmp;
+	int r;
+
+	if (mkdir(path, mode) == 0)
+		return 0;
+	if (errno != ENOENT)
+		return -1;
+
+	for (n = strlen(path); n > 0 && path[n] != '/'; n--)
+		;
+	if (n == 0)
+		return -1;
+	tmp = path[n];
+	path[n] = '\0';
+	r = mkdirp_recurse(path, mode);
+	path[n] = tmp;
+	if (r < 0)
+		return -1;
+	return mkdir(path, mode);
+}
+
+static int mkdirp(const char *path, int mode)
+{
+	char buf[PATH_MAX];
+	int n;
+
+	n = strlen(path);
+	if (n >= PATH_MAX) {
+		errno = ENAMETOOLONG;
+		return -1;
+	}
+	memcpy(buf, path, n+1);
+	return mkdirp_recurse(buf, mode);
+}
+
 static void copy_or_link_directory(char *src, char *dest)
 {
 	struct dirent *de;
@@ -404,7 +442,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
 	if (!option_bare) {
 		junk_work_tree = work_tree;
-		if (mkdir(work_tree, 0755))
+		if (mkdirp(work_tree, 0755))
 			die("could not create work tree dir '%s'.", work_tree);
 		set_git_work_tree(work_tree);
 	}
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 593d1a3..c2c83f0 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -30,4 +30,18 @@ test_expect_success 'clone checks out files' '
 
 '
 
+test_expect_success 'clone creates intermediate directories' '
+
+	git clone src long/path/to/dst &&
+	test -f long/path/to/dst/file
+
+'
+
+test_expect_failure 'clone creates intermediate directories for bare repo' '
+
+	git clone --bare src long/path/to/bare/dst &&
+	test -f long/path/to/bare/dst/config
+
+'
+
 test_done
-- 
1.5.6.105.gceec6.dirty
Previous: Daniel BarkalowNext: Brandon Casey
Message 3 of 10 in “Git clone behaviour change in 1.5.6 (vs 1.5.5.1)”
  1. Kalle VahlmanJun 23, 2008
  2. Daniel BarkalowJun 23, 2008
  3. Jeff KingJun 23, 2008
  4. Brandon CaseyJun 23, 2008
  5. clone: create intermediate directories of destination repoJeff King, Jun 24, 2008
  6. Junio C HamanoJun 24, 2008
  7. Jeff KingJun 24, 2008
  8. Daniel BarkalowJun 24, 2008
  9. Jeff KingJun 25, 2008
  10. Daniel BarkalowJun 25, 2008

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.