githistory: rewrite tags pointing to tags
When rewriting history, we've ignored tags pointing to other tags. This leads to problems for folks that are trying to shrink the size of their repository, since they may still have tags that point to the old history. Add additional handling for tags pointing to tags, recursively rewriting the inner tags until we reach a commit.
This commit is contained in:
parent
5346eb49fb
commit
ff410fa761
@ -57,12 +57,7 @@ func (r *refUpdater) UpdateRefs() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *refUpdater) updateOneTag(tag *gitobj.Tag) ([]byte, error) {
|
||||
toObj, okObj := r.CacheFn(tag.Object)
|
||||
if !okObj {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *refUpdater) updateOneTag(tag *gitobj.Tag, toObj []byte) ([]byte, error) {
|
||||
newTag, err := r.db.WriteTag(&gitobj.Tag{
|
||||
Object: toObj,
|
||||
ObjectType: tag.ObjectType,
|
||||
@ -93,11 +88,43 @@ func (r *refUpdater) updateOneRef(list *tasklog.ListTask, maxNameLen int, seen m
|
||||
|
||||
if ref.Type == git.RefTypeLocalTag {
|
||||
tag, _ := r.db.Tag(sha1)
|
||||
if tag != nil && tag.ObjectType == gitobj.CommitObjectType {
|
||||
// Assume that a non-nil error is an indication
|
||||
// that the tag is bare (without annotation).
|
||||
if tag != nil && tag.ObjectType == gitobj.TagObjectType {
|
||||
innerTag, _ := r.db.Tag(tag.Object)
|
||||
name := fmt.Sprintf("refs/tags/%s", innerTag.Name)
|
||||
if _, ok := seen[name]; !ok {
|
||||
old, err := git.ResolveRef(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newTag, err := r.updateOneTag(tag)
|
||||
err = r.updateOneRef(list, maxNameLen, seen, old)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
updated, err := git.ResolveRef(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedSha, err := hex.DecodeString(updated.Sha)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not decode: %q", ref.Sha)
|
||||
}
|
||||
|
||||
newTag, err := r.updateOneTag(tag, updatedSha)
|
||||
if newTag == nil {
|
||||
return err
|
||||
}
|
||||
to = newTag
|
||||
ok = true
|
||||
} else if tag != nil && tag.ObjectType == gitobj.CommitObjectType {
|
||||
toObj, okObj := r.CacheFn(tag.Object)
|
||||
if !okObj {
|
||||
return nil
|
||||
}
|
||||
|
||||
newTag, err := r.updateOneTag(tag, toObj)
|
||||
if newTag == nil {
|
||||
return err
|
||||
}
|
||||
|
@ -578,6 +578,37 @@ begin_test "migrate import (--everything and --include with glob pattern)"
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "migrate import (--everything with tag pointing to tag)"
|
||||
(
|
||||
set -e
|
||||
|
||||
setup_multiple_local_branches
|
||||
|
||||
md_master_oid="$(calc_oid "$(git cat-file -p "refs/heads/master:a.md")")"
|
||||
txt_master_oid="$(calc_oid "$(git cat-file -p "refs/heads/master:a.txt")")"
|
||||
md_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.md")")"
|
||||
txt_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.txt")")"
|
||||
|
||||
git tag -a -m abc abc refs/heads/master
|
||||
git tag -a -m def def refs/tags/abc
|
||||
|
||||
git lfs migrate import --verbose --everything --include='*.[mM][dD]'
|
||||
|
||||
assert_pointer "refs/heads/master" "a.md" "$md_master_oid" "140"
|
||||
assert_pointer "refs/tags/abc" "a.md" "$md_master_oid" "140"
|
||||
assert_pointer "refs/tags/def" "a.md" "$md_master_oid" "140"
|
||||
assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "30"
|
||||
|
||||
git tag --points-at refs/tags/abc | grep -q def
|
||||
! git tag --points-at refs/tags/def | grep -q abc
|
||||
|
||||
assert_local_object "$md_master_oid" "140"
|
||||
assert_local_object "$md_feature_oid" "30"
|
||||
refute_local_object "$txt_master_oid"
|
||||
refute_local_object "$txt_feature_oid"
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "migrate import (nested sub-trees and --include with wildcard)"
|
||||
(
|
||||
set -e
|
||||
|
Loading…
Reference in New Issue
Block a user