Maple es un cliente de Git nativo, gratis y rápido para macOS hecho en SwiftUI. Sin webviews, sin Electron, sin suscripciones. Habla directo con
giten tu máquina y no pretende esconder el modelo real de Git detrás de abstracciones raras.Repo: https://github.com/poolcamacho/Maple · Licencia: MIT · 🇺🇸 Read in English
Por qué otro cliente de Git
En macOS ya hay GUIs de Git muy decentes — Tower y Fork son las que más me gustan. EmpecĂ© Maple por algo más especĂfico: querĂa una app que fuera gratis, open source, 100% SwiftUI nativo, y sin miedo a exponer el modelo real de Git para power users, y a la vez querĂa aprender SwiftUI moderno construyendo algo que yo mismo usara todos los dĂas.
Maple arrancĂł con un brief bien acotado:
- 100% SwiftUI nativo — sin webviews, sin Electron, abre tan rápido como Terminal.
- Gratis y MIT — nunca suscripción.
- Muestra Git como es — commit graph con topologĂa real, branches y merges visibles, vista de conflictos de verdad. Cero wizards que escondan lo que está pasando.
- Respeta tu flujo — shortcuts y acciones para lo que un power user realmente usa: interactive staging, stash, rebase, merge, cherry-pick.
No pretende reemplazar a Tower para todo el mundo. Es el cliente que yo querĂa que existiera.
Lo que ya hace
Esto es un post de avance, no un lanzamiento. Las capturas las subirĂ© en el prĂłximo post. Pero esto ya funciona de punta a punta en repos reales (llevo varios dĂas dogfooding con la misma app para commitear su propio cĂłdigo):
- Abrir cualquier repo local con el folder picker y validaciĂłn de
.git - Sidebar con lista de repos, branches locales y remotos
- Toolbar con Pull, Push, Fetch, Stash, Branch, Merge, Rebase
- Cuatro tabs: Changes, History, Branches, Stashes
- Diff viewer con hunks coloreados, nĂşmeros de lĂnea, y un toggle de Blame
- Commit graph con topologĂa real — algoritmo de lanes, edges curvos por cada parent, merges dibujados con cĂrculos anillados
-
Merge y rebase con manejo de conflictos — detecta
UU/AA/DD, banner de operaciĂłn con Abort / Continue / Skip, y resoluciĂłn por archivo conUse Ours/Use Theirs - Auto-refresh vĂa FSEvents sobre
.git/ - Layout adaptativo de desktops anchos a pantallas compactas
La arquitectura en una pantalla
Models/ — Data pura y Sendable (AppState, GitModels, StashModels)
Services/ — GitService (actor, ejecuta el CLI)
GitCoordinator (@MainActor, orquestaciĂłn)
Extensiones por comando (GitCommands, GitBranchOps,
GitStashOps, GitMergeRebase)
CommitGraphBuilder, ConflictParser, FileWatcher
Views/ — Un archivo por vista, cero lógica de negocio
Utils/ — FolderPicker, DateExtensions
Tres decisiones que vale la pena llamar aparte:
GitService es un actor, asà que todas las llamadas al CLI se serializan por un solo "portero". GitCoordinator es @MainActor y hace de pegamento entre la UI y el actor — las vistas solo llaman state.coordinator.* y nunca tocan un Process directamente. Resultado: lógica de negocio cero en las vistas, fácil de testear y refactorizar.
Cada invocaciĂłn de git abre un /dev/null fresco para stdin y cierra sus pipes explĂcitamente. Sin eso me salĂa NSPOSIXErrorDomain code=9 / EBADF despuĂ©s de comandos largos como push, porque FileHandle.nullDevice es un singleton compartido que termina en estados raros despuĂ©s de muchos posix_spawn. Abrir /dev/null por llamada con closeOnDealloc: true lo arregla de tajo.
El commit graph no es el "punto + lĂnea vertical" de toda la vida. Construye un layout real de lanes: para cada commit, reclama el lane que lo estaba esperando (el vĂnculo child→parent); si no hay, reusa un lane libre. Los primeros parents se quedan en el mismo lane para que la lĂnea principal quede recta; los parents adicionales de merges abren lanes laterales con edges curvos. Los edges se resuelven en una segunda pasada porque un parent puede aparecer muchas filas más abajo.
El UX de conflictos es por archivo, no por hunk — a propósito para v1. Cuando cae un merge con conflicto, el tab Changes marca cada archivo conflictivo con un ! morado, y cada uno tiene tres botones: Use Ours, Use Theirs, o editas los markers tú mismo en tu editor favorito. Arriba aparece un banner persistente que dice Merging X con Abort / Continue / Skip. Sin modales, sin secuestrarte el flujo.
Lo que ya está armado alrededor del código
Porque la idea es que esto crezca como proyecto OSS serio, no como experimento de fin de semana:
-
GitHub Actions CI — build +
xcodebuild analyze+ SwiftLint strict en cada push y PR - CodeQL — análisis semanal de Swift más en cada PR que toque código Swift
-
Workflow de release — taggeas
v*y sale un.appsin firmar zipeado automáticamente -
Branch protection en
master— status checks requeridos, no force push, no delete, conversations resueltas - Dependabot para GitHub Actions, asà las versiones no se quedan oxidadas
-
SECURITY.mdcon private vulnerability reporting activado - Issue forms y PR template que fuerza la regla de "ni una sola lĂnea de lĂłgica de negocio en las vistas"
Nada de esto es heroico. Es el andamiaje aburrido que separa un hobby project de un repo donde la gente realmente puede contribuir.
Lo que sigue
El roadmap que estoy atacando en orden:
- [ ] Interactive staging — stage de hunks o lĂneas individuales, no solo archivos enteros
- [ ] Tag management — crear, listar, borrar tags desde la UI
- [ ] Search / filtering — filtrar commits y archivos con fuzzy match
- [ ] Clone from URL — ahora solo abres repos existentes, clonar es el paso obvio
- [ ] Remote management — agregar, quitar, configurar remotes sin CLI
- [ ] Keyboard shortcuts —
Cmd+Sstage,Cmd+Entercommit,Cmd+Kcommand palette - [ ] Persistir repos abiertos entre sesiones
- [ ] Settings & preferences
- [ ] Releases firmados + notarizados cuando la app ya esté lista para usuarios no-devs
Pruébalo y ayúdame a darle forma
MIT, open source, todo en pĂşblico:
→ github.com/poolcamacho/Maple
Si tienes macOS 14+ y Xcode 16+, git clone + Cmd+R y lo tienes corriendo en menos de un minuto. Abre issues si te topas con un flujo de Git que la UI vuelve torpe — prefiero arreglar eso a adivinar qué necesitan los power users.
Si quieres patrocinar el proyecto para que se mantenga gratis y activo, hay botĂłn Sponsor arriba del repo, o directo en github.com/sponsors/poolcamacho. El patrocinio mantiene Maple libre para todos y me ayuda a cubrir el presupuesto de firma + notarizaciĂłn que voy a necesitar para shipear a usuarios no-devs.
El próximo post probablemente sea sobre interactive staging — es el problema de diseño más interesante de la lista. Nos leemos.













