threads / bug / 5778

[BUG] 'git mv a/fileA b/fileB' causes 'c/fileC' to be deleted

Subject: [BUG] 'git mv a/fileA b/fileB' causes 'c/fileC' to be deleted

## tl;dr

5 messages between Oct 1, 2006 and Oct 2, 2006.

replies: 4people: 2as markdown or json

Michael Cassar· Oct 1, 2006, 14:21 UTC · lore
Hi,

I'm new to git, so this may be user error, but I am getting some strange behaviour using the 'git mv' command. In particular, attempting to move a file from one directory to another (performing a rename in the process) causes an unrelated third-party file to be deleted after commit.

I have flicked through the git man pages and googled for git mv related issues, but haven't come up with anything.

Here is a transcript. These results are reproducable using the same files, but I can't seem to reproduce with different files.

## Create initial respository

[mike@simba ~] git version git version 1.4.2.1

[mike@simba ~] mkdir repos; cd repos

[mike@simba ~/repos] git init-db defaulting to local storage area

[mike@simba ~/repos] cp -r ~/thesis_work/* .

[mike@simba ~/repos] ls -a . .. .git metathesis notes papers partA

[mike@simba ~/repos] git add metathesis notes papers partA

[mike@simba ~/repos] git commit -m 'initial import' Committing initial tree 77d618ebc7c8e655c1d2f0e223e1957b6b5ff247

## Files that we are going to deal with. Note that 'outline.txt' is an ## innocent third party.

[mike@simba ~/repos] sha1sum partA/outline.txt 891256d20531ebc288f1abb5e23f9979597889d3 partA/outline.txt

[mike@simba ~/repos] sha1sum papers/unsorted/Thesis.pdf 52446ade19a067253e8407bf092b52e5efa35247 papers/unsorted/Thesis.pdf

## Move 'Thesis.pdf' to a new name, and commit

[mike@simba ~/repos] git mv papers/unsorted/Thesis.pdf papers/all-papers/new-name.pdf

[mike@simba ~/repos] git commit -m 'moved a file'

## Have a look at what git just did. In particular, note that 'outline.txt' ## has magically appeared in the log

[mike@simba ~/repos] cg log -f | head commit aa544a0d58118eb01fa6768e438fa0f521d6095b tree 07c4971e3946b7c33742515e8915ec6e8abc4e40 parent 0d4292e44aa999707eddf31c4bbcadd711a170be author mike <mike@simba.home> Sun, 01 Oct 2006 23:39:06 +1000 committer mike <mike@simba.home> Sun, 01 Oct 2006 23:39:06 +1000

    * papers/all-papers/new-name.pdf, partA/outline.txt:
    moved a file
## What changes are in the commit?
[mike@simba ~/repos] git show aa544a0d58118eb01fa6768e438fa0f521d6095b
| head -19
commit aa544a0d58118eb01fa6768e438fa0f521d6095b
Author: mike <mike@simba.home>
Date:   Sun Oct 1 23:39:06 2006 +1000
    moved a file
diff --git a/papers/all-papers/new-name.pdf b/papers/all-papers/new-name.pdf
new file mode 100644
index 0000000..5441543
Binary files /dev/null and b/papers/all-papers/new-name.pdf differ
diff --git a/partA/outline.txt b/partA/outline.txt
deleted file mode 100644
index d3ac280..0000000
--- a/partA/outline.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-
-Thesis Part A
-
[rest of file outline.txt deleted]

Is this just me being an idiot, or could there be a bigger problem
here?

Please CC me in any replies.

Cheers,

Mike
Junio C Hamano· Oct 1, 2006, 17:34 UTC · re: Michael Cassar · lore

Re: [BUG] 'git mv a/fileA b/fileB' causes 'c/fileC' to be deleted

"Michael Cassar" <m.e.cassar@gmail.com> writes:
> Is this just me being an idiot, or could there be a bigger problem
> here?
>
> Please CC me in any replies.

There could be a bigger problem, but it does not seem to easily reproduce as you noted in the message. It could be that some unrelated thing in the working tree is playing a role in this breakage, but I do not think of offhand what that is.

Here is what I just ran.

-- >8 cut >8 -- #!/bin/sh

report () {
	echo
	echo "* $*"
	echo
}

rm -fr test0 mkdir test0 cd test0

report working tree preparation mkdir -p partA papers/unsorted papers/all-papers echo outline >partA/outline.txt echo Thesis >papers/unsorted/Thesis.pdf

report repository initialization git init-db

report initial import git add papers partA git commit -m 'initial' git show --root --stat --summary

report run mv git mv papers/unsorted/Thesis.pdf papers/all-papers/Thesis.pdf

report before commit git diff --stat HEAD

report make a commit git commit -m 'moved a file'

report final result git show --stat --summary -- 8< cut 8< --

and I did not see the breakage. Care to show a bit more details on your working tree? I do not think this depends on any contents of the individual files, but

Show 19 quoted lines
> Here is a transcript. These results are reproducable using the same
> files, but I can't seem to reproduce with different files.
>
> ## Create initial respository
>
> [mike@simba ~] git version
> git version 1.4.2.1
>
> [mike@simba ~] mkdir repos; cd repos
>
> [mike@simba ~/repos] git init-db
> defaulting to local storage area
>
> [mike@simba ~/repos] cp -r ~/thesis_work/* .
>
> [mike@simba ~/repos] ls -a
> .  ..  .git  metathesis  notes  papers  partA
>
> [mike@simba ~/repos] git add metathesis notes papers partA

output from "find metathesis notes papers partA -ls" and "git ls-files -s" at this step may be a starter.

Michael Cassar· Oct 2, 2006, 01:33 UTC · re: Junio C Hamano · lore

Re: [BUG] 'git mv a/fileA b/fileB' causes 'c/fileC' to be deleted

On 10/2/06, Junio C Hamano <junkio@cox.net> wrote:
> There could be a bigger problem, but it does not seem to easily
> reproduce as you noted in the message.  It could be that some
> unrelated thing in the working tree is playing a role in this
> breakage, but I do not think of offhand what that is.
> [...]  Care to show a bit more details
> on your working tree?
Okay, I should stop being lazy and actually produce a minimal test-case.
Here we go:

--CUT-- #!/bin/bash

git init-db

mkdir papers mkdir papers/unsorted mkdir papers/all-papers mkdir partA echo 'moo' > papers/unsorted/Thesis.pdf echo 'cow' > partA/outline.txt echo 'this file has brackets in its filename' > 'papers/unsorted/(brackets).pdf'

git add papers partA git commit -m 'intial commit'

git mv papers/unsorted/Thesis.pdf papers/all-papers/moo-blah.pdf git commit -m 'move a file'

cg log -f --CUT--

The problem seems to have come from the fact that a file in the source directory of the move contained brackets in its filename.Removing the file causes the problem to go away.

Hope this helps a little,
Mike
Junio C Hamano· Oct 2, 2006, 05:05 UTC · re: Michael Cassar · lore

Re: [BUG] 'git mv a/fileA b/fileB' causes 'c/fileC' to be deleted

Thanks.  I see it reproduces.

It is a bug in git-mv that fails to update cache-tree data structure properly. This patch should fix it.

-- >8 -- git-mv: do not write out a bogus cache-tree in the index

The command updates the cache without invalidating the cache tree entries. Since this is not as performance critical as one-tree and two-tree git-read-tree and git-apply, disable use of cache-tree entirely.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
diff --git a/builtin-mv.c b/builtin-mv.c
index 4d21d88..9a4e2e0 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -83,6 +83,9 @@ int cmd_mv(int argc, const char **argv, 
 	if (read_cache() < 0)
 		die("index file corrupt");
 
+	/* This does not manage cache-tree properly */
+	cache_tree_free(&active_cache_tree);
+
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 
Junio C Hamano· Oct 2, 2006, 05:20 UTC · re: Junio C Hamano · lore

Re: [BUG] 'git mv a/fileA b/fileB' causes 'c/fileC' to be deleted

Junio C Hamano <junkio@cox.net> writes:
> Thanks.  I see it reproduces.
>
> It is a bug in git-mv that fails to update cache-tree data
> structure properly.  This patch should fix it.

The previous patch was safer but unnecessarily was a bit heavy handed. This should fix it nicer.

-- >8 -- git-mv: invalidate the removed path properly in cache-tree

The command updated the cache without invalidating the cache tree entries while removing an existing entry.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
diff --git a/builtin-mv.c b/builtin-mv.c
index 4d21d88..54dd3bf 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -278,6 +278,7 @@ int cmd_mv(int argc, const char **argv, 
 		for (i = 0; i < deleted.nr; i++) {
 			const char *path = deleted.items[i].path;
 			remove_file_from_cache(path);
+			cache_tree_invalidate_path(active_cache_tree, path);
 		}
 
 		if (active_cache_changed) {

← back to recent threads