commit f6dbcd6e78bee67c9aa0d8594048ff3763574c09 from: ale date: Thu Jul 23 20:02:18 2026 UTC Fase 4: commit y rollback desde la UI (got commit / got revert) GotCheckinEnvironment.commit() no usa 'got stage': commitea exactamente los paths seleccionados en el panel de Commit vía 'got commit -m msg ', agrupados por raíz got. También implementa scheduleUnversionedFilesForAddition ('got add') y scheduleMissingFileForDeletion ('got remove -f') para los flujos de añadir/eliminar desde la UI. GotRollbackEnvironment.rollbackChanges()/rollbackMissingFileDeletion() ejecutan 'got revert -R' sobre los paths afectados; got revert ya restaura tanto modificaciones como archivos borrados o añadidos localmente, así que ambos casos comparten la misma implementación. GotCommandLineWrapper gana commit/add/remove/revert. commit - ba570446954968ad7b2feb330d7b6371087d413b commit + f6dbcd6e78bee67c9aa0d8594048ff3763574c09 blob - 3c6290cecb06079e14f45563523a392484d336b2 blob + 3a132b68a94c64d99f1a7cfa3f540b599cfc9c73 --- src/main/kotlin/dev/nezzontli/gotvcs/GotCommandLineWrapper.kt +++ src/main/kotlin/dev/nezzontli/gotvcs/GotCommandLineWrapper.kt @@ -63,4 +63,28 @@ class GotCommandLineWrapper { ?: throw VcsException("got info no reportó un commit base para $workDir") return line.substringAfter("work tree base commit:").trim() } + + @Throws(VcsException::class) + fun commit(workDir: File, message: String, paths: List) { + if (paths.isEmpty()) return + run(workDir, *(arrayOf("commit", "-m", message) + paths)) + } + + @Throws(VcsException::class) + fun add(workDir: File, paths: List) { + if (paths.isEmpty()) return + run(workDir, *(arrayOf("add") + paths)) + } + + @Throws(VcsException::class) + fun remove(workDir: File, paths: List) { + if (paths.isEmpty()) return + run(workDir, *(arrayOf("remove", "-f") + paths)) + } + + @Throws(VcsException::class) + fun revert(workDir: File, paths: List) { + if (paths.isEmpty()) return + run(workDir, *(arrayOf("revert", "-R") + paths)) + } } blob - /dev/null blob + 51c4a974493b4ffe3d9726a408194e64017e917f (mode 644) --- /dev/null +++ src/main/kotlin/dev/nezzontli/gotvcs/GotCheckinEnvironment.kt @@ -0,0 +1,85 @@ +package dev.nezzontli.gotvcs + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vcs.FilePath +import com.intellij.openapi.vcs.ProjectLevelVcsManager +import com.intellij.openapi.vcs.VcsException +import com.intellij.openapi.vcs.changes.Change +import com.intellij.openapi.vcs.checkin.CheckinEnvironment +import com.intellij.openapi.vfs.VfsUtilCore +import com.intellij.openapi.vfs.VirtualFile +import java.io.File + +/** + * got no tiene un índice/staging equivalente al de git en el flujo normal + * (aparte de `got stage`, que no usamos aquí): en vez de eso, se commitean + * exactamente los paths seleccionados por el usuario en el panel de Commit, + * vía `got commit -m msg `. Ver got(1), sección commit. + */ +class GotCheckinEnvironment( + private val project: Project, + private val commandLine: GotCommandLineWrapper, +) : CheckinEnvironment { + + override fun getHelpId(): String? = null + + override fun getCheckinOperationName(): String = "Commit" + + override fun isRefreshAfterCommitNeeded(): Boolean = true + + override fun commit(changes: MutableList, commitMessage: String): MutableList { + val exceptions = mutableListOf() + val filePaths = changes.mapNotNull { it.afterRevision?.file ?: it.beforeRevision?.file } + for ((workDir, paths) in groupByRoot(filePaths)) { + try { + commandLine.commit(workDir, commitMessage, paths) + } catch (e: VcsException) { + exceptions.add(e) + } + } + return exceptions + } + + override fun scheduleMissingFileForDeletion(files: MutableList): MutableList { + val exceptions = mutableListOf() + for ((workDir, paths) in groupByRoot(files)) { + try { + commandLine.remove(workDir, paths) + } catch (e: VcsException) { + exceptions.add(e) + } + } + return exceptions + } + + override fun scheduleUnversionedFilesForAddition(files: MutableList): MutableList { + val exceptions = mutableListOf() + val vcsManager = ProjectLevelVcsManager.getInstance(project) + val byRoot = mutableMapOf>() + for (file in files) { + val vcsRoot = vcsManager.getVcsRootFor(file) ?: continue + val relativePath = VfsUtilCore.getRelativePath(file, vcsRoot) ?: continue + byRoot.getOrPut(File(vcsRoot.path)) { mutableListOf() }.add(relativePath) + } + for ((workDir, paths) in byRoot) { + try { + commandLine.add(workDir, paths) + } catch (e: VcsException) { + exceptions.add(e) + } + } + return exceptions + } + + private fun groupByRoot(filePaths: List): Map> { + val vcsManager = ProjectLevelVcsManager.getInstance(project) + val byRoot = mutableMapOf>() + for (filePath in filePaths) { + val vcsRoot = vcsManager.getVcsRootFor(filePath) ?: continue + val workDir = File(vcsRoot.path) + val relativePath = workDir.toPath().relativize(File(filePath.path).toPath()).toString() + byRoot.getOrPut(workDir) { mutableListOf() }.add(relativePath) + } + return byRoot + } +} blob - c7ec1298940b9e9368ea674e3d1b32b8ecdd8718 blob + 361c64c88ee0ab4cdf957b1ed9fc7d775b12f158 --- src/main/kotlin/dev/nezzontli/gotvcs/GotVcs.kt +++ src/main/kotlin/dev/nezzontli/gotvcs/GotVcs.kt @@ -4,13 +4,17 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.vcs.AbstractVcs import com.intellij.openapi.vcs.VcsKey import com.intellij.openapi.vcs.changes.ChangeProvider +import com.intellij.openapi.vcs.checkin.CheckinEnvironment import com.intellij.openapi.vcs.diff.DiffProvider +import com.intellij.openapi.vcs.rollback.RollbackEnvironment class GotVcs(project: Project) : AbstractVcs(project, NAME) { private val commandLine = GotCommandLineWrapper() private val changeProvider = GotChangeProvider(commandLine) private val diffProvider = GotDiffProvider(project, commandLine) + private val checkinEnvironment = GotCheckinEnvironment(project, commandLine) + private val rollbackEnvironment = GotRollbackEnvironment(project, commandLine) override fun getDisplayName(): String = NAME @@ -18,6 +22,10 @@ class GotVcs(project: Project) : AbstractVcs(project, override fun getDiffProvider(): DiffProvider = diffProvider + override fun getCheckinEnvironment(): CheckinEnvironment = checkinEnvironment + + override fun getRollbackEnvironment(): RollbackEnvironment = rollbackEnvironment + companion object { const val NAME = "got" blob - /dev/null blob + 872fb3d6af72f071f2821499de70d42b52630165 (mode 644) --- /dev/null +++ src/main/kotlin/dev/nezzontli/gotvcs/GotRollbackEnvironment.kt @@ -0,0 +1,67 @@ +package dev.nezzontli.gotvcs + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vcs.FilePath +import com.intellij.openapi.vcs.ProjectLevelVcsManager +import com.intellij.openapi.vcs.VcsException +import com.intellij.openapi.vcs.changes.Change +import com.intellij.openapi.vcs.rollback.RollbackEnvironment +import com.intellij.openapi.vcs.rollback.RollbackProgressListener +import com.intellij.openapi.vfs.VirtualFile +import java.io.File + +class GotRollbackEnvironment( + private val project: Project, + private val commandLine: GotCommandLineWrapper, +) : RollbackEnvironment { + + override fun getRollbackOperationName(): String = "Revert" + + override fun rollbackChanges( + changes: MutableList, + exceptions: MutableList, + listener: RollbackProgressListener, + ) { + listener.determinate() + val filePaths = changes.mapNotNull { it.afterRevision?.file ?: it.beforeRevision?.file } + revertPaths(filePaths, exceptions, listener) + } + + override fun rollbackMissingFileDeletion( + files: MutableList, + exceptions: MutableList, + listener: RollbackProgressListener, + ) { + listener.determinate() + revertPaths(files, exceptions, listener) + } + + override fun rollbackModifiedWithoutCheckout( + files: MutableList, + exceptions: MutableList, + listener: RollbackProgressListener, + ) = Unit + + private fun revertPaths( + filePaths: List, + exceptions: MutableList, + listener: RollbackProgressListener, + ) { + val vcsManager = ProjectLevelVcsManager.getInstance(project) + val byRoot = mutableMapOf>() + for (filePath in filePaths) { + val vcsRoot = vcsManager.getVcsRootFor(filePath) ?: continue + val workDir = File(vcsRoot.path) + val relativePath = workDir.toPath().relativize(File(filePath.path).toPath()).toString() + byRoot.getOrPut(workDir) { mutableListOf() }.add(relativePath) + } + for ((workDir, paths) in byRoot) { + try { + commandLine.revert(workDir, paths) + paths.forEach { listener.accept(File(workDir, it)) } + } catch (e: VcsException) { + exceptions.add(e) + } + } + } +}