aboutsummaryrefslogtreecommitdiff
path: root/commitquery/ancestor.go
blob: 4f182a95b2223ad9a9854c5d80251b5ca5d89b10 (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package commitquery

import objectid "codeberg.org/lindenii/furgit/object/id"

// IsAncestor reports whether ancestor is reachable from descendant through
// commit parent edges.
//
// Both inputs are peeled through annotated tags before commit traversal.
func (query *Query) IsAncestor(ancestor, descendant objectid.ObjectID) (bool, error) {
	ancestorIdx, err := query.resolveCommitish(ancestor)
	if err != nil {
		return false, err
	}

	descendantIdx, err := query.resolveCommitish(descendant)
	if err != nil {
		return false, err
	}

	return query.isAncestor(ancestorIdx, descendantIdx)
}

func (query *Query) isAncestor(ancestor, descendant nodeIndex) (bool, error) {
	if ancestor == descendant {
		return true, nil
	}

	ancestorGeneration := query.effectiveGeneration(ancestor)
	descendantGeneration := query.effectiveGeneration(descendant)

	if ancestorGeneration != generationInfinity &&
		descendantGeneration != generationInfinity &&
		ancestorGeneration > descendantGeneration {
		return false, nil
	}

	minGeneration := uint64(0)
	if ancestorGeneration != generationInfinity {
		minGeneration = ancestorGeneration
	}

	err := query.paintDownToCommon(ancestor, []nodeIndex{descendant}, minGeneration)
	if err != nil {
		return false, err
	}

	return query.hasAnyMarks(ancestor, markRight), nil
}