# [PATCH 2/2] filter-branch: subdirectory filter needs --full-history

3 messages from 2007-06-08 to 2007-06-13. Participants: Johannes Sixt, Linus Torvalds, Junio C Hamano.
Thread: https://gitlist.dev/t/8511

## Johannes Sixt, 2007-06-08 21:28

Subject: [PATCH 2/2] filter-branch: subdirectory filter needs --full-history
Message-ID: <200706082328.50923.johannes.sixt@telecom.at>
URL: https://gitlist.dev/e/200706082328.50923.johannes.sixt%40telecom.at

```
When two branches are merged that modify a subdirectory (possibly in
different intermediate steps) such that both end up identical, then
rev-list chooses only one branch. But when we filter history, we want to
keep both branches. Therefore, we must use --full-history.

Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>
---
 git-filter-branch.sh     |    2 +-
 t/t7003-filter-branch.sh |   21 +++++++++++++++++++++
 2 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index 4ef4570..2e4ccec 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -326,7 +326,7 @@ case "$filter_subdir" in
 	;;
 *)
 	git-rev-list --reverse --topo-order --default HEAD \
-		--parents "$@" -- "$filter_subdir"
+		--parents --full-history "$@" -- "$filter_subdir"
 esac > ../revs
 commits=$(cat ../revs | wc -l | tr -d " ")
 
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index 292b837..0fabe49 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -78,4 +78,25 @@ test_expect_success 'subdirectory filter result looks 
okay' '
 	! git show sub:subdir
 '
 
+test_expect_success 'setup and filter history that requires --full-history' '
+	git checkout master &&
+	mkdir subdir &&
+	echo A > subdir/new &&
+	git add subdir/new &&
+	test_tick &&
+	git commit -m "subdir on master" subdir/new &&
+	git rm a &&
+	test_tick &&
+	git commit -m "again subdir on master" &&
+	git merge branch &&
+	git-filter-branch --subdirectory-filter subdir sub-master
+'
+
+test_expect_success 'subdirectory filter result looks okay' '
+	test 3 = $(git-rev-list -1 --parents sub-master | wc -w) &&
+	git show sub-master^:new &&
+	git show sub-master^2:new &&
+	! git show sub:subdir
+'
+
 test_done
-- 
1.5.2

```

## Linus Torvalds, 2007-06-09 02:40

Subject: Re: [PATCH 2/2] filter-branch: subdirectory filter needs --full-history
Message-ID: <alpine.LFD.0.98.0706081822500.4205@woody.linux-foundation.org>
URL: https://gitlist.dev/e/alpine.LFD.0.98.0706081822500.4205%40woody.linux-foundation.org
In-Reply-To: <200706082328.50923.johannes.sixt@telecom.at>

```


On Fri, 8 Jun 2007, Johannes Sixt wrote:
>
> When two branches are merged that modify a subdirectory (possibly in
> different intermediate steps) such that both end up identical, then
> rev-list chooses only one branch. But when we filter history, we want to
> keep both branches. Therefore, we must use --full-history.

--full-history needs to be fixed up for this, I think.

It leaves *too* many merges around, in particular, it leaves merges where 
both parents end up (after simplification) being related to each other.

As an example, do this:

	mkdir hello
	cd hello/
	git init

	echo "Initial state" > file-A
	echo "Another initial state" > file-B
	git add file-A file-B
	git commit -m "Initial commit"

	echo "Add a line" >> file-A
	echo "Add another line" >> file-B
	git commit -a -m "On master branch"

	git checkout -b another HEAD^
	echo "Add a line" >> file-A
	git commit -a -m "On another branch"

	git checkout master
	git merge another

and then do

	gitk --full-history file-B

and notice what happens.. There was no actual developmet on branch 
"another", so all the commits went away, but it left the merge (because 
that's how --full-history works), which has now become pointless.

So you should do a "merge cleanup" phase after running --full-history.

			Linus

```

## Junio C Hamano, 2007-06-13 06:58

Subject: Re: [PATCH 2/2] filter-branch: subdirectory filter needs --full-history
Message-ID: <7vps40fihe.fsf@assigned-by-dhcp.pobox.com>
URL: https://gitlist.dev/e/7vps40fihe.fsf%40assigned-by-dhcp.pobox.com
In-Reply-To: <alpine.LFD.0.98.0706081822500.4205@woody.linux-foundation.org>

```
Linus Torvalds <torvalds@linux-foundation.org> writes:

> ... There was no actual developmet on branch 
> "another", so all the commits went away, but it left the merge (because 
> that's how --full-history works), which has now become pointless.
>
> So you should do a "merge cleanup" phase after running --full-history.

In short, you will end up with something like this:

             .---. (side branch)
            /     \
	---A---B---C (merge)

The "merge clean-up" would conceptually be a simple operation.
Whenever you see a merge C, you look at its parents A and B, and
cull the ones that are reachable from other parents.  You notice
that A is an ancestor of B, drop A from the parents of C, and
simplify the above down to:

	---A---B---C (not-a-merge)

However, I suspect that this is impossible without making
--full-history with "merge clean-up" imply "limited".

In the case of filter-branch, it needs to use topo-order in
order to guarantee that all its parents commits have been
rewritten before rewriting a commit, so the traversal is already
limited.  

It might be simpler for filter-branch to remove parents that are
ancestor of other parents ("git show-branch --independent" would
work well for this, I think), before feeding the list of mapped
parents to the parent-filter.

```
