Saltar al contenido principal

Git Integration: Fugitive y Herramientas

Git es fundamental en el desarrollo moderno, y Vim puede integrarse perfectamente con Git para crear un workflow eficiente sin salir del editor. En este capítulo aprenderás a dominar Git desde Vim.

🌟 Vim-Fugitive: Git en Vim

Fugitive es el plugin de Git más poderoso para Vim, creado por Tim Pope. Transforma Vim en un cliente Git completo.

Instalación y configuración básica

" Instalación con vim-plug
Plug 'tpope/vim-fugitive'

" Configuración básica
set diffopt+=vertical " Diffs verticales por defecto

" Mapeos básicos para Fugitive
nnoremap <Leader>gs :Git status<CR>
nnoremap <Leader>gc :Git commit<CR>
nnoremap <Leader>gp :Git push<CR>
nnoremap <Leader>gl :Git log --oneline<CR>
nnoremap <Leader>gd :Gdiff<CR>
nnoremap <Leader>gb :Git blame<CR>

📊 Git Status y Navegación

Comando :Git status

:Git status    " O simplemente :G
<Enter>     " Abrir archivo/diff
- " Stage/unstage archivo
cc " Commit
ca " Commit --amend
ce " Commit --amend --no-edit
cw " Commit --amend --only
U " Checkout (discard changes)
s " Stage archivo
u " Unstage archivo
X " Discard changes in archivo
= " Toggle inline diff
> " Show more context
< " Show less context

Ejemplo de workflow básico

" 1. Ver status
:G

" 2. Stage archivos (en la ventana de status)
" Usar 's' en cada archivo o '-' para toggle

" 3. Commit
" Presionar 'cc' en la ventana de status

" 4. Push
:Git push

🔍 Comandos Esenciales de Fugitive

Información del repositorio

:Git status           " Status del repositorio
:Git log " Log de commits
:Git log --oneline " Log compacto
:Git log -p " Log con diffs
:Git log --graph " Log con gráfico ASCII
:Git show <commit> " Mostrar commit específico
:Git blame " Blame del archivo actual

Gestión de cambios

:Gdiff               " Diff del archivo actual
:Gdiff HEAD~1 " Diff con commit anterior
:Gdiff main " Diff con rama main
:Git add % " Stage archivo actual
:Git add . " Stage todos los archivos
:Git reset % " Unstage archivo actual
:Git checkout % " Discard cambios del archivo actual

Commits y ramas

:Git commit          " Commit interactivo
:Git commit -m "msg" " Commit con mensaje
:Git commit --amend " Amend último commit
:Git branch " Listar ramas
:Git checkout <rama> " Cambiar de rama
:Git checkout -b <nueva_rama> " Crear y cambiar rama
:Git merge <rama> " Merge rama

🔄 Workflows Avanzados

Resolución de conflictos

" Durante un merge con conflictos
:Git status " Ver archivos en conflicto

" Abrir archivo con conflicto
:Gdiffsplit! " Three-way diff

" En el three-way diff:
" - Ventana izquierda: versión target (HEAD)
" - Ventana central: archivo de trabajo
" - Ventana derecha: versión merge

" Obtener cambios de una versión
:diffget //2 " Obtener de target (izquierda)
:diffget //3 " Obtener de merge (derecha)

" O usar atajos
do " diffget (obtener cambio)
dp " diffput (enviar cambio)

" Finalizar resolución
:Git add % " Stage archivo resuelto
:Git commit " Commit merge

Gestión de hunks (chunks de código)

" En modo diff o con gitgutter
]c " Siguiente hunk
[c " Hunk anterior

" Con vim-gitgutter (plugin adicional)
<Leader>hp " Preview hunk
<Leader>hs " Stage hunk
<Leader>hu " Undo hunk

Stash management

:Git stash           " Crear stash
:Git stash pop " Aplicar último stash
:Git stash list " Listar stashes
:Git stash show " Mostrar último stash
:Git stash drop " Eliminar último stash
:Git stash apply stash@{0} " Aplicar stash específico

🔧 Plugins Complementarios

1. vim-gitgutter (Indicadores visuales)

Plug 'airblade/vim-gitgutter'

" Configuración
let g:gitgutter_enabled = 1
let g:gitgutter_map_keys = 0 " Deshabilitar mapeos por defecto
let g:gitgutter_highlight_lines = 0 " No resaltar líneas completas
let g:gitgutter_sign_added = '+'
let g:gitgutter_sign_modified = '~'
let g:gitgutter_sign_removed = '-'

" Mapeos personalizados
nnoremap <Leader>hp :GitGutterPreviewHunk<CR>
nnoremap <Leader>hs :GitGutterStageHunk<CR>
nnoremap <Leader>hu :GitGutterUndoHunk<CR>
nnoremap <Leader>hn :GitGutterNextHunk<CR>
nnoremap <Leader>hN :GitGutterPrevHunk<CR>

2. vim-git (Sintaxis mejorada)

Plug 'tpope/vim-git'
" Mejora sintaxis para archivos Git (commit messages, etc.)

3. gv.vim (Git log visual)

Plug 'junegunn/gv.vim'

" Comandos
:GV " Git log gráfico para todo el repo
:GV! " Git log solo para archivo actual
:GV? " Git log para buscar commits

" Navegación en GV
o " Abrir commit
O " Abrir commit en nueva tab
gb " Git blame
]] " Siguiente commit
[[ " Commit anterior

📝 Configuración Completa de Git

.vimrc optimizado para Git

" ============================================================================
" GIT CONFIGURATION
" ============================================================================

" Plugins
Plug 'tpope/vim-fugitive'
Plug 'airblade/vim-gitgutter'
Plug 'junegunn/gv.vim'

" Configuración básica
set diffopt+=vertical,filler,closeoff
autocmd BufReadPost fugitive://* set bufhidden=delete

" === MAPEOS FUGITIVE ===
nnoremap <Leader>g :Git<CR>
nnoremap <Leader>gs :Git status<CR>
nnoremap <Leader>gc :Git commit<CR>
nnoremap <Leader>gca :Git commit --amend<CR>
nnoremap <Leader>gp :Git push<CR>
nnoremap <Leader>gP :Git pull<CR>
nnoremap <Leader>gf :Git fetch<CR>
nnoremap <Leader>gl :Git log --oneline<CR>
nnoremap <Leader>gL :GV<CR>
nnoremap <Leader>gd :Gdiff<CR>
nnoremap <Leader>gb :Git blame<CR>

" Ramas
nnoremap <Leader>gco :Git checkout<Space>
nnoremap <Leader>gcb :Git checkout -b<Space>
nnoremap <Leader>gm :Git merge<Space>

" Stash
nnoremap <Leader>gst :Git stash<CR>
nnoremap <Leader>gsp :Git stash pop<CR>
nnoremap <Leader>gsl :Git stash list<CR>

" === MAPEOS GITGUTTER ===
let g:gitgutter_map_keys = 0
nnoremap <Leader>hp :GitGutterPreviewHunk<CR>
nnoremap <Leader>hs :GitGutterStageHunk<CR>
nnoremap <Leader>hu :GitGutterUndoHunk<CR>
nnoremap ]h :GitGutterNextHunk<CR>
nnoremap [h :GitGutterPrevHunk<CR>

" === CONFIGURACIÓN GITGUTTER ===
let g:gitgutter_enabled = 1
let g:gitgutter_highlight_lines = 0
let g:gitgutter_sign_added = '▎'
let g:gitgutter_sign_modified = '▎'
let g:gitgutter_sign_removed = '▎'
let g:gitgutter_sign_removed_first_line = '▎'
let g:gitgutter_sign_modified_removed = '▎'

" Actualización más rápida
set updatetime=250

" === AUTOCOMANDOS ===
augroup GitConfiguration
autocmd!

" Configuración para commit messages
autocmd FileType gitcommit setlocal spell spelllang=en,es
autocmd FileType gitcommit setlocal textwidth=72
autocmd FileType gitcommit startinsert

" Configuración para rebase interactivo
autocmd FileType gitrebase nnoremap <buffer> p :s/^pick/pick/<CR>
autocmd FileType gitrebase nnoremap <buffer> r :s/^pick/reword/<CR>
autocmd FileType gitrebase nnoremap <buffer> e :s/^pick/edit/<CR>
autocmd FileType gitrebase nnoremap <buffer> s :s/^pick/squash/<CR>
autocmd FileType gitrebase nnoremap <buffer> f :s/^pick/fixup/<CR>
autocmd FileType gitrebase nnoremap <buffer> d :s/^pick/drop/<CR>

augroup END

🔄 Workflows Específicos

Workflow 1: Feature Branch

" 1. Crear rama para feature
:Git checkout -b feature/nueva-funcionalidad

" 2. Hacer cambios y commits
:G " Ver status
" Stage archivos con 's' en la ventana status
cc " Commit (en ventana status)

" 3. Push de la rama
:Git push -u origin feature/nueva-funcionalidad

" 4. Crear Pull Request (desde GitHub/GitLab)
" 5. Merge y cleanup
:Git checkout main
:Git pull
:Git branch -d feature/nueva-funcionalidad

Workflow 2: Hotfix

" 1. Crear rama hotfix desde main
:Git checkout main
:Git pull
:Git checkout -b hotfix/bug-critico

" 2. Fix rápido
" ... hacer cambios ...
:G
cc " Commit rápido

" 3. Push y merge inmediato
:Git push -u origin hotfix/bug-critico
:Git checkout main
:Git merge hotfix/bug-critico
:Git push
:Git branch -d hotfix/bug-critico

Workflow 3: Code Review

" 1. Ver cambios de un commit
:Git show <commit-hash>

" 2. Ver diferencias entre ramas
:Git diff main..feature/rama

" 3. Blame para contexto
:Git blame

" 4. Log para historia
:GV " Visual git log

🧹 Comandos de Limpieza

Cleanup del repositorio

" Ver ramas
:Git branch -a

" Eliminar ramas locales mergeadas
:Git branch --merged | grep -v '\*\|main\|master' | xargs git branch -d

" Limpiar ramas remotas eliminadas
:Git remote prune origin

" Garbage collection
:Git gc

" Ver tamaño del repositorio
:Git count-objects -vH

Comandos de información

" Estado general
:Git status --porcelain

" Información del repositorio
:Git remote -v
:Git config --list
:Git log --stat
:Git shortlog -sn

" Buscar en la historia
:Git log -S "función_específica" " Buscar cuando se agregó/quitó
:Git log -G "patrón_regex" " Buscar cambios en patrón
:Git log --grep="mensaje" " Buscar en mensajes de commit

📝 Ejercicios Prácticos

Ejercicio 1: Setup y comandos básicos

  1. Instala vim-fugitive y vim-gitgutter
  2. Configura mapeos personalizados
  3. Practica workflow básico: status, stage, commit, push
  4. Explora la ventana de Git status

Ejercicio 2: Resolución de conflictos

  1. Crea dos ramas con cambios conflictivos
  2. Intenta merge para generar conflicto
  3. Usa :Gdiffsplit! para resolver
  4. Practica con diffget y diffput

Ejercicio 3: Git log y navegación

  1. Usa :GV para explorar historia
  2. Practica navegación entre commits
  3. Usa Git blame para entender cambios
  4. Busca commits específicos con diferentes criterios

Ejercicio 4: Workflow completo

  1. Simula un feature branch completo
  2. Haz múltiples commits organizados
  3. Usa stash durante el desarrollo
  4. Practica cleanup al final

🏆 Tips Pro

1. Aliases útiles de Git

# En ~/.gitconfig
[alias]
st = status
co = checkout
br = branch
ci = commit
ca = commit --amend
unstage = reset HEAD --
last = log -1 HEAD
visual = !gitk
tree = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit

2. Configuración de merge tool

" En .vimrc para usar Vim como merge tool
if &diff
" Configuración específica para modo diff
set noro
map <Leader>1 :diffget LOCAL<CR>
map <Leader>2 :diffget BASE<CR>
map <Leader>3 :diffget REMOTE<CR>
endif

3. Funciones personalizadas

" Función para commit rápido
function! QuickCommit(message)
execute 'Git add .'
execute 'Git commit -m "' . a:message . '"'
endfunction
command! -nargs=1 Qcommit call QuickCommit(<q-args>)

" Función para branch rápido
function! QuickBranch(name)
execute 'Git checkout -b ' . a:name
endfunction
command! -nargs=1 Qbranch call QuickBranch(<q-args>)

4. Integración con status line

" Mostrar rama actual en statusline
function! GitBranch()
return system("git rev-parse --abbrev-ref HEAD 2>/dev/null | tr -d '\n'")
endfunction

set statusline+=%{GitBranch()}

🔗 Integración con Tmux

Workflow Git + Tmux

# Ventana dedicada a Git
tmux new-window -n 'git'
tmux send-keys 'vim' C-m

# En Vim, usar :G para management completo
# En panel adicional, comandos Git directos
tmux split-window -v
tmux send-keys 'git log --oneline' C-m

¡Con Fugitive y estas herramientas tendrás control total sobre Git sin salir de Vim!