From ef0815a002ce6a0a61a6e4d6be39da49993a6ba2 Mon Sep 17 00:00:00 2001 From: Paras14 Date: Thu, 27 Aug 2026 08:59:49 +0200 Subject: [PATCH 1/3] #840: Replace determineRemote with getRemotes and fetch from tracked remote --- .../com/devonfw/tools/ide/git/GitContext.java | 4 +- .../devonfw/tools/ide/git/GitContextImpl.java | 22 +++++++---- .../tools/ide/git/GitContextImplMock.java | 4 +- .../devonfw/tools/ide/git/GitContextMock.java | 4 +- .../devonfw/tools/ide/git/GitContextTest.java | 39 +++++++++++++++++++ 5 files changed, 59 insertions(+), 14 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/git/GitContext.java b/cli/src/main/java/com/devonfw/tools/ide/git/GitContext.java index e77957d290..b664e989b5 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/git/GitContext.java +++ b/cli/src/main/java/com/devonfw/tools/ide/git/GitContext.java @@ -241,9 +241,9 @@ default void reset(Path repository, String branch) { /** * @param repository the {@link Path} to the folder where the git repository is located. - * @return the name of the default origin. + * @return the {@link List} with the names of all configured remotes (e.g. "origin"), or an empty {@link List} if the repository has no remote configured. */ - String determineRemote(Path repository); + List getRemotes(Path repository); /** * Saves the current git commit ID of a repository to a file given as an argument. diff --git a/cli/src/main/java/com/devonfw/tools/ide/git/GitContextImpl.java b/cli/src/main/java/com/devonfw/tools/ide/git/GitContextImpl.java index 49adbb59cd..eeec3f922f 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/git/GitContextImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/git/GitContextImpl.java @@ -172,8 +172,7 @@ public void pullOrClone(GitUrl gitUrl, Path repository) { Objects.requireNonNull(gitUrl); if (Files.isDirectory(repository.resolve(GIT_FOLDER))) { // checks for remotes - String remote = determineRemote(repository); - if (remote == null) { + if (getRemotes(repository).isEmpty()) { String message = repository + " is a local git repository with no remote - if you did this for testing, you may continue...\n" + "Do you want to ignore the problem and continue anyhow?"; this.context.askToContinue(message); @@ -258,14 +257,16 @@ public void fetch(Path repository, String remote, String branch) { if (branch == null) { branch = determineCurrentBranch(repository); } - if (remote == null) { - remote = determineRemote(repository); + if ((remote == null) && (branch != null)) { + // the remote to fetch from is the one the current branch is tracking (see also "git rev-parse @{u}") + remote = getOptionalGitConfigValue(repository, "branch." + branch + ".remote"); } + String effectiveRemote = Objects.requireNonNullElse(remote, "origin"); - ProcessResult result = runGitCommand(repository, ProcessMode.DEFAULT_CAPTURE, "fetch", Objects.requireNonNullElse(remote, "origin"), branch); + ProcessResult result = runGitCommand(repository, ProcessMode.DEFAULT_CAPTURE, "fetch", effectiveRemote, branch); if (!result.isSuccessful()) { - LOG.warn("Git fetch for '{}/{} failed.'.", remote, branch); + LOG.warn("Git fetch for '{}/{} failed.'.", effectiveRemote, branch); } } @@ -276,9 +277,14 @@ public String determineCurrentBranch(Path repository) { } @Override - public String determineRemote(Path repository) { + public List getRemotes(Path repository) { - return runGitCommandAndGetSingleOutput("Failed to determine current origin of git repository.", repository, "remote"); + ProcessResult result = runGitCommand(repository, ProcessMode.DEFAULT_CAPTURE, ProcessErrorHandling.NONE, "remote"); + if (!result.isSuccessful()) { + LOG.warn("Failed to determine the remotes of git repository {}.", repository); + return List.of(); + } + return result.getOut(); } @Override diff --git a/cli/src/test/java/com/devonfw/tools/ide/git/GitContextImplMock.java b/cli/src/test/java/com/devonfw/tools/ide/git/GitContextImplMock.java index c5f6aa1855..c10925639d 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/git/GitContextImplMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/git/GitContextImplMock.java @@ -65,9 +65,9 @@ public void clone(GitUrl gitUrl, Path repository) { } @Override - public String determineRemote(Path repository) { + public List getRemotes(Path repository) { - return DEFAULT_REMOTE; + return List.of(DEFAULT_REMOTE); } @Override diff --git a/cli/src/test/java/com/devonfw/tools/ide/git/GitContextMock.java b/cli/src/test/java/com/devonfw/tools/ide/git/GitContextMock.java index d794f0ad12..735d8999bd 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/git/GitContextMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/git/GitContextMock.java @@ -256,8 +256,8 @@ public String determineCurrentBranch(Path repository) { } @Override - public String determineRemote(Path repository) { - return DEFAULT_REMOTE; + public List getRemotes(Path repository) { + return List.of(DEFAULT_REMOTE); } /** diff --git a/cli/src/test/java/com/devonfw/tools/ide/git/GitContextTest.java b/cli/src/test/java/com/devonfw/tools/ide/git/GitContextTest.java index 745e1802bd..23f19be827 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/git/GitContextTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/git/GitContextTest.java @@ -123,6 +123,45 @@ void testRunGitPullWithoutForce(@TempDir Path tempDir) { assertThat(tempDir.resolve(GitContext.GIT_FOLDER).resolve("update")).hasContent(this.processContext.getNow().toString()); } + /** + * Runs a simulated git pull on a repository with multiple remotes configured and checks that the pull is performed instead of asking the user to continue. See + * issue #840. + * + * @param tempDir a {@link TempDir} {@link Path}. + */ + @Test + void testRunGitPullWithMultipleRemotes(@TempDir Path tempDir) { + + // arrange + String gitRepoUrl = "https://github.com/test"; + IdeTestContext context = newGitContext(tempDir); + this.processContext.addOutputMessage(new OutputMessage(false, "origin")); + this.processContext.addOutputMessage(new OutputMessage(false, "upstream")); + FileAccess fileAccess = new FileAccessImpl(context); + fileAccess.mkdirs(tempDir.resolve(GitContext.GIT_FOLDER)); + // act + context.getGitContext().pullOrClone(GitUrl.of(gitRepoUrl), tempDir); + // assert + assertThat(tempDir.resolve(GitContext.GIT_FOLDER).resolve("update")).hasContent(this.processContext.getNow().toString()); + } + + /** + * Runs a simulated git pull on a repository without any remote and checks that the user is asked whether to continue. + * + * @param tempDir a {@link TempDir} {@link Path}. + */ + @Test + void testRunGitPullWithoutRemoteAsksToContinue(@TempDir Path tempDir) { + + // arrange + String gitRepoUrl = "https://github.com/test"; + IdeTestContext context = newGitContext(tempDir); + FileAccess fileAccess = new FileAccessImpl(context); + fileAccess.mkdirs(tempDir.resolve(GitContext.GIT_FOLDER)); + // act + assert (no answers are configured, so asking a question fails) + assertThrows(IllegalStateException.class, () -> context.getGitContext().pullOrClone(GitUrl.of(gitRepoUrl), tempDir)); + } + /** * Runs a git pull with force mode, creates temporary files to simulate a proper cleanup. * From cdc08b08de9915404e99313981b2bb7a093e8e63 Mon Sep 17 00:00:00 2001 From: Paras14 Date: Thu, 27 Aug 2026 09:18:27 +0200 Subject: [PATCH 2/3] #840: Apply mvn spotless --- .../test/java/com/devonfw/tools/ide/git/GitContextTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/git/GitContextTest.java b/cli/src/test/java/com/devonfw/tools/ide/git/GitContextTest.java index 23f19be827..4dc3304c26 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/git/GitContextTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/git/GitContextTest.java @@ -225,7 +225,7 @@ void testRunGitPullWithForceStartsCleanup(@TempDir Path tempDir) { @Test void testGitRepoIsRecognizedCorrectly(@TempDir Path tempDir) { String gitRepoUrl = "https://github.com/test"; - + IdeTestContext context = newGitContext(tempDir); GitContext gitContext = context.getGitContext(); @@ -238,7 +238,7 @@ void testGitRepoIsRecognizedCorrectly(@TempDir Path tempDir) { void testNormalDirIsNoRepo(@TempDir Path tempDir) { IdeTestContext context = newGitContext(tempDir); GitContext gitContext = context.getGitContext(); - + FileAccess fileAccess = context.getFileAccess(); fileAccess.mkdirs(tempDir.resolve("new-folder")); From da4eee42a8af5f28300b65e8924b659b7a2de042 Mon Sep 17 00:00:00 2001 From: Paras14 Date: Thu, 27 Aug 2026 10:58:08 +0200 Subject: [PATCH 3/3] #840: Fix line length --- .../test/java/com/devonfw/tools/ide/git/GitContextTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/git/GitContextTest.java b/cli/src/test/java/com/devonfw/tools/ide/git/GitContextTest.java index 4dc3304c26..04bed3b1e9 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/git/GitContextTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/git/GitContextTest.java @@ -124,8 +124,8 @@ void testRunGitPullWithoutForce(@TempDir Path tempDir) { } /** - * Runs a simulated git pull on a repository with multiple remotes configured and checks that the pull is performed instead of asking the user to continue. See - * issue #840. + * Runs a simulated git pull on a repository with multiple remotes configured and checks that the pull is performed instead of asking the user to continue. + * See issue #840. * * @param tempDir a {@link TempDir} {@link Path}. */