diff --git a/.idea/modules.xml b/.idea/modules.xml
index a6d589e24ce2..410ba357a8f7 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -1069,6 +1069,7 @@
+
diff --git a/intellij.idea.community.main.iml b/intellij.idea.community.main.iml
index 525812329703..72dc28ea20b0 100644
--- a/intellij.idea.community.main.iml
+++ b/intellij.idea.community.main.iml
@@ -239,5 +239,6 @@
+
\ No newline at end of file
diff --git a/plugins/git-modal-commit/intellij.vcs.git.commit.modal.iml b/plugins/git-modal-commit/intellij.vcs.git.commit.modal.iml
new file mode 100644
index 000000000000..e5261cc40691
--- /dev/null
+++ b/plugins/git-modal-commit/intellij.vcs.git.commit.modal.iml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/git-modal-commit/plugin-content.yaml b/plugins/git-modal-commit/plugin-content.yaml
new file mode 100644
index 000000000000..3efbd944b18d
--- /dev/null
+++ b/plugins/git-modal-commit/plugin-content.yaml
@@ -0,0 +1,3 @@
+- name: lib/vcs-git-commit-modal.jar
+ modules:
+ - name: intellij.vcs.git.commit.modal
\ No newline at end of file
diff --git a/plugins/git-modal-commit/resources/META-INF/plugin.xml b/plugins/git-modal-commit/resources/META-INF/plugin.xml
new file mode 100644
index 000000000000..4dfabc92ed6c
--- /dev/null
+++ b/plugins/git-modal-commit/resources/META-INF/plugin.xml
@@ -0,0 +1,24 @@
+
+ Git Modal Commit Interface
+ intellij.git.commit.modal
+ Version Controls
+ JetBrains
+
+
+
+
+
+
+
+
+ messages.GitModalCommitBundle
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/git-modal-commit/resources/META-INF/pluginIcon.svg b/plugins/git-modal-commit/resources/META-INF/pluginIcon.svg
new file mode 100644
index 000000000000..3c49eebb15a2
--- /dev/null
+++ b/plugins/git-modal-commit/resources/META-INF/pluginIcon.svg
@@ -0,0 +1,11 @@
+
diff --git a/plugins/git-modal-commit/resources/messages/GitModalCommitBundle.properties b/plugins/git-modal-commit/resources/messages/GitModalCommitBundle.properties
new file mode 100644
index 000000000000..7762d820ceeb
--- /dev/null
+++ b/plugins/git-modal-commit/resources/messages/GitModalCommitBundle.properties
@@ -0,0 +1,2 @@
+advanced.settings.git=Version Control. Git
+advanced.setting.git.non.modal.commit=Use modal commit interface
\ No newline at end of file
diff --git a/plugins/git-modal-commit/src/com/intellij/vcs/git/commit/modal/GitModalCommitModeProvider.kt b/plugins/git-modal-commit/src/com/intellij/vcs/git/commit/modal/GitModalCommitModeProvider.kt
new file mode 100644
index 000000000000..d4cc7ac3da7d
--- /dev/null
+++ b/plugins/git-modal-commit/src/com/intellij/vcs/git/commit/modal/GitModalCommitModeProvider.kt
@@ -0,0 +1,16 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.vcs.git.commit.modal
+
+import com.intellij.openapi.options.advanced.AdvancedSettings
+import com.intellij.vcs.commit.CommitMode
+import git4idea.commit.GitCommitModeProvider
+
+internal class GitModalCommitModeProvider : GitCommitModeProvider {
+ override fun getCommitMode(): CommitMode? {
+ return if (AdvancedSettings.getBoolean(SETTING_ID)) CommitMode.ModalCommitMode else null
+ }
+
+ companion object {
+ const val SETTING_ID = "git.non.modal.commit"
+ }
+}
diff --git a/plugins/git-modal-commit/src/com/intellij/vcs/git/commit/modal/GitModalCommitSettingsListener.kt b/plugins/git-modal-commit/src/com/intellij/vcs/git/commit/modal/GitModalCommitSettingsListener.kt
new file mode 100644
index 000000000000..7e5672449df4
--- /dev/null
+++ b/plugins/git-modal-commit/src/com/intellij/vcs/git/commit/modal/GitModalCommitSettingsListener.kt
@@ -0,0 +1,31 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.vcs.git.commit.modal
+
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.serviceAsync
+import com.intellij.openapi.options.advanced.AdvancedSettingsChangeListener
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.startup.ProjectActivity
+import com.intellij.vcs.commit.CommitModeManager
+import kotlinx.coroutines.CoroutineScope
+
+@Service
+internal class GitModalCommitSettingsListener(coroutineScope: CoroutineScope) {
+ init {
+ ApplicationManager.getApplication().messageBus.connect(coroutineScope)
+ .subscribe(AdvancedSettingsChangeListener.TOPIC, object : AdvancedSettingsChangeListener {
+ override fun advancedSettingChanged(id: String, oldValue: Any, newValue: Any) {
+ if (id == GitModalCommitModeProvider.SETTING_ID && oldValue != newValue) {
+ ApplicationManager.getApplication().messageBus.syncPublisher(CommitModeManager.SETTINGS).settingsChanged()
+ }
+ }
+ })
+ }
+
+ internal class InitOnStartup : ProjectActivity {
+ override suspend fun execute(project: Project) {
+ serviceAsync()
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/git4idea/resources/intellij.vcs.git.xml b/plugins/git4idea/resources/intellij.vcs.git.xml
index f7bf265e3be4..8c66b4eb47d5 100644
--- a/plugins/git4idea/resources/intellij.vcs.git.xml
+++ b/plugins/git4idea/resources/intellij.vcs.git.xml
@@ -865,6 +865,7 @@
+
@@ -885,6 +886,9 @@
qualifiedName="Git4Idea.gitPushNotificationCustomizer"
dynamic="true"
area="IDEA_PROJECT"/>
+
diff --git a/plugins/git4idea/src/git4idea/GitVcs.java b/plugins/git4idea/src/git4idea/GitVcs.java
index d8ee88bbf0c5..071f95763912 100644
--- a/plugins/git4idea/src/git4idea/GitVcs.java
+++ b/plugins/git4idea/src/git4idea/GitVcs.java
@@ -18,7 +18,6 @@ import com.intellij.openapi.vcs.rollback.RollbackEnvironment;
import com.intellij.openapi.vcs.update.UpdateEnvironment;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.SystemProperties;
import com.intellij.util.concurrency.annotations.RequiresEdt;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.VcsSynchronousProgressWrapper;
@@ -34,6 +33,7 @@ import git4idea.changes.GitOutgoingChangesProvider;
import git4idea.checkin.GitCheckinEnvironment;
import git4idea.checkin.GitCommitAndPushExecutor;
import git4idea.checkout.GitCheckoutProvider;
+import git4idea.commit.GitCommitModeProvider;
import git4idea.commit.GitStagingAreaCommitMode;
import git4idea.config.*;
import git4idea.diff.GitDiffProvider;
@@ -359,8 +359,9 @@ public final class GitVcs extends AbstractVcs {
if (GitVcsApplicationSettings.getInstance().isStagingAreaEnabled()) {
return GitStagingAreaCommitMode.INSTANCE;
}
- else if (SystemProperties.getBooleanProperty("vcs.force.modal.commit", false)) {
- return CommitMode.ModalCommitMode.INSTANCE;
+ CommitMode commitModeFromExtension = GitCommitModeProvider.EP_NAME.computeSafeIfAny(GitCommitModeProvider::getCommitMode);
+ if (commitModeFromExtension != null) {
+ return commitModeFromExtension;
}
else {
return null;
diff --git a/plugins/git4idea/src/git4idea/commit/GitCommitModeProvider.kt b/plugins/git4idea/src/git4idea/commit/GitCommitModeProvider.kt
new file mode 100644
index 000000000000..8959f7023aab
--- /dev/null
+++ b/plugins/git4idea/src/git4idea/commit/GitCommitModeProvider.kt
@@ -0,0 +1,16 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package git4idea.commit
+
+import com.intellij.openapi.extensions.ExtensionPointName
+import com.intellij.vcs.commit.CommitMode
+import org.jetbrains.annotations.ApiStatus
+
+@ApiStatus.Internal
+interface GitCommitModeProvider {
+ fun getCommitMode(): CommitMode?
+
+ companion object {
+ @JvmField
+ val EP_NAME: ExtensionPointName = ExtensionPointName("Git4Idea.gitCommitModeProvider")
+ }
+}
diff --git a/plugins/git4idea/src/git4idea/commit/GitStagingAreaCommitMode.kt b/plugins/git4idea/src/git4idea/commit/GitStagingAreaCommitMode.kt
index 3ac2befb88c7..6d30860ded1f 100644
--- a/plugins/git4idea/src/git4idea/commit/GitStagingAreaCommitMode.kt
+++ b/plugins/git4idea/src/git4idea/commit/GitStagingAreaCommitMode.kt
@@ -2,6 +2,13 @@
package git4idea.commit
import com.intellij.vcs.commit.CommitMode
+import git4idea.config.GitVcsApplicationSettings
+
+class GitStagingAreaCommitModeProvider : GitCommitModeProvider {
+ override fun getCommitMode(): CommitMode? {
+ return if (GitVcsApplicationSettings.getInstance().isStagingAreaEnabled) GitStagingAreaCommitMode else null
+ }
+}
data object GitStagingAreaCommitMode : CommitMode {
override fun useCommitToolWindow(): Boolean = true