# coc-git

<p align="center">
  <img src="assets/coc-git-logo.png" alt="coc-git logo" width="180">
</p>

[![CI](https://github.com/neoclide/coc-git/actions/workflows/ci.yaml/badge.svg)](https://github.com/neoclide/coc-git/actions/workflows/ci.yaml)

Git integration of [coc.nvim](https://github.com/neoclide/coc.nvim).

**Note:** many useful features not implemented, it's recommended to
use plugin like [vim-fugitive](https://github.com/tpope/vim-fugitive) at the
same time.

## Install

In your vim/neovim, run command:

```
:CocInstall coc-git
```

## Why

- Always async.
- Always refresh on TextChange.
- Powerful list support.
- Semantic commit and github issues completion support.
- Undo, stage & unstage change chunk under current cursor.

## Features

- Sign support for git status of current buffer.
- Git status of current project, by `g:coc_git_status`.
- Git status of current buffer, by`b:coc_git_status`.
- Git status of current line, by`b:coc_git_blame` for statusline, and `addGBlameToVirtualText` for inline blames.
- Git related lists, including `issues`, `gfiles`, `gstatus`, `gchanges`, `gchunks`, `commits`, `branches` & `bcommits`
- Keymaps for git chunks, including `<Plug>(coc-git-chunkinfo)` `<Plug>(coc-git-nextchunk)` & `<Plug>(coc-git-prevchunk)` ,
- Commands for chunks, including `git.chunkInfo` `git.chunkStage` `git.chunkUndo` and more.
- Keymaps & commands for git conflicts.
- Completion support for semantic commit.
- Completion support for GitHub/GitLab issues.
- Browse files changed by any commit in a read-only `Commit Files` TreeView.

**Note** for GitHub issues completion support:

- `GITHUB_API_TOKEN=xxx` needs to be set in env to fetch issues from private repositories

**Note** for GitLab issues completion support:

- current only API `v4` support, which availabled since GitLab 9.0
- `GITLAB_PRIVATE_TOKEN=XXX` needs to be set in env, check [Personal access tokens](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html)
- GitLab host needs to be set in `coc-settings.json`, for example `"git.gitlab.hosts": ["gitlab.example.com", "gitlab.com"]`

## Configuration

- `git.command`: Command for git, could be absolute path of git executable., default: `"git"`

- `git.remoteName`: Remote name for fetch github issues., default: `"origin"`

- `git.diffOptions`: Options for git diff command, eg: `["--ignore-all-space"]`, default: `[]`

- `git.foldContext`: Line count to leave below and above the fold, default: `0`.

- `git.browserRemoteName`: Remote name for browserOpen and copyUrl., default: `""`

- `git.browserBranchName`: Branch name for browserOpen and copyUrl., default: `""`

- `git.urlFix`: a object to configure the url style of copyUrl and browserOpen, make this two command support other git services like gitlab and gitea. default: `{}`

- `git.diffRevision`: Revision used as the gutter diff base, default: `""` (the current index).

- `git.issueFormat`: Formatting string for issue completion. Supported interpolation variables: %i - issue id. %r - repository name. %o - organization/owner name. %t - issue title. %b - issue body. %c - issue created at. %a - issue author. %u - issue url., default: `"#%i"`

- `git.virtualTextPrefix`: Prefix of git blame infomation to virtual text, require virtual text feature of neovim., default: `" "`

- `git.blameFormat`: Format of git blame virtual text. Supported placeholders: `%a` author, `%t` time, `%s` summary, `%S` short sha, `%%` literal percent., default: `"(%a %t) %s"`

- `git.addGBlameToVirtualText`: Add git blame information to virtual text, require virtual text feature of neovim., default: `false`

- `git.addGBlameToBufferVar`: Add git blame information to b:coc_git_blame., default: `false`

- `git.blameUseRealTime`: Use an absolute local timestamp in blame information, default: `false`.

- `git.branchCharacter`: Branch character used with g:coc_git_status, default: `""`

- `git.changedDecorator`: Git changed decorator used with g:coc_git_status, default: `"*"`

- `git.conflictedDecorator`: Git conflicted decorator used with g:coc_git_status, default: `"x"`

- `git.stagedDecorator`: Git staged decorator used with g:coc_git_status, default: `"●"`

- `git.untrackedDecorator`: Git untracked decorator used with g:coc_git_status, default: `"…"`

- `git.enableGlobalStatus`: Enable global g:coc_git_status., default: `true`

- `git.enableGutters`: Enable gutters in sign column., default: `true`

- `git.realtimeGutters`: Update gutters in realtime, default: true., default: `true`

- `git.enableStagedGutters`: Show staged changes in the sign column., default: `false`

- `git.signPriority`: Priority of sign gutters, default to `10`.

- `git.stagedSignPriority`: Priority of staged gutter signs., default: `9`.

- `git.pushArguments`: Additional arguments passed to `git push`, default: `[]`.

- `git.changedSign.text`: Text of changed sign., default: `"~"`

- `git.changedSign.hlGroup`: Highlight group for changed sign., default: `"DiffChange"`

- `git.addedSign.text`: Text of added sign., default: `"+"`

- `git.addedSign.hlGroup`: Highlight group for added sign., default: `"DiffAdd"`

- `git.removedSign.text`: Text of removed sign., default: `"_"`

- `git.removedSign.hlGroup`: Highlight group for removed sign., default: `"DiffDelete"`

- `git.topRemovedSign.text`: Text of top removed sign., default: `"‾"`

- `git.topRemovedSign.hlGroup`: Highlight group for top removed sign., default: `"DiffDelete"`

- `git.changeRemovedSign.text`: Text of change removed sign., default: `"≃"`

- `git.changeRemovedSign.hlGroup`: Highlight group for change removed sign., default: `"DiffChange"`

- `git.stagedAddedSign.text`: Text of staged added sign., default: `"┃"`

- `git.stagedAddedSign.hlGroup`: Highlight group for staged added sign., default: `"CocGitStagedAdd"`

- `git.stagedChangedSign.text`: Text of staged changed sign., default: `"┃"`

- `git.stagedChangedSign.hlGroup`: Highlight group for staged changed sign., default: `"CocGitStagedChange"`

- `git.stagedRemovedSign.text`: Text of staged removed sign., default: `"╻"`

- `git.stagedRemovedSign.hlGroup`: Highlight group for staged removed sign., default: `"CocGitStagedDelete"`

- `git.mixedSign.text`: Text of a sign shared by staged and unstaged changes., default: `"┋"`

- `git.mixedSign.hlGroup`: Highlight group for a mixed sign., default: `"CocGitMixed"`

- `git.semanticCommit.filetypes`: Enabled filetypes, default: `["gitcommit","gina-commit"]`

- `git.semanticCommit.scope`: Commit message with scope field, default: `true`

- `git.splitWindowCommand`: Command used when split new window for show commit., default: `"above sp"`

- `git.showCommitInFloating`: Show commit in floating or popup window, default: `false`

- `git.commitFiles.splitCommand`: Command used to open the changed-files TreeView for a commit, default: `"belowright 40vs"`

- `git.statusTree.splitCommand`: Command used to open the Git status TreeView, default: `"belowright 40vs"`

- `git.floatConfig`: Configure style of float window/popup, extends from floatFactory.floatConfig, default: `{}`.

- `git.gitlab.hosts`: Custom GitLab hosts, default: `["gitlab.com"]`

- `git.conflict.enabled`: Enable highlight conflict lines, default: `true`

- `git.conflict.current.hlGroup`: Highlight group for the current version of a merge conflict, default: `"DiffChange"`

- `git.conflict.incoming.hlGroup`: Highlight group for the incoming version of a merge conflict., default: `"DiffAdd"`

- `git.conflict.common.hlGroup`: Highlight group for diff3 common-ancestor sections, default: `"DiffText"`.

- `git.gstatus.saveBeforeOpen`: Save open buffers before loading the `gstatus` list, default: `false`.

- `coc.source.issues.enable`: Enable issue completion, default: `true`.

- `coc.source.issues.triggerCharacters`: Trigger characters for issue completion, default: `["#"]`.

- `coc.source.issues.priority`: Issue completion priority, default: `99`.

- `coc.source.issues.shortcut`: Issue completion menu shortcut, default: `"[I]"`.

- `coc.source.issues.filetypes`: Filetypes where issue completion is active, default: `["gitcommit", "gina-commit"]`.

more information, see [package.json](https://github.com/neoclide/coc-git/blob/master/package.json)

**Note** for user from [vim-gitgutter](https://github.com/airblade/vim-gitgutter),
if your have highlight groups defined for vim-gitgutter, you can use:

```json
"git.addedSign.hlGroup": "GitGutterAdd",
"git.changedSign.hlGroup": "GitGutterChange",
"git.removedSign.hlGroup": "GitGutterDelete",
"git.topRemovedSign.hlGroup": "GitGutterDelete",
"git.changeRemovedSign.hlGroup": "GitGutterChangeDelete",
```

When you have `git.addGBlameToVirtualText` enabled, use command
`let g:coc_git_hide_blame_virtual_text = !get(g:, 'coc_git_hide_blame_virtual_text', 0)` to dynamic toggle virtual text.

## Usage

### Statusline integration

- `g:coc_git_status` including git branch and current project status.
- `b:coc_git_status` including changed lines of current buffer.
- `b:coc_git_blame` including blame info of current line.

Example for lightline user:

```viml
" lightline
let g:lightline = {
  \ 'active': {
  \   'left': [
  \     [ 'mode', 'paste' ],
  \     [ 'ctrlpmark', 'git', 'diagnostic', 'cocstatus', 'filename', 'method' ]
  \   ],
  \   'right':[
  \     [ 'filetype', 'fileencoding', 'lineinfo', 'percent' ],
  \     [ 'blame' ]
  \   ],
  \ },
  \ 'component_function': {
  \   'blame': 'LightlineGitBlame',
  \ }
\ }

function! LightlineGitBlame() abort
  let blame = get(b:, 'coc_git_blame', '')
  " return blame
  return winwidth(0) > 120 ? blame : ''
endfunction
```

If you're not using statusline plugin, you can add them to statusline by:

```vim
set statusline^=%{get(g:,'coc_git_status','')}%{get(b:,'coc_git_status','')}%{get(b:,'coc_git_blame','')}
```

### User autocmd

```vim
autocmd User CocGitStatusChange {command}
```

Triggered after the `g:coc_git_status` `b:coc_git_status` `b:coc_git_blame` has changed.

Could be used for update the statusline.

### Keymaps

Create keymappings like:

```vim
" navigate chunks of current buffer
nmap [g <Plug>(coc-git-prevchunk)
nmap ]g <Plug>(coc-git-nextchunk)
" navigate conflicts of current buffer
nmap [c <Plug>(coc-git-prevconflict)
nmap ]c <Plug>(coc-git-nextconflict)
" resolve the conflict under the cursor
nmap <leader>cc <Plug>(coc-git-keepcurrent)
nmap <leader>ci <Plug>(coc-git-keepincoming)
nmap <leader>cb <Plug>(coc-git-keepboth)
" show chunk diff at current position
nmap gs <Plug>(coc-git-chunkinfo)
" show commit contains current position
nmap gc <Plug>(coc-git-commit)
" show blame details for the current line
nmap gb <Plug>(coc-git-showblamedoc)
" create text object for git chunks
omap ig <Plug>(coc-git-chunk-inner)
xmap ig <Plug>(coc-git-chunk-inner)
omap ag <Plug>(coc-git-chunk-outer)
xmap ag <Plug>(coc-git-chunk-outer)
```

### Commands

Use command `:CocCommand` to open commands and type `git.` to get all git
related commands.

- `:CocCommand git.copyUrl` Copy url of current line to clipboard.
- `:CocCommand git.copyPermalink` Copy a permalink for the current line to clipboard.
- `:CocCommand git.refresh` Refresh Git information for all buffers.
- `:CocCommand git.statusTree` Open files reported by Git status in a TreeView. File nodes show staged and unstaged status; opening a file jumps to its first changed line when Git can determine one.
- `:CocCommand git.nextChunk` Navigate to the next chunk.
- `:CocCommand git.prevChunk` Navigate to the previous chunk.
- `:CocCommand git.chunkInfo` Show chunk info under cursor.
- `:CocCommand git.allChunkInfo` Return all changed chunks in the current buffer.
- `:CocCommand git.keepCurrent` Keep the current part of the conflict under the cursor.
- `:CocCommand git.keepIncoming` Keep the incoming part of the conflict under the cursor.
- `:CocCommand git.keepBoth` Keep both parts of the conflict under the cursor.
- `:CocCommand git.chunkUndo` Undo current chunk.
- `:CocCommand git.chunkStage` Stage current chunk.
- `:CocCommand git.chunkUnstage` Unstage chunk that contains current line.
- `:CocCommand git.diffCached` Show cached diff in preview window.
- `:CocCommand git.showCommit` Show commit of current chunk.
- `:CocCommand git.showCommitTree` Open the commit associated with the current tracked line in the `Commit Files` TreeView, show the historical file, and jump to its blamed line.
- `:CocCommand git.showBlameDoc` Show blame details for the current line.
- `:CocCommand git.browserOpen` Open current line in browser
- `:CocCommand git.foldUnchanged` Fold unchanged lines of current buffer.
- `:CocCommand git.toggleGutters` Toggle git gutters in sign column.
- `:CocCommand git.push` push code of current branch to remote.

### Work with git lists

To open a specified coc list, you have different ways:

- Run `:CocList` and select the list by `<CR>`.
- Run `:CocList` and type name of list for completion.
- Create keymap for open specified list with list options, like:

  ```vim
  nnoremap <silent> <space>g  :<C-u>CocList --normal gstatus<CR>
  ```

To toggle list mode, use `<C-o>` and `i`.

To move up&down on insertmode, use `<C-j>` and `<C-k>`

To run a action, press `<tab>` and select the action.

#### Commit Files TreeView

The `commits` and `bcommits` lists provide a `changes` action that opens the
selected commit in the `Commit Files` TreeView. The existing `files` action
continues to open the complete file snapshot through the `gfiles` list.

The tree compares an ordinary commit with its parent and an initial commit with
the empty tree. Merge commits use the first parent by default; choose
`Select parent…` from the root node actions to compare another parent. The root
node starts expanded, and pressing `<CR>` on it runs `Show commit`. Pressing
`<CR>` on a directory toggles it, while pressing `<CR>` on a file runs
`Show code`.

`Show code`, `Open before version`, `Open after version`, and
`Open working tree file` open in the editor window that was active before the
TreeView. For a text file, `Show code` opens a read-only
`coc-git://<commit>/<path>` buffer with `buftype=nofile` and detects the
filetype from its path. Added lines use the `DiffAdd` background, and deleted
lines are rendered as virtual text using `DiffDelete`. Deleted files open their
complete parent version; binary and non-blob entries show object metadata
instead of text decorations.

Use `<Plug>(coc-git-nextchunk)`, `<Plug>(coc-git-prevchunk)`, `git.nextChunk`,
or `git.prevChunk` to navigate changed blocks in a `coc-git://` buffer. The
navigation wraps when Vim's `wrapscan` option is enabled.

When the buffer that opened the TreeView is one of the changed files, its
parent directories are expanded and the file is focused. `git.showCommitTree`
also opens that file's historical code automatically and places the cursor on
the original line reported by `git blame`. The command reports the existing
untracked or uncommitted-line warning when Git cannot associate the current
line with a commit.

Use `git.commitFiles.splitCommand` to configure how the TreeView split opens.

#### Git Status TreeView

Use `:CocCommand git.statusTree` to display staged, unstaged, conflicted, and
untracked files grouped by directory. Each file shows Git's two-column status
and a readable staged/unstaged description. Press `<CR>` on a file to open its
working-tree version in the previous editor window. For tracked files, the
cursor moves to the first changed line when Git provides a diff location;
otherwise it opens at line 1. Files deleted from the working tree open the
read-only `HEAD` version through the `coc-git:` scheme. The root node refreshes
the status snapshot. File actions follow each file's status: `Add` stages
unstaged or untracked files, `Restore staged changes` unstages a file, and
`Restore working tree changes` discards its tracked working-tree changes.

Use `git.statusTree.splitCommand` to configure how the TreeView split opens.

For more advance usage, checkout `:h coc-list`.

### Issue autocomplete from multiple GitHub repositories

To enable autocompletion of issues from multiple GitHub repositories, put a comma-separated list of issue repository specifiers in the git config variable `coc-git.issuesources`.
An issue repository specifier looks like this: `github/neoclide/coc-git`.

- The first part specifies the issue provider, currently only "github" is supported
- The second part specifies the organization or owner of the repository
- The third part specifies the repository name

Multiple repositories can be specified using comma separation, like this: `github/neoclide/coc-git,github/neoclide/coc.nvim`

## License

MIT
