Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Release with new features and bugfixes:
* https://github.com/devonfw/IDEasy/issues/1904[#1904]: Add Inso CLI to IDEasy commandlets
* https://github.com/devonfw/IDEasy/issues/1952[#1952]: Ability for platform specific dependencies
* https://github.com/devonfw/IDEasy/issues/1950[#1950]: Fix exit autocompletion
* https://github.com/devonfw/IDEasy/issues/1958[#1958]: Fix git pull on settings with local branch without remote

The full list of changes for this release can be found in https://github.com/devonfw/IDEasy/milestone/44?closed=1[milestone 2026.05.001].

Expand Down
60 changes: 59 additions & 1 deletion cli/src/main/java/com/devonfw/tools/ide/git/GitContextImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ public boolean fetchIfNeeded(Path repository, String remote, String branch) {
@Override
public boolean isRepositoryUpdateAvailable(Path repository) {

if (!hasUpstream(repository)) {
return false;
}
String localFailureMessage = String.format("Failed to get the local commit id of settings repository '%s'.", repository);
String remoteFailureMessage = String.format("Failed to get the remote commit id of settings repository '%s', missing remote upstream branch?", repository);
String localCommitId = runGitCommandAndGetSingleOutput(localFailureMessage, repository, ProcessMode.DEFAULT_CAPTURE, "rev-parse", "HEAD");
Expand All @@ -78,9 +81,14 @@ public boolean isRepositoryUpdateAvailable(Path repository, Path trackedCommitId
LOG.warn("Commit ID was not present at {}", trackedCommitIdPath);
return true;
}

if (!hasUpstream(repository)) {
return false;
}
String remoteFailureMessage = String.format("Failed to get the remote commit id of settings repository '%s', missing remote upstream branch?", repository);
String remoteCommitId = runGitCommandAndGetSingleOutput(remoteFailureMessage, repository, ProcessMode.DEFAULT_CAPTURE, "rev-parse", "@{u}");
if (remoteCommitId == null) {
return false;
}
return !trackedCommitId.equals(remoteCommitId);
}

Expand Down Expand Up @@ -382,6 +390,56 @@ private Path findGitInPath(Path gitPath) {
return binaryGitPath;
}

/**
* Retrieves an optional git config value from the given repository.
*
* @param directory the git repository directory.
* @param key the git config key.
* @return the config value or {@code null} if not available.
*/
private String getOptionalGitConfigValue(Path directory, String key) {

ProcessResult result = runGitCommand(
directory,
ProcessMode.DEFAULT_CAPTURE,
ProcessErrorHandling.NONE,
"config",
"--get",
key
);

if (result.isSuccessful() && result.getOut().size() == 1) {
return result.getOut().getFirst();
}

return null;

}

/**
* Checks if the current branch has an upstream remote branch configured.
*
* @param repository the git repository directory.
* @return {@code true} if an upstream is configured, {@code false} otherwise.
*/
private boolean hasUpstream(Path repository) {

String branch = determineCurrentBranch(repository);
if ((branch == null) || branch.isBlank()) {
return false;
}

String remote = getOptionalGitConfigValue(repository, "branch." + branch + ".remote");
String merge = getOptionalGitConfigValue(repository, "branch." + branch + ".merge");

if ((remote == null) || (merge == null)) {
LOG.warn("No upstream configured for branch {} in settings repository {}. Please switch to a branch with remote upstream.", branch, repository);
return false;
}

return true;
}

private void runGitCommand(Path directory, String... args) {

ProcessResult result = runGitCommand(directory, ProcessMode.DEFAULT, args);
Expand Down
Loading