mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[git] IJPL-84816 Suggest to unshallow repository
GitOrigin-RevId: 197ff50c9347d58aaea6400666236305511bf5c6
This commit is contained in:
committed by
intellij-monorepo-bot
parent
08e08e8603
commit
68707f6fc9
@@ -514,6 +514,8 @@
|
||||
<add-to-group group-id="CopyFileReference"/>
|
||||
<add-to-group group-id="Copy.Paste.Special" relative-to-action="CopyReference" anchor="after"/>
|
||||
</group>
|
||||
|
||||
<action id="Git.Unshallow" class="git4idea.actions.GitUnshallowRepositoryAction"/>
|
||||
</actions>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
@@ -728,6 +730,7 @@
|
||||
|
||||
<backgroundPostStartupActivity implementation="git4idea.ignore.GitIgnoreInStoreDirGeneratorActivity"/>
|
||||
<backgroundPostStartupActivity implementation="git4idea.config.GitSetupProjectConfig"/>
|
||||
<backgroundPostStartupActivity implementation="git4idea.repo.GitShallowRepositoryCheck"/>
|
||||
|
||||
<registryKey key="git.update.incoming.info.time" defaultValue="20"
|
||||
description="Time period (in minutes) between incoming commits checks." restartRequired="true"/>
|
||||
|
||||
@@ -484,6 +484,9 @@ unstash.clear.confirmation.title=Remove All Stashes?
|
||||
unstash.drop.confirmation.message=<html>Do you want to remove {0}?<br/>"{1}"</html>
|
||||
unstash.drop.confirmation.title=Remove Stash {0}?
|
||||
|
||||
unshallow.repository.notification.message=Shallow repository detected
|
||||
unshallow.repository.notification.title=This repository can be converted to a complete one
|
||||
|
||||
notification.title.unstash.failed=Unstash failed
|
||||
notification.title.unstash.failed.index.conflict=Unstash failed due to an index conflict
|
||||
exception.message.could.not.stash.root.error=Cannot stash {0}: {1}
|
||||
@@ -689,6 +692,9 @@ action.main.toolbar.git.Branches.text=VCS Widget
|
||||
action.main.toolbar.git.MergeRebase.text=VCS Merge/Rebase Widget
|
||||
action.not.possible.in.fresh.repo.generic=Action
|
||||
action.main.toolbar.git.project.not.trusted.separator.text=Safe mode, Version Control is not available
|
||||
action.Git.Unshallow.text=Unshallow Repository
|
||||
action.Git.Unshallow.progress.title=Unshallowing repository\u2026
|
||||
action.Git.Unshallow.failure.title=Failed to unshallow repository
|
||||
|
||||
settings.git.option.group=Git
|
||||
settings.commit.group.title=Commit
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package git4idea.actions
|
||||
|
||||
import com.intellij.dvcs.DvcsUtil
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import git4idea.GitVcs
|
||||
import git4idea.fetch.GitFetchSupport
|
||||
import git4idea.i18n.GitBundle
|
||||
import git4idea.repo.GitRepository
|
||||
import git4idea.repo.GitRepositoryManager
|
||||
|
||||
internal class GitUnshallowRepositoryAction : DumbAwareAction() {
|
||||
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
val project = e.project
|
||||
val guessedRepo: GitRepository? = project?.let {
|
||||
DvcsUtil.guessRepositoryForOperation(it, GitRepositoryManager.getInstance(it), e.dataContext)
|
||||
}
|
||||
|
||||
e.presentation.isEnabledAndVisible = guessedRepo != null && guessedRepo.info.isShallow
|
||||
}
|
||||
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val project = e.project ?: return
|
||||
val repository =
|
||||
DvcsUtil.guessRepositoryForOperation(project, GitRepositoryManager.getInstance(project), e.dataContext)
|
||||
?: return
|
||||
|
||||
val fetcher = GitFetchSupport.fetchSupport(project)
|
||||
val remote = fetcher.getDefaultRemoteToFetch(repository) ?: return
|
||||
|
||||
GitVcs.runInBackground(object : Task.Backgroundable(project, GitBundle.message("action.Git.Unshallow.progress.title")) {
|
||||
override fun run(indicator: ProgressIndicator) {
|
||||
fetcher.fetchUnshallow(repository, remote).showNotificationIfFailed(GitBundle.message("action.Git.Unshallow.failure.title"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
const val ACTION_ID = "Git.Unshallow"
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,9 @@ public interface GitFetchSupport {
|
||||
@NotNull
|
||||
GitFetchResult fetch(@NotNull GitRepository repository, @NotNull GitRemote remote);
|
||||
|
||||
@NotNull
|
||||
GitFetchResult fetchUnshallow(@NotNull GitRepository repository, @NotNull GitRemote remote);
|
||||
|
||||
/**
|
||||
* Fetches the given remotes.
|
||||
*/
|
||||
|
||||
@@ -97,6 +97,10 @@ internal class GitFetchSupportImpl(private val project: Project) : GitFetchSuppo
|
||||
return fetch(listOf(RemoteRefCoordinates(repository, remote)))
|
||||
}
|
||||
|
||||
override fun fetchUnshallow(repository: GitRepository, remote: GitRemote): GitFetchResult {
|
||||
return fetch(listOf(RemoteRefCoordinates(repository, remote, unshallow = true)))
|
||||
}
|
||||
|
||||
override fun fetch(repository: GitRepository, remote: GitRemote, refspec: @NonNls String): GitFetchResult {
|
||||
return fetch(listOf(RemoteRefCoordinates(repository, remote, refspec)))
|
||||
}
|
||||
@@ -152,7 +156,10 @@ internal class GitFetchSupportImpl(private val project: Project) : GitFetchSuppo
|
||||
val executor = AppExecutorUtil.createBoundedApplicationPoolExecutor("GitFetch pool", maxThreads)
|
||||
val commonIndicator = progressManager.progressIndicator ?: EmptyProgressIndicator()
|
||||
val authenticationGate = RestrictingAuthenticationGate()
|
||||
for ((repository, remote, refspec) in remotes) {
|
||||
for (fetchTarget in remotes) {
|
||||
val repository = fetchTarget.repository
|
||||
val remote = fetchTarget.remote
|
||||
|
||||
LOG.debug("Fetching $remote in $repository")
|
||||
val future: Future<SingleRemoteResult> = executor.submit<SingleRemoteResult> {
|
||||
commonIndicator.checkCanceled()
|
||||
@@ -161,7 +168,7 @@ internal class GitFetchSupportImpl(private val project: Project) : GitFetchSuppo
|
||||
ProgressManager.getInstance().executeProcessUnderProgress({
|
||||
commonIndicator.checkCanceled()
|
||||
result = fetchQueue.executeForRemote(repository, remote) {
|
||||
doFetch(repository, remote, refspec, authenticationGate)
|
||||
doFetch(fetchTarget, authenticationGate)
|
||||
}
|
||||
}, commonIndicator)
|
||||
result
|
||||
@@ -229,9 +236,7 @@ internal class GitFetchSupportImpl(private val project: Project) : GitFetchSuppo
|
||||
}
|
||||
}
|
||||
|
||||
private fun doFetch(repository: GitRepository, remote: GitRemote, refspec: String?, authenticationGate: AuthenticationGate? = null)
|
||||
: SingleRemoteResult {
|
||||
|
||||
private fun doFetch(fetchTarget: RemoteRefCoordinates, authenticationGate: AuthenticationGate?): SingleRemoteResult {
|
||||
val indicator = progressManager.progressIndicator
|
||||
val progressListener = GitLineHandlerListener { line, outputType ->
|
||||
if (indicator != null && outputType == ProcessOutputTypes.STDERR) {
|
||||
@@ -241,8 +246,15 @@ internal class GitFetchSupportImpl(private val project: Project) : GitFetchSuppo
|
||||
}
|
||||
|
||||
val recurseSubmodules = "--recurse-submodules=no"
|
||||
val params = if (refspec == null) arrayOf(recurseSubmodules) else arrayOf(refspec, recurseSubmodules)
|
||||
val result = git.fetch(repository, remote, listOf(progressListener), authenticationGate, *params)
|
||||
val params = buildList {
|
||||
if (fetchTarget.refspec != null) add(fetchTarget.refspec)
|
||||
add(recurseSubmodules)
|
||||
if (fetchTarget.unshallow) add("--unshallow")
|
||||
}.toTypedArray()
|
||||
|
||||
val repository = fetchTarget.repository
|
||||
val remote = fetchTarget.remote
|
||||
val result = git.fetch(fetchTarget.repository, remote, listOf(progressListener), authenticationGate, *params)
|
||||
val pruned = result.output.mapNotNull { getPrunedRef(it) }
|
||||
if (result.success()) {
|
||||
BackgroundTaskUtil.syncPublisher(repository.project, GIT_AUTHENTICATION_SUCCESS).authenticationSucceeded(repository, remote)
|
||||
@@ -257,7 +269,12 @@ internal class GitFetchSupportImpl(private val project: Project) : GitFetchSuppo
|
||||
return if (matcher.matches()) matcher.group(1) else null
|
||||
}
|
||||
|
||||
private data class RemoteRefCoordinates(val repository: GitRepository, val remote: GitRemote, val refspec: String? = null)
|
||||
private data class RemoteRefCoordinates(
|
||||
val repository: GitRepository,
|
||||
val remote: GitRemote,
|
||||
val refspec: String? = null,
|
||||
val unshallow: Boolean = false,
|
||||
)
|
||||
|
||||
private class FetchTask(val repository: GitRepository, val remote: GitRemote, val future: Future<SingleRemoteResult>)
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package git4idea.repo
|
||||
|
||||
import com.intellij.ide.util.RunOnceUtil
|
||||
import com.intellij.notification.NotificationAction
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.startup.ProjectActivity
|
||||
import com.intellij.openapi.vcs.VcsNotifier
|
||||
import git4idea.actions.GitUnshallowRepositoryAction
|
||||
import git4idea.fetch.GitFetchSupport
|
||||
import git4idea.i18n.GitBundle
|
||||
|
||||
internal class GitShallowRepositoryCheck() : ProjectActivity {
|
||||
override suspend fun execute(project: Project) {
|
||||
val repository = GitRepositoryManager.getInstance(project).repositories.singleOrNull() ?: return
|
||||
|
||||
RunOnceUtil.runOnceForProject(project, ID) {
|
||||
suggestToUnshallow(repository, project)
|
||||
}
|
||||
}
|
||||
|
||||
private fun suggestToUnshallow(repository: GitRepository, project: Project) {
|
||||
if (repository.info.isShallow) {
|
||||
val fetcher = GitFetchSupport.fetchSupport(project)
|
||||
val remote = fetcher.getDefaultRemoteToFetch(repository)
|
||||
if (remote == null) {
|
||||
LOG.debug("Couldn't detect remote for shallow repository")
|
||||
return
|
||||
}
|
||||
|
||||
VcsNotifier.getInstance(project).notify(
|
||||
VcsNotifier.importantNotification().createNotification(
|
||||
GitBundle.message("unshallow.repository.notification.message"),
|
||||
GitBundle.message("unshallow.repository.notification.title"),
|
||||
NotificationType.INFORMATION,
|
||||
).addAction(
|
||||
NotificationAction.createExpiring(GitBundle.message("action.Git.Unshallow.text")) { e, _ ->
|
||||
GitUnshallowRepositoryAction().actionPerformed(e)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val LOG = Logger.getInstance(GitShallowRepositoryCheck::class.java)
|
||||
|
||||
private const val ID = "git.unshallow"
|
||||
@@ -1,8 +1,11 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package git4idea.repo
|
||||
|
||||
import com.intellij.openapi.vcs.VcsException
|
||||
import git4idea.GitVcs
|
||||
import git4idea.commands.Git
|
||||
import git4idea.commands.GitShallowCloneOptions
|
||||
import git4idea.fetch.GitFetchSupport
|
||||
import git4idea.test.GitSingleRepoTest
|
||||
import git4idea.test.makeCommit
|
||||
import git4idea.test.registerRepo
|
||||
@@ -10,18 +13,52 @@ import kotlin.io.path.name
|
||||
|
||||
class GitShallowRepoTest: GitSingleRepoTest() {
|
||||
fun `test shallow repo detection`() {
|
||||
val copyRepo = setupShallowCLone()
|
||||
|
||||
assertFalse(repo.info.isShallow)
|
||||
assertTrue(copyRepo.info.isShallow)
|
||||
}
|
||||
|
||||
fun `test fetch unshallow repository`() {
|
||||
val copyRepo = setupShallowCLone()
|
||||
val fetchSupport = GitFetchSupport.fetchSupport(project)
|
||||
val remote = fetchSupport.getDefaultRemoteToFetch(copyRepo)
|
||||
|
||||
assertNotNull(remote)
|
||||
val fetchResult = fetchSupport.fetchUnshallow(copyRepo, remote!!)
|
||||
fetchResult.throwExceptionIfFailed()
|
||||
|
||||
GitVcs.getInstance(project).vfsListener.waitForExternalFilesEventsProcessedInTestMode()
|
||||
|
||||
assertFalse(copyRepo.info.isShallow)
|
||||
}
|
||||
|
||||
fun `test normal repository can't be unshallowed`() {
|
||||
val cloneResult = createClone(null)
|
||||
val fetchSupport = GitFetchSupport.fetchSupport(project)
|
||||
val remote = fetchSupport.getDefaultRemoteToFetch(cloneResult)
|
||||
assertNotNull(remote)
|
||||
val fetchResult = fetchSupport.fetchUnshallow(cloneResult, remote!!)
|
||||
assertThrows(VcsException::class.java) {
|
||||
fetchResult.throwExceptionIfFailed()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupShallowCLone(): GitRepository {
|
||||
makeCommit("1.txt")
|
||||
makeCommit("2.txt")
|
||||
makeCommit("3.txt")
|
||||
|
||||
assertFalse(repo.info.isShallow)
|
||||
return createClone(GitShallowCloneOptions(1))
|
||||
}
|
||||
|
||||
private fun createClone(shallowCloneOptions: GitShallowCloneOptions? = null): GitRepository {
|
||||
val copy = projectNioRoot.resolve("copy")
|
||||
val cloneResult = Git.getInstance().clone(project,
|
||||
copy.parent.toFile(),
|
||||
"file://${repo.root.path}", copy.name, GitShallowCloneOptions(1))
|
||||
"file://${repo.root.path}", copy.name, shallowCloneOptions)
|
||||
assertTrue(cloneResult.success())
|
||||
val copyRepo = registerRepo(project, copy)
|
||||
assertTrue(copyRepo.info.isShallow)
|
||||
|
||||
return registerRepo(this.project, copy)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user