permgit

package module
v0.3.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 25, 2023 License: MIT Imports: 14 Imported by: 0

README

permgit

Go Reference

Commit, Tree, and Blob

Each commit in git contains the following

  • tree hash
  • parent hashes, lexicographical sorted.
  • the author name and email, and the author timestamp.
  • the committor name and email, and the committor timestamp.
  • commmit message.

hash of the commit is the hash of the above content.

Tree is like a folder structure, all entries lexicographical sorted by names. A tree entry is

  • file mode (regular file, executable file, symlink, tree)
  • name
  • hash

A file (either regular or executable), or blob contains only its content, and the hash is the hash of the header + content.

Create New Linear History

Provided a linear history of commits, we can use the same author/committor/commit message and filter the tree in the commit and create a deterministic new commit.

See Example

Documentation

Overview

permgit is filtered git repo generator. It provides the functionality to create a linear history of commits from another linear history commits by applying selected filters on the entries contained in the commit tree.

See FilterLinearHistory for details.

Example

Example cloning a repo into in-memory store, select several commits from a specific commit, and filter it into another in-memory store.

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/storage/memory"

	"github.com/fardream/permgit"
)

func orPanic(err error) {
	if err != nil {
		log.Panic(err)
	}
}

// Example cloning a repo into in-memory store, select several commits from a specific commit, and filter it into another in-memory store.
func main() {
	// URL for the repo
	url := "https://github.com/fardream/gmsk"
	// commit to start from
	headcommithash := plumbing.NewHash("e0235243feee0ec1bde865be5fa2c0b761eff804")

	// Clone repo
	r, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
		URL: url,
	})
	orPanic(err)

	// find the commit
	headcommit, err := r.CommitObject(headcommithash)
	orPanic(err)

	// obtain the history of the repo.
	hist, err := permgit.GetLinearHistory(context.Background(), headcommit, plumbing.ZeroHash, 10)
	orPanic(err)

	// select 3 files
	orfilter, err := permgit.NewOrFilterForPatterns(
		"README.md",
		"LICENSE",
		"capis.go",
	)
	orPanic(err)

	// output storer
	outputfs := memory.NewStorage()

	newhist, err := permgit.FilterLinearHistory(context.Background(), hist, outputfs, orfilter)
	orPanic(err)

	// Note the result is deterministic
	fmt.Printf("From %d commits, generated %d commits.\nHead commit is:\n", len(hist), len(newhist))
	fmt.Println(newhist[5].String())

}
Output:

From 10 commits, generated 6 commits.
Head commit is:
commit 65e88d11b1331c3031945587c4c28635886fdc92
Author: Chao Xu <fardream@users.noreply.github.com>
Date:   Sat Sep 02 20:19:42 2023 -0400

    Update doc for slice input. (#57)

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func CopyTree added in v0.3.5

func CopyTree(ctx context.Context, t *object.Tree, s storer.Storer) error

func DumpTree added in v0.3.1

func DumpTree(ctx context.Context, prepath []string, tree *object.Tree, filter Filter, output io.Writer) error

func ExpandCommit added in v0.2.0

func ExpandCommit(
	ctx context.Context,
	sourceStorer storer.Storer,
	filteredOrig *object.Commit,
	filteredNew *object.Commit,
	target *object.Commit,
	targetStorer storer.Storer,
	filter Filter,
) (*object.Commit, error)

ExpandCommit added the changes contained in the filteredNew to filteredOrig and try to apply them to target, it will generate a new commit.

func ExpandTree added in v0.2.0

func ExpandTree(
	ctx context.Context,
	sourceStorer storer.Storer,
	filteredOrig *object.Tree,
	filteredNew *object.Tree,
	target *object.Tree,
	targetStorer storer.Storer,
	filter Filter,
) (*object.Tree, error)

ExpandTree apply the changes made in the filteredNew tree to filteredOrig tree and apply them to target tree, it returns a new tree.

func FilterCommit

func FilterCommit(
	ctx context.Context,
	c *object.Commit,
	parent *object.Commit,
	s storer.Storer,
	filters Filter,
) (*object.Commit, error)

FilterCommit creates a new object.Commit in the given storer.Storer by applying filters to the tree in the input object.Commit. Optionally a parent commit can set on the generated commit. The author info, committor info, commit message will be copied from the input commit. Howver, GPG sign information will be dropped.

  • If after filtering, the tree is empty, a nil will be returned, and error will also be nil.
  • If the generated tree is exactly the same as the parent's, the parent commit will be returned and no new commit will be generated.

Submodules will be silently ignored.

func FilterLinearHistory

func FilterLinearHistory(
	ctx context.Context,
	hist []*object.Commit,
	s storer.Storer,
	filter Filter,
) ([]*object.Commit, error)

FilterLinearHistory performs filters on a sequence of commits of a linear history and produces new commits in the provided storer.Store. The first commit is the earliest commit, and the last one is the latest or head.

  • The first commit will become the new root of the filtered repo.
  • Filtered commits containing empty trees cause all previous commits to be dropped. The next commit with non-empty tree will become the new root.
  • Filtered commits containing the exact same tree as its parent will also be dropped, and commit after it will consider its parent its own parent.

The newly created commits will have exact same author info, committor info, commit message, but will parent correctly linked and gpg sign information dropped.

The input commits can be obtained from GetLinearHistory.

func FilterTree

func FilterTree(
	ctx context.Context,
	t *object.Tree,
	prepath []string,
	s storer.Storer,
	filter Filter,
) (*object.Tree, error)

FilterTree filters the entries of the tree by the filter and stores it in the given storer.Storer. If after filtering the tree is empty, nil will be returned for the tree and the error.

Note: Submodules will be silently ignored.

func GetHash added in v0.2.0

func GetHash(o object.Object) (*plumbing.Hash, error)

GetHash returns the hash of the

func GetLinearHistory

func GetLinearHistory(
	ctx context.Context,
	head *object.Commit,
	startHash plumbing.Hash,
	numCommit int,
) ([]*object.Commit, error)

GetLinearHistory produces the linear history from a given head commit.

  • the number of commits can be limit by number of commits included in the history. A limit <= 0 indicates no limit on how many commits can be returned
  • the start commit can be specified by the startHash

It returns an error when more than one parents exist for the commit in the historical list.

func LoadPatternStringFromString added in v0.3.2

func LoadPatternStringFromString(str string, ignoreUnsupported bool) ([]string, error)

LoadPatternStringFromString loads from the string content of a pattern file like .gitignore. Similar to LoadPatternFilterFromString, a false ignoreUnsupported will error if unsupported patterns are encountered.

func RemoveGPGForLinearHistory added in v0.2.0

func RemoveGPGForLinearHistory(ctx context.Context, hist []*object.Commit, s storer.Storer) ([]*object.Commit, error)

func SetLogger added in v0.2.0

func SetLogger(l *slog.Logger)

Types

type AndFilter

type AndFilter struct {
	// contains filtered or unexported fields
}

AndFilter combines multiple [TreeEntryFilter] into one [TreeEntryFilter] with an "and" operation, the path will only be included when all the filters include it.

func NewAndFilter

func NewAndFilter(filters ...Filter) *AndFilter

NewAndFilter creates a new filter with and operations.

func (*AndFilter) Add

func (f *AndFilter) Add(filters ...Filter)

func (*AndFilter) Filter added in v0.3.1

func (f *AndFilter) Filter(paths []string, isdir bool) FilterResult

type CachedFilter added in v0.3.2

type CachedFilter struct {
	// contains filtered or unexported fields
}

CachedFilter records the paths it sees - the cache is no concurrent safe.

func NewCachedFilter added in v0.3.2

func NewCachedFilter(underlying Filter) *CachedFilter

func (*CachedFilter) Filter added in v0.3.2

func (f *CachedFilter) Filter(paths []string, isdir bool) FilterResult

func (*CachedFilter) Reset added in v0.3.2

func (f *CachedFilter) Reset()

Reset clears up the cache

type FilePatchError added in v0.2.0

type FilePatchError struct {
	FromFile string
	ToError  string
}

FilePatchError is an error containing the information about the invalid file patch.

func (*FilePatchError) Error added in v0.2.0

func (e *FilePatchError) Error() string

type Filter added in v0.3.1

type Filter interface {
	Filter(paths []string, isdir bool) FilterResult
}

Filter is the interface used to filter the path of the tree.

func NewOrFilterForPatterns added in v0.3.1

func NewOrFilterForPatterns(patterns ...string) (Filter, error)

NewOrFilterForPatterns creates a new Or filter for all the patterns

type FilterResult added in v0.3.1

type FilterResult uint8

FilterResult indicates the result of a filter, it can be

  • the input is out
  • the input is directory, and its entries should be filtered
  • the input is in

the logic or operation for filter result:

  • If out and in, in
  • If out and dir_dive, dir_dive
  • If dir_dive and in, in

the logic and operation for filter result:

  • if out and int, out
  • if out and dir_dive, out
  • if dir_dive and in, dir_dive

Notice that the enum values has FilterResult_In at 2, FilterResult_DirDive at 1, and FilterResult_Out at 0, therefore the or operation is finding the max, and and operation is finding the min.

const (
	FilterResult_Out     FilterResult = iota // Out
	FilterResult_DirDive                     // DirDive
	FilterResult_In                          // In
)

func DirFilter added in v0.3.1

func DirFilter(paths []string, filtersegs []string) FilterResult

DirFilter filters the directory according to a directory filter.

  • In, if filters match all the leading path segments, and there are zero or more path trailing. | p | p | p | p | f | f | f Or | p | p | p | f | f | f
  • DirDive, if size of path segments is smaller than filters, and those path segments match the corresponding filters | p | p | p | f | f | f | f
  • otherwise it's out.

func FilterPath added in v0.3.2

func FilterPath(f Filter, fullpath string, isdir bool) FilterResult

FilterPath calls Filter f on fullpath string.

func FilterResultsAnd added in v0.3.1

func FilterResultsAnd(r ...FilterResult) FilterResult

FilterResultsAnd perform and operation on the filter results:

  • if out and int, out
  • if out and dir_dive, out
  • if dir_dive and in, dir_dive

func FilterResultsOr added in v0.3.1

func FilterResultsOr(r ...FilterResult) FilterResult

FilterResultsOr perform or operation on filter results:

  • If out and in, in
  • If out and dir_dive, dir_dive
  • If dir_dive and in, in

This is equivalent to take the max value of the input.

func (FilterResult) IsIn added in v0.3.1

func (r FilterResult) IsIn() bool

If the filter result is in

func (FilterResult) String added in v0.3.1

func (i FilterResult) String() string

type OrFilter

type OrFilter struct {
	// contains filtered or unexported fields
}

OrFilter combines multiple [TreeEntryFilter] into one [TreeEntryFilter] with an "or" operation, the path will be inclueded if any one of the filters includes it.

func NewOrFilter

func NewOrFilter(filters ...Filter) *OrFilter

func (*OrFilter) Add

func (f *OrFilter) Add(filters ...Filter)

func (*OrFilter) Filter added in v0.3.1

func (f *OrFilter) Filter(paths []string, isdir bool) FilterResult

type PatternFilter added in v0.3.1

type PatternFilter struct {
	// contains filtered or unexported fields
}

PatternFilter filters the entries according to a restricted pattern of .gitignore

  • '**' is for multi level directories, and it can only appear once in the match.
  • '*' is for match one level of names.
  • '!' and escapes are unsupported.

func LoadPatternFilterFromString added in v0.3.2

func LoadPatternFilterFromString(str string, ignoreUnsupported bool) ([]*PatternFilter, error)

LoadPatternFilterFromString loads the string content of a pattern file like .gitignore. If ignoreUnsupported is set to false, the loader will error if the any unsupported patterns like ! (reverse) is encountered.

func NewPatternFilter added in v0.3.1

func NewPatternFilter(pattern string) (*PatternFilter, error)

func (*PatternFilter) Filter added in v0.3.1

func (f *PatternFilter) Filter(paths []string, isdir bool) FilterResult

type TrueFilter added in v0.3.1

type TrueFilter struct{}

TrueFilter always return FilterResult_In for any input.

func (TrueFilter) Filter added in v0.3.1

func (TrueFilter) Filter(path []string, isdir bool) FilterResult

Directories

Path Synopsis
cmd
cmd package contains helper functions for various commands.
cmd package contains helper functions for various commands.
dump-git-tree
dump-git-tree dumps the git tree and optionally apply pattern filters.
dump-git-tree dumps the git tree and optionally apply pattern filters.
expand-git-commit
expand-git-commit adds back the changes made in a repo filtered by filter-git-hist to the unfiltered repo.
expand-git-commit adds back the changes made in a repo filtered by filter-git-hist to the unfiltered repo.
filter-git-hist
filter-git-hist is a more robust but limited git-filter-branch.
filter-git-hist is a more robust but limited git-filter-branch.
remove-git-gpg
remove-git-gpg removes gpg information from series of commits.
remove-git-gpg removes gpg information from series of commits.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL