Merge branch 'tr/rev-list-docs' into tr/filter-branch
authorJunio C Hamano <gitster@pobox.com>
Sun, 31 Aug 2008 17:41:01 +0000 (10:41 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 1 Sep 2008 00:04:56 +0000 (17:04 -0700)
This prepares the necessary parts to merge filter-branch
fix based on simplify-merges to master.

git-filter-branch.sh
revision.c
revision.h
t/t7003-filter-branch.sh
index a324cf0596ee0f05831190ce724fe9134bc7f568..2688254af399ddc452b120734d41b41292b0ed69 100755 (executable)
@@ -232,11 +232,11 @@ mkdir ../map || die "Could not create map/ directory"
 case "$filter_subdir" in
 "")
        git rev-list --reverse --topo-order --default HEAD \
-               --parents "$@"
+               --parents --simplify-merges "$@"
        ;;
 *)
        git rev-list --reverse --topo-order --default HEAD \
-               --parents "$@" -- "$filter_subdir"
+               --parents --simplify-merges "$@" -- "$filter_subdir"
 esac > ../revs || die "Could not get the commits"
 commits=$(wc -l <../revs | tr -d " ")
 
@@ -317,24 +317,20 @@ done <../revs
 
 # In case of a subdirectory filter, it is possible that a specified head
 # is not in the set of rewritten commits, because it was pruned by the
-# revision walker.  Fix it by mapping these heads to the next rewritten
-# ancestor(s), i.e. the boundaries in the set of rewritten commits.
+# revision walker.  Fix it by mapping these heads to the unique nearest
+# ancestor that survived the pruning.
 
-# NEEDSWORK: we should sort the unmapped refs topologically first
-while read ref
-do
-       sha1=$(git rev-parse "$ref"^0)
-       test -f "$workdir"/../map/$sha1 && continue
-       # Assign the boundarie(s) in the set of rewritten commits
-       # as the replacement commit(s).
-       # (This would look a bit nicer if --not --stdin worked.)
-       for p in $( (cd "$workdir"/../map; ls | sed "s/^/^/") |
-               git rev-list $ref --boundary --stdin |
-               sed -n "s/^-//p")
+if test "$filter_subdir"
+then
+       while read ref
        do
-               map $p >> "$workdir"/../map/$sha1
-       done
-done < "$tempdir"/heads
+               sha1=$(git rev-parse "$ref"^0)
+               test -f "$workdir"/../map/$sha1 && continue
+               ancestor=$(git rev-list --simplify-merges -1 \
+                               $ref -- "$filter_subdir")
+               test "$ancestor" && echo $(map $ancestor) >> "$workdir"/../map/$sha1
+       done < "$tempdir"/heads
+fi
 
 # Finally update the refs
 
index 0aaa4c10b9692b39eb3dfb1cf0e45890d598550e..db2ab2b11a39c295373488f6ff28c1340a9a666d 100644 (file)
@@ -1408,16 +1408,34 @@ static int remove_duplicate_parents(struct commit *commit)
        return surviving_parents;
 }
 
-static struct commit_list **simplify_one(struct commit *commit, struct commit_list **tail)
+struct merge_simplify_state {
+       struct commit *simplified;
+};
+
+static struct merge_simplify_state *locate_simplify_state(struct rev_info *revs, struct commit *commit)
+{
+       struct merge_simplify_state *st;
+
+       st = lookup_decoration(&revs->merge_simplification, &commit->object);
+       if (!st) {
+               st = xcalloc(1, sizeof(*st));
+               add_decoration(&revs->merge_simplification, &commit->object, st);
+       }
+       return st;
+}
+
+static struct commit_list **simplify_one(struct rev_info *revs, struct commit *commit, struct commit_list **tail)
 {
        struct commit_list *p;
+       struct merge_simplify_state *st, *pst;
        int cnt;
 
+       st = locate_simplify_state(revs, commit);
+
        /*
-        * We store which commit each one simplifies to in its util field.
         * Have we handled this one?
         */
-       if (commit->util)
+       if (st->simplified)
                return tail;
 
        /*
@@ -1426,7 +1444,7 @@ static struct commit_list **simplify_one(struct commit *commit, struct commit_li
         * anyway.
         */
        if ((commit->object.flags & UNINTERESTING) || !commit->parents) {
-               commit->util = commit;
+               st->simplified = commit;
                return tail;
        }
 
@@ -1435,19 +1453,24 @@ static struct commit_list **simplify_one(struct commit *commit, struct commit_li
         * Otherwise we are not ready to rewrite this one yet.
         */
        for (cnt = 0, p = commit->parents; p; p = p->next) {
-               if (!p->item->util) {
+               pst = locate_simplify_state(revs, p->item);
+               if (!pst->simplified) {
                        tail = &commit_list_insert(p->item, tail)->next;
                        cnt++;
                }
        }
-       if (cnt)
+       if (cnt) {
+               tail = &commit_list_insert(commit, tail)->next;
                return tail;
+       }
 
        /*
         * Rewrite our list of parents.
         */
-       for (p = commit->parents; p; p = p->next)
-               p->item = p->item->util;
+       for (p = commit->parents; p; p = p->next) {
+               pst = locate_simplify_state(revs, p->item);
+               p->item = pst->simplified;
+       }
        cnt = remove_duplicate_parents(commit);
 
        /*
@@ -1482,9 +1505,11 @@ static struct commit_list **simplify_one(struct commit *commit, struct commit_li
            (commit->object.flags & UNINTERESTING) ||
            !(commit->object.flags & TREESAME) ||
            (1 < cnt))
-               commit->util = commit;
-       else
-               commit->util = commit->parents->item->util;
+               st->simplified = commit;
+       else {
+               pst = locate_simplify_state(revs, commit->parents->item);
+               st->simplified = pst->simplified;
+       }
        return tail;
 }
 
@@ -1493,7 +1518,10 @@ static void simplify_merges(struct rev_info *revs)
        struct commit_list *list;
        struct commit_list *yet_to_do, **tail;
 
-       sort_in_topological_order(&revs->commits, revs->lifo);
+       if (!revs->topo_order)
+               sort_in_topological_order(&revs->commits, revs->lifo);
+       if (!revs->prune)
+               return;
 
        /* feed the list reversed */
        yet_to_do = NULL;
@@ -1508,7 +1536,7 @@ static void simplify_merges(struct rev_info *revs)
                        struct commit_list *next = list->next;
                        free(list);
                        list = next;
-                       tail = simplify_one(commit, tail);
+                       tail = simplify_one(revs, commit, tail);
                }
        }
 
@@ -1519,9 +1547,11 @@ static void simplify_merges(struct rev_info *revs)
        while (list) {
                struct commit *commit = list->item;
                struct commit_list *next = list->next;
+               struct merge_simplify_state *st;
                free(list);
                list = next;
-               if (commit->util == commit)
+               st = locate_simplify_state(revs, commit);
+               if (st->simplified == commit)
                        tail = &commit_list_insert(commit, tail)->next;
        }
 }
index dfa06b52106da5ac3dfc65676ea5dd043c95d3cf..765ef6c5e2f3bf0fbf84479cf83e0c0e4c82dda4 100644 (file)
@@ -110,6 +110,7 @@ struct rev_info {
 
        struct reflog_walk_info *reflog_info;
        struct decoration children;
+       struct decoration merge_simplification;
 };
 
 #define REV_TREE_SAME          0
index a0ab096c8fdee153a89a1428f85c9bf107badada..233254f2b541b7c67d99aa738eb55f0a0a6d3131 100755 (executable)
@@ -96,13 +96,17 @@ test_expect_success 'filter subdirectory only' '
        test_tick &&
        git commit -m "again not subdir" &&
        git branch sub &&
-       git-filter-branch -f --subdirectory-filter subdir refs/heads/sub
+       git branch sub-earlier HEAD~2 &&
+       git-filter-branch -f --subdirectory-filter subdir \
+               refs/heads/sub refs/heads/sub-earlier
 '
 
 test_expect_success 'subdirectory filter result looks okay' '
        test 2 = $(git rev-list sub | wc -l) &&
        git show sub:new &&
-       test_must_fail git show sub:subdir
+       test_must_fail git show sub:subdir &&
+       git show sub-earlier:new &&
+       test_must_fail git show sub-earlier:subdir
 '
 
 test_expect_success 'more setup' '