1 Commits

Author SHA1 Message Date
Tim Pope
ef87434b87 Provide :Git difftool and :Git mergetool
References https://github.com/tpope/vim-fugitive/issues/132
2020-01-05 16:36:11 -05:00
7 changed files with 2954 additions and 5484 deletions

View File

@@ -1,66 +1,51 @@
# fugitive.vim # fugitive.vim
Fugitive is the premier Vim plugin for Git. Or maybe it's the premier Git I'm not going to lie to you; fugitive.vim may very well be the best
plugin for Vim? Either way, it's "so awesome, it should be illegal". That's Git wrapper of all time. Check out these features:
why it's called Fugitive.
The crown jewel of Fugitive is `:Git` (or just `:G`), which calls any Bring up an enhanced version of `git status` with `:G` (also known as
arbitrary Git command. If you know how to use Git at the command line, you `:Gstatus`). Press `g?` to bring up a list of maps for numerous operations
know how to use `:Git`. It's vaguely akin to `:!git` but with numerous including diffing, staging, committing, rebasing, and stashing.
improvements:
* The default behavior is to directly echo the command's output. Quiet View any blob, tree, commit, or tag in the repository with `:Gedit` (and
commands like `:Git add` avoid the dreaded "Press ENTER or type command to `:Gsplit`, `:Gvsplit`, `:Gtabedit`, ...). Edit a file in the index and
continue" prompt. write to it to stage the changes. Use `:Gdiffsplit` to bring up the staged
* `:Git commit`, `:Git rebase -i`, and other commands that invoke an editor do version of the file side by side with the working tree version and use
their editing in the current Vim instance. Vim's diff handling capabilities to stage a subset of the file's
* `:Git diff`, `:Git log`, and other verbose, paginated commands have their changes.
output loaded into a temporary buffer. Force this behavior for any command
with `:Git --paginate` or `:Git -p`.
* `:Git blame` uses a temporary buffer with maps for additional triage. Press
enter on a line to view the commit where the line changed, or `g?` to see
other available maps. Omit the filename argument and the currently edited
file will be blamed in a vertical, scroll-bound split.
* `:Git mergetool` and `:Git difftool` load their changesets into the quickfix
list.
* Called with no arguments, `:Git` opens a summary window with dirty files and
unpushed and unpulled commits. Press `g?` to bring up a list of maps for
numerous operations including diffing, staging, committing, rebasing, and
stashing. (This is the successor to the old `:Gstatus`.)
* This command (along with all other commands) always uses the current
buffer's repository, so you don't need to worry about the current working
directory.
Additional commands are provided for higher level operations: Commit, merge, and rebase with `:Gcommit`, `:Gmerge`, and `:Grebase`, using
the current Vim instance to edit commit messages and the rebase todo list.
Use `:Gpush`, `:Gfetch`, and `:Gpull` to send and retrieve upstream changes.
* View any blob, tree, commit, or tag in the repository with `:Gedit` (and `:Gblame` brings up an interactive vertical split with `git blame`
`:Gsplit`, etc.). For example, `:Gedit HEAD~3:%` loads the current file as output. Press enter on a line to edit the commit where the line
it existed 3 commits ago. changed, or `o` to open it in a split. When you're done, use `:Gedit`
* `:Gdiffsplit` (or `:Gvdiffsplit`) brings up the staged version of the file in the historic buffer to go back to the work tree version.
side by side with the working tree version. Use Vim's diff handling
capabilities to apply changes to the staged version, and write that buffer `:Gmove` does a `git mv` on a file and simultaneously renames the
to stage the changes. You can also give an arbitrary `:Gedit` argument to buffer. `:Gdelete` does a `git rm` on a file and simultaneously deletes
diff against older versions of the file. the buffer.
* `:Gread` is a variant of `git checkout -- filename` that operates on the
buffer rather than the file itself. This means you can use `u` to undo it Use `:Ggrep` to search the work tree (or any arbitrary commit) with
and you never get any warnings about the file changing outside Vim. `git grep`, skipping over that which is not tracked in the repository.
* `:Gwrite` writes to both the work tree and index versions of a file, making `:Gclog` and `:Gllog` load all previous commits into the quickfix or location
it like `git add` when called from a work tree file and like `git checkout` list. Give them a range (e.g., using visual mode and `:'<,'>Gclog`) to
when called from the index or a blob in history. iterate over every change to that portion of the current file.
* `:Ggrep` is `:grep` for `git grep`. `:Glgrep` is `:lgrep` for the same.
* `:GMove` does a `git mv` on the current file and changes the buffer name to `:Gread` is a variant of `git checkout -- filename` that operates on the
match. `:GRename` does the same with a destination filename relative to the buffer rather than the filename. This means you can use `u` to undo it
current file's directory. and you never get any warnings about the file changing outside Vim.
* `:GDelete` does a `git rm` on the current file and simultaneously deletes `:Gwrite` writes to both the work tree and index versions of a file,
the buffer. `:GRemove` does the same but leaves the (now empty) buffer making it like `git add` when called from a work tree file and like
open. `git checkout` when called from the index or a blob in history.
* `:GBrowse` to open the current file on the web front-end of your favorite
hosting provider, with optional line range (try it in visual mode). Plugins Use `:Gbrowse` to open the current file on the web front-end of your favorite
are available for popular providers such as [GitHub][rhubarb.vim], hosting provider, with optional line range (try it in visual mode). Plugins
[GitLab][fugitive-gitlab.vim], [Bitbucket][fubitive.vim], are available for popular providers such as [GitHub][rhubarb.vim],
[Gitee][fugitive-gitee.vim], [Pagure][pagure], [GitLab][fugitive-gitlab.vim], [Bitbucket][fubitive.vim],
[Phabricator][vim-phabricator], [Azure DevOps][fugitive-azure-devops.vim], [Gitee][fugitive-gitee.vim], [Pagure][pagure], and
and [sourcehut][srht.vim]. [Phabricator][vim-phabricator].
[rhubarb.vim]: https://github.com/tpope/vim-rhubarb [rhubarb.vim]: https://github.com/tpope/vim-rhubarb
[fugitive-gitlab.vim]: https://github.com/shumphrey/fugitive-gitlab.vim [fugitive-gitlab.vim]: https://github.com/shumphrey/fugitive-gitlab.vim
@@ -68,12 +53,12 @@ Additional commands are provided for higher level operations:
[fugitive-gitee.vim]: https://github.com/linuxsuren/fugitive-gitee.vim [fugitive-gitee.vim]: https://github.com/linuxsuren/fugitive-gitee.vim
[pagure]: https://github.com/FrostyX/vim-fugitive-pagure [pagure]: https://github.com/FrostyX/vim-fugitive-pagure
[vim-phabricator]: https://github.com/jparise/vim-phabricator [vim-phabricator]: https://github.com/jparise/vim-phabricator
[fugitive-azure-devops.vim]: https://github.com/cedarbaum/fugitive-azure-devops.vim
[srht.vim]: https://git.sr.ht/~willdurand/srht.vim
Add `%{FugitiveStatusline()}` to `'statusline'` to get an indicator Add `%{FugitiveStatusline()}` to `'statusline'` to get an indicator
with the current branch in your statusline. with the current branch in your statusline.
Last but not least, there's `:Git` for running any arbitrary command.
For more information, see `:help fugitive`. For more information, see `:help fugitive`.
## Screencasts ## Screencasts
@@ -86,8 +71,7 @@ For more information, see `:help fugitive`.
## Installation ## Installation
Install using your favorite package manager, or use Vim's built-in package Install using your favorite package manager, or use Vim's built-in package support:
support:
mkdir -p ~/.vim/pack/tpope/start mkdir -p ~/.vim/pack/tpope/start
cd ~/.vim/pack/tpope/start cd ~/.vim/pack/tpope/start
@@ -96,31 +80,20 @@ support:
## FAQ ## FAQ
> What happened to the dispatch.vim backed asynchronous `:Gpush` and > Why can't I enter my password when I `:Gpush`?
> `:Gfetch`?
This behavior was divisive, confusing, and complicated inputting passwords, so It is highly recommended to use SSH keys or [credentials caching][] to avoid
it was removed. Use `:Git! push` to use Fugitive's own asynchronous entering your password on every upstream interaction. If this isn't an
execution, or retroactively make `:Git push` asynchronous by pressing option, the official solution is to use the `core.askPass` Git option to
`CTRL-D`. request the password via a GUI. Fugitive will configure this for you
automatically if you have `ssh-askpass` or `git-gui` installed; otherwise it's
your responsibility to set this up.
> Why am I getting `core.worktree is required when using an external Git dir`? As an absolute last resort, you can invoke `:Git --paginate push`. Fugitive
recognizes the pagination request and fires up a `:terminal`, which allows for
interactive password entry.
Git generally sets `core.worktree` for you automatically when necessary, but [credentials caching]: https://help.github.com/en/articles/caching-your-github-password-in-git
if you're doing something weird, or using a third-party tool that does
something weird, you may need to set it manually:
git config core.worktree "$PWD"
This may be necessary even when simple `git` commands seem to work fine
without it.
> So I have a symlink and...
Stop. Just stop. If Git won't deal with your symlink, then Fugitive won't
either. Consider using a [plugin that resolves
symlinks](https://github.com/aymericbeaumet/symlink.vim), or even better,
using fewer symlinks.
## Self-Promotion ## Self-Promotion

File diff suppressed because it is too large Load Diff

View File

@@ -15,47 +15,63 @@ COMMANDS *fugitive-commands*
These commands are local to the buffers in which they work (generally, buffers These commands are local to the buffers in which they work (generally, buffers
that are part of Git repositories). that are part of Git repositories).
*fugitive-:G* *:Git* *fugitive-:G*
:G [args] Same as :Git, but two characters shorter. :Git {args} Run an arbitrary git command. Similar to :!git [args]
:G {args} but chdir to the repository tree first. For some
*fugitive-summary* subcommands, a Fugitive command is called instead.
:Git With no arguments, bring up a summary window vaguely
akin to git-status. If a summary window is already
open for the current repository, it is focused
instead. Press g? or see |fugitive-maps| for usage.
*:Git*
:Git {args} Run an arbitrary git command and display any output.
On UNIX this uses a pty and on other platforms it uses
a pipe, which will cause some behavior differences
such as the absence of progress bars. Any file the
command edits (for example, a commit message) will be
loaded into a split window. Closing that window will
resume running the command. A few Git subcommands
have different behavior; these are documented below.
*:Git!* *:Git!*
:Git! {args} Run an arbitrary git command in the background and :Git! {args} Like |:Git|, but capture the output into a temp file,
stream the output to the preview window. Requires a :Git --no-pager {args} and |:split| that temp file. Use :0Git to
Vim with |setbufline()|. Press CTRL-D during an :Git -P {args} |:edit| the temp file instead. A temp file is always
interactive :Git invocation to switch to this mode used for diff and log commands.
retroactively.
*:Git_--paginate* *:Git_-p* *:Gstatus*
:Git --paginate {args} Run an arbitrary git command, capture output to a temp :Git Bring up a summary window vaguely akin to git-status.
:Git -p {args} file, and |:split| that temp file. Pass ++curwin as :G Press g? or see |fugitive-maps| for usage.
the first argument to |:edit| the temp file instead. :Gstatus
A temp file is always used for commands like diff and
log that typically uses a pager, and for any command
that has the pager.<cmd> Git configuration option set.
:{range}Git! --paginate {args} *:Git-commit* *:Gcommit*
:{range}Git! -p {args} Run an arbitrary git command, and insert the output :Git commit [args] A wrapper around git-commit. Unless the arguments
after {range} in the current buffer. :Gcommit [args] given would skip the invocation of an editor (e.g.,
-m), a split window will be used to obtain a commit
message, or a new tab if -v is given. Write and close
the window (:wq) to finish the commit. To cancel, use
an empty message.
*:Git_blame* *:Git-revert* *:Grevert*
:Git revert [args] A wrapper around git-revert. Similar to |:Gcommit|.
:Grevert [args]
*:Git-merge* *:Gmerge*
:Git merge [args] Calls git-merge and loads errors and conflicted files
:Gmerge [args] into the |quickfix| list. Opens a |:Gcommit| style
split window for the commit message if the merge
succeeds. If called during a merge conflict, the
conflicted files from the current index are loaded
into the |quickfix| list.
*:Git-pull* *:Gpull*
:Git pull [args] Like |:Gmerge|, but for git-pull.
:Gpull [args]
*:Git-rebase* *:Grebase*
:Git rebase [args] Like |:Gmerge|, but for git-rebase. Interactive
:Grebase [args] rebase is experimentally supported.
*:Git-push* *:Gpush*
:Git push [args] Invoke git-push, load the results into the |quickfix|
:Gpush [args] list, and invoke |:cwindow| to reveal any errors.
|:Dispatch| is used if available for asynchronous
invocation.
*:Git-fetch* *:Gfetch*
:Git fetch [args] Like |:Gpush|, but for git-fetch.
:Gfetch [args]
*:Git-blame* *:Gblame*
:Git blame [flags] Run git-blame [flags] on the current file and open the :Git blame [flags] Run git-blame [flags] on the current file and open the
results in a scroll-bound vertical split. The :Gblame [flags] results in a scroll-bound vertical split. The
following maps, which work on the cursor line commit following maps, which work on the cursor line commit
where sensible, are provided: where sensible, are provided:
@@ -71,29 +87,23 @@ that are part of Git repositories).
O jump to patch or blob in new tab O jump to patch or blob in new tab
p jump to patch or blob in preview window p jump to patch or blob in preview window
- reblame at commit - reblame at commit
~ reblame at [count]th first grandparent
P reblame at [count]th parent (like HEAD^[count])
The maps |fugitive_P| and |fugitive_~| are also :[range]Gblame [flags] If a range is given, just that part of the file will
supported to reblame on a parent commit, but this is :Gblame [flags] {file} be blamed, and a horizontal split without
inherently fragile, as the line being blamed will no :Git blame ... scrollbinding is used. You can also give an arbitrary
longer exist. The preferred alternative is to use
<CR> to open up the commit, select the corresponding
`-` line that you care about, and press <CR> twice
more to reblame at that line. Viewing the commit also
gives you additional context as to why the line
changed.
*g:fugitive_dynamic_colors*
In the GUI or a 256 color terminal, commit hashes will
be highlighted in different colors. To disable this:
>
let g:fugitive_dynamic_colors = 0
<
:[range]Git blame [...] If a range is given, just that part of the file will
:Git blame [...] {file} be blamed, and a horizontal split without
scrollbinding is used. You can also give an arbitrary
filename. filename.
*:Git_difftool* *:Ggrep* *:Gcgrep* *:Git-grep*
:Ggrep[!] [args] |:grep|[!] with git-grep as 'grepprg'.
:Git[!] grep [args]
*:Glgrep*
:Glgrep[!] [args] |:lgrep|[!] with git-grep as 'grepprg'.
:0Git[!] grep [args]
*:Git-difftool*
:Git[!] difftool [args] Invoke `git diff [args]` and load the changes into the :Git[!] difftool [args] Invoke `git diff [args]` and load the changes into the
quickfix list. Each changed hunk gets a separate quickfix list. Each changed hunk gets a separate
quickfix entry unless you pass an option like quickfix entry unless you pass an option like
@@ -101,39 +111,16 @@ that are part of Git repositories).
change unless [!] is given. change unless [!] is given.
:Git difftool -y [args] Invoke `git diff [args]`, open each changed file in a :Git difftool -y [args] Invoke `git diff [args]`, open each changed file in a
new tab, and invoke |:Gdiffsplit!| against the new tab, and invoke `:Gdiffsplit` against the
appropriate commit. appropriate commit.
*:Git_mergetool* *:Git-mergetool*
:Git mergetool [args] Like |:Git_difftool|, but target merge conflicts. :Git mergetool [args] Like |:Git-difftool|, but target merge conflicts.
Wrappers for Vim built-ins ~ *:Gclog* *:Glog*
These all directly map onto a built-in Vim command, and generally have names
that prepend "G" to the command they are wrapping. For example, :Ggrep is G
plus |:grep|.
*:Ggrep* *:Git_grep*
:Ggrep[!] [args] An approximation of |:grep|[!] with git-grep as
:Git[!] grep -O [args] 'grepprg'.
:Ggrep[!] --quiet [args]
:Ggrep[!] -q [args] Like |:Ggrep|, but instead of displaying output, open
the quickfix list.
*:Glgrep*
:Glgrep[!] [args] :Ggrep but for |:lgrep|.
:0Git[!] grep -O [args]
*:Gclog*
:Gclog[!] [args] Use git-log [args] to load the commit history into the :Gclog[!] [args] Use git-log [args] to load the commit history into the
|quickfix| list. Jumps to the first commit unless [!] :Glog[!] [args] |quickfix| list. Jumps to the first commit unless [!]
is given. This command wraps |:cfile|. is given.
The quickfix list can be awkward for many use cases
and exhibits extremely poor performance with larger
data sets. Consider using |:Git| log --oneline
instead.
:{range}Gclog[!] [args] Use git-log -L to load previous revisions of the given :{range}Gclog[!] [args] Use git-log -L to load previous revisions of the given
range of the current file into the |quickfix| list. range of the current file into the |quickfix| list.
@@ -166,8 +153,12 @@ plus |:grep|.
*:Gpedit* *:Gpedit*
:Gpedit [object] |:pedit| a |fugitive-object|. :Gpedit [object] |:pedit| a |fugitive-object|.
*:Gdrop* :Gsplit! [args] *:Gsplit!* *:Gvsplit!*
:Gdrop [object] |:drop| a |fugitive-object|. :Gvsplit! [args] *:Gtabedit!* *:Gpedit!*
:Gtabedit! [args] Capture the output of `git [args]` to a temp file and
:Gpedit! [args] open it in a split, tab, or preview window. Use
:0Gsplit! to suppress the split and open it in the
current window.
*:Gread* *fugitive-:Gr* *:Gread* *fugitive-:Gr*
:Gread [object] Empty the buffer and |:read| a |fugitive-object|. :Gread [object] Empty the buffer and |:read| a |fugitive-object|.
@@ -177,6 +168,12 @@ plus |:grep|.
:{range}Gread [object] |:read| in a |fugitive-object| after {range}. :{range}Gread [object] |:read| in a |fugitive-object| after {range}.
*:Gread!* *fugitive-:Gr!*
:Gread! [args] Empty the buffer and |:read| the output of a Git
command. For example, :Gread! show HEAD:%.
:{range}Gread! [args] |:read| the output of a Git command after {range}.
*:Gwrite* *fugitive-:Gw* *:Gwrite* *fugitive-:Gw*
:Gwrite Write to the current file's path and stage the results. :Gwrite Write to the current file's path and stage the results.
When run in a work tree file, it is effectively git When run in a work tree file, it is effectively git
@@ -201,17 +198,17 @@ plus |:grep|.
:Gdiffsplit [object] Perform a |vimdiff| against the given file, or if a :Gdiffsplit [object] Perform a |vimdiff| against the given file, or if a
commit is given, the current file in that commit. commit is given, the current file in that commit.
With no argument, the version in the index or work With no argument, the version in the index or work
tree is used, and the work tree version is always tree is used. The newer of the two files is placed to
placed to the right or bottom, depending on available the right or bottom, depending on 'diffopt' and the
width. Use Vim's |do| and |dp| to stage and unstage width of the window relative to 'textwidth'. Use
changes. Vim's |do| and |dp| to stage and unstage changes.
*:Gdiffsplit!* *:Gdiffsplit!*
:Gdiffsplit! Diff against any and all direct ancestors, retaining :Gdiffsplit! Diff against any and all direct ancestors, retaining
focus on the current window. During a merge conflict, focus on the current window. During a merge conflict,
this is a three-way diff against the "ours" and this is a three-way diff against the "ours" and
"theirs" ancestors. Additional d2o and d3o maps are "theirs" ancestors. Additional d2o and d3o maps are
provided to obtain the hunk from the "ours" or provided to to obtain the hunk from the "ours" or
"theirs" ancestor, respectively. "theirs" ancestor, respectively.
:Gdiffsplit! {object} Like |:Gdiffsplit|, but retain focus on the current :Gdiffsplit! {object} Like |:Gdiffsplit|, but retain focus on the current
@@ -220,68 +217,58 @@ plus |:grep|.
*:Gvdiffsplit* *:Gvdiffsplit*
:Gvdiffsplit [object] Like |:Gdiffsplit|, but always split vertically. :Gvdiffsplit [object] Like |:Gdiffsplit|, but always split vertically.
*:Ghdiffsplit* *:Ghdiffsplit* *:Gsdiff*
:Gdiffsplit ++novertical [object] :Ghdiffsplit [object] Like |:Gdiffsplit|, but always split horizontally.
:Ghdiffsplit [object] Like |:Gdiffsplit|, but with "vertical" removed from
'diffopt'. The split will still be vertical if
combined with |:vertical|.
Other commands ~ *:Gmove*
:Gmove {destination} Wrapper around git-mv that renames the buffer
These do not directly correspond to any built-in Vim command, and have a
capital letter after the "G" to convey this. For example, the file move
operation has nothing to do with the |:move| built-in, so it is named :GMove,
not :Gmove.
*:GMove*
:GMove {destination} Wrapper around git-mv that renames the buffer
afterward. Add a ! to pass -f. afterward. Add a ! to pass -f.
*:GRename* *:Grename*
:GRename {destination} Like |:GMove| but operates relative to the parent :Grename {destination} Like |:Gmove| but operates relative to the parent
directory of the current file. directory of the current file.
*:GDelete* *:Gdelete*
:GDelete Wrapper around git-rm that deletes the buffer :Gdelete Wrapper around git-rm that deletes the buffer
afterward. When invoked in an index file, --cached is afterward. When invoked in an index file, --cached is
passed. Add a ! to pass -f and forcefully discard the passed. Add a ! to pass -f and forcefully discard the
buffer. buffer.
*:GRemove* *:GUnlink* *:Gremove*
:GRemove Like |:GDelete|, but keep the (now empty) buffer around. :Gremove Like :Gdelete, but keep the (now empty) buffer around.
:GUnlink
*:GBrowse* *:Gbrowse*
:GBrowse Open the current file, blob, tree, commit, or tag :Gbrowse Open the current file, blob, tree, commit, or tag
in your browser at the upstream hosting provider. in your browser at the upstream hosting provider.
If a range is given, it is appropriately appended to
the URL as an anchor.
Upstream providers can be added by installing an Upstream providers can be added by installing an
appropriate Vim plugin. For example, GitHub can be appropriate Vim plugin. For example, GitHub can be
supported by installing rhubarb.vim, available at supported by installing rhubarb.vim, available at
<https://github.com/tpope/vim-rhubarb>. <https://github.com/tpope/vim-rhubarb>.
:GBrowse {object} Like :GBrowse, but for a given |fugitive-object|. :Gbrowse {object} Like :Gbrowse, but for a given |fugitive-object|.
:{range}GBrowse [args] Appends an anchor to the URL that emphasizes the :Gbrowse [...]@{remote} Force using the given remote rather than the remote
for the current branch. The remote is used to
determine which upstream repository to link to.
:{range}Gbrowse [args] Appends an anchor to the URL that emphasizes the
selected lines. This also forces the URL to include a selected lines. This also forces the URL to include a
commit rather than a branch name so it remains valid commit rather than a branch name so it remains valid
if the file changes. You can give a range of "0" to if the file changes. You can give a range of "0" to
force this behavior without including an anchor. force this behavior without including an anchor.
:GBrowse [...]@{remote} Force using the given remote rather than the remote :[range]Gbrowse! [args] Like :Gbrowse, but put the URL on the clipboard rather
for the current branch. The remote is used to
determine which upstream repository to link to.
:GBrowse {url} Open an arbitrary URL in your browser.
:[range]GBrowse! [args] Like :GBrowse, but put the URL on the clipboard rather
than opening it. than opening it.
MAPS *fugitive-maps* MAPS *fugitive-maps*
These maps are available in both the |fugitive-summary| buffer and Fugitive These maps are available in both the |:Gstatus| buffer and Fugitive object
object buffers, although not all maps make sense in all buffers. Mappings buffers, although not all maps make sense in all buffers. Mappings that
that operate on the file or hunk under the cursor are generally available in operate on the file or hunk under the cursor are generally available in visual
visual mode to operate on multiple files or partial hunks. mode to operate on multiple files or partial hunks.
*fugitive-staging-maps* *fugitive-staging-maps*
Staging/unstaging maps ~ Staging/unstaging maps ~
@@ -302,9 +289,10 @@ U Unstage everything.
X Discard the change under the cursor. This uses X Discard the change under the cursor. This uses
`checkout` or `clean` under the hood. A command is `checkout` or `clean` under the hood. A command is
echoed that shows how to undo the change. Consult echoed that shows how to undo the change. Consult
`:messages` to see it again. During a merge conflict, `:messages` to see it again. You can use this during
use 2X to call `checkout --ours` or 3X to call a merge conflict do discard "our" changes (--theirs)
`checkout --theirs` . in the "Unstaged" section or discard "their" changes
(--ours) in the "Staged" section.
*fugitive_=* *fugitive_=*
= Toggle an inline diff of the file under the cursor. = Toggle an inline diff of the file under the cursor.
@@ -327,7 +315,7 @@ P under the cursor. On untracked files, this instead
*fugitive_d* *fugitive_d*
Diff maps ~ Diff maps ~
*fugitive_dp* *fugitive_dp*
dp Invoke |:Git| diff on the file under the cursor. dp Invoke |:Git!| diff on the file under the cursor.
Deprecated in favor of inline diffs. Deprecated in favor of inline diffs.
*fugitive_dd* *fugitive_dd*
@@ -339,10 +327,9 @@ dv Perform a |:Gvdiffsplit| on the file under the cursor.
*fugitive_ds* *fugitive_dh* *fugitive_ds* *fugitive_dh*
ds Perform a |:Ghdiffsplit| on the file under the cursor. ds Perform a |:Ghdiffsplit| on the file under the cursor.
dh dh
*fugitive_dq* *fugitive_dq*
dq Close all but the currently focused diff buffer, and dq Close all but one diff buffer, and |:diffoff|! the
invoke |:diffoff|!. last one.
*fugitive_d?* *fugitive_d?*
d? Show this help. d? Show this help.
@@ -352,7 +339,7 @@ Navigation maps ~
*fugitive_<CR>* *fugitive_<CR>*
<CR> Open the file or |fugitive-object| under the cursor. <CR> Open the file or |fugitive-object| under the cursor.
In a blob, this and similar maps jump to the patch in a blob, this and similar maps jump to the patch
from the diff where this was added, or where it was from the diff where this was added, or where it was
removed if a count was given. If the line is still in removed if a count was given. If the line is still in
the work tree version, passing a count takes you to the work tree version, passing a count takes you to
@@ -380,9 +367,6 @@ p Open the file or |fugitive-object| under the cursor in
*fugitive_P* *fugitive_P*
P Open the current file in the [count]th parent. P Open the current file in the [count]th parent.
Experimental: In the "Unpushed" section of the status
buffer, this will populate the command line with a
":Git push" command for the commit under the cursor.
*fugitive_C* *fugitive_C*
C Open the commit containing the current file. C Open the commit containing the current file.
@@ -430,7 +414,7 @@ i Jump to the next file or hunk, expanding inline diffs
][ Jump [count] section ends forward. ][ Jump [count] section ends forward.
*fugitive_star* *fugitive_star*
* On the first column of a + or - diff line, search for * One the first column of a + or - diff line, search for
the corresponding - or + line. Otherwise, defer to the corresponding - or + line. Otherwise, defer to
built-in |star|. built-in |star|.
@@ -465,18 +449,15 @@ Commit maps ~
cc Create a commit. cc Create a commit.
cvc Create a commit with -v.
ca Amend the last commit and edit the message. ca Amend the last commit and edit the message.
cva Amend the last commit with -v.
ce Amend the last commit without editing the message. ce Amend the last commit without editing the message.
cw Reword the last commit. cw Reword the last commit.
cW Create an `amend!` commit that rewords the commit cvc Create a commit with -v.
under the cursor.
cva Amend the last commit with -v
cf Create a `fixup!` commit for the commit under the cf Create a `fixup!` commit for the commit under the
cursor. cursor.
@@ -490,8 +471,8 @@ cs Create a `squash!` commit for the commit under the
cS Create a `squash!` commit for the commit under the cS Create a `squash!` commit for the commit under the
cursor and immediately rebase it. cursor and immediately rebase it.
cn Create a `squash!` commit for the commit under the cA Create a `squash!` commit for the commit under the
(formerly cA) cursor and edit the message. cursor and edit the message.
c<Space> Populate command line with ":Git commit ". c<Space> Populate command line with ":Git commit ".
@@ -527,10 +508,8 @@ Stash maps ~
czz Push stash. Pass a [count] of 1 to add czz Push stash. Pass a [count] of 1 to add
`--include-untracked` or 2 to add `--all`. `--include-untracked` or 2 to add `--all`.
czw Push stash of the work-tree. Like `czz` with czw Push stash of worktree. Like `czz` with
`--keep-index`. `--include-index`.
czs Push stash of the stage. Does not accept a count.
czA Apply topmost stash, or stash@{count}. czA Apply topmost stash, or stash@{count}.
@@ -639,9 +618,7 @@ Makefile The file named Makefile in the work tree
!:Makefile The file named Makefile in the commit owning the current file !:Makefile The file named Makefile in the commit owning the current file
!3^2 The second parent of the commit owning buffer #3 !3^2 The second parent of the commit owning buffer #3
.git/config The repo config file .git/config The repo config file
: The |fugitive-summary| buffer : Same as |:Gstatus|
- A temp file containing the last |:Git| invocation's output
<cfile> The file or commit under the cursor
STATUSLINE *fugitive-statusline* STATUSLINE *fugitive-statusline*
@@ -652,91 +629,11 @@ a statusline, this one matches the default when 'ruler' is set:
> >
set statusline=%<%f\ %h%m%r%{FugitiveStatusline()}%=%-14.(%l,%c%V%)\ %P set statusline=%<%f\ %h%m%r%{FugitiveStatusline()}%=%-14.(%l,%c%V%)\ %P
< <
AUTOCOMMANDS *fugitive-autocommands* *FugitiveHead(...)* *fugitive#head(...)*
Use FugitiveHead() to return the name of the current branch. If the current
A handful of |User| |autocommands| are provided to allow extending and HEAD is detached, FugitiveHead() will return the empty string, unless the
overriding Fugitive behaviors. Example usage: optional argument is given, in which case the hash of the current commit will
> be truncated to the given number of characters.
autocmd User FugitiveBlob,FugitiveStageBlob call s:BlobOverrides()
<
*User_FugitiveTag*
FugitiveTag After loading a tag object.
*User_FugitiveCommit*
FugitiveCommit After loading a commit object.
*User_FugitiveTree*
FugitiveTree After loading a tree (directory) object.
*User_FugitiveBlob*
FugitiveBlob After loading a committed blob (file) object.
*User_FugitiveObject*
FugitiveObject After loading any of the 4 above buffer types.
*User_FugitiveStageBlob*
FugitiveStageBlob After loading a staged blob (file) object. These
buffers are 'modifiable' and oftentimes don't want the
same behavior as the other buffer types.
*User_FugitiveIndex*
FugitiveIndex After loading the |fugitive-summary| buffer.
*User_FugitivePager*
FugitivePager After loading a temp file created by a command like
:Git --paginate or :Git blame.
*User_FugitiveEditor*
FugitiveEditor After a :Git command (e.g., :Git commit) edits a file
(e.g., the commit message).
*User_FugitiveChanged*
FugitiveChanged After any event which can potentially change the
repository, for example, any invocation of |:Git|.
Originally intended for expiring caches, but can have
other uses.
API *fugitive-api*
Officially supported functions are documented inline in plugin/fugitive.vim.
DEPRECATIONS *fugitive-deprecated*
The following commands are deprecated in favor of replacements that adhere to
a new naming scheme. Remember that |:Git| can be shortened to |:G|, so
replacements using it are just one space character longer than the legacy
version.
*:Gremove* Superseded by |:GRemove|.
*:Gdelete* Superseded by |:GDelete|.
*:Gmove* Superseded by |:GMove|.
*:Grename* Superseded by |:GRename|.
*:Gbrowse* Superseded by |:GBrowse|.
*:Gdiff* Superseded by |:Gdiffsplit|
*:Gsdiff* Superseded by |:Ghdiffsplit|
*:Gvdiff* Superseded by |:Gvdiffsplit| or |:vert| |:Gdiffsplit|.
*:Gblame* Superseded by |:Git_blame|.
*:Gcommit* Superseded by |:Git| commit.
*:Gmerge* Superseded by |:Git| merge and |:Git_mergetool|.
*:Gpull* Superseded by |:Git| pull.
*:Grebase* Superseded by |:Git| rebase.
*:Grevert* Superseded by |:Git| revert.
*:Gpush* Superseded by |:Git| push.
*:Gfetch* Superseded by |:Git| fetch.
*:Glog* Superseded by |:Gclog|.
*:Gstatus* Superseded by |:Git| (with no arguments).
*:Gsplit!* Superseded by |:Git_--paginate|.
*:Gvsplit!* Superseded by :vert Git --paginate.
*:Gtabsplit!* Superseded by :tab Git --paginate.
*:Gpedit!* Superseded by :Git! --paginate.
*User_Fugitive*
Fugitive used to support `:autocmd User Fugitive` to run an autocommand after
loading any buffer belonging to a Git repository, but this has been phased
out. Instead, one can leverage regular autocommand events like |BufNewFile|
and |BufReadPost|, and check !empty(FugitiveGitDir()) to confirm Fugitive has
found a repository. See also |fugitive-autocommands| for other, more
selective events.
ABOUT *fugitive-about* ABOUT *fugitive-about*

View File

@@ -1,6 +0,0 @@
if exists("b:did_ftplugin") || !exists("*FugitiveGitDir")
finish
endif
let b:did_ftplugin = 1
call fugitive#BlameFileType()

View File

@@ -1,6 +1,6 @@
" fugitive.vim - A Git wrapper so awesome, it should be illegal " fugitive.vim - A Git wrapper so awesome, it should be illegal
" Maintainer: Tim Pope <http://tpo.pe/> " Maintainer: Tim Pope <http://tpo.pe/>
" Version: 3.7 " Version: 3.1
" GetLatestVimScripts: 2975 1 :AutoInstall: fugitive.vim " GetLatestVimScripts: 2975 1 :AutoInstall: fugitive.vim
if exists('g:loaded_fugitive') if exists('g:loaded_fugitive')
@@ -8,38 +8,20 @@ if exists('g:loaded_fugitive')
endif endif
let g:loaded_fugitive = 1 let g:loaded_fugitive = 1
let s:bad_git_dir = '/$\|^fugitive:'
" FugitiveGitDir() returns the detected Git dir for the given buffer number,
" or the current buffer if no argument is passed. This will be an empty
" string if no Git dir was found. Use !empty(FugitiveGitDir()) to check if
" Fugitive is active in the current buffer. Do not rely on this for direct
" filesystem access; use FugitiveFind('.git/whatever') instead.
function! FugitiveGitDir(...) abort function! FugitiveGitDir(...) abort
if v:version < 704 if !a:0 || type(a:1) == type(0) && a:1 < 0
return ''
elseif !a:0 || type(a:1) == type(0) && a:1 < 0 || a:1 is# get(v:, 'true', -1)
if exists('g:fugitive_event') if exists('g:fugitive_event')
return g:fugitive_event return g:fugitive_event
endif endif
let dir = get(b:, 'git_dir', '') let dir = get(b:, 'git_dir', '')
if empty(dir) && (empty(bufname('')) && &filetype !=# 'netrw' || &buftype =~# '^\%(nofile\|acwrite\|quickfix\|terminal\|prompt\)$') if empty(dir) && (empty(bufname('')) || &buftype =~# '^\%(nofile\|acwrite\|quickfix\|prompt\)$')
return FugitiveExtractGitDir(getcwd()) return FugitiveExtractGitDir(getcwd())
elseif (!exists('b:git_dir') || b:git_dir =~# s:bad_git_dir) && &buftype =~# '^\%(nowrite\)\=$'
let b:git_dir = FugitiveExtractGitDir(bufnr(''))
return b:git_dir
endif endif
return dir =~# s:bad_git_dir ? '' : dir return dir
elseif type(a:1) == type(0) && a:1 isnot# 0 elseif type(a:1) == type(0)
if a:1 == bufnr('') && (!exists('b:git_dir') || b:git_dir =~# s:bad_git_dir) && &buftype =~# '^\%(nowrite\)\=$' return getbufvar(a:1, 'git_dir')
let b:git_dir = FugitiveExtractGitDir(a:1)
endif
let dir = getbufvar(a:1, 'git_dir')
return dir =~# s:bad_git_dir ? '' : dir
elseif type(a:1) == type('') elseif type(a:1) == type('')
return substitute(s:Slash(a:1), '/$', '', '') return substitute(s:Slash(a:1), '/$', '', '')
elseif type(a:1) == type({})
return get(a:1, 'fugitive_dir', get(a:1, 'git_dir', ''))
else else
return '' return ''
endif endif
@@ -55,11 +37,7 @@ endfunction
" exists, call FooReal("foo://bar"). " exists, call FooReal("foo://bar").
function! FugitiveReal(...) abort function! FugitiveReal(...) abort
let file = a:0 ? a:1 : @% let file = a:0 ? a:1 : @%
if type(file) ==# type({}) if file =~# '^\a\a\+:' || a:0 > 1
let dir = FugitiveGitDir(file)
let tree = s:Tree(dir)
return s:VimSlash(empty(tree) ? dir : tree)
elseif file =~# '^\a\a\+:' || a:0 > 1
return call('fugitive#Real', [file] + a:000[1:-1]) return call('fugitive#Real', [file] + a:000[1:-1])
elseif file =~# '^/\|^\a:\|^$' elseif file =~# '^/\|^\a:\|^$'
return file return file
@@ -76,302 +54,116 @@ endfunction
" An optional second argument provides the Git dir, or the buffer number of a " An optional second argument provides the Git dir, or the buffer number of a
" buffer with a Git dir. The default is the current buffer. " buffer with a Git dir. The default is the current buffer.
function! FugitiveFind(...) abort function! FugitiveFind(...) abort
if a:0 && (type(a:1) ==# type({}) || type(a:1) ==# type(0)) return fugitive#Find(a:0 ? a:1 : bufnr(''), FugitiveGitDir(a:0 > 1 ? a:2 : -1))
return call('fugitive#Find', a:000[1:-1] + [FugitiveGitDir(a:1)])
else
return fugitive#Find(a:0 ? a:1 : bufnr(''), FugitiveGitDir(a:0 > 1 ? a:2 : -1))
endif
endfunction
" FugitiveParse() takes a fugitive:// URL and returns a 2 element list
" containing an object name ("commit:file") and the Git dir. It's effectively
" the inverse of FugitiveFind().
function! FugitiveParse(...) abort
let path = s:Slash(a:0 ? a:1 : @%)
if path !~# '^fugitive://'
return ['', '']
endif
let [rev, dir] = fugitive#Parse(path)
if !empty(dir)
return [rev, dir]
endif
throw 'fugitive: invalid Fugitive URL ' . path
endfunction
" FugitiveGitVersion() queries the version of Git in use. Pass up to 3
" arguments to return a Boolean of whether a certain minimum version is
" available (FugitiveGitVersion(2,3,4) checks for 2.3.4 or higher) or no
" arguments to get a raw string.
function! FugitiveGitVersion(...) abort
return call('fugitive#GitVersion', a:000)
endfunction
" FugitiveResult() returns an object encapsulating the result of the most
" recent :Git command. Will be empty if no result is available. During a
" User FugitiveChanged event, this is guaranteed to correspond to the :Git
" command that triggered the event, or be empty if :Git was not the trigger.
" Pass in the name of a temp buffer to get the result object for that command
" instead. Contains the following keys:
"
" * "args": List of command arguments, starting with the subcommand. Will be
" empty for usages like :Git --help.
" * "git_dir": Git dir of the relevant repository.
" * "exit_status": The integer exit code of the process.
" * "flags": Flags passed directly to Git, like -c and --help.
" * "file": Path to file containing command output. Not guaranteed to exist,
" so verify with filereadable() before trying to access it.
function! FugitiveResult(...) abort
return call('fugitive#Result', a:000)
endfunction
" FugitiveExecute() runs Git with a list of arguments and returns a dictionary
" with the following keys:
"
" * "exit_status": The integer exit code of the process.
" * "stdout": The stdout produced by the process, as a list of lines.
" * "stderr": The stdout produced by the process, as a list of lines.
"
" An optional second argument provides the Git dir, or the buffer number of a
" buffer with a Git dir. The default is the current buffer.
"
" An optional final argument is a callback Funcref, for asynchronous
" execution.
function! FugitiveExecute(args, ...) abort
return call('fugitive#Execute', [a:args] + a:000)
endfunction
" FugitiveShellCommand() turns an array of arguments into a Git command string
" which can be executed with functions like system() and commands like :!.
" Integer arguments will be treated as buffer numbers, and the appropriate
" relative path inserted in their place.
"
" An optional second argument provides the Git dir, or the buffer number of a
" buffer with a Git dir. The default is the current buffer.
function! FugitiveShellCommand(...) abort
return call('fugitive#ShellCommand', a:000)
endfunction
" FugitiveConfig() get returns an opaque structure that can be passed to other
" FugitiveConfig functions in lieu of a Git directory. This can be faster
" when performing multiple config queries. Do not rely on the internal
" structure of the return value as it is not guaranteed. If you want a full
" dictionary of every config value, use FugitiveConfigGetRegexp('.*').
"
" An optional argument provides the Git dir, or the buffer number of a
" buffer with a Git dir. The default is the current buffer. Pass a blank
" string to limit to the global config.
function! FugitiveConfig(...) abort
return call('fugitive#Config', a:000)
endfunction
" FugitiveConfigGet() retrieves a Git configuration value. An optional second
" argument can be either the object returned by FugitiveConfig(), or a Git
" dir or buffer number to be passed along to FugitiveConfig().
function! FugitiveConfigGet(name, ...) abort
return get(call('FugitiveConfigGetAll', [a:name] + (a:0 ? [a:1] : [])), -1, get(a:, 2, ''))
endfunction
" FugitiveConfigGetAll() is like FugitiveConfigGet() but returns a list of
" all values.
function! FugitiveConfigGetAll(name, ...) abort
return call('fugitive#ConfigGetAll', [a:name] + a:000)
endfunction
" FugitiveConfigGetRegexp() retrieves a dictionary of all configuration values
" with a key matching the given pattern. Like git config --get-regexp, but
" using a Vim regexp. Second argument has same semantics as
" FugitiveConfigGet().
function! FugitiveConfigGetRegexp(pattern, ...) abort
return call('fugitive#ConfigGetRegexp', [a:pattern] + a:000)
endfunction
" FugitiveRemoteUrl() retrieves the remote URL for the given remote name,
" defaulting to the current branch's remote or "origin" if no argument is
" given. Similar to `git remote get-url`, but also attempts to resolve HTTP
" redirects and SSH host aliases.
"
" An optional second argument provides the Git dir, or the buffer number of a
" buffer with a Git dir. The default is the current buffer.
function! FugitiveRemoteUrl(...) abort
return call('fugitive#RemoteUrl', a:000)
endfunction
" FugitiveRemote() returns a data structure parsed from the remote URL.
" For example, for remote URL "https://me@example.com:1234/repo.git", the
" returned dictionary will contain the following:
"
" * "scheme": "https"
" * "authority": "user@example.com:1234"
" * "path": "/repo.git" (for SSH URLs this may be a relative path)
" * "pathname": "/repo.git" (always coerced to absolute path)
" * "host": "example.com:1234"
" * "hostname": "example.com"
" * "port": "1234"
" * "user": "me"
" * "path": "/repo.git"
" * "url": "https://me@example.com:1234/repo.git"
function! FugitiveRemote(...) abort
return call('fugitive#Remote', a:000)
endfunction
" FugitiveDidChange() triggers a FugitiveChanged event and reloads the summary
" buffer for the current or given buffer number's repository. You can also
" give the result of a FugitiveExecute() and that context will be made
" available inside the FugitiveChanged() event.
"
" Passing the special argument 0 (the number zero) softly expires summary
" buffers for all repositories. This can be used after a call to system()
" with unclear implications.
function! FugitiveDidChange(...) abort
return call('fugitive#DidChange', a:000)
endfunction
" FugitiveHead() retrieves the name of the current branch. If the current HEAD
" is detached, FugitiveHead() will return the empty string, unless the
" optional argument is given, in which case the hash of the current commit
" will be truncated to the given number of characters.
"
" An optional second argument provides the Git dir, or the buffer number of a
" buffer with a Git dir. The default is the current buffer.
function! FugitiveHead(...) abort
if a:0 && (type(a:1) ==# type({}) || type(a:1) ==# type('') && a:1 !~# '^\d\+$')
let dir = FugitiveGitDir(a:1)
let arg = get(a:, 2, 0)
elseif a:0 > 1
let dir = FugitiveGitDir(a:2)
let arg = a:1
else
let dir = FugitiveGitDir()
let arg = get(a:, 1, 0)
endif
if empty(dir)
return ''
endif
return fugitive#Head(arg, dir)
endfunction endfunction
function! FugitivePath(...) abort function! FugitivePath(...) abort
if a:0 > 2 && type(a:1) ==# type({}) if a:0 > 1
return fugitive#Path(a:2, a:3, FugitiveGitDir(a:1))
elseif a:0 && type(a:1) ==# type({})
return FugitiveReal(a:0 > 1 ? a:2 : @%)
elseif a:0 > 1
return fugitive#Path(a:1, a:2, FugitiveGitDir(a:0 > 2 ? a:3 : -1)) return fugitive#Path(a:1, a:2, FugitiveGitDir(a:0 > 2 ? a:3 : -1))
else else
return FugitiveReal(a:0 ? a:1 : @%) return FugitiveReal(a:0 ? a:1 : @%)
endif endif
endfunction endfunction
" FugitiveParse() takes a fugitive:// URL and returns a 2 element list
" containing the Git dir and an object name ("commit:file"). It's effectively
" then inverse of FugitiveFind().
function! FugitiveParse(...) abort
let path = s:Slash(a:0 ? a:1 : @%)
if path !~# '^fugitive:'
return ['', '']
endif
let vals = matchlist(path, '\c^fugitive:\%(//\)\=\(.\{-\}\)\%(//\|::\)\(\x\{40,\}\|[0-3]\)\(/.*\)\=$')
if len(vals)
return [(vals[2] =~# '^.$' ? ':' : '') . vals[2] . substitute(vals[3], '^/', ':', ''), vals[1]]
endif
let v:errmsg = 'fugitive: invalid Fugitive URL ' . path
throw v:errmsg
endfunction
" FugitivePrepare() constructs a Git command string which can be executed with
" functions like system() and commands like :!. Integer arguments will be
" treated as buffer numbers, and the appropriate relative path inserted in
" their place.
"
" If the first argument is a string that looks like a path or an empty string,
" it will be used as the Git dir. If it's a buffer number, the Git dir for
" that buffer will be used. The default is the current buffer.
function! FugitivePrepare(...) abort
return call('fugitive#Prepare', a:000)
endfunction
function! FugitiveConfig(...) abort
if a:0 == 2 && type(a:2) != type({})
return fugitive#Config(a:1, FugitiveGitDir(a:2))
elseif a:0 == 1 && a:1 !~# '^[[:alnum:]-]\+\.'
return fugitive#Config(FugitiveGitDir(a:1))
else
return call('fugitive#Config', a:000)
endif
endfunction
function! FugitiveRemoteUrl(...) abort
return fugitive#RemoteUrl(a:0 ? a:1 : '', FugitiveGitDir(a:0 > 1 ? a:2 : -1))
endfunction
function! FugitiveHead(...) abort
let dir = FugitiveGitDir(a:0 > 1 ? a:2 : -1)
if empty(dir)
return ''
endif
return fugitive#Head(a:0 ? a:1 : 0, dir)
endfunction
function! FugitiveStatusline(...) abort function! FugitiveStatusline(...) abort
if empty(FugitiveGitDir(bufnr(''))) if !exists('b:git_dir')
return '' return ''
endif endif
return fugitive#Statusline() return fugitive#Statusline()
endfunction endfunction
let s:resolved_git_dirs = {}
function! FugitiveActualDir(...) abort
let dir = call('FugitiveGitDir', a:000)
if empty(dir)
return ''
endif
if !has_key(s:resolved_git_dirs, dir)
let s:resolved_git_dirs[dir] = s:ResolveGitDir(dir)
endif
return empty(s:resolved_git_dirs[dir]) ? dir : s:resolved_git_dirs[dir]
endfunction
let s:commondirs = {}
function! FugitiveCommonDir(...) abort function! FugitiveCommonDir(...) abort
let dir = call('FugitiveActualDir', a:000) let dir = FugitiveGitDir(a:0 ? a:1 : -1)
if empty(dir) if empty(dir)
return '' return ''
endif endif
if has_key(s:commondirs, dir) return fugitive#CommonDir(dir)
return s:commondirs[dir]
endif
if getfsize(dir . '/HEAD') >= 10
let cdir = get(s:ReadFile(dir . '/commondir', 1), 0, '')
if cdir =~# '^/\|^\a:/'
let s:commondirs[dir] = s:Slash(FugitiveVimPath(cdir))
elseif len(cdir)
let s:commondirs[dir] = simplify(dir . '/' . cdir)
else
let s:commondirs[dir] = dir
endif
else
let s:commondirs[dir] = dir
endif
return s:commondirs[dir]
endfunction endfunction
function! FugitiveWorkTree(...) abort function! FugitiveWorkTree(...) abort
let tree = s:Tree(FugitiveGitDir(a:0 ? a:1 : -1)) return s:Tree(FugitiveGitDir(a:0 ? a:1 : -1))
if tree isnot# 0 || a:0 > 1
return tree
else
return ''
endif
endfunction endfunction
function! FugitiveIsGitDir(...) abort function! FugitiveIsGitDir(path) abort
if !a:0 || type(a:1) !=# type('') let path = substitute(a:path, '[\/]$', '', '') . '/'
return !empty(call('FugitiveGitDir', a:000)) return len(a:path) && getfsize(path.'HEAD') > 10 && (
endif
let path = substitute(a:1, '[\/]$', '', '') . '/'
return len(path) && getfsize(path.'HEAD') > 10 && (
\ isdirectory(path.'objects') && isdirectory(path.'refs') || \ isdirectory(path.'objects') && isdirectory(path.'refs') ||
\ getftype(path.'commondir') ==# 'file') \ getftype(path.'commondir') ==# 'file')
endfunction endfunction
function! s:ReadFile(path, line_count) abort
if v:version < 800 && !filereadable(a:path)
return []
endif
try
return readfile(a:path, 'b', a:line_count)
catch
return []
endtry
endfunction
let s:worktree_for_dir = {} let s:worktree_for_dir = {}
let s:dir_for_worktree = {} let s:dir_for_worktree = {}
function! s:Tree(path) abort function! s:Tree(path) abort
if a:path =~# '/\.git$' let dir = a:path
return len(a:path) ==# 5 ? '/' : a:path[0:-6] if dir =~# '/\.git$'
elseif a:path ==# '' return len(dir) ==# 5 ? '/' : dir[0:-6]
elseif dir ==# ''
return '' return ''
endif endif
let dir = FugitiveActualDir(a:path)
if !has_key(s:worktree_for_dir, dir) if !has_key(s:worktree_for_dir, dir)
let s:worktree_for_dir[dir] = '' let s:worktree_for_dir[dir] = ''
let ext_wtc_pat = 'v:val =~# "^\\s*worktreeConfig *= *\\%(true\\|yes\\|on\\|1\\) *$"' let config_file = dir . '/config'
let config = s:ReadFile(dir . '/config', 50) if filereadable(config_file)
if len(config) let config = readfile(config_file,'',10)
let ext_wtc_config = filter(copy(config), ext_wtc_pat) call filter(config,'v:val =~# "^\\s*worktree *="')
if len(ext_wtc_config) == 1 && filereadable(dir . '/config.worktree') if len(config) == 1
let config += s:ReadFile(dir . '/config.worktree', 50) let worktree = FugitiveVimPath(matchstr(config[0], '= *\zs.*'))
endif endif
else elseif filereadable(dir . '/gitdir')
let worktree = fnamemodify(FugitiveVimPath(get(s:ReadFile(dir . '/gitdir', 1), '0', '')), ':h') let worktree = fnamemodify(FugitiveVimPath(readfile(dir . '/gitdir')[0]), ':h')
if worktree ==# '.' if worktree ==# '.'
unlet! worktree unlet! worktree
endif endif
if len(filter(s:ReadFile(FugitiveCommonDir(dir) . '/config', 50), ext_wtc_pat))
let config = s:ReadFile(dir . '/config.worktree', 50)
endif
endif
if len(config)
let wt_config = filter(copy(config), 'v:val =~# "^\\s*worktree *="')
if len(wt_config)
let worktree = FugitiveVimPath(matchstr(wt_config[0], '= *\zs.*'))
elseif !exists('worktree')
call filter(config,'v:val =~# "^\\s*bare *= *true *$"')
if empty(config)
let s:worktree_for_dir[dir] = 0
endif
endif
endif endif
if exists('worktree') if exists('worktree')
let s:worktree_for_dir[dir] = s:Slash(resolve(worktree)) let s:worktree_for_dir[dir] = s:Slash(resolve(worktree))
@@ -393,60 +185,42 @@ function! s:CeilingDirectories() abort
if empty(dir) if empty(dir)
let resolve = 0 let resolve = 0
elseif resolve elseif resolve
call add(s:ceiling_directories, s:Slash(resolve(dir))) call add(s:ceiling_directories, resolve(dir))
else else
call add(s:ceiling_directories, s:Slash(dir)) call add(s:ceiling_directories, dir)
endif endif
endfor endfor
endif endif
return s:ceiling_directories + get(g:, 'ceiling_directories', [s:Slash(fnamemodify(expand('~'), ':h'))]) return s:ceiling_directories + get(g:, 'ceiling_directories', [])
endfunction
function! s:ResolveGitDir(git_dir) abort
let type = getftype(a:git_dir)
if type ==# 'dir' && FugitiveIsGitDir(a:git_dir)
return a:git_dir
elseif type ==# 'link' && FugitiveIsGitDir(a:git_dir)
return resolve(a:git_dir)
elseif type !=# ''
let line = get(s:ReadFile(a:git_dir, 1), 0, '')
let file_dir = s:Slash(FugitiveVimPath(matchstr(line, '^gitdir: \zs.*')))
if file_dir !~# '^/\|^\a:\|^$' && a:git_dir =~# '/\.git$' && FugitiveIsGitDir(a:git_dir[0:-5] . file_dir)
return simplify(a:git_dir[0:-5] . file_dir)
elseif file_dir =~# '^/\|^\a:' && FugitiveIsGitDir(file_dir)
return file_dir
endif
endif
return ''
endfunction endfunction
function! FugitiveExtractGitDir(path) abort function! FugitiveExtractGitDir(path) abort
if type(a:path) ==# type({}) let path = s:Slash(a:path)
return get(a:path, 'fugitive_dir', get(a:path, 'git_dir', '')) if path =~# '^fugitive:'
elseif type(a:path) == type(0) return matchstr(path, '\C^fugitive:\%(//\)\=\zs.\{-\}\ze\%(//\|::\|$\)')
let path = s:Slash(a:path > 0 ? bufname(a:path) : bufname(''))
if getbufvar(a:path, '&filetype') ==# 'netrw'
let path = s:Slash(getbufvar(a:path, 'netrw_curdir', path))
endif
else
let path = s:Slash(a:path)
endif
if path =~# '^fugitive://'
return fugitive#Parse(path)[1]
elseif empty(path) elseif empty(path)
return '' return ''
elseif isdirectory(path)
let path = fnamemodify(path, ':p:s?/$??')
else
let path = fnamemodify(path, ':p:h:s?/$??')
endif endif
let pre = substitute(matchstr(path, '^\a\a\+\ze:'), '^.', '\u&', '') let pre = substitute(matchstr(path, '^\a\a\+\ze:'), '^.', '\u&', '')
if len(pre) && exists('*' . pre . 'Real') if len(pre) && exists('*' . pre . 'Real')
let path = {pre}Real(path) let path = s:Slash({pre}Real(path))
endif
let root = resolve(path)
if root !=# path
silent! exe (haslocaldir() ? 'lcd' : exists(':tcd') && haslocaldir(-1) ? 'tcd' : 'cd') '.'
endif endif
let root = s:Slash(fnamemodify(path, ':p:h'))
let previous = "" let previous = ""
let env_git_dir = len($GIT_DIR) ? s:Slash(simplify(fnamemodify(FugitiveVimPath($GIT_DIR), ':p:s?[\/]$??'))) : '' let env_git_dir = len($GIT_DIR) ? s:Slash(simplify(fnamemodify(FugitiveVimPath($GIT_DIR), ':p:s?[\/]$??'))) : ''
call s:Tree(env_git_dir) call s:Tree(env_git_dir)
let ceiling_directories = s:CeilingDirectories() while root !=# previous
while root !=# previous && root !~# '^$\|^//[^/]*$' if root =~# '\v^//%([^/]+/?)?$'
if index(ceiling_directories, root) >= 0 break
endif
if index(s:CeilingDirectories(), root) >= 0
break break
endif endif
if root ==# $GIT_WORK_TREE && FugitiveIsGitDir(env_git_dir) if root ==# $GIT_WORK_TREE && FugitiveIsGitDir(env_git_dir)
@@ -455,12 +229,20 @@ function! FugitiveExtractGitDir(path) abort
return s:dir_for_worktree[root] return s:dir_for_worktree[root]
endif endif
let dir = substitute(root, '[\/]$', '', '') . '/.git' let dir = substitute(root, '[\/]$', '', '') . '/.git'
let resolved = s:ResolveGitDir(dir) let type = getftype(dir)
if !empty(resolved) if type ==# 'dir' && FugitiveIsGitDir(dir)
let s:resolved_git_dirs[dir] = resolved return dir
return dir is# resolved || s:Tree(resolved) is# 0 ? dir : resolved elseif type ==# 'link' && FugitiveIsGitDir(dir)
return resolve(dir)
elseif type !=# '' && filereadable(dir)
let line = get(readfile(dir, '', 1), 0, '')
let file_dir = s:Slash(FugitiveVimPath(matchstr(line, '^gitdir: \zs.*')))
if file_dir !~# '^/\|^\a:' && FugitiveIsGitDir(root . '/' . file_dir)
return simplify(root . '/' . file_dir)
elseif len(file_dir) && FugitiveIsGitDir(file_dir)
return file_dir
endif
elseif FugitiveIsGitDir(root) elseif FugitiveIsGitDir(root)
let s:resolved_git_dirs[root] = root
return root return root
endif endif
let previous = root let previous = root
@@ -469,58 +251,40 @@ function! FugitiveExtractGitDir(path) abort
return '' return ''
endfunction endfunction
function! FugitiveDetect(...) abort function! FugitiveDetect(path) abort
if v:version < 704 if exists('b:git_dir') && b:git_dir =~# '^$\|/$\|^fugitive:'
return ''
endif
if exists('b:git_dir') && b:git_dir =~# '^$\|' . s:bad_git_dir
unlet b:git_dir unlet b:git_dir
endif endif
if !exists('b:git_dir') if !exists('b:git_dir')
let b:git_dir = FugitiveExtractGitDir(a:0 ? a:1 : bufnr('')) let dir = FugitiveExtractGitDir(a:path)
if dir !=# ''
let b:git_dir = dir
endif
endif
if exists('b:git_dir')
return fugitive#Init()
endif
endfunction
function! FugitiveVimPath(path) abort
if exists('+shellslash') && !&shellslash
return tr(a:path, '/', '\')
else
return a:path
endif endif
return ''
endfunction endfunction
function! FugitiveGitPath(path) abort function! FugitiveGitPath(path) abort
return s:Slash(a:path) return s:Slash(a:path)
endfunction endfunction
if exists('+shellslash') function! s:Slash(path) abort
if exists('+shellslash')
function! s:Slash(path) abort
return tr(a:path, '\', '/') return tr(a:path, '\', '/')
endfunction
function! s:VimSlash(path) abort
return tr(a:path, '\/', &shellslash ? '//' : '\\')
endfunction
function FugitiveVimPath(path) abort
return tr(a:path, '\/', &shellslash ? '//' : '\\')
endfunction
else
function! s:Slash(path) abort
return a:path
endfunction
function! s:VimSlash(path) abort
return a:path
endfunction
if has('win32unix') && filereadable('/git-bash.exe')
function! FugitiveVimPath(path) abort
return substitute(a:path, '^\(\a\):', '/\l\1', '')
endfunction
else else
function! FugitiveVimPath(path) abort return a:path
return a:path
endfunction
endif endif
endfunction
endif
function! s:ProjectionistDetect() abort function! s:ProjectionistDetect() abort
let file = s:Slash(get(g:, 'projectionist_file', '')) let file = s:Slash(get(g:, 'projectionist_file', ''))
@@ -529,117 +293,20 @@ function! s:ProjectionistDetect() abort
if empty(base) if empty(base)
let base = s:Tree(dir) let base = s:Tree(dir)
endif endif
if !empty(base) if len(base)
if exists('+shellslash') && !&shellslash if exists('+shellslash') && !&shellslash
let base = tr(base, '/', '\') let base = tr(base, '/', '\')
endif endif
let file = FugitiveFind('.git/info/projections.json', dir) let file = FugitiveCommonDir(dir) . '/info/projections.json'
if filereadable(file) if filereadable(file)
call projectionist#append(base, file) call projectionist#append(base, file)
endif endif
endif endif
endfunction endfunction
let s:addr_other = has('patch-8.1.560') || has('nvim-0.5.0') ? '-addr=other' : '' if v:version + has('patch061') < 703
let s:addr_tabs = has('patch-7.4.542') ? '-addr=tabs' : '' runtime! autoload/fugitive.vim
let s:addr_wins = has('patch-7.4.542') ? '-addr=windows' : ''
if exists(':G') != 2
command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#Complete G exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)
endif endif
command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#Complete Git exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)
if exists(':Gstatus') != 2 && get(g:, 'fugitive_legacy_commands', 0)
exe 'command! -bang -bar -range=-1' s:addr_other 'Gstatus exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
\ '|echohl WarningMSG|echomsg ":Gstatus is deprecated in favor of :Git (with no arguments)"|echohl NONE'
endif
for s:cmd in ['Commit', 'Revert', 'Merge', 'Rebase', 'Pull', 'Push', 'Fetch', 'Blame']
if exists(':G' . tolower(s:cmd)) != 2 && get(g:, 'fugitive_legacy_commands', 0)
exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#' . s:cmd . 'Complete G' . tolower(s:cmd)
\ 'echohl WarningMSG|echomsg ":G' . tolower(s:cmd) . ' is deprecated in favor of :Git ' . tolower(s:cmd) . '"|echohl NONE|'
\ 'exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", "' . tolower(s:cmd) . ' " . <q-args>)'
endif
endfor
unlet s:cmd
exe "command! -bar -bang -nargs=? -complete=customlist,fugitive#CdComplete Gcd exe fugitive#Cd(<q-args>, 0)"
exe "command! -bar -bang -nargs=? -complete=customlist,fugitive#CdComplete Glcd exe fugitive#Cd(<q-args>, 1)"
exe 'command! -bang -nargs=? -range=-1' s:addr_wins '-complete=customlist,fugitive#GrepComplete Ggrep exe fugitive#GrepCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bang -nargs=? -range=-1' s:addr_wins '-complete=customlist,fugitive#GrepComplete Glgrep exe fugitive#GrepCommand(0, <count> > 0 ? <count> : 0, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#LogComplete Gclog :exe fugitive#LogCommand(<line1>,<count>,+"<range>",<bang>0,"<mods>",<q-args>, "c")'
exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#LogComplete GcLog :exe fugitive#LogCommand(<line1>,<count>,+"<range>",<bang>0,"<mods>",<q-args>, "c")'
exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#LogComplete Gllog :exe fugitive#LogCommand(<line1>,<count>,+"<range>",<bang>0,"<mods>",<q-args>, "l")'
exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#LogComplete GlLog :exe fugitive#LogCommand(<line1>,<count>,+"<range>",<bang>0,"<mods>",<q-args>, "l")'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Ge exe fugitive#Open("edit<bang>", 0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gedit exe fugitive#Open("edit<bang>", 0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gpedit exe fugitive#Open("pedit", <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=* -range=-1' s:addr_other '-complete=customlist,fugitive#EditComplete Gsplit exe fugitive#Open((<count> > 0 ? <count> : "").(<count> ? "split" : "edit"), <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=* -range=-1' s:addr_other '-complete=customlist,fugitive#EditComplete Gvsplit exe fugitive#Open((<count> > 0 ? <count> : "").(<count> ? "vsplit" : "edit!"), <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=* -range=-1' s:addr_tabs '-complete=customlist,fugitive#EditComplete Gtabedit exe fugitive#Open((<count> >= 0 ? <count> : "")."tabedit", <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gdrop exe fugitive#DropCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
if exists(':Gr') != 2
exe 'command! -bar -bang -nargs=* -range=-1 -complete=customlist,fugitive#ReadComplete Gr exe fugitive#ReadCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
endif
exe 'command! -bar -bang -nargs=* -range=-1 -complete=customlist,fugitive#ReadComplete Gread exe fugitive#ReadCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gdiffsplit exe fugitive#Diffsplit(1, <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Ghdiffsplit exe fugitive#Diffsplit(0, <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gvdiffsplit exe fugitive#Diffsplit(0, <bang>0, "vertical <mods>", <q-args>)'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gw exe fugitive#WriteCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gwrite exe fugitive#WriteCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gwq exe fugitive#WqCommand( <line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=0 GRemove exe fugitive#RemoveCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=0 GUnlink exe fugitive#UnlinkCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=0 GDelete exe fugitive#DeleteCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=1 -complete=customlist,fugitive#CompleteObject GMove exe fugitive#MoveCommand( <line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bar -bang -nargs=1 -complete=customlist,fugitive#RenameComplete GRename exe fugitive#RenameCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
if exists(':Gremove') != 2 && get(g:, 'fugitive_legacy_commands', 0)
exe 'command! -bar -bang -nargs=0 Gremove exe fugitive#RemoveCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
\ '|echohl WarningMSG|echomsg ":Gremove is deprecated in favor of :GRemove"|echohl NONE'
elseif exists(':Gremove') != 2 && !exists('g:fugitive_legacy_commands')
exe 'command! -bar -bang -nargs=0 Gremove echoerr ":Gremove has been removed in favor of :GRemove"'
endif
if exists(':Gdelete') != 2 && get(g:, 'fugitive_legacy_commands', 0)
exe 'command! -bar -bang -nargs=0 Gdelete exe fugitive#DeleteCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
\ '|echohl WarningMSG|echomsg ":Gdelete is deprecated in favor of :GDelete"|echohl NONE'
elseif exists(':Gdelete') != 2 && !exists('g:fugitive_legacy_commands')
exe 'command! -bar -bang -nargs=0 Gdelete echoerr ":Gdelete has been removed in favor of :GDelete"'
endif
if exists(':Gmove') != 2 && get(g:, 'fugitive_legacy_commands', 0)
exe 'command! -bar -bang -nargs=1 -complete=customlist,fugitive#CompleteObject Gmove exe fugitive#MoveCommand( <line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
\ '|echohl WarningMSG|echomsg ":Gmove is deprecated in favor of :GMove"|echohl NONE'
elseif exists(':Gmove') != 2 && !exists('g:fugitive_legacy_commands')
exe 'command! -bar -bang -nargs=? -complete=customlist,fugitive#CompleteObject Gmove'
\ 'echoerr ":Gmove has been removed in favor of :GMove"'
endif
if exists(':Grename') != 2 && get(g:, 'fugitive_legacy_commands', 0)
exe 'command! -bar -bang -nargs=1 -complete=customlist,fugitive#RenameComplete Grename exe fugitive#RenameCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
\ '|echohl WarningMSG|echomsg ":Grename is deprecated in favor of :GRename"|echohl NONE'
elseif exists(':Grename') != 2 && !exists('g:fugitive_legacy_commands')
exe 'command! -bar -bang -nargs=? -complete=customlist,fugitive#RenameComplete Grename'
\ 'echoerr ":Grename has been removed in favor of :GRename"'
endif
exe 'command! -bar -bang -range=-1 -nargs=* -complete=customlist,fugitive#CompleteObject GBrowse exe fugitive#BrowseCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
if exists(':Gbrowse') != 2 && get(g:, 'fugitive_legacy_commands', 0)
exe 'command! -bar -bang -range=-1 -nargs=* -complete=customlist,fugitive#CompleteObject Gbrowse exe fugitive#BrowseCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
\ '|if <bang>1|redraw!|endif|echohl WarningMSG|echomsg ":Gbrowse is deprecated in favor of :GBrowse"|echohl NONE'
elseif exists(':Gbrowse') != 2 && !exists('g:fugitive_legacy_commands')
exe 'command! -bar -bang -range=-1 -nargs=* -complete=customlist,fugitive#CompleteObject Gbrowse'
\ 'echoerr ":Gbrowse has been removed in favor of :GBrowse"'
endif
if v:version < 704
finish
endif
let g:io_fugitive = { let g:io_fugitive = {
\ 'simplify': function('fugitive#simplify'), \ 'simplify': function('fugitive#simplify'),
\ 'resolve': function('fugitive#resolve'), \ 'resolve': function('fugitive#resolve'),
@@ -660,59 +327,52 @@ let g:io_fugitive = {
augroup fugitive augroup fugitive
autocmd! autocmd!
autocmd BufNewFile,BufReadPost * autocmd BufNewFile,BufReadPost * call FugitiveDetect(expand('<amatch>:p'))
\ if exists('b:git_dir') && b:git_dir =~# '^$\|' . s:bad_git_dir | autocmd FileType netrw call FugitiveDetect(fnamemodify(get(b:, 'netrw_curdir', expand('<amatch>')), ':p'))
\ unlet b:git_dir |
\ endif
autocmd FileType netrw
\ if exists('b:git_dir') && b:git_dir =~# '^$\|' . s:bad_git_dir |
\ unlet b:git_dir |
\ endif
autocmd BufFilePost * unlet! b:git_dir
autocmd FileType git autocmd FileType git
\ call fugitive#MapCfile() \ if len(FugitiveGitDir()) |
\ call fugitive#MapJumps() |
\ call fugitive#MapCfile() |
\ endif
autocmd FileType gitcommit autocmd FileType gitcommit
\ call fugitive#MapCfile('fugitive#MessageCfile()') \ if len(FugitiveGitDir()) |
autocmd FileType git,gitcommit \ call fugitive#MapCfile('fugitive#MessageCfile()') |
\ if &foldtext ==# 'foldtext()' |
\ setlocal foldtext=fugitive#Foldtext() |
\ endif \ endif
autocmd FileType fugitive autocmd FileType fugitive
\ call fugitive#MapCfile('fugitive#PorcelainCfile()') \ if len(FugitiveGitDir()) |
\ call fugitive#MapCfile('fugitive#StatusCfile()') |
\ endif
autocmd FileType gitrebase autocmd FileType gitrebase
\ let &l:include = '^\%(pick\|squash\|edit\|reword\|fixup\|drop\|[pserfd]\)\>' | \ let &l:include = '^\%(pick\|squash\|edit\|reword\|fixup\|drop\|[pserfd]\)\>' |
\ if &l:includeexpr !~# 'Fugitive' | \ if len(FugitiveGitDir()) |
\ let &l:includeexpr = 'v:fname =~# ''^\x\{4,\}$'' && len(FugitiveGitDir()) ? FugitiveFind(v:fname) : ' . \ let &l:includeexpr = 'v:fname =~# ''^\x\{4,\}$'' ? FugitiveFind(v:fname) : ' .
\ (len(&l:includeexpr) ? &l:includeexpr : 'v:fname') | \ (len(&l:includeexpr) ? &l:includeexpr : 'v:fname') |
\ endif | \ endif |
\ let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'exe') . '|setl inex= inc=' \ let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'exe') . '|setl inex= inc='
autocmd BufReadCmd index{,.lock} nested autocmd BufReadCmd index{,.lock}
\ if FugitiveIsGitDir(expand('<amatch>:p:h')) | \ if FugitiveIsGitDir(expand('<amatch>:p:h')) |
\ let b:git_dir = s:Slash(expand('<amatch>:p:h')) | \ let b:git_dir = s:Slash(expand('<amatch>:p:h')) |
\ exe fugitive#BufReadStatus(v:cmdbang) | \ exe fugitive#BufReadStatus() |
\ echohl WarningMSG |
\ echo "fugitive: Direct editing of .git/" . expand('%:t') . " is deprecated" |
\ echohl NONE |
\ elseif filereadable(expand('<amatch>')) | \ elseif filereadable(expand('<amatch>')) |
\ silent doautocmd BufReadPre | \ silent doautocmd BufReadPre |
\ keepalt noautocmd read <amatch> | \ keepalt read <amatch> |
\ silent 1delete_ | \ 1delete_ |
\ silent doautocmd BufReadPost | \ silent doautocmd BufReadPost |
\ else | \ else |
\ silent doautocmd BufNewFile | \ silent doautocmd BufNewFile |
\ endif \ endif
autocmd BufReadCmd fugitive://* nested exe fugitive#BufReadCmd() | autocmd BufReadCmd fugitive://*//* exe fugitive#BufReadCmd() |
\ if &path =~# '^\.\%(,\|$\)' | \ if &path =~# '^\.\%(,\|$\)' |
\ let &l:path = substitute(&path, '^\.,\=', '', '') | \ let &l:path = substitute(&path, '^\.,\=', '', '') |
\ endif \ endif
autocmd BufWriteCmd fugitive://* nested exe fugitive#BufWriteCmd() autocmd BufWriteCmd fugitive://*//[0-3]/* exe fugitive#BufWriteCmd()
autocmd FileReadCmd fugitive://* nested exe fugitive#FileReadCmd() autocmd FileReadCmd fugitive://*//* exe fugitive#FileReadCmd()
autocmd FileWriteCmd fugitive://* nested exe fugitive#FileWriteCmd() autocmd FileWriteCmd fugitive://*//[0-3]/* exe fugitive#FileWriteCmd()
if exists('##SourceCmd') if exists('##SourceCmd')
autocmd SourceCmd fugitive://* nested exe fugitive#SourceCmd() autocmd SourceCmd fugitive://*//* nested exe fugitive#SourceCmd()
endif endif
autocmd User Flags call Hoist('buffer', function('FugitiveStatusline')) autocmd User Flags call Hoist('buffer', function('FugitiveStatusline'))
@@ -720,19 +380,77 @@ augroup fugitive
autocmd User ProjectionistDetect call s:ProjectionistDetect() autocmd User ProjectionistDetect call s:ProjectionistDetect()
augroup END augroup END
nmap <script><silent> <Plug>fugitive:y<C-G> :<C-U>call setreg(v:register, fugitive#Object(@%))<CR> let s:addr_other = has('patch-8.1.560') ? '-addr=other' : ''
nmap <script> <Plug>fugitive: <Nop> let s:addr_tabs = has('patch-7.4.542') ? '-addr=tabs' : ''
let s:addr_wins = has('patch-7.4.542') ? '-addr=windows' : ''
exe 'command! -bang -nargs=? -range=-1' s:addr_other '-complete=customlist,fugitive#Complete G exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bang -nargs=? -range=-1' s:addr_other '-complete=customlist,fugitive#Complete Git exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bang -bar -range=-1' s:addr_other 'Gstatus exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)'
exe 'command! -bang -nargs=? -range=-1' s:addr_other '-complete=customlist,fugitive#CommitComplete Gcommit exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", "commit " . <q-args>)'
exe 'command! -bang -nargs=? -range=-1' s:addr_other '-complete=customlist,fugitive#RevertComplete Grevert exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", "revert " . <q-args>)'
exe 'command! -bang -nargs=? -range=-1' s:addr_other '-complete=customlist,fugitive#MergeComplete Gmerge exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", "merge " . <q-args>)'
exe 'command! -bang -nargs=? -range=-1' s:addr_other '-complete=customlist,fugitive#RebaseComplete Grebase exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", "rebase " . <q-args>)'
exe 'command! -bang -nargs=? -range=-1' s:addr_other '-complete=customlist,fugitive#PullComplete Gpull exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", "pull " . <q-args>)'
exe 'command! -bang -nargs=? -range=-1' s:addr_other '-complete=customlist,fugitive#PushComplete Gpush exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", "push " . <q-args>)'
exe 'command! -bang -nargs=? -range=-1' s:addr_other '-complete=customlist,fugitive#FetchComplete Gfetch exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", "fetch " . <q-args>)'
exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#BlameComplete Gblame exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", "blame " . <q-args>)'
exe "command! -bar -bang -nargs=? -complete=customlist,fugitive#CdComplete Gcd exe fugitive#Cd(<q-args>, 0)"
exe "command! -bar -bang -nargs=? -complete=customlist,fugitive#CdComplete Glcd exe fugitive#Cd(<q-args>, 1)"
exe 'command! -bang -nargs=? -range=-1' s:addr_wins '-complete=customlist,fugitive#GrepComplete Ggrep exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", "grep " . <q-args>)'
exe 'command! -bang -nargs=? -range=-1' s:addr_wins '-complete=customlist,fugitive#GrepComplete Gcgrep exe fugitive#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", "grep " . <q-args>)'
exe 'command! -bang -nargs=? -range=-1' s:addr_wins '-complete=customlist,fugitive#GrepComplete Glgrep exe fugitive#Command(0, <count> > 0 ? <count> : 0, +"<range>", <bang>0, "<mods>", "grep " . <q-args>)'
exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#LogComplete Glog :exe fugitive#LogCommand(<line1>,<count>,+"<range>",<bang>0,"<mods>",<q-args>, "")'
exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#LogComplete Gclog :exe fugitive#LogCommand(<line1>,<count>,+"<range>",<bang>0,"<mods>",<q-args>, "c")'
exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#LogComplete Gllog :exe fugitive#LogCommand(<line1>,<count>,+"<range>",<bang>0,"<mods>",<q-args>, "l")'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Ge exe fugitive#Open("edit<bang>", 0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gedit exe fugitive#Open("edit<bang>", 0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#ReadComplete Gpedit exe fugitive#Open("pedit", <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=* -range=-1' s:addr_other '-complete=customlist,fugitive#ReadComplete Gsplit exe fugitive#Open((<count> > 0 ? <count> : "").(<count> ? "split" : "edit"), <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=* -range=-1' s:addr_other '-complete=customlist,fugitive#ReadComplete Gvsplit exe fugitive#Open((<count> > 0 ? <count> : "").(<count> ? "vsplit" : "edit!"), <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=* -range=-1' s:addr_tabs '-complete=customlist,fugitive#ReadComplete Gtabedit exe fugitive#Open((<count> >= 0 ? <count> : "")."tabedit", <bang>0, "<mods>", <q-args>, [<f-args>])'
if exists(':Gr') != 2
exe 'command! -bar -bang -nargs=* -range=-1 -complete=customlist,fugitive#ReadComplete Gr exe fugitive#ReadCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>, [<f-args>])'
endif
exe 'command! -bar -bang -nargs=* -range=-1 -complete=customlist,fugitive#ReadComplete Gread exe fugitive#ReadCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gdiffsplit exe fugitive#Diffsplit(1, <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Ghdiffsplit exe fugitive#Diffsplit(0, <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gvdiffsplit exe fugitive#Diffsplit(0, <bang>0, "vert <mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gw exe fugitive#WriteCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gwrite exe fugitive#WriteCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gwq exe fugitive#WqCommand( <line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=0 -complete=customlist,fugitive#CompleteObject Gremove exe fugitive#RemoveCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=0 -complete=customlist,fugitive#CompleteObject Gdelete exe fugitive#DeleteCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=1 -complete=customlist,fugitive#CompleteObject Gmove exe fugitive#MoveCommand( <line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -nargs=1 -complete=customlist,fugitive#RenameComplete Grename exe fugitive#RenameCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>, [<f-args>])'
exe 'command! -bar -bang -range=-1 -nargs=* -complete=customlist,fugitive#CompleteObject Gbrowse exe fugitive#BrowseCommand(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>, [<f-args>])'
if get(g:, 'fugitive_no_maps') if get(g:, 'fugitive_no_maps')
finish finish
endif endif
function! s:Map(mode, lhs, rhs, flags) abort let s:nowait = v:version >= 704 ? '<nowait>' : ''
let flags = a:flags . (a:rhs =~# '<Plug>' ? '' : '<script>') . '<nowait>'
let head = a:lhs function! s:Map(mode, lhs, rhs, ...) abort
let tail = '' for mode in split(a:mode, '\zs')
let keys = get(g:, a:mode.'remap', {}) let flags = (a:0 ? a:1 : '') . (a:rhs =~# '<Plug>' ? '' : '<script>')
if len(keys) && type(keys) == type({}) let head = a:lhs
let tail = ''
let keys = get(g:, mode.'remap', {})
if type(keys) == type([])
return
endif
while !empty(head) while !empty(head)
if has_key(keys, head) if has_key(keys, head)
let head = keys[head] let head = keys[head]
@@ -744,10 +462,10 @@ function! s:Map(mode, lhs, rhs, flags) abort
let tail = matchstr(head, '<[^<>]*>$\|.$') . tail let tail = matchstr(head, '<[^<>]*>$\|.$') . tail
let head = substitute(head, '<[^<>]*>$\|.$', '', '') let head = substitute(head, '<[^<>]*>$\|.$', '', '')
endwhile endwhile
endif if flags !~# '<unique>' || empty(mapcheck(head.tail, mode))
if empty(mapcheck(head.tail, a:mode)) exe mode.'map' s:nowait flags head.tail a:rhs
exe a:mode.'map' flags head.tail a:rhs endif
endif endfor
endfunction endfunction
call s:Map('c', '<C-R><C-G>', 'fnameescape(fugitive#Object(@%))', '<expr>') call s:Map('c', '<C-R><C-G>', 'fnameescape(fugitive#Object(@%))', '<expr>')

View File

@@ -7,16 +7,12 @@ syn spell notoplevel
syn include @fugitiveDiff syntax/diff.vim syn include @fugitiveDiff syntax/diff.vim
syn match fugitiveHeader /^[A-Z][a-z][^:]*:/ syn match fugitiveHeader /^[A-Z][a-z][^:]*:/ nextgroup=fugitiveHash,fugitiveSymbolicRef skipwhite
syn match fugitiveHeader /^Head:/ nextgroup=fugitiveHash,fugitiveSymbolicRef skipwhite
syn match fugitiveHeader /^Pull:\|^Rebase:\|^Merge:\|^Push:/ nextgroup=fugitiveSymbolicRef skipwhite
syn match fugitiveHelpHeader /^Help:/ nextgroup=fugitiveHelpTag skipwhite
syn match fugitiveHelpTag /\S\+/ contained
syn region fugitiveSection start=/^\%(.*(\d\++\=)$\)\@=/ contains=fugitiveHeading end=/^$/ fold syn region fugitiveSection start=/^\%(.*(\d\+)$\)\@=/ contains=fugitiveHeading end=/^$/
syn cluster fugitiveSection contains=fugitiveSection syn cluster fugitiveSection contains=fugitiveSection
syn match fugitiveHeading /^[A-Z][a-z][^:]*\ze (\d\++\=)$/ contains=fugitivePreposition contained nextgroup=fugitiveCount skipwhite syn match fugitiveHeading /^[A-Z][a-z][^:]*\ze (\d\+)$/ contains=fugitivePreposition contained nextgroup=fugitiveCount skipwhite
syn match fugitiveCount /(\d\++\=)/hs=s+1,he=e-1 contained syn match fugitiveCount /(\d\+)/hs=s+1,he=e-1 contained
syn match fugitivePreposition /\<\%([io]nto\|from\|to\|Rebasing\%( detached\)\=\)\>/ transparent contained nextgroup=fugitiveHash,fugitiveSymbolicRef skipwhite syn match fugitivePreposition /\<\%([io]nto\|from\|to\|Rebasing\%( detached\)\=\)\>/ transparent contained nextgroup=fugitiveHash,fugitiveSymbolicRef skipwhite
syn match fugitiveInstruction /^\l\l\+\>/ contained containedin=@fugitiveSection nextgroup=fugitiveHash skipwhite syn match fugitiveInstruction /^\l\l\+\>/ contained containedin=@fugitiveSection nextgroup=fugitiveHash skipwhite
@@ -24,22 +20,20 @@ syn match fugitiveDone /^done\>/ contained containedin=@fugitiveSection nextgrou
syn match fugitiveStop /^stop\>/ contained containedin=@fugitiveSection nextgroup=fugitiveHash skipwhite syn match fugitiveStop /^stop\>/ contained containedin=@fugitiveSection nextgroup=fugitiveHash skipwhite
syn match fugitiveModifier /^[MADRCU?]\{1,2} / contained containedin=@fugitiveSection syn match fugitiveModifier /^[MADRCU?]\{1,2} / contained containedin=@fugitiveSection
syn match fugitiveSymbolicRef /\.\@!\%(\.\.\@!\|[^[:space:][:cntrl:]\:.]\)\+\.\@<!/ contained syn match fugitiveSymbolicRef /\.\@!\%(\.\.\@!\|[^[:space:][:cntrl:]\:.]\)\+\.\@<!/ contained
syn match fugitiveHash /^\x\{4,\}\S\@!/ contained containedin=@fugitiveSection syn match fugitiveHash /^\x\{4,\}\>/ contained containedin=@fugitiveSection
syn match fugitiveHash /\S\@<!\x\{4,\}\S\@!/ contained syn match fugitiveHash /\<\x\{4,\}\>/ contained
syn region fugitiveHunk start=/^\%(@@\+ -\)\@=/ end=/^\%([A-Za-z?@]\|$\)\@=/ contains=diffLine,diffRemoved,diffAdded,diffNoEOL containedin=@fugitiveSection fold syn region fugitiveHunk start=/^\%(@@\+ -\)\@=/ end=/^\%([A-Za-z?@]\|$\)\@=/ contains=@fugitiveDiff containedin=@fugitiveSection fold
for s:section in ['Untracked', 'Unstaged', 'Staged'] for s:section in ['Untracked', 'Unstaged', 'Staged']
exe 'syn region fugitive' . s:section . 'Section start=/^\%(' . s:section . ' .*(\d\++\=)$\)\@=/ contains=fugitive' . s:section . 'Heading end=/^$/ fold' exe 'syn region fugitive' . s:section . 'Section start=/^\%(' . s:section . ' .*(\d\+)$\)\@=/ contains=fugitive' . s:section . 'Heading end=/^$/'
exe 'syn match fugitive' . s:section . 'Modifier /^[MADRCU?] / contained containedin=fugitive' . s:section . 'Section' exe 'syn match fugitive' . s:section . 'Modifier /^[MADRCU?] / contained containedin=fugitive' . s:section . 'Section'
exe 'syn cluster fugitiveSection add=fugitive' . s:section . 'Section' exe 'syn cluster fugitiveSection add=fugitive' . s:section . 'Section'
exe 'syn match fugitive' . s:section . 'Heading /^[A-Z][a-z][^:]*\ze (\d\++\=)$/ contains=fugitivePreposition contained nextgroup=fugitiveCount skipwhite' exe 'syn match fugitive' . s:section . 'Heading /^[A-Z][a-z][^:]*\ze (\d\+)$/ contains=fugitivePreposition contained nextgroup=fugitiveCount skipwhite'
endfor endfor
unlet s:section unlet s:section
hi def link fugitiveHelpHeader fugitiveHeader
hi def link fugitiveHeader Label hi def link fugitiveHeader Label
hi def link fugitiveHelpTag Tag
hi def link fugitiveHeading PreProc hi def link fugitiveHeading PreProc
hi def link fugitiveUntrackedHeading PreCondit hi def link fugitiveUntrackedHeading PreCondit
hi def link fugitiveUnstagedHeading Macro hi def link fugitiveUnstagedHeading Macro

View File

@@ -1,4 +1,4 @@
if exists("b:current_syntax") || !exists("*FugitiveGitDir") if exists("b:current_syntax")
finish finish
endif endif