threads / patch / 22160

patchRemove empty directories when checking out a commit with fewer submodules

Subject: [PATCH] Remove empty directories when checking out a commit with fewer submodules

## tl;dr

5 messages between Jan 11, 2010 and Jan 11, 2010. Diffs are folded; open one to read it.

replies: 4people: 4as markdown or json

Peter Collingbourne· Jan 11, 2010, 02:59 UTC · lore

Change the unlink_entry function to use rmdir to remove submodule directories. Currently we try to use unlink, which will never succeed.

Of course rmdir will only succeed for empty (i.e. not checked out) submodule directories. Behaviour if a submodule is checked out stays essentially the same: print a warning message and keep the submodule directory.

Signed-off-by: Peter Collingbourne <peter@pcc.me.uk>
---
 t/t7400-submodule-basic.sh |    9 +++++++++
 unpack-trees.c             |   12 ++++++++++--
 2 files changed, 19 insertions(+), 2 deletions(-)
Show changes to 2 files +19 −2

t/t7400-submodule-basic.sh, unpack-trees.c

diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index a0cc99a..1a4dc5f 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -299,6 +299,15 @@ test_expect_success 'ls-files gracefully handles trailing slash' '
 
 '
 
+test_expect_success 'moving to a commit without submodule does not leave empty dir' '
+	rm -rf init &&
+	mkdir init &&
+	git reset --hard &&
+	git checkout initial &&
+	test ! -d init &&
+	git checkout second
+'
+
 test_expect_success 'submodule <invalid-path> warns' '
 
 	git submodule no-such-submodule 2> output.err &&
diff --git a/unpack-trees.c b/unpack-trees.c
index dd5999c..b69847d 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -61,8 +61,16 @@ static void unlink_entry(struct cache_entry *ce)
 {
 	if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
 		return;
-	if (unlink_or_warn(ce->name))
-		return;
+	if (S_ISGITLINK(ce->ce_mode)) {
+		if (rmdir(ce->name)) {
+			warning("unable to rmdir %s: %s",
+				ce->name, strerror(errno));
+			return;
+		}
+	}
+	else
+		if (unlink_or_warn(ce->name))
+			return;
 	schedule_dir_for_removal(ce->name, ce_namelen(ce));
 }
 
-- 
1.6.5
Johannes Schindelin· Jan 11, 2010, 08:57 UTC · re: Peter Collingbourne · lore

Re: [PATCH] Remove empty directories when checking out a commit with fewer submodules

Hi,
On Mon, 11 Jan 2010, Peter Collingbourne wrote:
> Change the unlink_entry function to use rmdir to remove submodule
> directories.

NAK. We should not even try to _unlink_ submodule subdirectories; it would be _way_ too easy to lose data that way. Remember, submodules are a totally different beast from regular files. They can contain valuable, yet uncommitted data, that is not even meant to be committed.

So you say if the submodule directories are empty, it is safe? Not so. They will never be empty: there is always .git/, and _that_ can contain valuable information that you do not want to throw away, too. Think of unpushed branches, for example. That would be _fatal_ if you rmdir() that for me.

So please, no, Dscho

Johan Herland· Jan 11, 2010, 09:32 UTC · re: Johannes Schindelin · lore

Re: [PATCH] Remove empty directories when checking out a commit with fewer submodules

On Monday 11 January 2010, Johannes Schindelin wrote:
Show 19 quoted lines
> Hi,
>
> On Mon, 11 Jan 2010, Peter Collingbourne wrote:
> > Change the unlink_entry function to use rmdir to remove submodule
> > directories.
>
> NAK.  We should not even try to _unlink_ submodule subdirectories; it
> would be _way_ too easy to lose data that way.  Remember, submodules
> are a totally different beast from regular files.  They can contain
> valuable, yet uncommitted data, that is not even meant to be
> committed.
>
> So you say if the submodule directories are empty, it is safe?  Not
> so. They will never be empty: there is always .git/, and _that_ can
> contain valuable information that you do not want to throw away, too.
>  Think of unpushed branches, for example.  That would be _fatal_ if
> you rmdir() that for me.
>
> So please, no,

I believe what Peter is referring to is the _empty_ directories (and that includes no .git/) that are placeholders for submodules that are deliberately not cloned/checked out. This lets you do things like:

	git clone url:to/some/project
	cd project
	git checkout some-other-branch-with-different-submodules
	git submodule update --init

Of course, once you clone/checkout a submodule, there will be contents in that directory (including the .git/), and Git should not try to remove it.

Have fun! :)
...Johan
-- 
Johan Herland, <johan@herland.net>
www.herland.net
Johannes Schindelin· Jan 11, 2010, 09:45 UTC · re: Johan Herland · lore

Re: [PATCH] Remove empty directories when checking out a commit with fewer submodules

Hi,
On Mon, 11 Jan 2010, Johan Herland wrote:
Show 33 quoted lines
> On Monday 11 January 2010, Johannes Schindelin wrote:
> > Hi,
> >
> > On Mon, 11 Jan 2010, Peter Collingbourne wrote:
> > > Change the unlink_entry function to use rmdir to remove submodule
> > > directories.
> >
> > NAK.  We should not even try to _unlink_ submodule subdirectories; it
> > would be _way_ too easy to lose data that way.  Remember, submodules
> > are a totally different beast from regular files.  They can contain
> > valuable, yet uncommitted data, that is not even meant to be
> > committed.
> >
> > So you say if the submodule directories are empty, it is safe?  Not
> > so. They will never be empty: there is always .git/, and _that_ can
> > contain valuable information that you do not want to throw away, too.
> >  Think of unpushed branches, for example.  That would be _fatal_ if
> > you rmdir() that for me.
> >
> > So please, no,
> 
> I believe what Peter is referring to is the _empty_ directories (and 
> that includes no .git/) that are placeholders for submodules that are 
> deliberately not cloned/checked out. This lets you do things like:
> 
> 	git clone url:to/some/project
> 	cd project
> 	git checkout some-other-branch-with-different-submodules
> 	git submodule update --init
> 
> Of course, once you clone/checkout a submodule, there will be contents 
> in that directory (including the .git/), and Git should not try to 
> remove it.

Yes, this might very well have been my confusion. Peter, could you please refer to such submodules as "uninitialized" rather than "empty" in the future? This would help simple minds like mine to understand you better.

Ciao, Dscho

Junio C Hamano· Jan 11, 2010, 09:53 UTC · re: Johannes Schindelin · lore

Re: [PATCH] Remove empty directories when checking out a commit with fewer submodules

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
Show 7 quoted lines
> NAK.  We should not even try to _unlink_ submodule subdirectories; it 
> would be _way_ too easy to lose data that way.  Remember, submodules are a 
> totally different beast from regular files.  They can contain valuable, 
> yet uncommitted data, that is not even meant to be committed.
>
> So you say if the submodule directories are empty, it is safe?  Not so.  
> They will never be empty: there is always .git/...
NACK on NAK.

Don't worry, your data will be safe. The only case rmdir would actually remove it is (1) you check out superproject that has submodule A, but you choose not to "submodule init/update" it, because you don't need a checkout of that part of the tree for your job, and then (2) you switch to a different version of the superproject that doesn't anymore (or didn't back then) have that submodule. In such a use case, you will have only an empty directory for A in step (1). The unnecessary empty directory A will be left behind, even after switching to a version that shouldn't have the directory there in step (2), if you do not rmdir it. So the patch is a strict bugfix (it attempted to unlink, which is a bug; it really meant "rmdir" and not "rm -rf" which you seem to be worried about).

It is a separate matter to _enhance_ the codepath to actually either (A) refuse to overwrite (if the version of the superproject you are switching to in step (2) had a regular file or a directory that is part of the superproject there, and/or (B) move it away to somewhere safe (recall the discussion of ".git/modules/$submodule" hierarchy of the superproject?) automatically when it will disappear. Such enhancements will help people who _do_ "submodule init/update" the submodule in step (1) and switch to a version of the superproject that lacks it in step (2).

← back to recent threads