Implemented merge & rebase
This commit is contained in:
parent
ca1eeb2d11
commit
42fec7c591
@ -3,13 +3,8 @@ package app.git
|
||||
import app.extensions.isBranch
|
||||
import app.extensions.simpleName
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.eclipse.jgit.api.CreateBranchCommand
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.api.ListBranchCommand
|
||||
import org.eclipse.jgit.api.MergeCommand
|
||||
import org.eclipse.jgit.api.*
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
import org.eclipse.jgit.revwalk.RevCommit
|
||||
import javax.inject.Inject
|
||||
@ -50,19 +45,6 @@ class BranchesManager @Inject constructor() {
|
||||
.call()
|
||||
}
|
||||
|
||||
suspend fun mergeBranch(git: Git, branch: Ref, fastForward: Boolean) = withContext(Dispatchers.IO) {
|
||||
val fastForwardMode = if (fastForward)
|
||||
MergeCommand.FastForwardMode.FF
|
||||
else
|
||||
MergeCommand.FastForwardMode.NO_FF
|
||||
|
||||
git
|
||||
.merge()
|
||||
.include(branch)
|
||||
.setFastForward(fastForwardMode)
|
||||
.call()
|
||||
}
|
||||
|
||||
suspend fun deleteBranch(git: Git, branch: Ref) = withContext(Dispatchers.IO) {
|
||||
git
|
||||
.branchDelete()
|
||||
|
@ -25,7 +25,7 @@ class LogManager @Inject constructor(
|
||||
suspend fun loadLog(git: Git, currentBranch: Ref?) = withContext(Dispatchers.IO) {
|
||||
val commitList = GraphCommitList()
|
||||
val repositoryState = git.repository.repositoryState
|
||||
|
||||
println("Repository state ${repositoryState.description}")
|
||||
if(currentBranch != null || repositoryState.isRebasing) { // Current branch is null when there is no log (new repo) or rebasing
|
||||
val logList = git.log().setMaxCount(2).call().toList()
|
||||
|
||||
|
31
src/main/kotlin/app/git/MergeManager.kt
Normal file
31
src/main/kotlin/app/git/MergeManager.kt
Normal file
@ -0,0 +1,31 @@
|
||||
package app.git
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.api.MergeCommand
|
||||
import org.eclipse.jgit.api.ResetCommand
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
import javax.inject.Inject
|
||||
|
||||
class MergeManager @Inject constructor() {
|
||||
suspend fun mergeBranch(git: Git, branch: Ref, fastForward: Boolean) = withContext(Dispatchers.IO) {
|
||||
val fastForwardMode = if (fastForward)
|
||||
MergeCommand.FastForwardMode.FF
|
||||
else
|
||||
MergeCommand.FastForwardMode.NO_FF
|
||||
|
||||
git
|
||||
.merge()
|
||||
.include(branch)
|
||||
.setFastForward(fastForwardMode)
|
||||
.call()
|
||||
}
|
||||
|
||||
suspend fun abortBranch(git: Git) = withContext(Dispatchers.IO) {
|
||||
git.repository.writeMergeCommitMsg(null);
|
||||
git.repository.writeMergeHeads(null);
|
||||
|
||||
git.reset().setMode(ResetCommand.ResetType.HARD).call();
|
||||
}
|
||||
}
|
36
src/main/kotlin/app/git/RebaseManager.kt
Normal file
36
src/main/kotlin/app/git/RebaseManager.kt
Normal file
@ -0,0 +1,36 @@
|
||||
package app.git
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.api.RebaseCommand
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
import javax.inject.Inject
|
||||
|
||||
class RebaseManager @Inject constructor() {
|
||||
|
||||
suspend fun rebaseBranch(git: Git, ref: Ref) = withContext(Dispatchers.IO) {
|
||||
git.rebase()
|
||||
.setOperation(RebaseCommand.Operation.BEGIN)
|
||||
.setUpstream(ref.objectId)
|
||||
.call()
|
||||
}
|
||||
|
||||
suspend fun continueRebase(git: Git) = withContext(Dispatchers.IO) {
|
||||
git.rebase()
|
||||
.setOperation(RebaseCommand.Operation.CONTINUE)
|
||||
.call()
|
||||
}
|
||||
|
||||
suspend fun abortRebase(git: Git) = withContext(Dispatchers.IO) {
|
||||
git.rebase()
|
||||
.setOperation(RebaseCommand.Operation.ABORT)
|
||||
.call()
|
||||
}
|
||||
|
||||
suspend fun skipRebase(git: Git) = withContext(Dispatchers.IO) {
|
||||
git.rebase()
|
||||
.setOperation(RebaseCommand.Operation.SKIP)
|
||||
.call()
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ import app.ui.components.SideMenuSubentry
|
||||
import app.ui.components.entryHeight
|
||||
import app.ui.context_menu.branchContextMenuItems
|
||||
import app.ui.dialogs.MergeDialog
|
||||
import app.ui.dialogs.RebaseDialog
|
||||
import app.viewmodels.BranchesViewModel
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
|
||||
@ -30,6 +31,7 @@ fun Branches(
|
||||
val branches by branchesViewModel.branches.collectAsState()
|
||||
val currentBranch by branchesViewModel.currentBranch.collectAsState()
|
||||
val (mergeBranch, setMergeBranch) = remember { mutableStateOf<Ref?>(null) }
|
||||
val (rebaseBranch, setRebaseBranch) = remember { mutableStateOf<Ref?>(null) }
|
||||
|
||||
Column {
|
||||
SideMenuEntry("Local branches")
|
||||
@ -43,13 +45,14 @@ fun Branches(
|
||||
Box(modifier = Modifier.heightIn(max = maxHeight.dp)) {
|
||||
ScrollableLazyColumn(modifier = Modifier.fillMaxWidth()) {
|
||||
itemsIndexed(branches) { _, branch ->
|
||||
BranchRow(
|
||||
BranchLineEntry(
|
||||
branch = branch,
|
||||
isCurrentBranch = currentBranch == branch.name,
|
||||
onBranchClicked = { onBranchClicked(branch) },
|
||||
onCheckoutBranch = { branchesViewModel.checkoutRef(branch) },
|
||||
onMergeBranch = { setMergeBranch(branch) },
|
||||
onDeleteBranch = { branchesViewModel.deleteBranch(branch) },
|
||||
onRebaseBranch = { branchesViewModel.deleteBranch(branch) },
|
||||
onDeleteBranch = { setRebaseBranch(branch) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -64,16 +67,26 @@ fun Branches(
|
||||
onAccept = { ff -> branchesViewModel.mergeBranch(mergeBranch, ff) }
|
||||
)
|
||||
}
|
||||
|
||||
if (rebaseBranch != null) {
|
||||
RebaseDialog(
|
||||
currentBranch,
|
||||
rebaseBranchName = rebaseBranch.name,
|
||||
onReject = { setRebaseBranch(null) },
|
||||
onAccept = { branchesViewModel.rebaseBranch(rebaseBranch) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun BranchRow(
|
||||
private fun BranchLineEntry(
|
||||
branch: Ref,
|
||||
isCurrentBranch: Boolean,
|
||||
onBranchClicked: () -> Unit,
|
||||
onCheckoutBranch: () -> Unit,
|
||||
onMergeBranch: () -> Unit,
|
||||
onRebaseBranch: () -> Unit,
|
||||
onDeleteBranch: () -> Unit,
|
||||
) {
|
||||
ContextMenuArea(
|
||||
@ -84,6 +97,7 @@ private fun BranchRow(
|
||||
onCheckoutBranch = onCheckoutBranch,
|
||||
onMergeBranch = onMergeBranch,
|
||||
onDeleteBranch = onDeleteBranch,
|
||||
onRebaseBranch = onRebaseBranch,
|
||||
)
|
||||
}
|
||||
) {
|
||||
|
@ -22,7 +22,6 @@ import androidx.compose.ui.input.pointer.pointerMoveFilter
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import app.extensions.filePath
|
||||
@ -58,7 +57,7 @@ fun UncommitedChanges(
|
||||
staged = stageStatus.staged
|
||||
unstaged = stageStatus.unstaged
|
||||
LaunchedEffect(staged) {
|
||||
if(selectedEntryType != null) {
|
||||
if (selectedEntryType != null) {
|
||||
checkIfSelectedEntryShouldBeUpdated(
|
||||
selectedEntryType = selectedEntryType,
|
||||
staged = staged,
|
||||
@ -69,8 +68,8 @@ fun UncommitedChanges(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
staged = listOf<StatusEntry>()
|
||||
unstaged = listOf<StatusEntry>() // return empty lists if still loading
|
||||
staged = listOf()
|
||||
unstaged = listOf() // return empty lists if still loading
|
||||
}
|
||||
|
||||
val doCommit = {
|
||||
@ -134,16 +133,20 @@ fun UncommitedChanges(
|
||||
allActionTitle = "Stage all"
|
||||
)
|
||||
|
||||
Card(
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.height(192.dp)
|
||||
.run {
|
||||
// When rebasing, we don't need a fixed size as we don't show the message TextField
|
||||
if(!repositoryState.isRebasing) {
|
||||
height(192.dp)
|
||||
} else
|
||||
this
|
||||
}
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
) {
|
||||
// Don't show the message TextField when rebasing as it can't be edited
|
||||
if (!repositoryState.isRebasing)
|
||||
TextField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@ -159,32 +162,131 @@ fun UncommitedChanges(
|
||||
onValueChange = { statusViewModel.newCommitMessage = it },
|
||||
label = { Text("Write your commit message here", fontSize = 14.sp) },
|
||||
colors = TextFieldDefaults.textFieldColors(backgroundColor = MaterialTheme.colors.background),
|
||||
textStyle = TextStyle.Default.copy(fontSize = 14.sp),
|
||||
textStyle = TextStyle.Default.copy(fontSize = 14.sp, color = MaterialTheme.colors.primaryTextColor),
|
||||
)
|
||||
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
onClick = {
|
||||
doCommit()
|
||||
},
|
||||
enabled = canCommit,
|
||||
shape = RectangleShape,
|
||||
) {
|
||||
val buttonText = if(repositoryState.isMerging)
|
||||
"Merge"
|
||||
else if (repositoryState.isRebasing)
|
||||
"Continue rebasing"
|
||||
else
|
||||
"Commit"
|
||||
Text(
|
||||
text = buttonText,
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
when {
|
||||
repositoryState.isMerging -> MergeButtons(
|
||||
haveConflictsBeenSolved = unstaged.isEmpty(),
|
||||
onAbort = { statusViewModel.abortMerge() },
|
||||
onMerge = { doCommit() }
|
||||
)
|
||||
repositoryState.isRebasing -> RebasingButtons(
|
||||
canContinue = staged.isNotEmpty() || unstaged.isNotEmpty(),
|
||||
haveConflictsBeenSolved = unstaged.isEmpty(),
|
||||
onAbort = { statusViewModel.abortRebase() },
|
||||
onContinue = { statusViewModel.continueRebase() },
|
||||
onSkip = { statusViewModel.skipRebase() },
|
||||
)
|
||||
else -> {
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
onClick = doCommit,
|
||||
enabled = canCommit,
|
||||
shape = RectangleShape,
|
||||
) {
|
||||
|
||||
Text(
|
||||
text = "Commit",
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MergeButtons(
|
||||
haveConflictsBeenSolved: Boolean,
|
||||
onAbort: () -> Unit,
|
||||
onMerge: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Button(
|
||||
onClick = onAbort,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 8.dp, end = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = "Abort",
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
}
|
||||
|
||||
Button(
|
||||
onClick = onMerge,
|
||||
enabled = haveConflictsBeenSolved,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 8.dp, end = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = "Merge",
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RebasingButtons(
|
||||
canContinue: Boolean,
|
||||
haveConflictsBeenSolved: Boolean,
|
||||
onAbort: () -> Unit,
|
||||
onContinue: () -> Unit,
|
||||
onSkip: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Button(
|
||||
onClick = onAbort,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 8.dp, end = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = "Abort",
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
}
|
||||
|
||||
if (canContinue) {
|
||||
Button(
|
||||
onClick = onContinue,
|
||||
enabled = haveConflictsBeenSolved,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 8.dp, end = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = "Continue",
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Button(
|
||||
onClick = onSkip,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 8.dp, end = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = "Skip",
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This logic should be part of the diffViewModel where it gets the latest version of the diffEntry
|
||||
@ -199,9 +301,10 @@ fun checkIfSelectedEntryShouldBeUpdated(
|
||||
val selectedEntryTypeNewId = selectedDiffEntry.newId.name()
|
||||
|
||||
if (selectedEntryType is DiffEntryType.StagedDiff) {
|
||||
val entryType = staged.firstOrNull { stagedEntry -> stagedEntry.diffEntry.newPath == selectedDiffEntry.newPath }?.diffEntry
|
||||
val entryType =
|
||||
staged.firstOrNull { stagedEntry -> stagedEntry.diffEntry.newPath == selectedDiffEntry.newPath }?.diffEntry
|
||||
|
||||
if(
|
||||
if (
|
||||
entryType != null &&
|
||||
selectedEntryTypeNewId != entryType.newId.name()
|
||||
) {
|
||||
@ -210,15 +313,15 @@ fun checkIfSelectedEntryShouldBeUpdated(
|
||||
} else if (entryType == null) {
|
||||
onStagedDiffEntrySelected(null)
|
||||
}
|
||||
} else if(selectedEntryType is DiffEntryType.UnstagedDiff) {
|
||||
} else if (selectedEntryType is DiffEntryType.UnstagedDiff) {
|
||||
val entryType = unstaged.firstOrNull { unstagedEntry ->
|
||||
if(selectedDiffEntry.changeType == DiffEntry.ChangeType.DELETE)
|
||||
if (selectedDiffEntry.changeType == DiffEntry.ChangeType.DELETE)
|
||||
unstagedEntry.diffEntry.oldPath == selectedDiffEntry.oldPath
|
||||
else
|
||||
unstagedEntry.diffEntry.newPath == selectedDiffEntry.newPath
|
||||
}
|
||||
|
||||
if(entryType != null) {
|
||||
if (entryType != null) {
|
||||
onUnstagedDiffEntrySelected(entryType.diffEntry)
|
||||
} else
|
||||
onStagedDiffEntrySelected(null)
|
||||
|
@ -9,22 +9,29 @@ fun branchContextMenuItems(
|
||||
isLocal: Boolean,
|
||||
onCheckoutBranch: () -> Unit,
|
||||
onMergeBranch: () -> Unit,
|
||||
onRebaseBranch: () -> Unit,
|
||||
onDeleteBranch: () -> Unit,
|
||||
): List<ContextMenuItem> {
|
||||
return mutableListOf(
|
||||
ContextMenuItem(
|
||||
label = "Checkout branch",
|
||||
onClick = onCheckoutBranch
|
||||
),
|
||||
|
||||
).apply {
|
||||
return mutableListOf<ContextMenuItem>().apply {
|
||||
if (!isCurrentBranch) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
label = "Checkout branch",
|
||||
onClick = onCheckoutBranch
|
||||
)
|
||||
)
|
||||
add(
|
||||
ContextMenuItem(
|
||||
label = "Merge branch",
|
||||
onClick = onMergeBranch
|
||||
)
|
||||
)
|
||||
add(
|
||||
ContextMenuItem(
|
||||
label = "Rebase branch",
|
||||
onClick = onRebaseBranch
|
||||
)
|
||||
)
|
||||
}
|
||||
if (isLocal && !isCurrentBranch) {
|
||||
add(
|
||||
|
83
src/main/kotlin/app/ui/dialogs/RebaseDialog.kt
Normal file
83
src/main/kotlin/app/ui/dialogs/RebaseDialog.kt
Normal file
@ -0,0 +1,83 @@
|
||||
package app.ui.dialogs
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.theme.primaryTextColor
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun RebaseDialog(
|
||||
currentBranchName: String,
|
||||
rebaseBranchName: String,
|
||||
onReject: () -> Unit,
|
||||
onAccept: () -> Unit
|
||||
) {
|
||||
MaterialDialog {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colors.background),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = currentBranchName,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
)
|
||||
|
||||
|
||||
Text(
|
||||
text = "will rebase ",
|
||||
modifier = Modifier.padding(horizontal = 8.dp),
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = rebaseBranchName,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = "After completing the operation, $currentBranchName will contain $rebaseBranchName changes",
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 16.dp)
|
||||
.align(Alignment.End)
|
||||
) {
|
||||
TextButton(
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
onClick = {
|
||||
onReject()
|
||||
}
|
||||
) {
|
||||
Text("Cancel")
|
||||
}
|
||||
Button(
|
||||
onClick = {
|
||||
onAccept()
|
||||
}
|
||||
) {
|
||||
Text("Rebase")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -39,10 +39,7 @@ import app.ui.components.AvatarImage
|
||||
import app.ui.components.ScrollableLazyColumn
|
||||
import app.ui.context_menu.branchContextMenuItems
|
||||
import app.ui.context_menu.tagContextMenuItems
|
||||
import app.ui.dialogs.MergeDialog
|
||||
import app.ui.dialogs.NewBranchDialog
|
||||
import app.ui.dialogs.NewTagDialog
|
||||
import app.ui.dialogs.ResetBranchDialog
|
||||
import app.ui.dialogs.*
|
||||
import app.viewmodels.LogStatus
|
||||
import app.viewmodels.LogViewModel
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
@ -156,6 +153,7 @@ fun Log(
|
||||
showCreateNewTag = { showLogDialog.value = LogDialog.NewTag(graphNode) },
|
||||
resetBranch = { showLogDialog.value = LogDialog.ResetBranch(graphNode) },
|
||||
onMergeBranch = { ref -> showLogDialog.value = LogDialog.MergeBranch(ref) },
|
||||
onRebaseBranch = { ref -> showLogDialog.value = LogDialog.RebaseBranch(ref) },
|
||||
onRevCommitSelected = {
|
||||
onItemSelected(SelectedItem.Commit(graphNode))
|
||||
}
|
||||
@ -212,6 +210,19 @@ fun LogDialogs(
|
||||
onResetShowLogDialog()
|
||||
}
|
||||
)
|
||||
is LogDialog.RebaseBranch -> {
|
||||
if(currentBranch != null) {
|
||||
RebaseDialog(
|
||||
currentBranchName = currentBranch.simpleName,
|
||||
rebaseBranchName = showLogDialog.ref.simpleName,
|
||||
onReject = onResetShowLogDialog,
|
||||
onAccept = {
|
||||
logViewModel.rebaseBranch(showLogDialog.ref)
|
||||
onResetShowLogDialog()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
LogDialog.None -> {
|
||||
}
|
||||
}
|
||||
@ -334,6 +345,7 @@ fun CommitLine(
|
||||
showCreateNewTag: () -> Unit,
|
||||
resetBranch: (GraphNode) -> Unit,
|
||||
onMergeBranch: (Ref) -> Unit,
|
||||
onRebaseBranch: (Ref) -> Unit,
|
||||
onRevCommitSelected: (GraphNode) -> Unit,
|
||||
) {
|
||||
val commitRefs = graphNode.refs
|
||||
@ -405,6 +417,7 @@ fun CommitLine(
|
||||
onMergeBranch = { ref -> onMergeBranch(ref) },
|
||||
onDeleteBranch = { ref -> logViewModel.deleteBranch(ref) },
|
||||
onDeleteTag = { ref -> logViewModel.deleteTag(ref) },
|
||||
onRebaseBranch = { ref -> onRebaseBranch(ref) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -422,6 +435,7 @@ fun CommitMessage(
|
||||
onCheckoutRef: (ref: Ref) -> Unit,
|
||||
onMergeBranch: (ref: Ref) -> Unit,
|
||||
onDeleteBranch: (ref: Ref) -> Unit,
|
||||
onRebaseBranch: (ref: Ref) -> Unit,
|
||||
onDeleteTag: (ref: Ref) -> Unit,
|
||||
) {
|
||||
val textColor = if (selected) {
|
||||
@ -467,6 +481,7 @@ fun CommitMessage(
|
||||
onCheckoutBranch = { onCheckoutRef(ref) },
|
||||
onMergeBranch = { onMergeBranch(ref) },
|
||||
onDeleteBranch = { onDeleteBranch(ref) },
|
||||
onRebaseBranch = { onRebaseBranch(ref) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -644,6 +659,7 @@ fun BranchChip(
|
||||
onCheckoutBranch: () -> Unit,
|
||||
onMergeBranch: () -> Unit,
|
||||
onDeleteBranch: () -> Unit,
|
||||
onRebaseBranch: () -> Unit,
|
||||
color: Color,
|
||||
) {
|
||||
val contextMenuItemsList = {
|
||||
@ -653,6 +669,7 @@ fun BranchChip(
|
||||
onCheckoutBranch = onCheckoutBranch,
|
||||
onMergeBranch = onMergeBranch,
|
||||
onDeleteBranch = onDeleteBranch,
|
||||
onRebaseBranch = onRebaseBranch,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -9,4 +9,5 @@ sealed class LogDialog {
|
||||
data class NewTag(val graphNode: GraphNode) : LogDialog()
|
||||
data class ResetBranch(val graphNode: GraphNode) : LogDialog()
|
||||
data class MergeBranch(val ref: Ref) : LogDialog()
|
||||
data class RebaseBranch(val ref: Ref) : LogDialog()
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
package app.viewmodels
|
||||
|
||||
import app.git.BranchesManager
|
||||
import app.git.RefreshType
|
||||
import app.git.TabState
|
||||
import app.git.*
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.eclipse.jgit.api.Git
|
||||
@ -12,6 +10,8 @@ import javax.inject.Inject
|
||||
|
||||
class BranchesViewModel @Inject constructor(
|
||||
private val branchesManager: BranchesManager,
|
||||
private val rebaseManager: RebaseManager,
|
||||
private val mergeManager: MergeManager,
|
||||
private val tabState: TabState,
|
||||
) {
|
||||
private val _branches = MutableStateFlow<List<Ref>>(listOf())
|
||||
@ -37,7 +37,7 @@ class BranchesViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
fun mergeBranch(ref: Ref, fastForward: Boolean) = tabState.safeProcessing { git ->
|
||||
branchesManager.mergeBranch(git, ref, fastForward)
|
||||
mergeManager.mergeBranch(git, ref, fastForward)
|
||||
|
||||
return@safeProcessing RefreshType.ALL_DATA
|
||||
}
|
||||
@ -57,4 +57,10 @@ class BranchesViewModel @Inject constructor(
|
||||
suspend fun refresh(git: Git) {
|
||||
loadBranches(git)
|
||||
}
|
||||
|
||||
fun rebaseBranch(ref: Ref) = tabState.safeProcessing { git ->
|
||||
rebaseManager.rebaseBranch(git, ref)
|
||||
|
||||
return@safeProcessing RefreshType.ALL_DATA
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@ import app.git.*
|
||||
import app.git.graph.GraphCommitList
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
import org.eclipse.jgit.revwalk.RevCommit
|
||||
@ -14,7 +13,9 @@ class LogViewModel @Inject constructor(
|
||||
private val logManager: LogManager,
|
||||
private val statusManager: StatusManager,
|
||||
private val branchesManager: BranchesManager,
|
||||
private val rebaseManager: RebaseManager,
|
||||
private val tagsManager: TagsManager,
|
||||
private val mergeManager: MergeManager,
|
||||
private val tabState: TabState,
|
||||
) {
|
||||
private val _logStatus = MutableStateFlow<LogStatus>(LogStatus.Loading)
|
||||
@ -69,7 +70,7 @@ class LogViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
fun mergeBranch(ref: Ref, fastForward: Boolean) = tabState.safeProcessing { git ->
|
||||
branchesManager.mergeBranch(git, ref, fastForward)
|
||||
mergeManager.mergeBranch(git, ref, fastForward)
|
||||
|
||||
return@safeProcessing RefreshType.ALL_DATA
|
||||
}
|
||||
@ -89,6 +90,12 @@ class LogViewModel @Inject constructor(
|
||||
suspend fun refresh(git: Git) {
|
||||
loadLog(git)
|
||||
}
|
||||
|
||||
fun rebaseBranch(ref: Ref) = tabState.safeProcessing { git ->
|
||||
rebaseManager.rebaseBranch(git, ref)
|
||||
|
||||
return@safeProcessing RefreshType.ALL_DATA
|
||||
}
|
||||
}
|
||||
|
||||
sealed class LogStatus {
|
||||
|
@ -14,6 +14,8 @@ class StatusViewModel @Inject constructor(
|
||||
private val statusManager: StatusManager,
|
||||
private val branchesManager: BranchesManager,
|
||||
private val repositoryManager: RepositoryManager,
|
||||
private val rebaseManager: RebaseManager,
|
||||
private val mergeManager: MergeManager,
|
||||
) {
|
||||
private val _stageStatus = MutableStateFlow<StageStatus>(StageStatus.Loaded(listOf(), listOf()))
|
||||
val stageStatus: StateFlow<StageStatus> = _stageStatus
|
||||
@ -112,6 +114,30 @@ class StatusViewModel @Inject constructor(
|
||||
// Return true to update the log only if the uncommitedChanges status has changed
|
||||
return (hasNowUncommitedChanges != hadUncommitedChanges)
|
||||
}
|
||||
|
||||
fun continueRebase() = tabState.safeProcessing { git ->
|
||||
rebaseManager.continueRebase(git)
|
||||
|
||||
return@safeProcessing RefreshType.ALL_DATA
|
||||
}
|
||||
|
||||
fun abortRebase() = tabState.safeProcessing { git ->
|
||||
rebaseManager.abortRebase(git)
|
||||
|
||||
return@safeProcessing RefreshType.ALL_DATA
|
||||
}
|
||||
|
||||
fun skipRebase() = tabState.safeProcessing { git ->
|
||||
rebaseManager.skipRebase(git)
|
||||
|
||||
return@safeProcessing RefreshType.ALL_DATA
|
||||
}
|
||||
|
||||
fun abortMerge() = tabState.safeProcessing { git ->
|
||||
mergeManager.abortBranch(git)
|
||||
|
||||
return@safeProcessing RefreshType.ALL_DATA
|
||||
}
|
||||
}
|
||||
|
||||
sealed class StageStatus {
|
||||
|
Loading…
Reference in New Issue
Block a user