├── autoload
└── fugitive.vim
├── doc
└── fugitive.txt
├── ftdetect
└── fugitive.vim
├── ftplugin
└── fugitiveblame.vim
├── plugin
└── fugitive.vim
└── syntax
├── fugitive.vim
└── fugitiveblame.vim
/doc/fugitive.txt:
--------------------------------------------------------------------------------
1 | *fugitive.txt* A Git wrapper so awesome, it should be illegal
2 |
3 | Author: Tim Pope
4 | License: Same terms as Vim itself (see |license|)
5 |
6 | This plugin is only available if 'compatible' is not set.
7 |
8 | INTRODUCTION *fugitive*
9 |
10 | Whenever you edit a file from a Git repository, a set of commands is defined
11 | that serve as a gateway to Git.
12 |
13 | COMMANDS *fugitive-commands*
14 |
15 | These commands are local to the buffers in which they work (generally, buffers
16 | that are part of Git repositories).
17 |
18 | *fugitive-:G*
19 | :G [args] Same as :Git, but two characters shorter.
20 |
21 | *fugitive-summary*
22 | :Git With no arguments, bring up a summary window vaguely
23 | akin to git-status. If a summary window is already
24 | open for the current repository, it is focused
25 | instead. Press g? or see |fugitive-maps| for usage.
26 |
27 | *:Git*
28 | :Git {args} Run an arbitrary git command and display any output.
29 | On UNIX this uses a pty and on other platforms it uses
30 | a pipe, which will cause some behavior differences
31 | such as the absence of progress bars. Any file the
32 | command edits (for example, a commit message) will be
33 | loaded into a split window. Closing that window will
34 | resume running the command. A few Git subcommands
35 | have different behavior; these are documented below.
36 |
37 | *:Git!*
38 | :Git! {args} Run an arbitrary git command in the background and
39 | stream the output to the preview window. Requires a
40 | Vim with |setbufline()|. Press CTRL-D during an
41 | interactive :Git invocation to switch to this mode
42 | retroactively.
43 |
44 | *:Git_--paginate* *:Git_-p*
45 | :Git --paginate {args} Run an arbitrary git command, capture output to a temp
46 | :Git -p {args} file, and |:split| that temp file. Pass ++curwin as
47 | the first argument to |:edit| the temp file instead.
48 | A temp file is always used for commands like diff and
49 | log that typically uses a pager, and for any command
50 | that has the pager. Git configuration option set.
51 |
52 | :{range}Git! --paginate {args}
53 | :{range}Git! -p {args} Run an arbitrary git command, and insert the output
54 | after {range} in the current buffer.
55 |
56 | *:Git_blame*
57 | :Git blame [flags] Run git-blame [flags] on the current file and open the
58 | results in a scroll-bound vertical split. The
59 | following maps, which work on the cursor line commit
60 | where sensible, are provided:
61 |
62 | g? show this help
63 | A resize to end of author column
64 | C resize to end of commit column
65 | D resize to end of date/time column
66 | gq close blame, then |:Gedit| to return to work
67 | tree version
68 | close blame, and jump to patch that added line
69 | (or directly to blob for boundary commit)
70 | o jump to patch or blob in horizontal split
71 | O jump to patch or blob in new tab
72 | p jump to patch or blob in preview window
73 | - reblame at commit
74 |
75 | The maps |fugitive_P| and |fugitive_~| are also
76 | supported to reblame on a parent commit, but this is
77 | inherently fragile, as the line being blamed will no
78 | longer exist. The preferred alternative is to use
79 | to open up the commit, select the corresponding
80 | `-` line that you care about, and press twice
81 | more to reblame at that line. Viewing the commit also
82 | gives you additional context as to why the line
83 | changed.
84 |
85 | *g:fugitive_dynamic_colors*
86 | In the GUI or a 256 color terminal, commit hashes will
87 | be highlighted in different colors. To disable this:
88 | >
89 | let g:fugitive_dynamic_colors = 0
90 | <
91 | :[range]Git blame [...] If a range is given, just that part of the file will
92 | :Git blame [...] {file} be blamed, and a horizontal split without
93 | scrollbinding is used. You can also give an arbitrary
94 | filename.
95 |
96 | *:Git_difftool*
97 | :Git[!] difftool [args] Invoke `git diff [args]` and load the changes into the
98 | quickfix list. Each changed hunk gets a separate
99 | quickfix entry unless you pass an option like
100 | --name-only or --name-status. Jumps to the first
101 | change unless [!] is given.
102 |
103 | :Git difftool -y [args] Invoke `git diff [args]`, open each changed file in a
104 | new tab, and invoke |:Gdiffsplit!| against the
105 | appropriate commit.
106 |
107 | *:Git_mergetool*
108 | :Git mergetool [args] Like |:Git_difftool|, but target merge conflicts.
109 |
110 | Wrappers for Vim built-ins ~
111 |
112 | These all directly map onto a built-in Vim command, and generally have names
113 | that prepend "G" to the command they are wrapping. For example, :Ggrep is G
114 | plus |:grep|.
115 |
116 | *:Ggrep* *:Git_grep*
117 | :Ggrep[!] [args] An approximation of |:grep|[!] with git-grep as
118 | :Git[!] grep -O [args] 'grepprg'.
119 |
120 | :Ggrep[!] --quiet [args]
121 | :Ggrep[!] -q [args] Like |:Ggrep|, but instead of displaying output, open
122 | the quickfix list.
123 |
124 | *:Glgrep*
125 | :Glgrep[!] [args] :Ggrep but for |:lgrep|.
126 | :0Git[!] grep -O [args]
127 |
128 | *:Gclog*
129 | :Gclog[!] [args] Use git-log [args] to load the commit history into the
130 | |quickfix| list. Jumps to the first commit unless [!]
131 | is given. This command wraps |:cfile|.
132 |
133 | The quickfix list can be awkward for many use cases
134 | and exhibits extremely poor performance with larger
135 | data sets. Consider using |:Git| log --oneline
136 | instead.
137 |
138 | :{range}Gclog[!] [args] Use git-log -L to load previous revisions of the given
139 | range of the current file into the |quickfix| list.
140 | The cursor is positioned on the first line of the
141 | first diff hunk for each commit. Use :0Gclog to
142 | target the entire file.
143 |
144 | *:Gllog*
145 | :Gllog [args] Like |:Gclog|, but use the location list instead of the
146 | |quickfix| list.
147 |
148 | *:Gcd*
149 | :Gcd [directory] |:cd| relative to the repository.
150 |
151 | *:Glcd*
152 | :Glcd [directory] |:lcd| relative to the repository.
153 |
154 | *:Gedit* *fugitive-:Ge*
155 | :Gedit [object] |:edit| a |fugitive-object|.
156 |
157 | *:Gsplit*
158 | :Gsplit [object] |:split| a |fugitive-object|.
159 |
160 | *:Gvsplit*
161 | :Gvsplit [object] |:vsplit| a |fugitive-object|.
162 |
163 | *:Gtabedit*
164 | :Gtabedit [object] |:tabedit| a |fugitive-object|.
165 |
166 | *:Gpedit*
167 | :Gpedit [object] |:pedit| a |fugitive-object|.
168 |
169 | *:Gdrop*
170 | :Gdrop [object] |:drop| a |fugitive-object|.
171 |
172 | *:Gread* *fugitive-:Gr*
173 | :Gread [object] Empty the buffer and |:read| a |fugitive-object|.
174 | When the argument is omitted, this is similar to
175 | git-checkout on a work tree file or git-add on a stage
176 | file, but without writing anything to disk.
177 |
178 | :{range}Gread [object] |:read| in a |fugitive-object| after {range}.
179 |
180 | *:Gwrite* *fugitive-:Gw*
181 | :Gwrite Write to the current file's path and stage the results.
182 | When run in a work tree file, it is effectively git
183 | add. Elsewhere, it is effectively git-checkout. A
184 | great deal of effort is expended to behave sensibly
185 | when the work tree or index version of the file is
186 | open in another buffer.
187 |
188 | :Gwrite {path} You can give |:Gwrite| an explicit path of where in
189 | the work tree to write. You can also give a path like
190 | :0:foo.txt or :0:% to write to just that stage in
191 | the index.
192 |
193 | *:Gwq*
194 | :Gwq [path] Like |:Gwrite| followed by |:quit| if the write
195 | succeeded.
196 |
197 | :Gwq! [path] Like |:Gwrite|! followed by |:quit|! if the write
198 | succeeded.
199 |
200 | *:Gdiffsplit*
201 | :Gdiffsplit [object] Perform a |vimdiff| against the given file, or if a
202 | commit is given, the current file in that commit.
203 | With no argument, the version in the index or work
204 | tree is used, and the work tree version is always
205 | placed to the right or bottom, depending on available
206 | width. Use Vim's |do| and |dp| to stage and unstage
207 | changes.
208 |
209 | *:Gdiffsplit!*
210 | :Gdiffsplit! Diff against any and all direct ancestors, retaining
211 | focus on the current window. During a merge conflict,
212 | this is a three-way diff against the "ours" and
213 | "theirs" ancestors. Additional d2o and d3o maps are
214 | provided to obtain the hunk from the "ours" or
215 | "theirs" ancestor, respectively.
216 |
217 | :Gdiffsplit! {object} Like |:Gdiffsplit|, but retain focus on the current
218 | window.
219 |
220 | *:Gvdiffsplit*
221 | :Gvdiffsplit [object] Like |:Gdiffsplit|, but always split vertically.
222 |
223 | *:Ghdiffsplit*
224 | :Gdiffsplit ++novertical [object]
225 | :Ghdiffsplit [object] Like |:Gdiffsplit|, but with "vertical" removed from
226 | 'diffopt'. The split will still be vertical if
227 | combined with |:vertical|.
228 |
229 | Other commands ~
230 |
231 | These do not directly correspond to any built-in Vim command, and have a
232 | capital letter after the "G" to convey this. For example, the file move
233 | operation has nothing to do with the |:move| built-in, so it is named :GMove,
234 | not :Gmove.
235 |
236 | *:GMove*
237 | :GMove {destination} Wrapper around git-mv that renames the buffer
238 | afterward. Add a ! to pass -f.
239 |
240 | *:GRename*
241 | :GRename {destination} Like |:GMove| but operates relative to the parent
242 | directory of the current file.
243 |
244 | *:GDelete*
245 | :GDelete Wrapper around git-rm that deletes the buffer
246 | afterward. When invoked in an index file, --cached is
247 | passed. Add a ! to pass -f and forcefully discard the
248 | buffer.
249 |
250 | *:GRemove* *:GUnlink*
251 | :GRemove Like |:GDelete|, but keep the (now empty) buffer around.
252 | :GUnlink
253 |
254 | *:GBrowse*
255 | :GBrowse Open the current file, blob, tree, commit, or tag
256 | in your browser at the upstream hosting provider.
257 | Upstream providers can be added by installing an
258 | appropriate Vim plugin. For example, GitHub can be
259 | supported by installing rhubarb.vim, available at
260 | .
261 |
262 | :GBrowse {object} Like :GBrowse, but for a given |fugitive-object|.
263 |
264 | :{range}GBrowse [args] Appends an anchor to the URL that emphasizes the
265 | selected lines. This also forces the URL to include a
266 | commit rather than a branch name so it remains valid
267 | if the file changes. You can give a range of "0" to
268 | force this behavior without including an anchor.
269 |
270 | :GBrowse [...]@{remote} Force using the given remote rather than the remote
271 | for the current branch. The remote is used to
272 | determine which upstream repository to link to.
273 |
274 | :GBrowse {url} Open an arbitrary URL in your browser.
275 |
276 | :[range]GBrowse! [args] Like :GBrowse, but put the URL on the clipboard rather
277 | than opening it.
278 |
279 | MAPS *fugitive-maps*
280 |
281 | These maps are available in both the |fugitive-summary| buffer and Fugitive
282 | object buffers, although not all maps make sense in all buffers. Mappings
283 | that operate on the file or hunk under the cursor are generally available in
284 | visual mode to operate on multiple files or partial hunks.
285 |
286 | *fugitive-staging-maps*
287 | Staging/unstaging maps ~
288 |
289 | *fugitive_s*
290 | s Stage (add) the file or hunk under the cursor.
291 |
292 | *fugitive_u*
293 | u Unstage (reset) the file or hunk under the cursor.
294 |
295 | *fugitive_-*
296 | - Stage or unstage the file or hunk under the cursor.
297 |
298 | *fugitive_U*
299 | U Unstage everything.
300 |
301 | *fugitive_X*
302 | X Discard the change under the cursor. This uses
303 | `checkout` or `clean` under the hood. A command is
304 | echoed that shows how to undo the change. Consult
305 | `:messages` to see it again. During a merge conflict,
306 | use 2X to call `checkout --ours` or 3X to call
307 | `checkout --theirs` .
308 |
309 | *fugitive_=*
310 | = Toggle an inline diff of the file under the cursor.
311 |
312 | *fugitive_>*
313 | > Insert an inline diff of the file under the cursor.
314 |
315 | *fugitive_<*
316 | < Remove the inline diff of the file under the cursor.
317 |
318 | *fugitive_gI*
319 | gI Open .git/info/exclude in a split and add the file
320 | under the cursor. Use a count to open .gitignore.
321 |
322 | *fugitive_I*
323 | I Invoke |:Git| add --patch or reset --patch on the file
324 | P under the cursor. On untracked files, this instead
325 | calls |:Git| add --intent-to-add.
326 |
327 | *fugitive_d*
328 | Diff maps ~
329 | *fugitive_dp*
330 | dp Invoke |:Git| diff on the file under the cursor.
331 | Deprecated in favor of inline diffs.
332 |
333 | *fugitive_dd*
334 | dd Perform a |:Gdiffsplit| on the file under the cursor.
335 |
336 | *fugitive_dv*
337 | dv Perform a |:Gvdiffsplit| on the file under the cursor.
338 |
339 | *fugitive_ds* *fugitive_dh*
340 | ds Perform a |:Ghdiffsplit| on the file under the cursor.
341 | dh
342 |
343 | *fugitive_dq*
344 | dq Close all but the currently focused diff buffer, and
345 | invoke |:diffoff|!.
346 |
347 | *fugitive_d?*
348 | d? Show this help.
349 |
350 | *fugitive-navigation-maps*
351 | Navigation maps ~
352 |
353 | *fugitive_*
354 | Open the file or |fugitive-object| under the cursor.
355 | In a blob, this and similar maps jump to the patch
356 | from the diff where this was added, or where it was
357 | removed if a count was given. If the line is still in
358 | the work tree version, passing a count takes you to
359 | it.
360 |
361 | *fugitive_o*
362 | o Open the file or |fugitive-object| under the cursor in
363 | a new split.
364 |
365 | *fugitive_gO*
366 | gO Open the file or |fugitive-object| under the cursor in
367 | a new vertical split.
368 |
369 | *fugitive_O*
370 | O Open the file or |fugitive-object| under the cursor in
371 | a new tab.
372 |
373 | *fugitive_p*
374 | p Open the file or |fugitive-object| under the cursor in
375 | a preview window. In the status buffer, 1p is
376 | required to bypass the legacy usage instructions.
377 |
378 | *fugitive_~*
379 | ~ Open the current file in the [count]th first ancestor.
380 |
381 | *fugitive_P*
382 | P Open the current file in the [count]th parent.
383 | Experimental: In the "Unpushed" section of the status
384 | buffer, this will populate the command line with a
385 | ":Git push" command for the commit under the cursor.
386 |
387 | *fugitive_C*
388 | C Open the commit containing the current file.
389 |
390 | *fugitive_CTRL-P* *fugitive_(*
391 | ( Jump to the previous file, hunk, or revision.
392 |
393 | *fugitive_CTRL-N* *fugitive_)*
394 | ) Jump to the next file, hunk, or revision.
395 |
396 | *fugitive_[c*
397 | [c Jump to previous hunk, expanding inline diffs
398 | automatically. (This shadows the Vim built-in |[c|
399 | that provides a similar operation in |diff| mode.)
400 |
401 | *fugitive_]c*
402 | ]c Jump to next hunk, expanding inline diffs
403 | automatically. (This shadows the Vim built-in |]c|
404 | that provides a similar operation in |diff| mode.)
405 |
406 | *fugitive_[/* *fugitive_[m*
407 | [/ Jump to previous file, collapsing inline diffs
408 | [m automatically. (Mnemonic: "/" appears in filenames,
409 | "m" appears in "filenames".)
410 |
411 | *fugitive_]/* *fugitive_]m*
412 | ]/ Jump to next file, collapsing inline diffs
413 | ]m automatically. (Mnemonic: "/" appears in filenames,
414 | "m" appears in "filenames".)
415 |
416 | *fugitive_i*
417 | i Jump to the next file or hunk, expanding inline diffs
418 | automatically.
419 |
420 | *fugitive_[[*
421 | [[ Jump [count] sections backward.
422 |
423 | *fugitive_]]*
424 | ]] Jump [count] sections forward.
425 |
426 | *fugitive_[]*
427 | [] Jump [count] section ends backward.
428 |
429 | *fugitive_][*
430 | ][ Jump [count] section ends forward.
431 |
432 | *fugitive_star*
433 | * On the first column of a + or - diff line, search for
434 | the corresponding - or + line. Otherwise, defer to
435 | built-in |star|.
436 |
437 | *fugitive_#*
438 | # Same as "*", but search backward.
439 |
440 | *fugitive_gu*
441 | gu Jump to file [count] in the "Untracked" or "Unstaged"
442 | section.
443 |
444 | *fugitive_gU*
445 | gU Jump to file [count] in the "Unstaged" section.
446 |
447 | *fugitive_gs*
448 | gs Jump to file [count] in the "Staged" section.
449 |
450 | *fugitive_gp*
451 | gp Jump to file [count] in the "Unpushed" section.
452 |
453 | *fugitive_gP*
454 | gP Jump to file [count] in the "Unpulled" section.
455 |
456 | *fugitive_gr*
457 | gr Jump to file [count] in the "Rebasing" section.
458 |
459 | *fugitive_gi*
460 | gi Open .git/info/exclude in a split. Use a count to
461 | open .gitignore.
462 |
463 | *fugitive_c*
464 | Commit maps ~
465 |
466 | cc Create a commit.
467 |
468 | cvc Create a commit with -v.
469 |
470 | ca Amend the last commit and edit the message.
471 |
472 | cva Amend the last commit with -v.
473 |
474 | ce Amend the last commit without editing the message.
475 |
476 | cw Reword the last commit.
477 |
478 | cW Create an `amend!` commit that rewords the commit
479 | under the cursor.
480 |
481 | cf Create a `fixup!` commit for the commit under the
482 | cursor.
483 |
484 | cF Create a `fixup!` commit for the commit under the
485 | cursor and immediately rebase it.
486 |
487 | cs Create a `squash!` commit for the commit under the
488 | cursor.
489 |
490 | cS Create a `squash!` commit for the commit under the
491 | cursor and immediately rebase it.
492 |
493 | cn Create a `squash!` commit for the commit under the
494 | (formerly cA) cursor and edit the message.
495 |
496 | c Populate command line with ":Git commit ".
497 |
498 | *fugitive_cr*
499 | crc Revert the commit under the cursor.
500 |
501 | crn Revert the commit under the cursor in the index and
502 | work tree, but do not actually commit the changes.
503 |
504 | cr Populate command line with ":Git revert ".
505 |
506 | *fugitive_cm*
507 | cm Populate command line with ":Git merge ".
508 |
509 | c? Show this help.
510 |
511 | *fugitive_cb*
512 | *fugitive_co*
513 | Checkout/branch maps ~
514 |
515 | coo Check out the commit under the cursor.
516 |
517 | cb Populate command line with ":Git branch ".
518 |
519 | co Populate command line with ":Git checkout ".
520 |
521 | cb? Show this help.
522 | co?
523 |
524 | *fugitive_cz*
525 | Stash maps ~
526 |
527 | czz Push stash. Pass a [count] of 1 to add
528 | `--include-untracked` or 2 to add `--all`.
529 |
530 | czw Push stash of the work-tree. Like `czz` with
531 | `--keep-index`.
532 |
533 | czs Push stash of the stage. Does not accept a count.
534 |
535 | czA Apply topmost stash, or stash@{count}.
536 |
537 | cza Apply topmost stash, or stash@{count}, preserving the
538 | index.
539 |
540 | czP Pop topmost stash, or stash@{count}.
541 |
542 | czp Pop topmost stash, or stash@{count}, preserving the
543 | index.
544 |
545 | cz Populate command line with ":Git stash ".
546 |
547 | cz? Show this help.
548 |
549 | *fugitive_r*
550 | Rebase maps ~
551 |
552 | ri Perform an interactive rebase. Uses ancestor of
553 | u commit under cursor as upstream if available.
554 |
555 | rf Perform an autosquash rebase without editing the todo
556 | list. Uses ancestor of commit under cursor as
557 | upstream if available.
558 |
559 | ru Perform an interactive rebase against @{upstream}.
560 |
561 | rp Perform an interactive rebase against @{push}.
562 |
563 | rr Continue the current rebase.
564 |
565 | rs Skip the current commit and continue the current
566 | rebase.
567 |
568 | ra Abort the current rebase.
569 |
570 | re Edit the current rebase todo list.
571 |
572 | rw Perform an interactive rebase with the commit under
573 | the cursor set to `reword`.
574 |
575 | rm Perform an interactive rebase with the commit under
576 | the cursor set to `edit`.
577 |
578 | rd Perform an interactive rebase with the commit under
579 | the cursor set to `drop`.
580 |
581 | r Populate command line with ":Git rebase ".
582 |
583 | r? Show this help.
584 |
585 | *fugitive-misc-maps*
586 | Miscellaneous maps ~
587 |
588 | *fugitive_gq* *fugitive_q*
589 | gq Close the status buffer.
590 |
591 | *fugitive_.*
592 | . Start a |:| command line with the file under the
593 | cursor prepopulated.
594 |
595 | *fugitive_g?*
596 | g? Show help for |fugitive-maps|.
597 |
598 | *fugitive-global-maps*
599 | Global maps ~
600 |
601 | *fugitive_c_CTRL-R_CTRL-G*
602 | On the command line, recall the path to the current
603 | |fugitive-object| (that is, a representation of the
604 | object recognized by |:Gedit|).
605 |
606 | *fugitive_y_CTRL-G*
607 | ["x]y Yank the path to the current |fugitive-object|.
608 |
609 | *g:fugitive_no_maps*
610 | Global maps can be disabled with the g:fugitive_no_maps option.
611 | >
612 | let g:fugitive_no_maps = 1
613 | <
614 | SPECIFYING OBJECTS *fugitive-object* *fugitive-revision*
615 |
616 | Fugitive objects are either work tree files or Git revisions as defined in the
617 | "SPECIFYING REVISIONS" section in the git-rev-parse man page, with expansions
618 | inspired by |cmdline-special| layered on top. For commands that accept an
619 | optional object, the default is the file in the index for work tree files and
620 | the work tree file for everything else. Example objects follow.
621 |
622 | Object Meaning ~
623 | @ The commit referenced by @ aka HEAD
624 | master The commit referenced by master
625 | master^ The parent of the commit referenced by master
626 | master...other The merge base of master and other
627 | master: The tree referenced by master
628 | ./master The file named master in the working directory
629 | :(top)master The file named master in the work tree
630 | Makefile The file named Makefile in the work tree
631 | @^:Makefile The file named Makefile in the parent of HEAD
632 | :Makefile The file named Makefile in the index (writable)
633 | @~2:% The current file in the grandparent of HEAD
634 | :% The current file in the index
635 | :1:% The current file's common ancestor during a conflict
636 | :2:# The alternate file in the target branch during a conflict
637 | :3:#5 The file from buffer #5 in the merged branch during a conflict
638 | ! The commit owning the current file
639 | !:Makefile The file named Makefile in the commit owning the current file
640 | !3^2 The second parent of the commit owning buffer #3
641 | .git/config The repo config file
642 | : The |fugitive-summary| buffer
643 | - A temp file containing the last |:Git| invocation's output
644 | The file or commit under the cursor
645 |
646 | STATUSLINE *fugitive-statusline*
647 |
648 | *FugitiveStatusline()* *fugitive#statusline()*
649 | Add %{FugitiveStatusline()} to your statusline to get an indicator including
650 | the current branch and the currently edited file's commit. If you don't have
651 | a statusline, this one matches the default when 'ruler' is set:
652 | >
653 | set statusline=%<%f\ %h%m%r%{FugitiveStatusline()}%=%-14.(%l,%c%V%)\ %P
654 | <
655 | AUTOCOMMANDS *fugitive-autocommands*
656 |
657 | A handful of |User| |autocommands| are provided to allow extending and
658 | overriding Fugitive behaviors. Example usage:
659 | >
660 | autocmd User FugitiveBlob,FugitiveStageBlob call s:BlobOverrides()
661 | <
662 | *User_FugitiveTag*
663 | FugitiveTag After loading a tag object.
664 |
665 | *User_FugitiveCommit*
666 | FugitiveCommit After loading a commit object.
667 |
668 | *User_FugitiveTree*
669 | FugitiveTree After loading a tree (directory) object.
670 |
671 | *User_FugitiveBlob*
672 | FugitiveBlob After loading a committed blob (file) object.
673 |
674 | *User_FugitiveObject*
675 | FugitiveObject After loading any of the 4 above buffer types.
676 |
677 | *User_FugitiveStageBlob*
678 | FugitiveStageBlob After loading a staged blob (file) object. These
679 | buffers are 'modifiable' and oftentimes don't want the
680 | same behavior as the other buffer types.
681 |
682 | *User_FugitiveIndex*
683 | FugitiveIndex After loading the |fugitive-summary| buffer.
684 |
685 | *User_FugitivePager*
686 | FugitivePager After loading a temp file created by a command like
687 | :Git --paginate or :Git blame.
688 |
689 | *User_FugitiveEditor*
690 | FugitiveEditor After a :Git command (e.g., :Git commit) edits a file
691 | (e.g., the commit message).
692 |
693 | *User_FugitiveChanged*
694 | FugitiveChanged After any event which can potentially change the
695 | repository, for example, any invocation of |:Git|.
696 | Originally intended for expiring caches, but can have
697 | other uses.
698 |
699 | API *fugitive-api*
700 |
701 | Officially supported functions are documented inline in plugin/fugitive.vim.
702 |
703 | DEPRECATIONS *fugitive-deprecated*
704 |
705 | The following commands are deprecated in favor of replacements that adhere to
706 | a new naming scheme. Remember that |:Git| can be shortened to |:G|, so
707 | replacements using it are just one space character longer than the legacy
708 | version.
709 |
710 | *:Gremove* Superseded by |:GRemove|.
711 | *:Gdelete* Superseded by |:GDelete|.
712 | *:Gmove* Superseded by |:GMove|.
713 | *:Grename* Superseded by |:GRename|.
714 | *:Gbrowse* Superseded by |:GBrowse|.
715 | *:Gdiff* Superseded by |:Gdiffsplit|
716 | *:Gsdiff* Superseded by |:Ghdiffsplit|
717 | *:Gvdiff* Superseded by |:Gvdiffsplit| or |:vert| |:Gdiffsplit|.
718 | *:Gblame* Superseded by |:Git_blame|.
719 | *:Gcommit* Superseded by |:Git| commit.
720 | *:Gmerge* Superseded by |:Git| merge and |:Git_mergetool|.
721 | *:Gpull* Superseded by |:Git| pull.
722 | *:Grebase* Superseded by |:Git| rebase.
723 | *:Grevert* Superseded by |:Git| revert.
724 | *:Gpush* Superseded by |:Git| push.
725 | *:Gfetch* Superseded by |:Git| fetch.
726 | *:Glog* Superseded by |:Gclog|.
727 | *:Gstatus* Superseded by |:Git| (with no arguments).
728 | *:Gsplit!* Superseded by |:Git_--paginate|.
729 | *:Gvsplit!* Superseded by :vert Git --paginate.
730 | *:Gtabsplit!* Superseded by :tab Git --paginate.
731 | *:Gpedit!* Superseded by :Git! --paginate.
732 |
733 | *User_Fugitive*
734 | Fugitive used to support `:autocmd User Fugitive` to run an autocommand after
735 | loading any buffer belonging to a Git repository, but this has been phased
736 | out. Instead, one can leverage regular autocommand events like |BufNewFile|
737 | and |BufReadPost|, and check !empty(FugitiveGitDir()) to confirm Fugitive has
738 | found a repository. See also |fugitive-autocommands| for other, more
739 | selective events.
740 |
741 | ABOUT *fugitive-about*
742 |
743 | Grab the latest version or report a bug on GitHub:
744 |
745 | https://github.com/tpope/vim-fugitive
746 |
747 | vim:tw=78:et:ft=help:norl:
748 |
--------------------------------------------------------------------------------
/ftdetect/fugitive.vim:
--------------------------------------------------------------------------------
1 | autocmd BufReadPost *.fugitiveblame setfiletype fugitiveblame
2 |
--------------------------------------------------------------------------------
/ftplugin/fugitiveblame.vim:
--------------------------------------------------------------------------------
1 | if exists("b:did_ftplugin") || !exists("*FugitiveGitDir")
2 | finish
3 | endif
4 | let b:did_ftplugin = 1
5 |
6 | call fugitive#BlameFileType()
7 |
--------------------------------------------------------------------------------
/plugin/fugitive.vim:
--------------------------------------------------------------------------------
1 | " fugitive.vim - A Git wrapper so awesome, it should be illegal
2 | " Maintainer: Tim Pope
3 | " Version: 3.7
4 | " GetLatestVimScripts: 2975 1 :AutoInstall: fugitive.vim
5 |
6 | if exists('g:loaded_fugitive')
7 | finish
8 | endif
9 | let g:loaded_fugitive = 1
10 |
11 | let s:bad_git_dir = '/$\|^fugitive:'
12 |
13 | " FugitiveGitDir() returns the detected Git dir for the given buffer number,
14 | " or the current buffer if no argument is passed. This will be an empty
15 | " string if no Git dir was found. Use !empty(FugitiveGitDir()) to check if
16 | " Fugitive is active in the current buffer. Do not rely on this for direct
17 | " filesystem access; use FugitiveFind('.git/whatever') instead.
18 | function! FugitiveGitDir(...) abort
19 | if v:version < 704
20 | return ''
21 | elseif !a:0 || type(a:1) == type(0) && a:1 < 0 || a:1 is# get(v:, 'true', -1)
22 | if exists('g:fugitive_event')
23 | return g:fugitive_event
24 | endif
25 | let dir = get(b:, 'git_dir', '')
26 | if empty(dir) && (empty(bufname('')) && &filetype !=# 'netrw' || &buftype =~# '^\%(nofile\|acwrite\|quickfix\|terminal\|prompt\)$')
27 | return FugitiveExtractGitDir(getcwd())
28 | elseif (!exists('b:git_dir') || b:git_dir =~# s:bad_git_dir) && &buftype =~# '^\%(nowrite\)\=$'
29 | let b:git_dir = FugitiveExtractGitDir(bufnr(''))
30 | return b:git_dir
31 | endif
32 | return dir =~# s:bad_git_dir ? '' : dir
33 | elseif type(a:1) == type(0) && a:1 isnot# 0
34 | if a:1 == bufnr('') && (!exists('b:git_dir') || b:git_dir =~# s:bad_git_dir) && &buftype =~# '^\%(nowrite\)\=$'
35 | let b:git_dir = FugitiveExtractGitDir(a:1)
36 | endif
37 | let dir = getbufvar(a:1, 'git_dir')
38 | return dir =~# s:bad_git_dir ? '' : dir
39 | elseif type(a:1) == type('')
40 | return substitute(s:Slash(a:1), '/$', '', '')
41 | elseif type(a:1) == type({})
42 | return get(a:1, 'fugitive_dir', get(a:1, 'git_dir', ''))
43 | else
44 | return ''
45 | endif
46 | endfunction
47 |
48 | " FugitiveReal() takes a fugitive:// URL and returns the corresponding path in
49 | " the work tree. This may be useful to get a cleaner path for inclusion in
50 | " the statusline, for example. Note that the file and its parent directories
51 | " are not guaranteed to exist.
52 | "
53 | " This is intended as an abstract API to be used on any "virtual" path. For a
54 | " buffer named foo://bar, check for a function named FooReal(), and if it
55 | " exists, call FooReal("foo://bar").
56 | function! FugitiveReal(...) abort
57 | let file = a:0 ? a:1 : @%
58 | if type(file) ==# type({})
59 | let dir = FugitiveGitDir(file)
60 | let tree = s:Tree(dir)
61 | return s:VimSlash(empty(tree) ? dir : tree)
62 | elseif file =~# '^\a\a\+:' || a:0 > 1
63 | return call('fugitive#Real', [file] + a:000[1:-1])
64 | elseif file =~# '^/\|^\a:\|^$'
65 | return file
66 | else
67 | return fnamemodify(file, ':p' . (file =~# '[\/]$' ? '' : ':s?[\/]$??'))
68 | endif
69 | endfunction
70 |
71 | " FugitiveFind() takes a Fugitive object and returns the appropriate Vim
72 | " buffer name. You can use this to generate Fugitive URLs ("HEAD:README") or
73 | " to get the absolute path to a file in the Git dir (".git/HEAD"), the common
74 | " dir (".git/config"), or the work tree (":(top)Makefile").
75 | "
76 | " An optional second argument provides the Git dir, or the buffer number of a
77 | " buffer with a Git dir. The default is the current buffer.
78 | function! FugitiveFind(...) abort
79 | if a:0 && (type(a:1) ==# type({}) || type(a:1) ==# type(0))
80 | return call('fugitive#Find', a:000[1:-1] + [FugitiveGitDir(a:1)])
81 | else
82 | return fugitive#Find(a:0 ? a:1 : bufnr(''), FugitiveGitDir(a:0 > 1 ? a:2 : -1))
83 | endif
84 | endfunction
85 |
86 | " FugitiveParse() takes a fugitive:// URL and returns a 2 element list
87 | " containing an object name ("commit:file") and the Git dir. It's effectively
88 | " the inverse of FugitiveFind().
89 | function! FugitiveParse(...) abort
90 | let path = s:Slash(a:0 ? a:1 : @%)
91 | if path !~# '^fugitive://'
92 | return ['', '']
93 | endif
94 | let [rev, dir] = fugitive#Parse(path)
95 | if !empty(dir)
96 | return [rev, dir]
97 | endif
98 | throw 'fugitive: invalid Fugitive URL ' . path
99 | endfunction
100 |
101 | " FugitiveGitVersion() queries the version of Git in use. Pass up to 3
102 | " arguments to return a Boolean of whether a certain minimum version is
103 | " available (FugitiveGitVersion(2,3,4) checks for 2.3.4 or higher) or no
104 | " arguments to get a raw string.
105 | function! FugitiveGitVersion(...) abort
106 | return call('fugitive#GitVersion', a:000)
107 | endfunction
108 |
109 | " FugitiveResult() returns an object encapsulating the result of the most
110 | " recent :Git command. Will be empty if no result is available. During a
111 | " User FugitiveChanged event, this is guaranteed to correspond to the :Git
112 | " command that triggered the event, or be empty if :Git was not the trigger.
113 | " Pass in the name of a temp buffer to get the result object for that command
114 | " instead. Contains the following keys:
115 | "
116 | " * "args": List of command arguments, starting with the subcommand. Will be
117 | " empty for usages like :Git --help.
118 | " * "git_dir": Git dir of the relevant repository.
119 | " * "exit_status": The integer exit code of the process.
120 | " * "flags": Flags passed directly to Git, like -c and --help.
121 | " * "file": Path to file containing command output. Not guaranteed to exist,
122 | " so verify with filereadable() before trying to access it.
123 | function! FugitiveResult(...) abort
124 | return call('fugitive#Result', a:000)
125 | endfunction
126 |
127 | " FugitiveExecute() runs Git with a list of arguments and returns a dictionary
128 | " with the following keys:
129 | "
130 | " * "exit_status": The integer exit code of the process.
131 | " * "stdout": The stdout produced by the process, as a list of lines.
132 | " * "stderr": The stdout produced by the process, as a list of lines.
133 | "
134 | " An optional second argument provides the Git dir, or the buffer number of a
135 | " buffer with a Git dir. The default is the current buffer.
136 | "
137 | " An optional final argument is a callback Funcref, for asynchronous
138 | " execution.
139 | function! FugitiveExecute(args, ...) abort
140 | return call('fugitive#Execute', [a:args] + a:000)
141 | endfunction
142 |
143 | " FugitiveShellCommand() turns an array of arguments into a Git command string
144 | " which can be executed with functions like system() and commands like :!.
145 | " Integer arguments will be treated as buffer numbers, and the appropriate
146 | " relative path inserted in their place.
147 | "
148 | " An optional second argument provides the Git dir, or the buffer number of a
149 | " buffer with a Git dir. The default is the current buffer.
150 | function! FugitiveShellCommand(...) abort
151 | return call('fugitive#ShellCommand', a:000)
152 | endfunction
153 |
154 | " FugitiveConfig() get returns an opaque structure that can be passed to other
155 | " FugitiveConfig functions in lieu of a Git directory. This can be faster
156 | " when performing multiple config queries. Do not rely on the internal
157 | " structure of the return value as it is not guaranteed. If you want a full
158 | " dictionary of every config value, use FugitiveConfigGetRegexp('.*').
159 | "
160 | " An optional argument provides the Git dir, or the buffer number of a
161 | " buffer with a Git dir. The default is the current buffer. Pass a blank
162 | " string to limit to the global config.
163 | function! FugitiveConfig(...) abort
164 | return call('fugitive#Config', a:000)
165 | endfunction
166 |
167 | " FugitiveConfigGet() retrieves a Git configuration value. An optional second
168 | " argument can be either the object returned by FugitiveConfig(), or a Git
169 | " dir or buffer number to be passed along to FugitiveConfig().
170 | function! FugitiveConfigGet(name, ...) abort
171 | return get(call('FugitiveConfigGetAll', [a:name] + (a:0 ? [a:1] : [])), -1, get(a:, 2, ''))
172 | endfunction
173 |
174 | " FugitiveConfigGetAll() is like FugitiveConfigGet() but returns a list of
175 | " all values.
176 | function! FugitiveConfigGetAll(name, ...) abort
177 | return call('fugitive#ConfigGetAll', [a:name] + a:000)
178 | endfunction
179 |
180 | " FugitiveConfigGetRegexp() retrieves a dictionary of all configuration values
181 | " with a key matching the given pattern. Like git config --get-regexp, but
182 | " using a Vim regexp. Second argument has same semantics as
183 | " FugitiveConfigGet().
184 | function! FugitiveConfigGetRegexp(pattern, ...) abort
185 | return call('fugitive#ConfigGetRegexp', [a:pattern] + a:000)
186 | endfunction
187 |
188 | " FugitiveRemoteUrl() retrieves the remote URL for the given remote name,
189 | " defaulting to the current branch's remote or "origin" if no argument is
190 | " given. Similar to `git remote get-url`, but also attempts to resolve HTTP
191 | " redirects and SSH host aliases.
192 | "
193 | " An optional second argument provides the Git dir, or the buffer number of a
194 | " buffer with a Git dir. The default is the current buffer.
195 | function! FugitiveRemoteUrl(...) abort
196 | return call('fugitive#RemoteUrl', a:000)
197 | endfunction
198 |
199 | " FugitiveRemote() returns a data structure parsed from the remote URL.
200 | " For example, for remote URL "https://me@example.com:1234/repo.git", the
201 | " returned dictionary will contain the following:
202 | "
203 | " * "scheme": "https"
204 | " * "authority": "user@example.com:1234"
205 | " * "path": "/repo.git" (for SSH URLs this may be a relative path)
206 | " * "pathname": "/repo.git" (always coerced to absolute path)
207 | " * "host": "example.com:1234"
208 | " * "hostname": "example.com"
209 | " * "port": "1234"
210 | " * "user": "me"
211 | " * "path": "/repo.git"
212 | " * "url": "https://me@example.com:1234/repo.git"
213 | function! FugitiveRemote(...) abort
214 | return call('fugitive#Remote', a:000)
215 | endfunction
216 |
217 | " FugitiveDidChange() triggers a FugitiveChanged event and reloads the summary
218 | " buffer for the current or given buffer number's repository. You can also
219 | " give the result of a FugitiveExecute() and that context will be made
220 | " available inside the FugitiveChanged() event.
221 | "
222 | " Passing the special argument 0 (the number zero) softly expires summary
223 | " buffers for all repositories. This can be used after a call to system()
224 | " with unclear implications.
225 | function! FugitiveDidChange(...) abort
226 | return call('fugitive#DidChange', a:000)
227 | endfunction
228 |
229 | " FugitiveHead() retrieves the name of the current branch. If the current HEAD
230 | " is detached, FugitiveHead() will return the empty string, unless the
231 | " optional argument is given, in which case the hash of the current commit
232 | " will be truncated to the given number of characters.
233 | "
234 | " An optional second argument provides the Git dir, or the buffer number of a
235 | " buffer with a Git dir. The default is the current buffer.
236 | function! FugitiveHead(...) abort
237 | if a:0 && (type(a:1) ==# type({}) || type(a:1) ==# type('') && a:1 !~# '^\d\+$')
238 | let dir = FugitiveGitDir(a:1)
239 | let arg = get(a:, 2, 0)
240 | elseif a:0 > 1
241 | let dir = FugitiveGitDir(a:2)
242 | let arg = a:1
243 | else
244 | let dir = FugitiveGitDir()
245 | let arg = get(a:, 1, 0)
246 | endif
247 | if empty(dir)
248 | return ''
249 | endif
250 | return fugitive#Head(arg, dir)
251 | endfunction
252 |
253 | function! FugitivePath(...) abort
254 | if a:0 > 2 && type(a:1) ==# type({})
255 | return fugitive#Path(a:2, a:3, FugitiveGitDir(a:1))
256 | elseif a:0 && type(a:1) ==# type({})
257 | return FugitiveReal(a:0 > 1 ? a:2 : @%)
258 | elseif a:0 > 1
259 | return fugitive#Path(a:1, a:2, FugitiveGitDir(a:0 > 2 ? a:3 : -1))
260 | else
261 | return FugitiveReal(a:0 ? a:1 : @%)
262 | endif
263 | endfunction
264 |
265 | function! FugitiveStatusline(...) abort
266 | if empty(FugitiveGitDir(bufnr('')))
267 | return ''
268 | endif
269 | return fugitive#Statusline()
270 | endfunction
271 |
272 | let s:resolved_git_dirs = {}
273 | function! FugitiveActualDir(...) abort
274 | let dir = call('FugitiveGitDir', a:000)
275 | if empty(dir)
276 | return ''
277 | endif
278 | if !has_key(s:resolved_git_dirs, dir)
279 | let s:resolved_git_dirs[dir] = s:ResolveGitDir(dir)
280 | endif
281 | return empty(s:resolved_git_dirs[dir]) ? dir : s:resolved_git_dirs[dir]
282 | endfunction
283 |
284 | let s:commondirs = {}
285 | function! FugitiveCommonDir(...) abort
286 | let dir = call('FugitiveActualDir', a:000)
287 | if empty(dir)
288 | return ''
289 | endif
290 | if has_key(s:commondirs, dir)
291 | return s:commondirs[dir]
292 | endif
293 | if getfsize(dir . '/HEAD') >= 10
294 | let cdir = get(s:ReadFile(dir . '/commondir', 1), 0, '')
295 | if cdir =~# '^/\|^\a:/'
296 | let s:commondirs[dir] = s:Slash(FugitiveVimPath(cdir))
297 | elseif len(cdir)
298 | let s:commondirs[dir] = simplify(dir . '/' . cdir)
299 | else
300 | let s:commondirs[dir] = dir
301 | endif
302 | else
303 | let s:commondirs[dir] = dir
304 | endif
305 | return s:commondirs[dir]
306 | endfunction
307 |
308 | function! FugitiveWorkTree(...) abort
309 | let tree = s:Tree(FugitiveGitDir(a:0 ? a:1 : -1))
310 | if tree isnot# 0 || a:0 > 1
311 | return tree
312 | else
313 | return ''
314 | endif
315 | endfunction
316 |
317 | function! FugitiveIsGitDir(...) abort
318 | if !a:0 || type(a:1) !=# type('')
319 | return !empty(call('FugitiveGitDir', a:000))
320 | endif
321 | let path = substitute(a:1, '[\/]$', '', '') . '/'
322 | return len(path) && getfsize(path.'HEAD') > 10 && (
323 | \ isdirectory(path.'objects') && isdirectory(path.'refs') ||
324 | \ getftype(path.'commondir') ==# 'file')
325 | endfunction
326 |
327 | function! s:ReadFile(path, line_count) abort
328 | if v:version < 800 && !filereadable(a:path)
329 | return []
330 | endif
331 | try
332 | return readfile(a:path, 'b', a:line_count)
333 | catch
334 | return []
335 | endtry
336 | endfunction
337 |
338 | let s:worktree_for_dir = {}
339 | let s:dir_for_worktree = {}
340 | function! s:Tree(path) abort
341 | if a:path =~# '/\.git$'
342 | return len(a:path) ==# 5 ? '/' : a:path[0:-6]
343 | elseif a:path ==# ''
344 | return ''
345 | endif
346 | let dir = FugitiveActualDir(a:path)
347 | if !has_key(s:worktree_for_dir, dir)
348 | let s:worktree_for_dir[dir] = ''
349 | let ext_wtc_pat = 'v:val =~# "^\\s*worktreeConfig *= *\\%(true\\|yes\\|on\\|1\\) *$"'
350 | let config = s:ReadFile(dir . '/config', 50)
351 | if len(config)
352 | let ext_wtc_config = filter(copy(config), ext_wtc_pat)
353 | if len(ext_wtc_config) == 1 && filereadable(dir . '/config.worktree')
354 | let config += s:ReadFile(dir . '/config.worktree', 50)
355 | endif
356 | else
357 | let worktree = fnamemodify(FugitiveVimPath(get(s:ReadFile(dir . '/gitdir', 1), '0', '')), ':h')
358 | if worktree ==# '.'
359 | unlet! worktree
360 | endif
361 | if len(filter(s:ReadFile(FugitiveCommonDir(dir) . '/config', 50), ext_wtc_pat))
362 | let config = s:ReadFile(dir . '/config.worktree', 50)
363 | endif
364 | endif
365 | if len(config)
366 | let wt_config = filter(copy(config), 'v:val =~# "^\\s*worktree *="')
367 | if len(wt_config)
368 | let worktree = FugitiveVimPath(matchstr(wt_config[0], '= *\zs.*'))
369 | elseif !exists('worktree')
370 | call filter(config,'v:val =~# "^\\s*bare *= *true *$"')
371 | if empty(config)
372 | let s:worktree_for_dir[dir] = 0
373 | endif
374 | endif
375 | endif
376 | if exists('worktree')
377 | let s:worktree_for_dir[dir] = s:Slash(resolve(worktree))
378 | let s:dir_for_worktree[s:worktree_for_dir[dir]] = dir
379 | endif
380 | endif
381 | if s:worktree_for_dir[dir] =~# '^\.'
382 | return simplify(dir . '/' . s:worktree_for_dir[dir])
383 | else
384 | return s:worktree_for_dir[dir]
385 | endif
386 | endfunction
387 |
388 | function! s:CeilingDirectories() abort
389 | if !exists('s:ceiling_directories')
390 | let s:ceiling_directories = []
391 | let resolve = 1
392 | for dir in split($GIT_CEILING_DIRECTORIES, has('win32') ? ';' : ':', 1)
393 | if empty(dir)
394 | let resolve = 0
395 | elseif resolve
396 | call add(s:ceiling_directories, s:Slash(resolve(dir)))
397 | else
398 | call add(s:ceiling_directories, s:Slash(dir))
399 | endif
400 | endfor
401 | endif
402 | return s:ceiling_directories + get(g:, 'ceiling_directories', [s:Slash(fnamemodify(expand('~'), ':h'))])
403 | endfunction
404 |
405 | function! s:ResolveGitDir(git_dir) abort
406 | let type = getftype(a:git_dir)
407 | if type ==# 'dir' && FugitiveIsGitDir(a:git_dir)
408 | return a:git_dir
409 | elseif type ==# 'link' && FugitiveIsGitDir(a:git_dir)
410 | return resolve(a:git_dir)
411 | elseif type !=# ''
412 | let line = get(s:ReadFile(a:git_dir, 1), 0, '')
413 | let file_dir = s:Slash(FugitiveVimPath(matchstr(line, '^gitdir: \zs.*')))
414 | if file_dir !~# '^/\|^\a:\|^$' && a:git_dir =~# '/\.git$' && FugitiveIsGitDir(a:git_dir[0:-5] . file_dir)
415 | return simplify(a:git_dir[0:-5] . file_dir)
416 | elseif file_dir =~# '^/\|^\a:' && FugitiveIsGitDir(file_dir)
417 | return file_dir
418 | endif
419 | endif
420 | return ''
421 | endfunction
422 |
423 | function! FugitiveExtractGitDir(path) abort
424 | if type(a:path) ==# type({})
425 | return get(a:path, 'fugitive_dir', get(a:path, 'git_dir', ''))
426 | elseif type(a:path) == type(0)
427 | let path = s:Slash(a:path > 0 ? bufname(a:path) : bufname(''))
428 | if getbufvar(a:path, '&filetype') ==# 'netrw'
429 | let path = s:Slash(getbufvar(a:path, 'netrw_curdir', path))
430 | endif
431 | else
432 | let path = s:Slash(a:path)
433 | endif
434 | if path =~# '^fugitive://'
435 | return fugitive#Parse(path)[1]
436 | elseif empty(path)
437 | return ''
438 | endif
439 | let pre = substitute(matchstr(path, '^\a\a\+\ze:'), '^.', '\u&', '')
440 | if len(pre) && exists('*' . pre . 'Real')
441 | let path = {pre}Real(path)
442 | endif
443 | let root = s:Slash(fnamemodify(path, ':p:h'))
444 | let previous = ""
445 | let env_git_dir = len($GIT_DIR) ? s:Slash(simplify(fnamemodify(FugitiveVimPath($GIT_DIR), ':p:s?[\/]$??'))) : ''
446 | call s:Tree(env_git_dir)
447 | let ceiling_directories = s:CeilingDirectories()
448 | while root !=# previous && root !~# '^$\|^//[^/]*$'
449 | if index(ceiling_directories, root) >= 0
450 | break
451 | endif
452 | if root ==# $GIT_WORK_TREE && FugitiveIsGitDir(env_git_dir)
453 | return env_git_dir
454 | elseif has_key(s:dir_for_worktree, root)
455 | return s:dir_for_worktree[root]
456 | endif
457 | let dir = substitute(root, '[\/]$', '', '') . '/.git'
458 | let resolved = s:ResolveGitDir(dir)
459 | if !empty(resolved)
460 | let s:resolved_git_dirs[dir] = resolved
461 | return dir is# resolved || s:Tree(resolved) is# 0 ? dir : resolved
462 | elseif FugitiveIsGitDir(root)
463 | let s:resolved_git_dirs[root] = root
464 | return root
465 | endif
466 | let previous = root
467 | let root = fnamemodify(root, ':h')
468 | endwhile
469 | return ''
470 | endfunction
471 |
472 | function! FugitiveDetect(...) abort
473 | if v:version < 704
474 | return ''
475 | endif
476 | if exists('b:git_dir') && b:git_dir =~# '^$\|' . s:bad_git_dir
477 | unlet b:git_dir
478 | endif
479 | if !exists('b:git_dir')
480 | let b:git_dir = FugitiveExtractGitDir(a:0 ? a:1 : bufnr(''))
481 | endif
482 | return ''
483 | endfunction
484 |
485 | function! FugitiveGitPath(path) abort
486 | return s:Slash(a:path)
487 | endfunction
488 |
489 | if exists('+shellslash')
490 |
491 | function! s:Slash(path) abort
492 | return tr(a:path, '\', '/')
493 | endfunction
494 |
495 | function! s:VimSlash(path) abort
496 | return tr(a:path, '\/', &shellslash ? '//' : '\\')
497 | endfunction
498 |
499 | function FugitiveVimPath(path) abort
500 | return tr(a:path, '\/', &shellslash ? '//' : '\\')
501 | endfunction
502 |
503 | else
504 |
505 | function! s:Slash(path) abort
506 | return a:path
507 | endfunction
508 |
509 | function! s:VimSlash(path) abort
510 | return a:path
511 | endfunction
512 |
513 | if has('win32unix') && filereadable('/git-bash.exe')
514 | function! FugitiveVimPath(path) abort
515 | return substitute(a:path, '^\(\a\):', '/\l\1', '')
516 | endfunction
517 | else
518 | function! FugitiveVimPath(path) abort
519 | return a:path
520 | endfunction
521 | endif
522 |
523 | endif
524 |
525 | function! s:ProjectionistDetect() abort
526 | let file = s:Slash(get(g:, 'projectionist_file', ''))
527 | let dir = FugitiveExtractGitDir(file)
528 | let base = matchstr(file, '^fugitive://.\{-\}//\x\+')
529 | if empty(base)
530 | let base = s:Tree(dir)
531 | endif
532 | if !empty(base)
533 | if exists('+shellslash') && !&shellslash
534 | let base = tr(base, '/', '\')
535 | endif
536 | let file = FugitiveFind('.git/info/projections.json', dir)
537 | if filereadable(file)
538 | call projectionist#append(base, file)
539 | endif
540 | endif
541 | endfunction
542 |
543 | let s:addr_other = has('patch-8.1.560') || has('nvim-0.5.0') ? '-addr=other' : ''
544 | let s:addr_tabs = has('patch-7.4.542') ? '-addr=tabs' : ''
545 | let s:addr_wins = has('patch-7.4.542') ? '-addr=windows' : ''
546 |
547 | if exists(':G') != 2
548 | command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#Complete G exe fugitive#Command(, , +"", 0, "", )
549 | endif
550 | command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#Complete Git exe fugitive#Command(, , +"", 0, "", )
551 |
552 | if exists(':Gstatus') != 2 && get(g:, 'fugitive_legacy_commands', 0)
553 | exe 'command! -bang -bar -range=-1' s:addr_other 'Gstatus exe fugitive#Command(, , +"", 0, "", )'
554 | \ '|echohl WarningMSG|echomsg ":Gstatus is deprecated in favor of :Git (with no arguments)"|echohl NONE'
555 | endif
556 |
557 | for s:cmd in ['Commit', 'Revert', 'Merge', 'Rebase', 'Pull', 'Push', 'Fetch', 'Blame']
558 | if exists(':G' . tolower(s:cmd)) != 2 && get(g:, 'fugitive_legacy_commands', 0)
559 | exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#' . s:cmd . 'Complete G' . tolower(s:cmd)
560 | \ 'echohl WarningMSG|echomsg ":G' . tolower(s:cmd) . ' is deprecated in favor of :Git ' . tolower(s:cmd) . '"|echohl NONE|'
561 | \ 'exe fugitive#Command(, , +"", 0, "", "' . tolower(s:cmd) . ' " . )'
562 | endif
563 | endfor
564 | unlet s:cmd
565 |
566 | exe "command! -bar -bang -nargs=? -complete=customlist,fugitive#CdComplete Gcd exe fugitive#Cd(, 0)"
567 | exe "command! -bar -bang -nargs=? -complete=customlist,fugitive#CdComplete Glcd exe fugitive#Cd(, 1)"
568 |
569 | exe 'command! -bang -nargs=? -range=-1' s:addr_wins '-complete=customlist,fugitive#GrepComplete Ggrep exe fugitive#GrepCommand(, , +"", 0, "", )'
570 | exe 'command! -bang -nargs=? -range=-1' s:addr_wins '-complete=customlist,fugitive#GrepComplete Glgrep exe fugitive#GrepCommand(0, > 0 ? : 0, +"", 0, "", )'
571 |
572 | exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#LogComplete Gclog :exe fugitive#LogCommand(,,+"",0,"",, "c")'
573 | exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#LogComplete GcLog :exe fugitive#LogCommand(,,+"",0,"",, "c")'
574 | exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#LogComplete Gllog :exe fugitive#LogCommand(,,+"",0,"",, "l")'
575 | exe 'command! -bang -nargs=? -range=-1 -complete=customlist,fugitive#LogComplete GlLog :exe fugitive#LogCommand(,,+"",0,"",, "l")'
576 |
577 | exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Ge exe fugitive#Open("edit", 0, "", )'
578 | exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gedit exe fugitive#Open("edit", 0, "", )'
579 | exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gpedit exe fugitive#Open("pedit", 0, "", )'
580 | exe 'command! -bar -bang -nargs=* -range=-1' s:addr_other '-complete=customlist,fugitive#EditComplete Gsplit exe fugitive#Open(( > 0 ? : "").( ? "split" : "edit"), 0, "", )'
581 | exe 'command! -bar -bang -nargs=* -range=-1' s:addr_other '-complete=customlist,fugitive#EditComplete Gvsplit exe fugitive#Open(( > 0 ? : "").( ? "vsplit" : "edit!"), 0, "", )'
582 | exe 'command! -bar -bang -nargs=* -range=-1' s:addr_tabs '-complete=customlist,fugitive#EditComplete Gtabedit exe fugitive#Open(( >= 0 ? : "")."tabedit", 0, "", )'
583 | exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gdrop exe fugitive#DropCommand(, , +"", 0, "", )'
584 |
585 | if exists(':Gr') != 2
586 | exe 'command! -bar -bang -nargs=* -range=-1 -complete=customlist,fugitive#ReadComplete Gr exe fugitive#ReadCommand(, , +"", 0, "", )'
587 | endif
588 | exe 'command! -bar -bang -nargs=* -range=-1 -complete=customlist,fugitive#ReadComplete Gread exe fugitive#ReadCommand(, , +"", 0, "", )'
589 |
590 | exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gdiffsplit exe fugitive#Diffsplit(1, 0, "", )'
591 | exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Ghdiffsplit exe fugitive#Diffsplit(0, 0, "", )'
592 | exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gvdiffsplit exe fugitive#Diffsplit(0, 0, "vertical ", )'
593 |
594 | exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gw exe fugitive#WriteCommand(, , +"", 0, "", )'
595 | exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gwrite exe fugitive#WriteCommand(, , +"", 0, "", )'
596 | exe 'command! -bar -bang -nargs=* -complete=customlist,fugitive#EditComplete Gwq exe fugitive#WqCommand( , , +"", 0, "", )'
597 |
598 | exe 'command! -bar -bang -nargs=0 GRemove exe fugitive#RemoveCommand(, , +"", 0, "", )'
599 | exe 'command! -bar -bang -nargs=0 GUnlink exe fugitive#UnlinkCommand(, , +"", 0, "", )'
600 | exe 'command! -bar -bang -nargs=0 GDelete exe fugitive#DeleteCommand(, , +"", 0, "", )'
601 | exe 'command! -bar -bang -nargs=1 -complete=customlist,fugitive#CompleteObject GMove exe fugitive#MoveCommand( , , +"", 0, "", )'
602 | exe 'command! -bar -bang -nargs=1 -complete=customlist,fugitive#RenameComplete GRename exe fugitive#RenameCommand(, , +"", 0, "", )'
603 | if exists(':Gremove') != 2 && get(g:, 'fugitive_legacy_commands', 0)
604 | exe 'command! -bar -bang -nargs=0 Gremove exe fugitive#RemoveCommand(, , +"", 0, "", )'
605 | \ '|echohl WarningMSG|echomsg ":Gremove is deprecated in favor of :GRemove"|echohl NONE'
606 | elseif exists(':Gremove') != 2 && !exists('g:fugitive_legacy_commands')
607 | exe 'command! -bar -bang -nargs=0 Gremove echoerr ":Gremove has been removed in favor of :GRemove"'
608 | endif
609 | if exists(':Gdelete') != 2 && get(g:, 'fugitive_legacy_commands', 0)
610 | exe 'command! -bar -bang -nargs=0 Gdelete exe fugitive#DeleteCommand(, , +"", 0, "", )'
611 | \ '|echohl WarningMSG|echomsg ":Gdelete is deprecated in favor of :GDelete"|echohl NONE'
612 | elseif exists(':Gdelete') != 2 && !exists('g:fugitive_legacy_commands')
613 | exe 'command! -bar -bang -nargs=0 Gdelete echoerr ":Gdelete has been removed in favor of :GDelete"'
614 | endif
615 | if exists(':Gmove') != 2 && get(g:, 'fugitive_legacy_commands', 0)
616 | exe 'command! -bar -bang -nargs=1 -complete=customlist,fugitive#CompleteObject Gmove exe fugitive#MoveCommand( , , +"", 0, "", )'
617 | \ '|echohl WarningMSG|echomsg ":Gmove is deprecated in favor of :GMove"|echohl NONE'
618 | elseif exists(':Gmove') != 2 && !exists('g:fugitive_legacy_commands')
619 | exe 'command! -bar -bang -nargs=? -complete=customlist,fugitive#CompleteObject Gmove'
620 | \ 'echoerr ":Gmove has been removed in favor of :GMove"'
621 | endif
622 | if exists(':Grename') != 2 && get(g:, 'fugitive_legacy_commands', 0)
623 | exe 'command! -bar -bang -nargs=1 -complete=customlist,fugitive#RenameComplete Grename exe fugitive#RenameCommand(, , +"", 0, "", )'
624 | \ '|echohl WarningMSG|echomsg ":Grename is deprecated in favor of :GRename"|echohl NONE'
625 | elseif exists(':Grename') != 2 && !exists('g:fugitive_legacy_commands')
626 | exe 'command! -bar -bang -nargs=? -complete=customlist,fugitive#RenameComplete Grename'
627 | \ 'echoerr ":Grename has been removed in favor of :GRename"'
628 | endif
629 |
630 | exe 'command! -bar -bang -range=-1 -nargs=* -complete=customlist,fugitive#CompleteObject GBrowse exe fugitive#BrowseCommand(, , +"", 0, "", )'
631 | if exists(':Gbrowse') != 2 && get(g:, 'fugitive_legacy_commands', 0)
632 | exe 'command! -bar -bang -range=-1 -nargs=* -complete=customlist,fugitive#CompleteObject Gbrowse exe fugitive#BrowseCommand(, , +"", 0, "", )'
633 | \ '|if 1|redraw!|endif|echohl WarningMSG|echomsg ":Gbrowse is deprecated in favor of :GBrowse"|echohl NONE'
634 | elseif exists(':Gbrowse') != 2 && !exists('g:fugitive_legacy_commands')
635 | exe 'command! -bar -bang -range=-1 -nargs=* -complete=customlist,fugitive#CompleteObject Gbrowse'
636 | \ 'echoerr ":Gbrowse has been removed in favor of :GBrowse"'
637 | endif
638 |
639 | if v:version < 704
640 | finish
641 | endif
642 |
643 | let g:io_fugitive = {
644 | \ 'simplify': function('fugitive#simplify'),
645 | \ 'resolve': function('fugitive#resolve'),
646 | \ 'getftime': function('fugitive#getftime'),
647 | \ 'getfsize': function('fugitive#getfsize'),
648 | \ 'getftype': function('fugitive#getftype'),
649 | \ 'filereadable': function('fugitive#filereadable'),
650 | \ 'filewritable': function('fugitive#filewritable'),
651 | \ 'isdirectory': function('fugitive#isdirectory'),
652 | \ 'getfperm': function('fugitive#getfperm'),
653 | \ 'setfperm': function('fugitive#setfperm'),
654 | \ 'readfile': function('fugitive#readfile'),
655 | \ 'writefile': function('fugitive#writefile'),
656 | \ 'glob': function('fugitive#glob'),
657 | \ 'delete': function('fugitive#delete'),
658 | \ 'Real': function('FugitiveReal')}
659 |
660 | augroup fugitive
661 | autocmd!
662 |
663 | autocmd BufNewFile,BufReadPost *
664 | \ if exists('b:git_dir') && b:git_dir =~# '^$\|' . s:bad_git_dir |
665 | \ unlet b:git_dir |
666 | \ endif
667 | autocmd FileType netrw
668 | \ if exists('b:git_dir') && b:git_dir =~# '^$\|' . s:bad_git_dir |
669 | \ unlet b:git_dir |
670 | \ endif
671 | autocmd BufFilePost * unlet! b:git_dir
672 |
673 | autocmd FileType git
674 | \ call fugitive#MapCfile()
675 | autocmd FileType gitcommit
676 | \ call fugitive#MapCfile('fugitive#MessageCfile()')
677 | autocmd FileType git,gitcommit
678 | \ if &foldtext ==# 'foldtext()' |
679 | \ setlocal foldtext=fugitive#Foldtext() |
680 | \ endif
681 | autocmd FileType fugitive
682 | \ call fugitive#MapCfile('fugitive#PorcelainCfile()')
683 | autocmd FileType gitrebase
684 | \ let &l:include = '^\%(pick\|squash\|edit\|reword\|fixup\|drop\|[pserfd]\)\>' |
685 | \ if &l:includeexpr !~# 'Fugitive' |
686 | \ let &l:includeexpr = 'v:fname =~# ''^\x\{4,\}$'' && len(FugitiveGitDir()) ? FugitiveFind(v:fname) : ' .
687 | \ (len(&l:includeexpr) ? &l:includeexpr : 'v:fname') |
688 | \ endif |
689 | \ let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'exe') . '|setl inex= inc='
690 |
691 | autocmd BufReadCmd index{,.lock} nested
692 | \ if FugitiveIsGitDir(expand(':p:h')) |
693 | \ let b:git_dir = s:Slash(expand(':p:h')) |
694 | \ exe fugitive#BufReadStatus(v:cmdbang) |
695 | \ echohl WarningMSG |
696 | \ echo "fugitive: Direct editing of .git/" . expand('%:t') . " is deprecated" |
697 | \ echohl NONE |
698 | \ elseif filereadable(expand('')) |
699 | \ silent doautocmd BufReadPre |
700 | \ keepalt noautocmd read |
701 | \ silent 1delete_ |
702 | \ silent doautocmd BufReadPost |
703 | \ else |
704 | \ silent doautocmd BufNewFile |
705 | \ endif
706 |
707 | autocmd BufReadCmd fugitive://* nested exe fugitive#BufReadCmd() |
708 | \ if &path =~# '^\.\%(,\|$\)' |
709 | \ let &l:path = substitute(&path, '^\.,\=', '', '') |
710 | \ endif
711 | autocmd BufWriteCmd fugitive://* nested exe fugitive#BufWriteCmd()
712 | autocmd FileReadCmd fugitive://* nested exe fugitive#FileReadCmd()
713 | autocmd FileWriteCmd fugitive://* nested exe fugitive#FileWriteCmd()
714 | if exists('##SourceCmd')
715 | autocmd SourceCmd fugitive://* nested exe fugitive#SourceCmd()
716 | endif
717 |
718 | autocmd User Flags call Hoist('buffer', function('FugitiveStatusline'))
719 |
720 | autocmd User ProjectionistDetect call s:ProjectionistDetect()
721 | augroup END
722 |
723 | nmap