Generate shareable URLs to files and line ranges in hosted git repositories, from the command line.
Inspired by the Emacs package git-link.
cargo install forgelink-cliThis installs a binary named forgelink.
Use print to generate a stable URL pinned to the current commit SHA:
$ forgelink print src/main.rs
https://github.com/user/repo/blob/abc123def.../src/main.rsAppend :N for a single line or :N-M for a range:
$ forgelink print src/main.rs:42
https://github.com/user/repo/blob/abc123def.../src/main.rs#L42
$ forgelink print src/main.rs:42-55
https://github.com/user/repo/blob/abc123def.../src/main.rs#L42-L55Target a remote other than origin with --remote:
$ forgelink print --remote upstream src/main.rs
https://github.com/upstream-owner/repo/blob/abc123def.../src/main.rsUse the current branch name instead of the commit SHA with --branch:
$ forgelink print --branch src/main.rs
https://github.com/user/repo/blob/main/src/main.rs--branch requires HEAD to be on a named branch. It errors on a detached
HEAD, which includes Jujutsu (jj) working copies. Use the default
commit-pinned link in that case.
Copy the URL to the clipboard with copy:
forgelink copy src/main.rsOpen the URL in your default browser with open:
forgelink open src/main.rscopy and open do not print the URL. Use print when you want stdout.
When available, all subcommands support the same --remote and --branch options.
Clipboard and browser support are default-on cargo features (clipboard and
browser). Build with --no-default-features to drop the arboard and open
dependencies, which also removes the copy and open subcommands. On Linux
under X11 the clipboard is owned by the running process, so the copied URL may
not persist after forgelink exits. macOS and Windows are unaffected.
It works from any subdirectory inside the repository:
$ cd src && forgelink print main.rs
https://github.com/user/repo/blob/abc123def.../src/main.rsYou can also pass an absolute path to link to a file in any repository, regardless of your current directory:
$ forgelink print ~/Developer/other-repo/src/main.rs
https://github.com/user/other-repo/blob/abc123def.../src/main.rsforgelink detects the forge from the hostname in the Git remote. Add a host entry for SSH aliases and forges on custom domains.
# git@gh-work:owner/repo.git
[[hosts]]
host = "gh-work"
base-url = "https://github.com"
forge = "github"
# git@git.company.tld:group/repo.git
[[hosts]]
host = "git.company.tld"
base-url = "https://git.company.tld"
forge = "gitlab"Host entries require all three fields:
hostis the hostname from the Git remote.base-urlis the HTTP or HTTPS URL used to build links. It may include a custom port or path prefix, but not credentials, a query, or a fragment.forgeis one ofgithub,gitlab,sourcehut,bitbucket, orcodeberg.
Host matching is exact and case-insensitive. A matching entry skips automatic forge detection. Wildcards and chained mappings are not supported.
Use --config to pick a file:
forgelink --config path/to/config.toml print src/main.rsOtherwise, forgelink checks these locations in order:
$XDG_CONFIG_HOME/forgelink/config.toml, whenXDG_CONFIG_HOMEis an absolute path.- The native platform configuration directory:
- Linux:
~/.config/forgelink/config.toml - macOS:
~/Library/Application Support/forgelink/config.toml - Windows:
%APPDATA%\forgelink\config.toml
- Linux:
forgelink uses the first applicable location in the order shown. It does not
merge configuration files. A missing default file is ignored, while a missing
file passed with --config is an error. forgelink does not read
~/.ssh/config; add each SSH alias as a host entry.
The file argument accepts path:line syntax, so any editor that can run a shell
command with the current buffer path and cursor line can bind it with no plugin
required. Use copy to copy directly, or print to capture stdout yourself.
In ~/.config/helix/config.toml:
[keys.normal.space]
o = ":sh forgelink copy \"%{file_path_absolute}:%{cursor_line}\""space o copies a link to the current line. %{file_path_absolute} is used so
it works regardless of the directory Helix was launched from.
If you are using a version released before
helix-editor/helix#12989 was
merged (i.e.: 25.07.1), you should use %{buffer_name} in place of
%{file_path_absolute}.
In ~/.config/kak/kakrc:
define-command -docstring 'copy a forge link to the current line' forge-link %{
nop %sh{ forgelink copy "$kak_buffile:$kak_cursor_line" }
}
map global user o ': forge-link<ret>' -docstring 'forge link'The following is a Lua implementation for using forgelink in Neovim. It copies a link to the file path in normal mode and a link to the line(s) selected in visual mode to the system clipboard.
if vim.fn.exepath('forgelink') ~= '' then
vim.keymap.set('n', '<leader>cf',
function()
local curFile = vim.api.nvim_buf_get_name(0)
local output = vim.fn.system({ 'forgelink', 'print', curFile })
vim.fn.setreg('+', vim.trim(output))
end,
{ desc = "Copy URL to Git forge for current file to clipboard" }
)
vim.keymap.set('v', '<leader>cf',
function()
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Esc>", true, false, true), "x", false)
local curFile = vim.api.nvim_buf_get_name(0)
local startLine = vim.fn.line("'<")
local endLine = vim.fn.line("'>")
local lineRef = startLine == endLine and tostring(startLine) or (startLine .. '-' .. endLine)
local output = vim.fn.system({ 'forgelink', 'print', curFile .. ':' .. lineRef })
vim.fn.setreg('+', vim.trim(output))
end,
{ desc = "Copy URL to Git forge for current file with selected line numbers to clipboard" }
)
endLicensed under either of MIT or Apache-2.0 at your option.