From 52b98a7d2f12b5d0dd076221d40f8fa93598e11a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 4 Apr 2010 15:40:06 -0700 Subject: [PATCH] write-index: check and warn when worktree crosses a filesystem boundary As we are stopping the discovery for the repository directory at filesystem boundaries by default, you might find yourself in a situation like this: (1) You have a tarball of some sort; you extract it $there; $ mkdir $there && cd $there $ tar xf /var/tmp/tarball.tar (2) You notice that the filesystem lacks enough free space, and move some part (say "images/") to a separate filesystem, and bind-mount; $ mv images $another/. && rm -fr images && mkdir images $ mount --bind $another/images images (3) You add everything to start the project; $ git init && git add . Up to this point it would work just fine, as you are at the top of the working tree and there is no need for repository discovery. (4) Go down to a subdirectory and start futzing; $ cd images && gimp naughty.jpg && git add -u This will break as the repository discovery will not go up outside of the "images" directory. Help users by making "git add" notice at the step (3) above that the working tree is spread across multiple filesystems and warn. Signed-off-by: Junio C Hamano --- read-cache.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/read-cache.c b/read-cache.c index f1f789b7b8..e381ea52a3 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1550,6 +1550,8 @@ int write_index(struct index_state *istate, int newfd) struct cache_entry **cache = istate->cache; int entries = istate->cache_nr; struct stat st; + int first_valid_ent = -1; + int more_than_one_dev; for (i = removed = extended = 0; i < entries; i++) { if (cache[i]->ce_flags & CE_REMOVE) @@ -1572,6 +1574,7 @@ int write_index(struct index_state *istate, int newfd) if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0) return -1; + more_than_one_dev = 0; for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; if (ce->ce_flags & CE_REMOVE) @@ -1580,8 +1583,19 @@ int write_index(struct index_state *istate, int newfd) ce_smudge_racily_clean_entry(ce); if (ce_write_entry(&c, newfd, ce) < 0) return -1; + if (ce_uptodate(ce)) { + if (first_valid_ent < 0) + first_valid_ent = i; + else if (ce->ce_dev != cache[first_valid_ent]->ce_dev) + more_than_one_dev = 1; + } } + if (more_than_one_dev && + !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0)) + warning("working tree spans across filesystems but " + "GIT_DISCOVERY_ACROSS_FILESYSTEM is not set."); + /* Write extension data here */ if (istate->cache_tree) { struct strbuf sb = STRBUF_INIT;