Involved Source Fileschange.godifftree.go
Package merkletrie provides support for n-ary trees that are at the same
time Merkle trees and Radix trees (tries).
Git trees are Radix n-ary trees in virtue of the names of their
tree entries. At the same time, git trees are Merkle trees thanks to
their hashes.
This package defines Merkle tries as nodes that should have:
- a hash: the Merkle part of the Merkle trie
- a key: the Radix part of the Merkle trie
The Merkle hash condition is not enforced by this package though. This
means that the hash of a node doesn't have to take into account the hashes of
their children, which is good for testing purposes.
Nodes in the Merkle trie are abstracted by the Noder interface. The
intended use is that git trees implements this interface, either
directly or using a simple wrapper.
This package provides an iterator for merkletries that can skip whole
directory-like noders and an efficient merkletrie comparison algorithm.
When comparing git trees, the simple approach of alphabetically sorting
their elements and comparing the resulting lists is too slow as it
depends linearly on the number of files in the trees: When a directory
has lots of files but none of them has been modified, this approach is
very expensive. We can do better by prunning whole directories that
have not change, just by looking at their hashes. This package provides
the tools to do exactly that.
doubleiter.goiter.go
Package-Level Type Names (total 8, in which 4 are exported)
A Change value represent how a noder has change between to merkletries.
The noder before the change or nil if it was inserted.
The noder after the change or nil if it was deleted.
Action is convenience method that returns what Action c represents.
String returns a single change in human readable form, using the
format: '<' + action + space + path + '>'. The contents of the file
before or after the change are not included in this format.
Example: inserting a file at the path a/b/c.txt will return "<Insert
a/b/c.txt>".
T : expvar.Var
T : fmt.Stringer
T : context.stringer
T : runtime.stringer
func NewDelete(n noder.Path) Change
func NewInsert(n noder.Path) Change
func NewModify(a, b noder.Path) Change
func (*Changes).Add(c Change)
func github.com/go-git/go-git/v5.nameFromAction(ch *Change) string
func github.com/go-git/go-git/v5.(*Worktree).checkoutChange(ch Change, t *object.Tree, idx *git.indexBuilder) error
func github.com/go-git/go-git/v5/plumbing/object.newChange(c Change) (*object.Change, error)
Iter is an iterator for merkletries (only the trie part of the
merkletrie is relevant here, it does not use the Hasher interface).
The iteration is performed in depth-first pre-order. Entries at each
depth are traversed in (case-sensitive) alphabetical order.
This is the kind of traversal you will expect when listing ordinary
files and directories recursively, for example:
Trie Traversal order
---- ---------------
.
/ | \ c
/ | \ d/
d c z ===> d/a
/ \ d/b
b a z
This iterator is somewhat especial as you can chose to skip whole
"directories" when iterating:
- The Step method will iterate normally.
- the Next method will not descend deeper into the tree.
For example, if the iterator is at `d/`, the Step method will return
`d/a` while the Next would have returned `z` instead (skipping `d/`
and its descendants). The name of the these two methods are based on
the well known "next" and "step" operations, quite common in
debuggers, like gdb.
The paths returned by the iterator will be relative, if the iterator
was created from a single node, or absolute, if the iterator was
created from the path to the node (the path will be prefixed to all
returned paths).
The base path used to turn the relative paths used internally by
the iterator into absolute paths used by external applications.
For relative iterator this will be nil.
The top of this stack has the current node and its siblings. The
rest of the stack keeps the ancestors of the current node and
their corresponding siblings. The current element is always the
top element of the top frame.
When "step"ping into a node, its children are pushed as a new
frame.
When "next"ing pass a node, the current element is dropped by
popping the top frame.
Tells if the iteration has started.
Next returns the path of the next node without descending deeper into
the trie and nil. If there are no more entries in the trie it
returns nil and io.EOF. In case of error, it will return nil and the
error.
Step returns the path to the next node in the trie, descending deeper
into it if needed, and nil. If there are no more nodes in the trie,
it returns nil and io.EOF. In case of error, it will return nil and
the error.
Advances the iterator in the desired direction: descend or
dontDescend.
Returns the new current element and a nil error on success. If there
are no more elements in the trie below the base, it returns nil, and
io.EOF. Returns nil and an error in case of errors.
Returns the path to the current node, adding the base if there was
one, and a nil error. If there were no noders left, it returns nil
and io.EOF. If an error occurred, it returns nil and the error.
removes the current node if any, and all the frames that become empty as a
consequence of this action.
(*T) push(f *frame.Frame)(*T) top() (*frame.Frame, bool)
func NewIter(n noder.Noder) (*Iter, error)
func NewIterFromPath(p noder.Path) (*Iter, error)
func newIter(root noder.Noder, base noder.Path) (*Iter, error)
Answers to a lot of questions you can ask about how to noders are
equal or different.
Are both nodes dirs?
Are both nodes files?
Is one a file and the other a dir?
Is the from node an empty dir?
Do both nodes have the same hash?
Is the to Node an empty dir?
A doubleIter is a convenience type to keep track of the current
noders in two merkletries that are going to be iterated in parallel.
It has methods for:
- iterating over the merkletries, both at the same time or
individually: nextFrom, nextTo, nextBoth, stepBoth
- checking if there are noders left in one or both of them with the
remaining method and its associated returned type.
- comparing the current noders of both merkletries in several ways,
with the compare method and its associated returned type.
fromstruct{iter *Iter; current noder.Path}hashEqualnoder.Equaltostruct{iter *Iter; current noder.Path}
Compare returns the comparison between the current elements in the
merkletries.
NextBoth makes d advance to the next noder in both merkletries. If
any of them is a directory, it skips its contents.
NextFrom makes d advance to the next noder in the "from" merkletrie,
skipping its contents if it is a directory.
NextTo makes d advance to the next noder in the "to" merkletrie,
skipping its contents if it is a directory.
Remaining returns if there are no more noders in the tree, if both
have noders or if one of them doesn't.
StepBoth makes d advance to the next noder in both merkletries,
getting deeper into directories if that is the case.
func newDoubleIter(from, to noder.Noder, hashEqual noder.Equal) (*doubleIter, error)
func diffDirs(changes *Changes, ii *doubleIter) error
func diffNodes(changes *Changes, ii *doubleIter) error
func diffNodesSameName(changes *Changes, ii *doubleIter) error
Package-Level Functions (total 14, in which 8 are exported)
DiffTree calculates the list of changes between two merkletries. It
uses the provided hashEqual callback to compare noders.
DiffTreeContext calculates the list of changes between two merkletries. It
uses the provided hashEqual callback to compare noders.
Error will be returned if context expires
Provided context must be non nil
NewChanges returns an empty list of changes.
NewDelete returns a new Change representing the deletion of n.
NewInsert returns a new Change representing the insertion of n.
NewIter returns a new relative iterator using the provider noder as
its unnamed root. When iterating, all returned paths will be
relative to node.
NewIterFromPath returns a new absolute iterator from the noder at the
end of the path p. When iterating, all returned paths will be
absolute, using the root of the path p as their root.
NewModify returns a new Change representing that a has been modified and
it is now b.
NewdoubleIter returns a new doubleIter for the merkletries "from" and
"to". The hashEqual callback function will be used by the doubleIter
to compare the hash of the noders in the merkletries. The doubleIter
will be initialized to the first elements in each merkletrie if any.
The pages are generated with Goldsv0.3.2-preview. (GOOS=darwin GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.