threads / bug / 33351

Bug in filter-branch -d option, new files are dumped into parent

Subject: Bug in filter-branch -d option, new files are dumped into parent

## tl;dr

2 messages between Apr 2, 2013 and Apr 2, 2013.

replies: 1people: 2as markdown or json

Martin Erik Werner· Apr 2, 2013, 12:32 UTC · lore

Hi, I think I have stumbled on a bug in the -d option of git filter-branch.

It seems like in the final stage of filter-branch, regardless of where -d is set, it will make updates to the "working directory" as being the parent of the -d directory, and the actual working directory is left as it were before the filtering.

For example if using -d /tmp/git-rewrite, the new checkout files are dumped into /tmp.

A simple test scenario:

### mkdir test cd test git init

echo foo >foo git add foo git commit -m"foo" echo bar >bar git add bar git commit -m"bar"

git checkout -b rewrite git filter-branch -d /tmp/git-rewrite --tree-filter 'echo baz >baz' -- rewrite # git status # shows 'baz' as unstaged-deleted in the working directory # # ls /tmp/ # shows the 'baz' file created in the root, above git-rewrite # # git log --stat --oneline # does show expected result though # # if you run it again you'll get an error because of the /tmp/baz file git reset --hard master git filter-branch -f -d /tmp/git-rewrite --tree-filter 'echo baz >baz' -- rewrite # Rewrite afac18542ac3d432b647866f5ac6918b81b3bb78 (2/2) # Ref 'refs/heads/rewrite' was rewritten # error: Untracked working tree file 'baz' would be overwritten by merge. # # At this point, 'baz' is instead staged-deleted in the working directory ###

-- 
Martin Erik Werner <martinerikwerner@gmail.com>
Jeff King· Apr 2, 2013, 14:22 UTC · re: Martin Erik Werner · lore

[PATCH] filter-branch: return to original dir after filtering

The first thing filter-branch does is to create a temporary directory, either ".git-rewrite" in the current directory (which may be the working tree or the repository if bare), or in a directory specified by "-d". We then chdir to $tempdir/t as our temporary working directory in which to run tree filters.

After finishing the filter, we then attempt to go back to the original directory with "cd ../..". This works in the .git-rewrite case, but if "-d" is used, we end up in a random directory. The only thing we do after this chdir is to run git-read-tree, but that means that:

  1. The working directory is not updated to reflect the
     filtered history.
  2. We dump random files into "$tempdir/.." (e.g., if you
     use "-d /tmp/foo", we dump junk into /tmp).

Fix it by recording the full path to the original directory and returning there explicitly.

Signed-off-by: Jeff King <peff@peff.net>
---
On Tue, Apr 02, 2013 at 02:32:21PM +0200, Martin Erik Werner wrote:
Show 6 quoted lines
> I think I have stumbled on a bug in the -d option of git filter-branch.
> 
> It seems like in the final stage of filter-branch, regardless of where
> -d is set, it will make updates to the "working directory" as being the
> parent of the -d directory, and the actual working directory is left as
> it were before the filtering.
Yep, definitely a bug. Thanks for reporting.
 git-filter-branch.sh     |  5 +++--
 t/t7003-filter-branch.sh | 14 ++++++++++++++
 2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index 5314249..ac2a005 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -199,6 +199,7 @@ esac
 	test -d "$tempdir" &&
 		die "$tempdir already exists, please remove it"
 esac
+orig_dir=$(pwd)
 mkdir -p "$tempdir/t" &&
 tempdir="$(cd "$tempdir"; pwd)" &&
 cd "$tempdir/t" &&
@@ -206,7 +207,7 @@ die ""
 die ""
 
 # Remove tempdir on exit
-trap 'cd ../..; rm -rf "$tempdir"' 0
+trap 'cd "$orig_dir"; rm -rf "$tempdir"' 0
 
 ORIG_GIT_DIR="$GIT_DIR"
 ORIG_GIT_WORK_TREE="$GIT_WORK_TREE"
@@ -469,7 +470,7 @@ fi
 	done
 fi
 
-cd ../..
+cd "$orig_dir"
 rm -rf "$tempdir"
 
 trap - 0
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index 1e7a209..9496736 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -64,6 +64,20 @@ test_expect_success 'correct GIT_DIR while using -d' '
 	grep drepo "$TRASHDIR/backup-refs"
 '
 
+test_expect_success 'tree-filter works with -d' '
+	git init drepo-tree &&
+	(
+		cd drepo-tree &&
+		test_commit one &&
+		git filter-branch -d "$TRASHDIR/dfoo" \
+			--tree-filter "echo changed >one.t" &&
+		echo changed >expect &&
+		git cat-file blob HEAD:one.t >actual &&
+		test_cmp expect actual &&
+		test_cmp one.t actual
+	)
+'
+
 test_expect_success 'Fail if commit filter fails' '
 	test_must_fail git filter-branch -f --commit-filter "exit 1" HEAD
 '
-- 
1.8.2.rc0.33.gd915649

← back to recent threads