Added push with lease + fixed push after changing tracking branch
Fixes #147
This commit is contained in:
parent
333d57e162
commit
3611f3339c
@ -9,11 +9,15 @@ import javax.inject.Inject
|
||||
|
||||
class GetTrackingBranchUseCase @Inject constructor() {
|
||||
operator fun invoke(git: Git, ref: Ref): TrackingBranch? {
|
||||
return this.invoke(git, ref.simpleName)
|
||||
}
|
||||
|
||||
operator fun invoke(git: Git, refName: String): TrackingBranch? {
|
||||
val repository: Repository = git.repository
|
||||
|
||||
val config: Config = repository.config
|
||||
val remote: String? = config.getString("branch", ref.simpleName, "remote")
|
||||
val branch: String? = config.getString("branch", ref.simpleName, "merge")
|
||||
val remote: String? = config.getString("branch", refName, "remote")
|
||||
val branch: String? = config.getString("branch", refName, "merge")
|
||||
|
||||
if (remote != null && branch != null) {
|
||||
return TrackingBranch(remote, branch.removePrefix(BranchesConstants.UPSTREAM_BRANCH_CONFIG_PREFIX))
|
||||
|
@ -1,28 +1,70 @@
|
||||
package com.jetpackduba.gitnuro.git.remote_operations
|
||||
|
||||
import com.jetpackduba.gitnuro.git.branches.GetTrackingBranchUseCase
|
||||
import com.jetpackduba.gitnuro.git.isRejected
|
||||
import com.jetpackduba.gitnuro.git.statusMessage
|
||||
import com.jetpackduba.gitnuro.preferences.AppSettings
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.lib.Constants
|
||||
import org.eclipse.jgit.lib.ProgressMonitor
|
||||
import org.eclipse.jgit.transport.RefLeaseSpec
|
||||
import org.eclipse.jgit.transport.RefSpec
|
||||
import javax.inject.Inject
|
||||
|
||||
class PushBranchUseCase @Inject constructor(
|
||||
private val handleTransportUseCase: HandleTransportUseCase,
|
||||
private val getTrackingBranchUseCase: GetTrackingBranchUseCase,
|
||||
private val appSettings: AppSettings,
|
||||
) {
|
||||
suspend operator fun invoke(git: Git, force: Boolean, pushTags: Boolean) = withContext(Dispatchers.IO) {
|
||||
val currentBranchRefSpec = git.repository.fullBranch
|
||||
val currentBranch = git.repository.fullBranch
|
||||
val tracking = getTrackingBranchUseCase(git, git.repository.branch)
|
||||
val refSpecStr = if (tracking != null) {
|
||||
"$currentBranch:${Constants.R_HEADS}${tracking.branch}"
|
||||
} else {
|
||||
currentBranch
|
||||
}
|
||||
|
||||
val pushResult = git
|
||||
.push()
|
||||
.setRefSpecs(RefSpec(currentBranchRefSpec))
|
||||
.setRefSpecs(RefSpec(refSpecStr))
|
||||
.run {
|
||||
if (tracking != null) {
|
||||
setRemote(tracking.remote)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
.setForce(force)
|
||||
.apply {
|
||||
if (pushTags)
|
||||
.run {
|
||||
if (force && appSettings.pushWithLease) {
|
||||
|
||||
if (tracking != null) {
|
||||
val remoteBranchName = "${Constants.R_REMOTES}$remote/${tracking.branch}"
|
||||
|
||||
val remoteBranchRef = git.repository.findRef(remoteBranchName)
|
||||
if (remoteBranchRef != null) {
|
||||
return@run setRefLeaseSpecs(
|
||||
RefLeaseSpec(
|
||||
"${Constants.R_HEADS}${tracking.branch}",
|
||||
remoteBranchRef.objectId.name
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return@run this
|
||||
}
|
||||
.run {
|
||||
if (pushTags) {
|
||||
setPushTags()
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
.setTransportConfigCallback { handleTransportUseCase(it, git) }
|
||||
.setProgressMonitor(object : ProgressMonitor {
|
||||
@ -35,14 +77,28 @@ class PushBranchUseCase @Inject constructor(
|
||||
})
|
||||
.call()
|
||||
|
||||
val results =
|
||||
pushResult.map { it.remoteUpdates.filter { remoteRefUpdate -> remoteRefUpdate.status.isRejected } }
|
||||
.flatten()
|
||||
val results = pushResult
|
||||
.map {
|
||||
it.remoteUpdates.filter { remoteRefUpdate -> remoteRefUpdate.status.isRejected }
|
||||
}
|
||||
.flatten()
|
||||
if (results.isNotEmpty()) {
|
||||
val error = StringBuilder()
|
||||
|
||||
results.forEach { result ->
|
||||
error.append(result.statusMessage)
|
||||
val statusMessage = result.statusMessage
|
||||
val extraMessage = if (statusMessage == "Ref rejected, old object id in remote has changed.") {
|
||||
"Force push can't be completed without fetching first the remote changes."
|
||||
} else
|
||||
null
|
||||
|
||||
error.append(statusMessage)
|
||||
|
||||
if (extraMessage != null) {
|
||||
error.append("\n")
|
||||
error.append(extraMessage)
|
||||
}
|
||||
|
||||
error.append("\n")
|
||||
}
|
||||
|
||||
|
@ -7,10 +7,7 @@ import com.jetpackduba.gitnuro.theme.ColorsScheme
|
||||
import com.jetpackduba.gitnuro.theme.Theme
|
||||
import com.jetpackduba.gitnuro.viewmodels.TextDiffType
|
||||
import com.jetpackduba.gitnuro.viewmodels.textDiffTypeFromValue
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.File
|
||||
@ -37,6 +34,7 @@ private const val PREF_TERMINAL_PATH = "terminalPath"
|
||||
|
||||
private const val PREF_GIT_FF_MERGE = "gitFFMerge"
|
||||
private const val PREF_GIT_PULL_REBASE = "gitPullRebase"
|
||||
private const val PREF_GIT_PUSH_WITH_LEASE = "gitPushWithLease"
|
||||
|
||||
private const val DEFAULT_COMMITS_LIMIT = 1000
|
||||
private const val DEFAULT_COMMITS_LIMIT_ENABLED = true
|
||||
@ -62,6 +60,9 @@ class AppSettings @Inject constructor() {
|
||||
private val _pullRebaseFlow = MutableStateFlow(pullRebase)
|
||||
val pullRebaseFlow = _pullRebaseFlow.asStateFlow()
|
||||
|
||||
private val _pushWithLeaseFlow = MutableStateFlow(pushWithLease)
|
||||
val pushWithLeaseFlow: StateFlow<Boolean> = _pushWithLeaseFlow.asStateFlow()
|
||||
|
||||
private val _commitsLimitFlow = MutableSharedFlow<Int>()
|
||||
val commitsLimitFlow = _commitsLimitFlow.asSharedFlow()
|
||||
|
||||
@ -164,6 +165,15 @@ class AppSettings @Inject constructor() {
|
||||
_pullRebaseFlow.value = value
|
||||
}
|
||||
|
||||
var pushWithLease: Boolean
|
||||
get() {
|
||||
return preferences.getBoolean(PREF_GIT_PUSH_WITH_LEASE, true)
|
||||
}
|
||||
set(value) {
|
||||
preferences.putBoolean(PREF_GIT_PUSH_WITH_LEASE, value)
|
||||
_pushWithLeaseFlow.value = value
|
||||
}
|
||||
|
||||
val commitsLimit: Int
|
||||
get() {
|
||||
return preferences.getInt(PREF_COMMITS_LIMIT, DEFAULT_COMMITS_LIMIT)
|
||||
|
@ -219,6 +219,7 @@ private fun CommitsHistory(settingsViewModel: SettingsViewModel) {
|
||||
@Composable
|
||||
private fun RemoteActions(settingsViewModel: SettingsViewModel) {
|
||||
val pullRebase by settingsViewModel.pullRebaseFlow.collectAsState()
|
||||
val pushWithLease by settingsViewModel.pushWithLeaseFlow.collectAsState()
|
||||
|
||||
SettingToggle(
|
||||
title = "Pull with rebase as default",
|
||||
@ -228,6 +229,15 @@ private fun RemoteActions(settingsViewModel: SettingsViewModel) {
|
||||
settingsViewModel.pullRebase = value
|
||||
}
|
||||
)
|
||||
|
||||
SettingToggle(
|
||||
title = "Force push with lease",
|
||||
subtitle = "Check if the local version remote branch is up to date to avoid accidentally overriding unintended commits",
|
||||
value = pushWithLease,
|
||||
onValueChanged = { value ->
|
||||
settingsViewModel.pushWithLease = value
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -24,6 +24,7 @@ class SettingsViewModel @Inject constructor(
|
||||
val themeState = appSettings.themeState
|
||||
val ffMergeFlow = appSettings.ffMergeFlow
|
||||
val pullRebaseFlow = appSettings.pullRebaseFlow
|
||||
val pushWithLeaseFlow = appSettings.pushWithLeaseFlow
|
||||
val commitsLimitEnabledFlow = appSettings.commitsLimitEnabledFlow
|
||||
val swapUncommitedChangesFlow = appSettings.swapUncommitedChangesFlow
|
||||
val terminalPathFlow = appSettings.terminalPathFlow
|
||||
@ -58,6 +59,12 @@ class SettingsViewModel @Inject constructor(
|
||||
appSettings.pullRebase = value
|
||||
}
|
||||
|
||||
var pushWithLease: Boolean
|
||||
get() = appSettings.pushWithLease
|
||||
set(value) {
|
||||
appSettings.pushWithLease = value
|
||||
}
|
||||
|
||||
var theme: Theme
|
||||
get() = appSettings.theme
|
||||
set(value) {
|
||||
|
Loading…
Reference in New Issue
Block a user