patch

package
v0.66.0 Latest Latest
Warning

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

Go to latest
Published: Oct 5, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ChangeLineIndexByIdentity added in v0.66.0

func ChangeLineIndexByIdentity(parsed *Patch) map[LineIdentity]int

ChangeLineIndexByIdentity indexes a parsed diff's change lines by their identity. An addition is numbered in the new file and a deletion in the old one. Two consecutive deletions share the one new-file position between them, and numbering them in the old file keeps them apart.

func ChangeLineIndicesForLines added in v0.66.0

func ChangeLineIndicesForLines(parsed *Patch, lines []LineIdentity) []int

ChangeLineIndicesForLines maps the given change lines of a parsed diff to their indices in it. A line that names no change line of the diff — a context line, or a line that isn't in the diff at all — contributes nothing.

func ExpandRange added in v0.38.0

func ExpandRange(start int, end int) []int

helper function that takes a start and end index and returns a slice of all indexes inbetween (inclusive)

Types

type FormatViewOpts added in v0.38.0

type FormatViewOpts struct {
	// line indices for tagged lines (e.g. lines added to a custom patch)
	IncLineIndices *set.Set[int]
}

type Hunk added in v0.38.0

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

type LineIdentity added in v0.66.0

type LineIdentity struct {
	LineNumber int
	IsDeletion bool
}

LineIdentity says which change line of a file is meant — the line number it has on the side it belongs to, and whether it is a deletion — without reference to where that line sits in the file's parsed diff.

It is how a diff shown in the main view speaks about its lines: what a rendered row resolves to is a line of a file, while the index of that line in the diff depends on how much of the diff is being shown and in what order a renderer laid it out.

type Patch added in v0.38.0

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

func Parse added in v0.38.0

func Parse(patchStr string) *Patch

func (*Patch) AdjustLineNumber added in v0.45.0

func (self *Patch) AdjustLineNumber(lineNumber int) int

Adjust the given line number (one-based) according to the current patch. The patch is supposed to be a diff of an old file state against the working directory; the line number is a line number in that old file, and the function returns the corresponding line number in the working directory file.

func (*Patch) ContainsChanges added in v0.38.0

func (self *Patch) ContainsChanges() bool

func (*Patch) FormatPlain added in v0.38.0

func (self *Patch) FormatPlain() string

Returns the patch as a plain string

func (*Patch) FormatRangePlain added in v0.38.0

func (self *Patch) FormatRangePlain(startIdx int, endIdx int) string

Returns a range of lines from the patch as a plain string (range is inclusive)

func (*Patch) FormatView added in v0.38.0

func (self *Patch) FormatView(opts FormatViewOpts) string

Returns the patch as a string with ANSI color codes for displaying in a view

func (*Patch) GetNextChangeIdx added in v0.38.0

func (self *Patch) GetNextChangeIdx(idx int) int

Returns the patch line index of the next change (i.e. addition or deletion).

func (*Patch) GetNextChangeIdxOfSameIncludedState added in v0.53.0

func (self *Patch) GetNextChangeIdxOfSameIncludedState(idx int, includedLines []int, included bool) (int, bool)

Returns the patch line index of the next change (i.e. addition or deletion) that matches the same "included" state, given the includedLines. If you don't care about included states, pass nil for includedLines and false for included.

func (*Patch) HunkContainingLine added in v0.38.0

func (self *Patch) HunkContainingLine(idx int) int

Returns hunk index containing the line at the given patch line index

func (*Patch) HunkCount added in v0.41.0

func (self *Patch) HunkCount() int

Returns the number of hunks of the patch

func (*Patch) HunkEndIdx added in v0.38.0

func (self *Patch) HunkEndIdx(hunkIndex int) int

Returns the patch line index of the last line in the given hunk

func (*Patch) HunkOldStartForLine added in v0.61.0

func (self *Patch) HunkOldStartForLine(idx int) int

Returns the old-file starting line number of the hunk containing the given patch line index. Returns 0 if the line is not inside any hunk.

func (*Patch) HunkStartIdx added in v0.38.0

func (self *Patch) HunkStartIdx(hunkIndex int) int

Returns the patch line index of the first line in the given hunk

func (*Patch) IsWellFormed added in v0.66.0

func (self *Patch) IsWellFormed() bool

IsWellFormed reports whether every hunk's body matches the lengths declared in its header. A faithful unified diff always satisfies this; a rendering that restructured the diff body does not — a diff renderer that puts line numbers in a gutter, say, shifts the +/- marker off the start of each line, so every body line reads as context and the computed lengths no longer match the header. That makes this the test for whether a rendered diff can be parsed as a unified diff at all, rather than trusting a mis-parse. Only meaningful for patches produced by Parse, which is where the declared lengths come from.

func (*Patch) IsWellFormedSoFar added in v0.66.0

func (self *Patch) IsWellFormedSoFar() bool

IsWellFormedSoFar is IsWellFormed for a patch parsed from a diff we have only the beginning of. Its last hunk holds the first lines of a body that hasn't all arrived, so every hunk but the last has to match its header exactly, as before, while the last one only has to fit within what its header declares.

The check exists to tell a faithful rendering from a restructured one, and it still does that. A rendering that moves the +/- marker off the start of the line makes us read a change as context, and a context line counts towards both lengths, so such a hunk comes out longer than its header declares rather than shorter.

func (*Patch) LineCount added in v0.38.0

func (self *Patch) LineCount() int

Returns the length of the patch in lines

func (*Patch) LineNumberOfLine added in v0.38.0

func (self *Patch) LineNumberOfLine(idx int) int

Takes a line index in the patch and returns the line number in the new file. If the line is a header line, returns 1. If the line is a hunk header line, returns the first file line number in that hunk. If the line is out of range below, returns the last file line number in the last hunk.

func (*Patch) Lines added in v0.38.0

func (self *Patch) Lines() []*PatchLine

Returns the lines of the patch

func (*Patch) OldLineNumberOfLine added in v0.66.0

func (self *Patch) OldLineNumberOfLine(idx int) int

Takes a line index in the patch and returns the line number in the old file. This is the old-file counterpart of LineNumberOfLine; for a deletion it gives the line's position in the old file (additions get the position they sit at). If the line is a header line, returns 1. If the line is a hunk header line, returns the first old-file line number in that hunk. If the line is out of range below, returns the last old-file line number in the last hunk.

func (*Patch) Transform added in v0.38.0

func (self *Patch) Transform(opts TransformOpts) *Patch

Returns a new patch with the specified transformation applied (e.g. only selecting a subset of changes). Leaves the original patch unchanged.

type PatchBuilder added in v0.38.0

type PatchBuilder struct {
	// To is the commit hash if we're dealing with files of a commit, or a stash ref for a stash
	To   string
	From string

	// CanRebase tells us whether we're allowed to modify our commits. CanRebase should be true for commits of the currently checked out branch and false for everything else
	// TODO: move this out into a proper mode struct in the gui package: it doesn't really belong here
	CanRebase bool

	Log *logrus.Entry
	// contains filtered or unexported fields
}

PatchBuilder manages the building of a patch for a commit to be applied to another commit (or the working tree, or removed from the current commit). We also support building patches from things like stashes, for which there is less flexibility

func NewPatchBuilder added in v0.38.0

func NewPatchBuilder(
	log *logrus.Entry, loadFileDiff loadFileDiffFunc, newTempDir func() (string, error),
) *PatchBuilder

func (*PatchBuilder) Active added in v0.38.0

func (p *PatchBuilder) Active() bool

func (*PatchBuilder) AddFileLineRange added in v0.38.0

func (p *PatchBuilder) AddFileLineRange(filename string, previousPath string, lineIndices []int) error

func (*PatchBuilder) AddFileWhole added in v0.38.0

func (p *PatchBuilder) AddFileWhole(filename string, previousPath string) error

func (*PatchBuilder) AllFilesInPatch added in v0.38.0

func (p *PatchBuilder) AllFilesInPatch() []string

func (*PatchBuilder) FilesInPatch added in v0.66.0

func (p *PatchBuilder) FilesInPatch() []PatchFile

FilesInPatch says which files the patch touches, in a stable order, and where each of them comes from.

func (*PatchBuilder) Generation added in v0.66.0

func (p *PatchBuilder) Generation() int

Generation says which version of the patch this is; see the field.

func (*PatchBuilder) GetFileIncLineIndices added in v0.38.0

func (p *PatchBuilder) GetFileIncLineIndices(filename string, previousPath string) ([]int, error)

func (*PatchBuilder) GetFileStatus added in v0.38.0

func (p *PatchBuilder) GetFileStatus(filename string, parent string) PatchStatus

func (*PatchBuilder) IncludedChangeLineIndices added in v0.66.0

func (p *PatchBuilder) IncludedChangeLineIndices(filename string) []int

IncludedChangeLineIndices says which of filename's change lines are in the patch, as their indices in the file's diff and in the order the file has them.

It is how a line of the patch as it is shown names the line of the diff it came from: all that can be said about a line of the patch is which of the file's changes it is, its line numbers being the patch's own — a patch that leaves an earlier addition out numbers everything after it differently from the diff it was built from.

func (*PatchBuilder) IncludedLineIdentities added in v0.66.0

func (p *PatchBuilder) IncludedLineIdentities(filename string) []LineIdentity

IncludedLineIdentities says which change lines of filename are in the patch, as the identities a diff of that file shown anywhere can be compared against. Empty for a file that is no part of the patch.

func (*PatchBuilder) IsEmpty added in v0.38.0

func (p *PatchBuilder) IsEmpty() bool

func (*PatchBuilder) NewPatchRequired added in v0.38.0

func (p *PatchBuilder) NewPatchRequired(from string, to string, reverse bool) bool

if any of these things change we'll need to reset and start a new patch

func (*PatchBuilder) PatchLineIndicesForLines added in v0.66.0

func (p *PatchBuilder) PatchLineIndicesForLines(
	filename string, previousPath string, lines []LineIdentity,
) (indices []int, everyChange bool, err error)

PatchLineIndicesForLines maps change lines of filename to their indices in that file's diff; the patch is built in terms of those indices. everyChange reports whether the given lines cover all of the file's changes; this distinguishes acting on some of a file's lines from acting on the file itself.

func (*PatchBuilder) PatchToApply added in v0.39.0

func (p *PatchBuilder) PatchToApply(reverse bool, turnAddedFilesIntoDiffAgainstEmptyFile bool) string

func (*PatchBuilder) RemoveFile added in v0.38.0

func (p *PatchBuilder) RemoveFile(filename string, previousPath string) error

func (*PatchBuilder) RemoveFileLineRange added in v0.38.0

func (p *PatchBuilder) RemoveFileLineRange(filename string, previousPath string, lineIndices []int) error

func (*PatchBuilder) RenderAggregatedPatch added in v0.38.0

func (p *PatchBuilder) RenderAggregatedPatch(plain bool) string

func (*PatchBuilder) RenderPatchForFile added in v0.38.0

func (p *PatchBuilder) RenderPatchForFile(opts RenderPatchForFileOpts) string

func (*PatchBuilder) Reset added in v0.38.0

func (p *PatchBuilder) Reset()

clears the patch

func (*PatchBuilder) Start added in v0.38.0

func (p *PatchBuilder) Start(from, to string, reverse bool, canRebase bool)

func (*PatchBuilder) TempDir added in v0.66.0

func (p *PatchBuilder) TempDir() string

TempDir is the directory the patch is materialized into for rendering, and "" when there is none — no patch, or a directory we failed to make.

type PatchFile added in v0.66.0

type PatchFile struct {
	// Path is the name the patch knows the file by: for a renamed file, the name it had
	// before where the patch carries the rename, and the name it was renamed to where the
	// patch keeps only a content change and leaves the rename behind.
	Path string
	// ContentPath is where the file's content before the patch is to be found in the
	// commit the patch is built from — for a renamed file always the name it had there,
	// whatever the patch calls it.
	ContentPath string
}

PatchFile records what materializing the patch needs to know about one of its files: where the patch expects to find it, and where its content before the patch comes from.

type PatchLine

type PatchLine struct {
	Kind    PatchLineKind
	Content string // something like '+ hello' (note the first character is not removed)
}

func (*PatchLine) IsAddition added in v0.61.0

func (self *PatchLine) IsAddition() bool

func (*PatchLine) IsChange added in v0.53.0

func (self *PatchLine) IsChange() bool

func (*PatchLine) IsDeletion added in v0.61.0

func (self *PatchLine) IsDeletion() bool

type PatchLineKind added in v0.27.1

type PatchLineKind int
const (
	PATCH_HEADER PatchLineKind = iota
	HUNK_HEADER
	ADDITION
	DELETION
	CONTEXT
	NEWLINE_MESSAGE
)

type PatchStatus added in v0.27.1

type PatchStatus int
const (
	// UNSELECTED is for when the commit file has not been added to the patch in any way
	UNSELECTED PatchStatus = iota
	// WHOLE is for when you want to add the whole diff of a file to the patch,
	// including e.g. if it was deleted
	WHOLE
	// PART is for when you're only talking about specific lines that have been modified
	PART
)

type RenderPatchForFileOpts added in v0.43.0

type RenderPatchForFileOpts struct {
	Filename                               string
	PreviousPath                           string
	Plain                                  bool
	Reverse                                bool
	TurnAddedFilesIntoDiffAgainstEmptyFile bool
}

type TransformOpts added in v0.38.0

type TransformOpts struct {
	// Create a patch that will applied in reverse with `git apply --reverse`.
	// This affects how unselected lines are treated when only parts of a hunk
	// are selected: usually, for unselected lines we change '-' lines to
	// context lines and remove '+' lines, but when Reverse is true we need to
	// turn '+' lines into context lines and remove '-' lines.
	Reverse bool

	// If set, we will replace the original header with one referring to this file name.
	// For staging/unstaging lines we don't want the original header because
	// it makes git confused e.g. when dealing with deleted/added files
	// but with building and applying patches the original header gives git
	// information it needs to cleanly apply patches
	FileNameOverride string

	// Custom patches tend to work better when treating new files as diffs
	// against an empty file. The only case where we need this to be false is
	// when moving a custom patch to an earlier commit; in that case the patch
	// command would fail with the error "file does not exist in index" if we
	// treat it as a diff against an empty file.
	TurnAddedFilesIntoDiffAgainstEmptyFile bool

	// When building a partial patch for a renamed file, strip the rename
	// metadata from the header and point it at the new path. Applying the
	// resulting patch then only changes the file's contents and leaves the
	// rename itself in place. (For a whole-file selection we keep the rename
	// so that it moves or is discarded together with the contents.)
	StripRename bool

	// The indices of lines that should be included in the patch.
	IncludedLineIndices []int
}

Jump to

Keyboard shortcuts

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