git

package module
v4.0.0-rc11+incompatible Latest Latest
Warning

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

Go to latest
Published: Jun 21, 2017 License: MIT Imports: 41 Imported by: 0

README

go-git GoDoc Build Status codecov.io codebeat badge

A highly extensible git implementation in pure Go.

go-git aims to reach the completeness of libgit2 or jgit, nowadays covers the majority of the plumbing read operations and some of the main write operations, but lacks the main porcelain operations such as merges.

It is highly extensible, we have been following the open/close principle in its design to facilitate extensions, mainly focusing the efforts on the persistence of the objects.

... is this production ready?

The master branch represents the v4 of the library, it is currently under active development and is planned to be released in early 2017.

If you are looking for a production ready version, please take a look to the v3 which is being used in production at source{d} since August 2015 to analyze all GitHub public repositories (i.e. 16M repositories).

We recommend the use of v4 to develop new projects since it includes much new functionality and provides a more idiomatic git API

Installation

The recommended way to install go-git is:

go get -u gopkg.in/src-d/go-git.v4/...

Examples

Please note that the functions CheckIfError and Info used in the examples are from the examples package just to be used in the examples.

Basic example

A basic example that mimics the standard git clone command

// Clone the given repository to the given directory
Info("git clone https://github.com/src-d/go-git")

_, err := git.PlainClone("/tmp/foo", false, &git.CloneOptions{
    URL:      "https://github.com/src-d/go-git",
    Progress: os.Stdout,
})

CheckIfError(err)

Outputs:

Counting objects: 4924, done.
Compressing objects: 100% (1333/1333), done.
Total 4924 (delta 530), reused 6 (delta 6), pack-reused 3533
In-memory example

Cloning a repository into memory and printing the history of HEAD, just like git log does

// Clones the given repository in memory, creating the remote, the local
// branches and fetching the objects, exactly as:
Info("git clone https://github.com/src-d/go-siva")

r, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
    URL: "https://github.com/src-d/go-siva",
})

CheckIfError(err)

// Gets the HEAD history from HEAD, just like does:
Info("git log")

// ... retrieves the branch pointed by HEAD
ref, err := r.Head()
CheckIfError(err)

// ... retrieves the commit object
commit, err := r.CommitObject(ref.Hash())
CheckIfError(err)

// ... retrieves the commit history
history, err := commit.History()
CheckIfError(err)

// ... just iterates over the commits, printing it
for _, c := range history {
    fmt.Println(c)
}

Outputs:

commit ded8054fd0c3994453e9c8aacaf48d118d42991e
Author: Santiago M. Mola <santi@mola.io>
Date:   Sat Nov 12 21:18:41 2016 +0100

    index: ReadFrom/WriteTo returns IndexReadError/IndexWriteError. (#9)

commit df707095626f384ce2dc1a83b30f9a21d69b9dfc
Author: Santiago M. Mola <santi@mola.io>
Date:   Fri Nov 11 13:23:22 2016 +0100

    readwriter: fix bug when writing index. (#10)

    When using ReadWriter on an existing siva file, absolute offset for
    index entries was not being calculated correctly.
...

You can find this example and many other at the examples folder

Comparison With Git

In the compatibility documentation you can find a comparison table of git with go-git.

Contribute

If you are interested on contributing to go-git, open an issue explaining which missing functionality you want to work in, and we will guide you through the implementation.

License

MIT, see LICENSE

Documentation

Overview

A highly extensible git implementation in pure Go.

go-git aims to reach the completeness of libgit2 or jgit, nowadays covers the majority of the plumbing read operations and some of the main write operations, but lacks the main porcelain operations such as merges.

It is highly extensible, we have been following the open/close principle in its design to facilitate extensions, mainly focusing the efforts on the persistence of the objects.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrObjectNotFound          = errors.New("object not found")
	ErrInvalidReference        = errors.New("invalid reference, should be a tag or a branch")
	ErrRepositoryNotExists     = errors.New("repository not exists")
	ErrRepositoryAlreadyExists = errors.New("repository already exists")
	ErrRemoteNotFound          = errors.New("remote not found")
	ErrRemoteExists            = errors.New("remote already exists")
	ErrWorktreeNotProvided     = errors.New("worktree should be provided")
	ErrIsBareRepository        = errors.New("worktree not available in a bare repository")
)
View Source
var (
	ErrSubmoduleAlreadyInitialized = errors.New("submodule already initialized")
	ErrSubmoduleNotInitialized     = errors.New("submodule not initialized")
)
View Source
var (
	ErrWorktreeNotClean  = errors.New("worktree is not clean")
	ErrSubmoduleNotFound = errors.New("submodule not found")
	ErrUnstaggedChanges  = errors.New("worktree contains unstagged changes")
)
View Source
var ErrDestinationExists = errors.New("destination exists")

ErrDestinationExists in an Move operation means that the target exists on the worktree.

View Source
var (
	ErrMissingAuthor = errors.New("author field is required")
)
View Source
var (
	ErrMissingURL = errors.New("URL field is required")
)
View Source
var NoErrAlreadyUpToDate = errors.New("already up-to-date")

Functions

This section is empty.

Types

type BlameResult

type BlameResult struct {
	// Path is the path of the File that we're blaming.
	Path string
	// Rev (Revision) is the hash of the specified Commit used to generate this result.
	Rev plumbing.Hash
	// Lines contains every line with its authorship.
	Lines []*Line
}

BlameResult represents the result of a Blame operation.

func Blame

func Blame(c *object.Commit, path string) (*BlameResult, error)

Blame returns a BlameResult with the information about the last author of each line from file `path` at commit `c`.

type CheckoutOptions

type CheckoutOptions struct {
	// Hash to be checked out, if used HEAD will in detached mode. Branch and
	// Hash are mutual exclusive.
	Hash plumbing.Hash
	// Branch to be checked out, if Branch and Hash are empty is set to `master`.
	Branch plumbing.ReferenceName
	// Force, if true when switching branches, proceed even if the index or the
	// working tree differs from HEAD. This is used to throw away local changes
	Force bool
}

CheckoutOptions describes how a checkout 31operation should be performed.

func (*CheckoutOptions) Validate

func (o *CheckoutOptions) Validate() error

Validate validates the fields and sets the default values.

type CloneOptions

type CloneOptions struct {
	// The (possibly remote) repository URL to clone from.
	URL string
	// Auth credentials, if required, to use with the remote repository.
	Auth transport.AuthMethod
	// Name of the remote to be added, by default `origin`.
	RemoteName string
	// Remote branch to clone.
	ReferenceName plumbing.ReferenceName
	// Fetch only ReferenceName if true.
	SingleBranch bool
	// Limit fetching to the specified number of commits.
	Depth int
	// RecurseSubmodules after the clone is created, initialize all submodules
	// within, using their default settings. This option is ignored if the
	// cloned repository does not have a worktree.
	RecurseSubmodules SubmoduleRescursivity
	// Progress is where the human readable information sent by the server is
	// stored, if nil nothing is stored and the capability (if supported)
	// no-progress, is sent to the server to avoid send this information.
	Progress sideband.Progress
}

CloneOptions describes how a clone should be performed.

func (*CloneOptions) Validate

func (o *CloneOptions) Validate() error

Validate validates the fields and sets the default values.

type CommitOptions

type CommitOptions struct {
	// All automatically stage files that have been modified and deleted, but
	// new files you have not told Git about are not affected.
	All bool
	// Author is the author's signature of the commit.
	Author *object.Signature
	// Committer is the committer's signature of the commit. If Committer is
	// nil the Author signature is used.
	Committer *object.Signature
	// Parents are the parents commits for the new commit, by default when
	// len(Parents) is zero, the hash of HEAD reference is used.
	Parents []plumbing.Hash
}

CommitOptions describes how a commit operation should be performed.

func (*CommitOptions) Validate

func (o *CommitOptions) Validate(r *Repository) error

Validate validates the fields and sets the default values.

type FetchOptions

type FetchOptions struct {
	// Name of the remote to fetch from. Defaults to origin.
	RemoteName string
	RefSpecs   []config.RefSpec
	// Depth limit fetching to the specified number of commits from the tip of
	// each remote branch history.
	Depth int
	// Auth credentials, if required, to use with the remote repository.
	Auth transport.AuthMethod
	// Progress is where the human readable information sent by the server is
	// stored, if nil nothing is stored and the capability (if supported)
	// no-progress, is sent to the server to avoid send this information.
	Progress sideband.Progress
}

FetchOptions describes how a fetch should be performed

func (*FetchOptions) Validate

func (o *FetchOptions) Validate() error

Validate validates the fields and sets the default values.

type FileStatus

type FileStatus struct {
	// Staging is the status of a file in the staging area
	Staging StatusCode
	// Worktree is the status of a file in the worktree
	Worktree StatusCode
	// Extra contains extra information, such as the previous name in a rename
	Extra string
}

FileStatus contains the status of a file in the worktree

type Line

type Line struct {
	// Author is the email address of the last author that modified the line.
	Author string
	// Text is the original text of the line.
	Text string
}

Line values represent the contents and author of a line in BlamedResult values.

type LogOptions

type LogOptions struct {
	// When the From option is set the log will only contain commits
	// reachable from it. If this option is not set, HEAD will be used as
	// the default From.
	From plumbing.Hash
}

LogOptions describes how a log action should be performed.

type PullOptions

type PullOptions struct {
	// Name of the remote to be pulled. If empty, uses the default.
	RemoteName string
	// Remote branch to clone. If empty, uses HEAD.
	ReferenceName plumbing.ReferenceName
	// Fetch only ReferenceName if true.
	SingleBranch bool
	// Limit fetching to the specified number of commits.
	Depth int
	// Auth credentials, if required, to use with the remote repository.
	Auth transport.AuthMethod
	// RecurseSubmodules controls if new commits of all populated submodules
	// should be fetched too.
	RecurseSubmodules SubmoduleRescursivity
	// Progress is where the human readable information sent by the server is
	// stored, if nil nothing is stored and the capability (if supported)
	// no-progress, is sent to the server to avoid send this information.
	Progress sideband.Progress
}

PullOptions describes how a pull should be performed.

func (*PullOptions) Validate

func (o *PullOptions) Validate() error

Validate validates the fields and sets the default values.

type PushOptions

type PushOptions struct {
	// RemoteName is the name of the remote to be pushed to.
	RemoteName string
	// RefSpecs specify what destination ref to update with what source
	// object. A refspec with empty src can be used to delete a reference.
	RefSpecs []config.RefSpec
	// Auth credentials, if required, to use with the remote repository.
	Auth transport.AuthMethod
}

PushOptions describes how a push should be performed.

func (*PushOptions) Validate

func (o *PushOptions) Validate() error

Validate validates the fields and sets the default values.

type Remote

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

Remote represents a connection to a remote repository.

func (*Remote) Config

func (r *Remote) Config() *config.RemoteConfig

Config returns the RemoteConfig object used to instantiate this Remote.

func (*Remote) Fetch

func (r *Remote) Fetch(o *FetchOptions) error

Fetch fetches references from the remote to the local repository. Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are no changes to be fetched and no local references to update, or an error.

func (*Remote) Push

func (r *Remote) Push(o *PushOptions) (err error)

Push performs a push to the remote. Returns NoErrAlreadyUpToDate if the remote was already up-to-date.

func (*Remote) String

func (r *Remote) String() string

type Repository

type Repository struct {
	Storer storage.Storer
	// contains filtered or unexported fields
}

Repository represents a git repository

func Clone

func Clone(s storage.Storer, worktree billy.Filesystem, o *CloneOptions) (*Repository, error)

Clone a repository into the given Storer and worktree Filesystem with the given options, if worktree is nil a bare repository is created. If the given storer is not empty ErrRepositoryAlreadyExists is returned

Example
Output:

Initial changelog

func Init

func Init(s storage.Storer, worktree billy.Filesystem) (*Repository, error)

Init creates an empty git repository, based on the given Storer and worktree. The worktree Filesystem is optional, if nil a bare repository is created. If the given storer is not empty ErrRepositoryAlreadyExists is returned

func Open

func Open(s storage.Storer, worktree billy.Filesystem) (*Repository, error)

Open opens a git repository using the given Storer and worktree filesystem, if the given storer is complete empty ErrRepositoryNotExists is returned. The worktree can be nil when the repository being opened is bare, if the repository is a normal one (not bare) and worktree is nil the err ErrWorktreeNotProvided is returned

func PlainClone

func PlainClone(path string, isBare bool, o *CloneOptions) (*Repository, error)

PlainClone a repository into the path with the given options, isBare defines if the new repository will be bare or normal. If the path is not empty ErrRepositoryAlreadyExists is returned

Example
Output:

Initial changelog

func PlainInit

func PlainInit(path string, isBare bool) (*Repository, error)

PlainInit create an empty git repository at the given path. isBare defines if the repository will have worktree (non-bare) or not (bare), if the path is not empty ErrRepositoryAlreadyExists is returned

func PlainOpen

func PlainOpen(path string) (*Repository, error)

PlainOpen opens a git repository from the given path. It detects if the repository is bare or a normal one. If the path doesn't contain a valid repository ErrRepositoryNotExists is returned

func (*Repository) BlobObject

func (r *Repository) BlobObject(h plumbing.Hash) (*object.Blob, error)

BlobObject returns a Blob with the given hash. If not found plumbing.ErrObjectNotFound is returned.

func (*Repository) BlobObjects

func (r *Repository) BlobObjects() (*object.BlobIter, error)

BlobObjects returns an unsorted BlobIter with all the blobs in the repository.

func (*Repository) Branches

func (r *Repository) Branches() (storer.ReferenceIter, error)

Branches returns all the References that are Branches.

func (*Repository) CommitObject

func (r *Repository) CommitObject(h plumbing.Hash) (*object.Commit, error)

CommitObject return a Commit with the given hash. If not found plumbing.ErrObjectNotFound is returned.

func (*Repository) CommitObjects

func (r *Repository) CommitObjects() (object.CommitIter, error)

CommitObjects returns an unsorted CommitIter with all the commits in the repository.

func (*Repository) Config

func (r *Repository) Config() (*config.Config, error)

Config return the repository config

func (*Repository) CreateRemote

func (r *Repository) CreateRemote(c *config.RemoteConfig) (*Remote, error)

CreateRemote creates a new remote

Example
Output:

func (*Repository) DeleteRemote

func (r *Repository) DeleteRemote(name string) error

DeleteRemote delete a remote from the repository and delete the config

func (*Repository) Fetch

func (r *Repository) Fetch(o *FetchOptions) error

Fetch fetches changes from a remote repository. Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are no changes to be fetched, or an error.

func (*Repository) Head

func (r *Repository) Head() (*plumbing.Reference, error)

Head returns the reference where HEAD is pointing to.

func (*Repository) Log

Log returns the commit history from the given LogOptions.

func (*Repository) Notes

func (r *Repository) Notes() (storer.ReferenceIter, error)

Notes returns all the References that are Branches.

func (*Repository) Object

Object returns an Object with the given hash. If not found plumbing.ErrObjectNotFound is returned.

func (*Repository) Objects

func (r *Repository) Objects() (*object.ObjectIter, error)

Objects returns an unsorted ObjectIter with all the objects in the repository.

func (*Repository) Pull

func (r *Repository) Pull(o *PullOptions) error

Pull incorporates changes from a remote repository into the current branch. Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are no changes to be fetched, or an error.

func (*Repository) Push

func (r *Repository) Push(o *PushOptions) error

Push pushes changes to a remote.

func (*Repository) Reference

func (r *Repository) Reference(name plumbing.ReferenceName, resolved bool) (
	*plumbing.Reference, error)

Reference returns the reference for a given reference name. If resolved is true, any symbolic reference will be resolved.

func (*Repository) References

func (r *Repository) References() (storer.ReferenceIter, error)

References returns an unsorted ReferenceIter for all references.

Example
Output:

func (*Repository) Remote

func (r *Repository) Remote(name string) (*Remote, error)

Remote return a remote if exists

func (*Repository) Remotes

func (r *Repository) Remotes() ([]*Remote, error)

Remotes returns a list with all the remotes

func (*Repository) ResolveRevision

func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, error)

ResolveRevision resolves revision to corresponding hash.

func (*Repository) TagObject

func (r *Repository) TagObject(h plumbing.Hash) (*object.Tag, error)

TagObject returns a Tag with the given hash. If not found plumbing.ErrObjectNotFound is returned. This method only returns annotated Tags, no lightweight Tags.

func (*Repository) TagObjects

func (r *Repository) TagObjects() (*object.TagIter, error)

TagObjects returns a unsorted TagIter that can step through all of the annotated tags in the repository.

func (*Repository) Tags

func (r *Repository) Tags() (storer.ReferenceIter, error)

Tags returns all the References from Tags. This method returns all the tag types, lightweight, and annotated ones.

func (*Repository) TreeObject

func (r *Repository) TreeObject(h plumbing.Hash) (*object.Tree, error)

TreeObject return a Tree with the given hash. If not found plumbing.ErrObjectNotFound is returned

func (*Repository) TreeObjects

func (r *Repository) TreeObjects() (*object.TreeIter, error)

TreeObjects returns an unsorted TreeIter with all the trees in the repository

func (*Repository) Worktree

func (r *Repository) Worktree() (*Worktree, error)

Worktree returns a worktree based on the given fs, if nil the default worktree will be used.

type ResetMode

type ResetMode int8

ResetMode defines the mode of a reset operation.

const (
	// HardReset resets the index and working tree. Any changes to tracked files
	// in the working tree are discarded.
	HardReset ResetMode = iota
	// MixedReset resets the index but not the working tree (i.e., the changed
	// files are preserved but not marked for commit) and reports what has not
	// been updated. This is the default action.
	MixedReset
	// MergeReset resets the index and updates the files in the working tree
	// that are different between Commit and HEAD, but keeps those which are
	// different between the index and working tree (i.e. which have changes
	// which have not been added).
	//
	// If a file that is different between Commit and the index has unstaged
	// changes, reset is aborted.
	MergeReset
)

type ResetOptions

type ResetOptions struct {
	// Commit, if commit is pressent set the current branch head (HEAD) to it.
	Commit plumbing.Hash
	// Mode, form resets the current branch head to Commit and possibly updates
	// the index (resetting it to the tree of Commit) and the working tree
	// depending on Mode. If empty MixedReset is used.
	Mode ResetMode
}

ResetOptions describes how a reset operation should be performed.

func (*ResetOptions) Validate

func (o *ResetOptions) Validate(r *Repository) error

Validate validates the fields and sets the default values.

type Status

type Status map[string]*FileStatus

Status represents the current status of a Worktree. The key of the map is the path of the file.

func (Status) File

func (s Status) File(path string) *FileStatus

File returns the FileStatus for a given path, if the FileStatus doesn't exists a new FileStatus is added to the map using the path as key.

func (Status) IsClean

func (s Status) IsClean() bool

IsClean returns true if all the files aren't in Unmodified status.

func (Status) String

func (s Status) String() string

type StatusCode

type StatusCode byte

StatusCode status code of a file in the Worktree

const (
	Unmodified         StatusCode = ' '
	Untracked          StatusCode = '?'
	Modified           StatusCode = 'M'
	Added              StatusCode = 'A'
	Deleted            StatusCode = 'D'
	Renamed            StatusCode = 'R'
	Copied             StatusCode = 'C'
	UpdatedButUnmerged StatusCode = 'U'
)

type Submodule

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

Submodule a submodule allows you to keep another Git repository in a subdirectory of your repository.

func (*Submodule) Config

func (s *Submodule) Config() *config.Submodule

Config returns the submodule config

func (*Submodule) Init

func (s *Submodule) Init() error

Init initialize the submodule reading the recorded Entry in the index for the given submodule

func (*Submodule) Repository

func (s *Submodule) Repository() (*Repository, error)

Repository returns the Repository represented by this submodule

func (*Submodule) Status

func (s *Submodule) Status() (*SubmoduleStatus, error)

Status returns the status of the submodule.

func (*Submodule) Update

func (s *Submodule) Update(o *SubmoduleUpdateOptions) error

Update the registered submodule to match what the superproject expects, the submodule should be initialized first calling the Init method or setting in the options SubmoduleUpdateOptions.Init equals true

type SubmoduleRescursivity

type SubmoduleRescursivity uint

SubmoduleRescursivity defines how depth will affect any submodule recursive operation.

const (
	// DefaultRemoteName name of the default Remote, just like git command.
	DefaultRemoteName = "origin"

	// NoRecurseSubmodules disables the recursion for a submodule operation.
	NoRecurseSubmodules SubmoduleRescursivity = 0
	// DefaultSubmoduleRecursionDepth allow recursion in a submodule operation.
	DefaultSubmoduleRecursionDepth SubmoduleRescursivity = 10
)

type SubmoduleStatus

type SubmoduleStatus struct {
	Path     string
	Current  plumbing.Hash
	Expected plumbing.Hash
	Branch   plumbing.ReferenceName
}

SubmoduleStatus contains the status for a submodule in the worktree

func (*SubmoduleStatus) IsClean

func (s *SubmoduleStatus) IsClean() bool

IsClean is the HEAD of the submodule is equals to the expected commit

func (*SubmoduleStatus) String

func (s *SubmoduleStatus) String() string

String is equivalent to `git submodule status <submodule>`

This will print the SHA-1 of the currently checked out commit for a submodule, along with the submodule path and the output of git describe fo the SHA-1. Each SHA-1 will be prefixed with - if the submodule is not initialized, + if the currently checked out submodule commit does not match the SHA-1 found in the index of the containing repository.

type SubmoduleUpdateOptions

type SubmoduleUpdateOptions struct {
	// Init, if true initializes the submodules recorded in the index.
	Init bool
	// NoFetch tell to the update command to not fetch new objects from the
	// remote site.
	NoFetch bool
	// RecurseSubmodules the update is performed not only in the submodules of
	// the current repository but also in any nested submodules inside those
	// submodules (and so on). Until the SubmoduleRescursivity is reached.
	RecurseSubmodules SubmoduleRescursivity
}

SubmoduleUpdateOptions describes how a submodule update should be performed.

type Submodules

type Submodules []*Submodule

Submodules list of several submodules from the same repository.

func (Submodules) Init

func (s Submodules) Init() error

Init initializes the submodules in this list.

func (Submodules) Status

func (s Submodules) Status() (SubmodulesStatus, error)

Status returns the status of the submodules.

func (Submodules) Update

Update updates all the submodules in this list.

type SubmodulesStatus

type SubmodulesStatus []*SubmoduleStatus

SubmodulesStatus contains the status for all submodiles in the worktree

func (SubmodulesStatus) String

func (s SubmodulesStatus) String() string

String is equivalent to `git submodule status`

type Worktree

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

Worktree represents a git worktree.

func (*Worktree) Add

func (w *Worktree) Add(path string) (plumbing.Hash, error)

Add adds the file contents of a file in the worktree to the index. if the file is already stagged in the index no error is returned.

func (*Worktree) Checkout

func (w *Worktree) Checkout(opts *CheckoutOptions) error

Checkout switch branches or restore working tree files.

func (*Worktree) Commit

func (w *Worktree) Commit(msg string, opts *CommitOptions) (plumbing.Hash, error)

Commit stores the current contents of the index in a new commit along with a log message from the user describing the changes.

func (*Worktree) Move

func (w *Worktree) Move(from, to string) (plumbing.Hash, error)

Move moves or rename a file in the worktree and the index, directories are not supported.

func (*Worktree) Remove

func (w *Worktree) Remove(path string) (plumbing.Hash, error)

Remove removes files from the working tree and from the index.

func (*Worktree) Reset

func (w *Worktree) Reset(opts *ResetOptions) error

Reset the worktree to a specified state.

func (*Worktree) Status

func (w *Worktree) Status() (Status, error)

Status returns the working tree status.

func (*Worktree) Submodule

func (w *Worktree) Submodule(name string) (*Submodule, error)

Submodule returns the submodule with the given name

func (*Worktree) Submodules

func (w *Worktree) Submodules() (Submodules, error)

Submodules returns all the available submodules

Directories

Path Synopsis
cli
Package config contains the abstraction of multiple config files
Package config contains the abstraction of multiple config files
internal
package plumbing implement the core interfaces and structs used by go-git
package plumbing implement the core interfaces and structs used by go-git
utils

Jump to

Keyboard shortcuts

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