Repository: vackosar/gitflow-incremental-builder
Pull request #192 (2020-07-11 00:08:07)

Adjustments after introduction of disableIfBranchRegex
As discussed here: https://github.com/vackosar/gitflow-incremental-builder/pull/185#pullrequestreview-446707646

/cc @maxxedev 


Patch:
diff --git a/README.md b/README.md
index b2009df..746aa5c 100644
--- a/README.md
+++ b/README.md
@@ -271,7 +271,7 @@ Maven pom properties configuration with default values is below:
 <properties>
     <gib.help>false</gib.help>                                                            <!-- or <gib.h>... -->
     <gib.enabled>true</gib.enabled>                                                       <!-- or <gib.e>... -->
-    <gib.disabledIfBranchRegex>.*</gib.disabledIfBranchRegex>                             <!-- or <gib.dibr>... -->
+    <gib.disableIfBranchRegex></gib.disableIfBranchRegex>                                 <!-- or <gib.dibr>... -->
     <gib.disableBranchComparison>false</gib.disableBranchComparison>                      <!-- or <gib.dbc>... -->
     <gib.referenceBranch>refs/remotes/origin/develop</gib.referenceBranch>                <!-- or <gib.rb>... -->
     <gib.fetchReferenceBranch>false</gib.fetchReferenceBranch>                            <!-- or <gib.frb>... -->
@@ -281,8 +281,8 @@ Maven pom properties configuration with default values is below:
     <gib.compareToMergeBase>true</gib.compareToMergeBase>                                 <!-- or <gib.ctmb>... -->
     <gib.uncommited>true</gib.uncommited>                                                 <!-- or <gib.uc>... -->
     <gib.untracked>true</gib.untracked>                                                   <!-- or <gib.ut>... -->
-    <gib.excludePathRegex>(?!x)x</gib.excludePathRegex>                                   <!-- or <gib.epr>... -->
-    <gib.includePathRegex>.*</gib.includePathRegex>                                       <!-- or <gib.ipr>... -->
+    <gib.excludePathRegex></gib.excludePathRegex>                                         <!-- or <gib.epr>... -->
+    <gib.includePathRegex></gib.includePathRegex>                                         <!-- or <gib.ipr>... -->
     <gib.buildAll>false</gib.buildAll>                                                    <!-- or <gib.ba>... -->
     <gib.buildAllIfNoChanges>false</gib.buildAllIfNoChanges>                              <!-- or <gib.bainc>... -->
     <gib.buildDownstream>always</gib.buildDownstream>                                     <!-- or <gib.bd>... -->
@@ -320,7 +320,9 @@ Can be used to disable this extension temporarily or permanently (e.g. to avoid
 
 ### gib.disabledIfBranchRegex
 
-Can be used to disable this extension only on certain branches (e.g. `master|develop`)
+Can be used to disable this extension on certain branches (e.g. `master|develop`). By default, GIB runs on all branches.
+
+Since: 3.11.0
 
 ### gib.disableBranchComparison
 
@@ -383,7 +385,7 @@ Detects files that are not yet tracked by git (see `git status` manual). This do
 
 ### gib.excludePathRegex
 
-Can be used to exclude certain changed files from being detected as changed, reducing the number of modules to build.
+Can be used to exclude certain changed files from being detected as changed, reducing the number of modules to build. By default, nothing is excluded.
 
 The regular expression does _not_ need to describe the entire (absolute) path, but only the relevant part _inside_ the git repository context. Example:
 ```
@@ -395,7 +397,7 @@ This the opposite of [gib.includePathRegex](#gibincludepathregex) which can be c
 
 ### gib.includePathRegex
 
-Can be used to include only certain changed files from being detected as changed, reducing the number of modules to build.
+Can be used to include only certain changed files from being detected as changed, reducing the number of modules to build. By default, everything is included.
 
 This the opposite of [gib.excludePathRegex](#gibexcludepathregex) which can be combined with this property, but `gib.excludePathRegex` will take precedence.
 
diff --git a/pom.xml b/pom.xml
index c5e402b..e75d2f7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -462,12 +462,12 @@
                                         <limit>
                                             <counter>INSTRUCTION</counter>
                                             <value>COVEREDRATIO</value>
-                                            <minimum>0.91</minimum>
+                                            <minimum>0.92</minimum>
                                         </limit>
                                         <limit>
                                             <counter>BRANCH</counter>
                                             <value>COVEREDRATIO</value>
-                                            <minimum>0.82</minimum>
+                                            <minimum>0.84</minimum>
                                         </limit>
                                         <limit>
                                             <counter>CLASS</counter>
diff --git a/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/Configuration.java b/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/Configuration.java
index 215710b..77fa2f8 100644
--- a/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/Configuration.java
+++ b/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/Configuration.java
@@ -43,8 +43,8 @@ public class Configuration {
     public final boolean compareToMergeBase;
     public final boolean uncommited;
     public final boolean untracked;
-    public final Predicate<String> excludePathRegex;
-    public final Predicate<String> includePathRegex;
+    public final Optional<Predicate<String>> excludePathRegex;
+    public final Optional<Predicate<String>> includePathRegex;
 
     public final boolean buildAll;
     public final boolean buildAllIfNoChanges;
@@ -63,12 +63,7 @@ public class Configuration {
         Properties projectProperties = getProjectProperties(session);
         checkProperties(projectProperties);
 
-        if (Property.Constants.NEVER_MATCH_REGEX.equals(Property.disableIfBranchRegex.getValue(projectProperties))) {
-            disableIfBranchRegex = Optional.empty();
-        } else {
-            Pattern regex = compilePattern(Property.disableIfBranchRegex, projectProperties);
-            disableIfBranchRegex = Optional.of(regex.asPredicate());
-        }
+        disableIfBranchRegex = compileOptionalPatternPredicate(Property.disableIfBranchRegex, projectProperties);
 
         // change detection config
 
@@ -81,8 +76,8 @@ public class Configuration {
         compareToMergeBase = Boolean.valueOf(Property.compareToMergeBase.getValue(projectProperties));
         uncommited = Boolean.valueOf(Property.uncommited.getValue(projectProperties));
         untracked = Boolean.valueOf(Property.untracked.getValue(projectProperties));
-        excludePathRegex = compilePattern(Property.excludePathRegex, projectProperties).asPredicate();
-        includePathRegex = compilePattern(Property.includePathRegex, projectProperties).asPredicate();
+        excludePathRegex = compileOptionalPatternPredicate(Property.excludePathRegex, projectProperties);
+        includePathRegex = compileOptionalPatternPredicate(Property.includePathRegex, projectProperties);
 
         // build config
 
@@ -217,8 +212,10 @@ public class Configuration {
         }
     }
 
-    private static Pattern compilePattern(Property property, Properties projectProperties) {
-        return compilePattern(property.getValue(projectProperties), property);
+    private static Optional<Predicate<String>> compileOptionalPatternPredicate(Property property, Properties projectProperties) {
+        return Optional.ofNullable(property.getValue(projectProperties))
+                .map(patternString -> compilePattern(patternString, property))
+                .map(Pattern::asPredicate);
     }
 
     public static enum BuildUpstreamMode {
diff --git a/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipant.java b/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipant.java
index ce1a296..b89f877 100644
--- a/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipant.java
+++ b/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipant.java
@@ -1,12 +1,11 @@
 package com.vackosar.gitflowincrementalbuild.boundary;
 
 import com.vackosar.gitflowincrementalbuild.control.Property;
-import com.vackosar.gitflowincrementalbuild.control.jgit.GitFactory;
+import com.vackosar.gitflowincrementalbuild.control.jgit.GitProvider;
 import com.vackosar.gitflowincrementalbuild.entity.SkipExecutionException;
 import org.apache.maven.AbstractMavenLifecycleParticipant;
 import org.apache.maven.MavenExecutionException;
 import org.apache.maven.execution.MavenSession;
-import org.eclipse.jgit.api.Git;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -15,6 +14,7 @@ import javax.inject.Named;
 import javax.inject.Singleton;
 
 import java.io.IOException;
+import java.io.UncheckedIOException;
 
 @Singleton
 @Named
@@ -26,6 +26,8 @@ public class MavenLifecycleParticipant extends AbstractMavenLifecycleParticipant
 
     @Inject private Configuration.Provider configProvider;
 
+    @Inject private GitProvider gitProvider;
+
     private final String implVersion;
 
     public MavenLifecycleParticipant() {
@@ -39,14 +41,6 @@ public class MavenLifecycleParticipant extends AbstractMavenLifecycleParticipant
 
     @Override
     public void afterProjectsRead(MavenSession session) throws MavenExecutionException {
-        try {
-            applyPlugin(session);
-        } finally {
-            GitFactory.destroy();
-        }
-    }
-
-    private void applyPlugin(MavenSession session) throws MavenExecutionException {
 
         if (Configuration.isHelpRequested(session)) {
             logHelp();
@@ -66,7 +60,16 @@ public class MavenLifecycleParticipant extends AbstractMavenLifecycleParticipant
         }
 
         try {
-            if (isDisabledForBranch(session)) {
+            perform();
+        } finally {
+            gitProvider.close();
+        }
+    }
+
+    private void perform() throws MavenExecutionException {
+
+        try {
+            if (isDisabledForBranch()) {
                 logger.info("gitflow-incremental-builder is disabled for this branch.");
                 return;
             }
@@ -85,15 +88,14 @@ public class MavenLifecycleParticipant extends AbstractMavenLifecycleParticipant
         logger.info("gitflow-incremental-builder exiting...");
     }
 
-    private boolean isDisabledForBranch(MavenSession session) throws IOException {
-        Configuration configuration = configProvider.get();
-        if (!configuration.disableIfBranchRegex.isPresent()) {
-            return false;
-        }
-        
-        Git git = GitFactory.getOrCreateThreadLocalGit(session, configuration);
-        String branchName = git.getRepository().getBranch();
-        return configuration.disableIfBranchRegex.get().test(branchName);
+    private boolean isDisabledForBranch() {
+        return configProvider.get().disableIfBranchRegex.map(predicate -> {
+            try {
+                return predicate.test(gitProvider.get().getRepository().getBranch());
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        }).orElse(false);
     }
 
     private void logHelp() {
diff --git a/src/main/java/com/vackosar/gitflowincrementalbuild/control/DifferentFiles.java b/src/main/java/com/vackosar/gitflowincrementalbuild/control/DifferentFiles.java
index 4ca7d5b..1a6ee6e 100644
--- a/src/main/java/com/vackosar/gitflowincrementalbuild/control/DifferentFiles.java
+++ b/src/main/java/com/vackosar/gitflowincrementalbuild/control/DifferentFiles.java
@@ -2,9 +2,8 @@ package com.vackosar.gitflowincrementalbuild.control;
 
 import com.vackosar.gitflowincrementalbuild.boundary.Configuration;
 import com.vackosar.gitflowincrementalbuild.control.jgit.AgentProxyAwareJschConfigSessionFactory;
-import com.vackosar.gitflowincrementalbuild.control.jgit.GitFactory;
+import com.vackosar.gitflowincrementalbuild.control.jgit.GitProvider;
 import com.vackosar.gitflowincrementalbuild.control.jgit.HttpDelegatingCredentialsProvider;
-import org.apache.maven.execution.MavenSession;
 import org.eclipse.jgit.api.FetchCommand;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.Status;
@@ -45,8 +44,8 @@ public class DifferentFiles {
 
     private Logger logger = LoggerFactory.getLogger(DifferentFiles.class);
 
-    @Inject private MavenSession mavenSession;
     @Inject private Configuration.Provider configProvider;
+    @Inject private GitProvider gitProvider;
 
     private final Map<String, String> additionalNativeGitEnvironment = new HashMap<>();
 
@@ -56,8 +55,7 @@ public class DifferentFiles {
         Configuration configuration = configProvider.get();
         Worker worker = null;
         try {
-            Git git = GitFactory.getOrCreateThreadLocalGit(mavenSession, configuration);
-            worker = new Worker(git, configuration);
+            worker = new Worker(gitProvider.get(), configuration);
 
             worker.fetch();
             worker.checkout();
@@ -220,9 +218,10 @@ public class DifferentFiles {
         }
 
         private boolean pathIncluded(Path path) {
-            boolean excluded = configuration.excludePathRegex.test(path.toString());
-            boolean included = !excluded && configuration.includePathRegex.test(path.toString());
-            logger.debug("included {}: {}", included, path);
+            final String pathString = path.toString();
+            boolean excluded = configuration.excludePathRegex.map(pred -> pred.test(pathString)).orElse(false);
+            boolean included = !excluded && configuration.includePathRegex.map(pred -> pred.test(pathString)).orElse(true);
+            logger.debug("included {}: {}", included, pathString);
             return included;
         }
     }
diff --git a/src/main/java/com/vackosar/gitflowincrementalbuild/control/Property.java b/src/main/java/com/vackosar/gitflowincrementalbuild/control/Property.java
index 7cc0a7a..b74237e 100644
--- a/src/main/java/com/vackosar/gitflowincrementalbuild/control/Property.java
+++ b/src/main/java/com/vackosar/gitflowincrementalbuild/control/Property.java
@@ -13,7 +13,7 @@ import java.util.stream.Stream;
 public enum Property {
     help("false", "h", true),
     enabled("true", "e", true),
-    disableIfBranchRegex(Constants.NEVER_MATCH_REGEX, "dibr"),
+    disableIfBranchRegex(null, "dibr"),
 
     disableBranchComparison("false", "dbc", true),
     referenceBranch("refs/remotes/origin/develop", "rb"),
@@ -24,8 +24,8 @@ public enum Property {
     compareToMergeBase("true", "ctmb", true),
     uncommited("true", "uc", true),
     untracked("true", "ut", true),
-    excludePathRegex(Constants.NEVER_MATCH_REGEX, "epr"),
-    includePathRegex(Constants.ALWAYS_MATCH_REGEX, "ipr"),
+    excludePathRegex(null, "epr"),
+    includePathRegex(null, "ipr"),
 
     buildAll("false", "ba", true),
     buildAllIfNoChanges("false", "bainc", true),
@@ -133,9 +133,4 @@ public enum Property {
         builder.append("</properties>\n");
         return builder.toString();
     }
-
-    public static interface Constants {
-        public static final String ALWAYS_MATCH_REGEX = ".*";
-        public static final String NEVER_MATCH_REGEX = "(?!x)x";
-    }
 }
diff --git a/src/main/java/com/vackosar/gitflowincrementalbuild/control/jgit/GitFactory.java b/src/main/java/com/vackosar/gitflowincrementalbuild/control/jgit/GitProvider.java
similarity index 67%
rename from src/main/java/com/vackosar/gitflowincrementalbuild/control/jgit/GitFactory.java
rename to src/main/java/com/vackosar/gitflowincrementalbuild/control/jgit/GitProvider.java
index d184504..0a2b4a8 100644
--- a/src/main/java/com/vackosar/gitflowincrementalbuild/control/jgit/GitFactory.java
+++ b/src/main/java/com/vackosar/gitflowincrementalbuild/control/jgit/GitProvider.java
@@ -1,51 +1,70 @@
 package com.vackosar.gitflowincrementalbuild.control.jgit;
 
-import com.vackosar.gitflowincrementalbuild.boundary.Configuration;
-import com.vackosar.gitflowincrementalbuild.entity.SkipExecutionException;
-import org.apache.maven.execution.MavenSession;
-import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.io.File;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.nio.file.Path;
 import java.util.Objects;
 import java.util.Optional;
 
-public class GitFactory {
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.execution.MavenSession;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.vackosar.gitflowincrementalbuild.boundary.Configuration;
+import com.vackosar.gitflowincrementalbuild.entity.SkipExecutionException;
 
-    private static final Logger logger = LoggerFactory.getLogger(GitFactory.class);
+@Singleton
+@Named
+public class GitProvider implements Provider<Git> {
 
     private static final String UNSUPPORTED_WORKTREE = "JGit unsupported separate worktree checkout detected from current git dir path: ";
 
-    private static final ThreadLocal<Git> threadLocal = new ThreadLocal<>();
-    
-    public static Git getOrCreateThreadLocalGit(MavenSession mavenSession, Configuration configuration) throws IOException {
-        if (threadLocal.get() != null) {
-            return threadLocal.get();
+    private Logger logger = LoggerFactory.getLogger(GitProvider.class);
+
+    private final MavenSession mavenSession;
+    private final Configuration configuration;
+
+    private Git git;
+
+    @Inject
+    public GitProvider(MavenSession mavenSession, Configuration configuration) {
+        this.mavenSession = mavenSession;
+        this.configuration = configuration;
+    }
+
+    /**
+     * Returns a {@link Git} instance which is constructed when first called. Subsequent calls will return the same instance.
+     *
+     * @return a {@link Git} instance
+     */
+    @Override
+    public Git get() {
+        if (git == null) {
+            try {
+                git = setupGit();
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
         }
-        Git git = setupGit(mavenSession, configuration);
-        threadLocal.set(git);
         return git;
     }
-    
-    public static void bind(Git git) {
-        destroy();
-        threadLocal.set(git);
-    }
 
-    public static void destroy() {
-        Git git = threadLocal.get();
-        threadLocal.remove();
+    public void close() {
         if (git != null) {
             git.close();
             git.getRepository().close();
         }
     }
 
-    private static Git setupGit(MavenSession mavenSession, Configuration configuration) throws IOException {
+    private Git setupGit() throws IOException {
         final FileRepositoryBuilder builder = new FileRepositoryBuilder();
         File pomDir = mavenSession.getCurrentProject().getBasedir().toPath().toFile();
         builder.findGitDir(pomDir);
@@ -73,8 +92,4 @@ public class GitFactory {
                 .map(parentParent -> parentParent.getFileName().toString().equals(".git"))
                 .orElse(false);
     }
-
-    private GitFactory() {
-        throw new AssertionError();
-    }
-}
\ No newline at end of file
+}


Test patch:
diff --git a/src/test/java/com/vackosar/gitflowincrementalbuild/BaseRepoTest.java b/src/test/java/com/vackosar/gitflowincrementalbuild/BaseRepoTest.java
index 95cba17..1fe474f 100644
--- a/src/test/java/com/vackosar/gitflowincrementalbuild/BaseRepoTest.java
+++ b/src/test/java/com/vackosar/gitflowincrementalbuild/BaseRepoTest.java
@@ -1,7 +1,6 @@
 package com.vackosar.gitflowincrementalbuild;
 
 import com.vackosar.gitflowincrementalbuild.control.Property;
-import com.vackosar.gitflowincrementalbuild.control.jgit.GitFactory;
 import com.vackosar.gitflowincrementalbuild.mocks.LocalRepoMock;
 import com.vackosar.gitflowincrementalbuild.mocks.MavenSessionMock;
 import com.vackosar.gitflowincrementalbuild.mocks.server.TestServerType;
@@ -76,7 +75,6 @@ public abstract class BaseRepoTest {
 
     @AfterEach
     protected void after() throws Exception {
-        GitFactory.destroy();
         if (localRepoMock != null) {
             localRepoMock.close();
         }
diff --git a/src/test/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipantTest.java b/src/test/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipantTest.java
index 0fc9de2..3bf79f3 100644
--- a/src/test/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipantTest.java
+++ b/src/test/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipantTest.java
@@ -2,7 +2,7 @@ package com.vackosar.gitflowincrementalbuild.boundary;
 
 import com.vackosar.gitflowincrementalbuild.LoggerSpyUtil;
 import com.vackosar.gitflowincrementalbuild.control.Property;
-import com.vackosar.gitflowincrementalbuild.control.jgit.GitFactory;
+import com.vackosar.gitflowincrementalbuild.control.jgit.GitProvider;
 import com.vackosar.gitflowincrementalbuild.entity.SkipExecutionException;
 import org.apache.maven.MavenExecutionException;
 import org.apache.maven.execution.MavenExecutionRequest;
@@ -11,7 +11,6 @@ import org.apache.maven.execution.ProjectDependencyGraph;
 import org.apache.maven.project.MavenProject;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.lib.Repository;
-import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -29,7 +28,6 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.contains;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -50,6 +48,9 @@ public class MavenLifecycleParticipantTest {
     @Mock
     private UnchangedProjectsRemover unchangedProjectsRemoverMock;
 
+    @Mock
+    private GitProvider gitProviderMock;
+
     @InjectMocks
     private MavenLifecycleParticipant underTest = new MavenLifecycleParticipant(TEST_IMPL_VERSION);
 
@@ -67,11 +68,6 @@ public class MavenLifecycleParticipantTest {
 
         Whitebox.setInternalState(underTest, new Configuration.Provider(mavenSessionMock));
     }
-    
-    @AfterEach
-    void after() {
-        GitFactory.destroy();
-    }
 
     @Test
     public void defaultlyEnabled() throws Exception {
@@ -190,10 +186,9 @@ public class MavenLifecycleParticipantTest {
     private void mockCurrentBranch(String branchName) throws IOException {
         Git git = mock(Git.class);
         Repository repository = mock(Repository.class);
-        doReturn(repository).when(git).getRepository();
-        doReturn(branchName).when(repository).getBranch();
-        
-        GitFactory.bind(git);
+        when(git.getRepository()).thenReturn(repository);
+        when(repository.getBranch()).thenReturn(branchName);
+        when(gitProviderMock.get()).thenReturn(git);
     }
 
     private void verifyHelpLogged(boolean logged) {
diff --git a/src/test/java/com/vackosar/gitflowincrementalbuild/control/BaseChangedProjectsTest.java b/src/test/java/com/vackosar/gitflowincrementalbuild/control/BaseChangedProjectsTest.java
index 46d428d..55c39c7 100644
--- a/src/test/java/com/vackosar/gitflowincrementalbuild/control/BaseChangedProjectsTest.java
+++ b/src/test/java/com/vackosar/gitflowincrementalbuild/control/BaseChangedProjectsTest.java
@@ -4,9 +4,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import com.vackosar.gitflowincrementalbuild.BaseRepoTest;
 import com.vackosar.gitflowincrementalbuild.boundary.Configuration;
+import com.vackosar.gitflowincrementalbuild.control.jgit.GitProvider;
 
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.project.MavenProject;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -45,18 +47,28 @@ public abstract class BaseChangedProjectsTest extends BaseRepoTest {
     protected ChangedProjects underTest;
 
     private MavenSession mavenSessionMock;
+    private GitProvider gitProvider;
 
     public BaseChangedProjectsTest(boolean useSymLinkedFolder) {
         super(useSymLinkedFolder, /* remoteRepoServerType */ null);
     }
 
     @BeforeEach
-    void injectMavenSessionMock() throws Exception {
+    void injectMavenSessionMockAndGitProvider() throws Exception {
         mavenSessionMock = getMavenSessionMock();
-        Whitebox.setInternalState(differentFilesSpy, mavenSessionMock, new Configuration.Provider(mavenSessionMock));
+        Configuration.Provider configProvider = new Configuration.Provider(mavenSessionMock);
+        gitProvider = new GitProvider(mavenSessionMock, configProvider.get());
+        Whitebox.setInternalState(differentFilesSpy, configProvider, gitProvider);
         Whitebox.setInternalState(underTest, mavenSessionMock);
     }
 
+    @AfterEach
+    void closeGitProvider() {
+        if (gitProvider != null) {
+            gitProvider.close();
+        }
+    }
+
     @Test
     public void list() throws Exception {
         final Set<Path> expected = new HashSet<>(Arrays.asList(
diff --git a/src/test/java/com/vackosar/gitflowincrementalbuild/control/BaseDifferentFilesTest.java b/src/test/java/com/vackosar/gitflowincrementalbuild/control/BaseDifferentFilesTest.java
index 2cab3fd..3ddbd1a 100644
--- a/src/test/java/com/vackosar/gitflowincrementalbuild/control/BaseDifferentFilesTest.java
+++ b/src/test/java/com/vackosar/gitflowincrementalbuild/control/BaseDifferentFilesTest.java
@@ -3,7 +3,7 @@ package com.vackosar.gitflowincrementalbuild.control;
 import com.vackosar.gitflowincrementalbuild.BaseRepoTest;
 import com.vackosar.gitflowincrementalbuild.LoggerSpyUtil;
 import com.vackosar.gitflowincrementalbuild.boundary.Configuration;
-import com.vackosar.gitflowincrementalbuild.control.jgit.GitFactory;
+import com.vackosar.gitflowincrementalbuild.control.jgit.GitProvider;
 import com.vackosar.gitflowincrementalbuild.mocks.server.TestServerType;
 import org.apache.maven.execution.MavenSession;
 import org.eclipse.jgit.api.Git;
@@ -50,7 +50,6 @@ public abstract class BaseDifferentFilesTest extends BaseRepoTest {
     @Override
     @AfterEach
     protected void after() throws Exception {
-        GitFactory.destroy();
         FS.DETECTED.setUserHome(jGitUserHomeBackup);
         super.after();
     }
@@ -77,13 +76,20 @@ public abstract class BaseDifferentFilesTest extends BaseRepoTest {
         mavenSessionMock.getTopLevelProject().getProperties().putAll(projectProperties);
 
         DifferentFiles underTest = new DifferentFiles();
-        Whitebox.setInternalState(underTest, mavenSessionMock, new Configuration.Provider(mavenSessionMock), loggerSpy);
+        Configuration.Provider configProvider = new Configuration.Provider(mavenSessionMock);
+        GitProvider gitProvider = new GitProvider(mavenSessionMock, configProvider.get());
+        Whitebox.setInternalState(underTest, configProvider, gitProvider, loggerSpy);
 
         // isolate a possible native git invocation from the settings of the system the test is runing on
         underTest.putAdditionalNativeGitEnvironment("GIT_CONFIG_NOSYSTEM", "1");
         underTest.putAdditionalNativeGitEnvironment("HOME", userHome.toAbsolutePath().toString());
 
-        Set<Path> result = underTest.get();
+        Set<Path> result;
+        try {
+            result = underTest.get();
+        } finally {
+            gitProvider.close();
+        }
 
         assertNotNull(result, "Resulting set is unexpectedly null");
         return result;
diff --git a/src/test/java/com/vackosar/gitflowincrementalbuild/jgit/GitFactoryTest.java b/src/test/java/com/vackosar/gitflowincrementalbuild/jgit/GitProviderTest.java
similarity index 58%
rename from src/test/java/com/vackosar/gitflowincrementalbuild/jgit/GitFactoryTest.java
rename to src/test/java/com/vackosar/gitflowincrementalbuild/jgit/GitProviderTest.java
index 9f453e5..09e386e 100644
--- a/src/test/java/com/vackosar/gitflowincrementalbuild/jgit/GitFactoryTest.java
+++ b/src/test/java/com/vackosar/gitflowincrementalbuild/jgit/GitProviderTest.java
@@ -2,15 +2,16 @@ package com.vackosar.gitflowincrementalbuild.jgit;
 
 import com.google.common.io.Files;
 import com.vackosar.gitflowincrementalbuild.boundary.Configuration;
-import com.vackosar.gitflowincrementalbuild.control.jgit.GitFactory;
+import com.vackosar.gitflowincrementalbuild.control.jgit.GitProvider;
 import com.vackosar.gitflowincrementalbuild.entity.SkipExecutionException;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.project.MavenProject;
-import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.lib.Repository;
 import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
 
 import java.io.File;
 import java.io.IOException;
@@ -18,50 +19,41 @@ import java.io.IOException;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoInteractions;
 
-public class GitFactoryTest {
+@ExtendWith(MockitoExtension.class)
+public class GitProviderTest {
 
-    private MavenSession mavenSessionMock = mock(MavenSession.class);
-    private Configuration configuration = mock(Configuration.class);
+    @Mock
+    private MavenSession mavenSessionMock;
+    @Mock
+    private Configuration configuration;
 
-    private void initSimple() throws IOException {
-        MavenProject mavenProject = new MavenProject();
-        File pomXmlInCwd = new File("pom.xml").getCanonicalFile();
-        File pomXmlInParent = new File("..", "pom.xml").getCanonicalFile();
-        mavenProject.setFile(pomXmlInParent);
-        if (pomXmlInCwd.exists()) {
-            mavenProject.setFile(pomXmlInCwd);
-        }
-        doReturn(mavenProject).when(mavenSessionMock).getCurrentProject();
-    }
+    @InjectMocks
+    private GitProvider underTest;
 
-    @BeforeEach
     @AfterEach
     public void tearDown() {
-        GitFactory.destroy();
+        underTest.close();
     }
 
     @Test
     public void test_simple() throws IOException {
         initSimple();
-        assertNotNull(GitFactory.getOrCreateThreadLocalGit(mavenSessionMock, configuration));
-        
+        assertNotNull(underTest.get());
+
         verify(mavenSessionMock).getCurrentProject();
     }
-    
-    @Test
-    public void test_bind() throws IOException {
-        Git git = mock(Git.class);
-        Repository repository = mock(Repository.class);
-        doReturn(repository).when(git).getRepository();
-        
-        GitFactory.bind(git);
-        assertNotNull(GitFactory.getOrCreateThreadLocalGit(mavenSessionMock, configuration));
-        
-        verifyNoInteractions(mavenSessionMock, configuration);
+
+    private void initSimple() throws IOException {
+        MavenProject mavenProject = new MavenProject();
+        File pomXmlInCwd = new File("pom.xml").getCanonicalFile();
+        File pomXmlInParent = new File("..", "pom.xml").getCanonicalFile();
+        mavenProject.setFile(pomXmlInParent);
+        if (pomXmlInCwd.exists()) {
+            mavenProject.setFile(pomXmlInCwd);
+        }
+        doReturn(mavenProject).when(mavenSessionMock).getCurrentProject();
     }
 
     @Test
@@ -73,6 +65,6 @@ public class GitFactoryTest {
         mavenProject.setFile(pom);
         doReturn(mavenProject).when(mavenSessionMock).getCurrentProject();
 
-        assertThrows(SkipExecutionException.class, () -> GitFactory.getOrCreateThreadLocalGit(mavenSessionMock, configuration));
+        assertThrows(SkipExecutionException.class, underTest::get);
     }
 }
\ No newline at end of file