Skip to content

Conversation

@wanling0000
Copy link
Collaborator

Closes #12350

This PR includes two major improvements:

  1. Decoupled GitHandler creation using a new GitHandlerRegistry

    • Ensures a single GitHandler instance per Git repository root.
  2. Improved semantic conflict detection logic

    • Updated SemanticConflictDetector to better handle edge cases in entry-level conflicts

Steps to test

All changes are covered by new or updated unit tests:

  • SemanticConflictDetectorTest covers the new edge cases for entry-level conflict detection.
  • GitHandlerRegistryTest verifies consistent handler retrieval and repo root resolution.

Mandatory checks

  • I own the copyright of the code submitted and I license it under the MIT license
  • [/] Change in CHANGELOG.md described in a way that is understandable for the average user (if change is visible to the user)
  • Tests created for changes (if applicable)
  • Manually tested changed features in running JabRef (always required)
  • [/] Screenshots added in PR description (if change is visible to the user)
  • [/] Checked developer's documentation: Is the information available and up to date? If not, I outlined it in this pull request.
  • Checked documentation: Is the information available and up to date? If not, I created an issue at https://github.com/JabRef/user-documentation/issues or, even better, I submitted a pull request to the documentation repository.

Decouple GitHandler creation via GitHandlerRegistry
@wanling0000 wanling0000 force-pushed the fix/semantic-conflict-logic branch from da6b7c8 to 267a42f Compare August 6, 2025 11:19
@wanling0000 wanling0000 force-pushed the fix/semantic-conflict-logic branch from 267a42f to 687698c Compare August 6, 2025 11:40
Comment on lines +87 to +88
boolean localDeleted = local == null;
boolean remoteDeleted = remote == null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
boolean localDeleted = local == null;
boolean remoteDeleted = remote == null;
boolean localDeleted = (local == null);
boolean remoteDeleted = (remote == null);

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like each time it is changed by OpenRewrite

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can skip then

Comment on lines 89 to 90
boolean localChanged = !localDeleted && !Objects.equals(base.getFieldMap(), local.getFieldMap());
boolean remoteChanged = !remoteDeleted && !Objects.equals(base.getFieldMap(), remote.getFieldMap());
Copy link
Member

@subhramit subhramit Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think since we have already checked for base != null and also since short circuiting guarantees that the respective second conditions are evaluated only if the first is not true (i.e, not null), we can use the plain equals method in these cases instead of Objects.equals?

Suggested change
boolean localChanged = !localDeleted && !Objects.equals(base.getFieldMap(), local.getFieldMap());
boolean remoteChanged = !remoteDeleted && !Objects.equals(base.getFieldMap(), remote.getFieldMap());
boolean localChanged = !localDeleted && !base.getFieldMap().equals(local.getFieldMap());
boolean remoteChanged = !remoteDeleted && !base.getFieldMap().equals(remote.getFieldMap());

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, no risk of NPE here. Changed to use equals() as suggested

Comment on lines 99 to 100
boolean localChanged = !Objects.equals(base.getFieldMap(), local.getFieldMap());
boolean remoteChanged = !Objects.equals(base.getFieldMap(), remote.getFieldMap());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 148 to 151
boolean localChanged = !Objects.equals(base.getType(), local.getType());
boolean remoteChanged = !Objects.equals(base.getType(), remote.getType());

return localChanged && remoteChanged && !Objects.equals(local.getType(), remote.getType());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here

Comment on lines 23 to 30
public GitHandler get(Path repoPath) {
if (repoPath == null) {
throw new IllegalArgumentException("Path must not be null");
}

Path normalized = repoPath.toAbsolutePath().normalize();
return handlerCache.computeIfAbsent(normalized, GitHandler::new);
}
Copy link
Member

@subhramit subhramit Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is debatable, but I am not a huge fan of using logical branching to throw exceptions. If there is a logical branch, it should not deal with an exceptional/unexpected case. Catch blocks are there for that.
How about

Suggested change
public GitHandler get(Path repoPath) {
if (repoPath == null) {
throw new IllegalArgumentException("Path must not be null");
}
Path normalized = repoPath.toAbsolutePath().normalize();
return handlerCache.computeIfAbsent(normalized, GitHandler::new);
}
public GitHandler get(Path repoPath) {
Path normalized = Objects.requireNonNull(repoPath, "Path must not be null")
.toAbsolutePath().normalize();
return handlerCache.computeIfAbsent(normalized, GitHandler::new);
}

Note that if you take this suggestion, you'll need the Objects import here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right, the path is already checked before calling this method, so this is really just a defensive guard (and to keep trag-bot happy). Switched to Objects.requireNonNull(...). Thanks!

Comment on lines 32 to 39
public Optional<GitHandler> fromAnyPath(Path anyPathInsideRepo) {
if (anyPathInsideRepo == null) {
throw new IllegalArgumentException("Path must not be null");
}

return GitHandler.findRepositoryRoot(anyPathInsideRepo)
.map(this::get);
}
Copy link
Member

@subhramit subhramit Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar comment as https://github.com/JabRef/jabref/pull/13666/files#r2257720507 here

public Optional<GitHandler> fromAnyPath(Path anyPathInsideRepo) {
        return GitHandler.findRepositoryRoot(Objects.requireNonNull(anyPathInsideRepo, "Path must not be null"))
                         .map(this::get);
}

InAnYan
InAnYan previously approved these changes Aug 7, 2025
Copy link
Member

@InAnYan InAnYan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good!

@trag-bot
Copy link

trag-bot bot commented Aug 7, 2025

@trag-bot didn't find any issues in the code! ✅✨

Copy link
Member

@subhramit subhramit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@Siedlerchr Siedlerchr added this pull request to the merge queue Aug 7, 2025
Merged via the queue into JabRef:main with commit 592fd18 Aug 7, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add (simple) git support

4 participants