Skip to content

Implemented Diff View Before Comitting feature - #16569

Draft
thesauravpoddar wants to merge 1 commit into
JabRef:mainfrom
thesauravpoddar:16341
Draft

Implemented Diff View Before Comitting feature#16569
thesauravpoddar wants to merge 1 commit into
JabRef:mainfrom
thesauravpoddar:16341

Conversation

@thesauravpoddar

Copy link
Copy Markdown
Contributor

PR Description

Implemented Diff view before commiting feature. This feature shows the diff view of files that changed only for currently opened .bib file not for whole Repository. Every change is visible in Git Diff dialog view so it is to track to what has been changed before commiting

image image

Steps to test

  1. Create a .bib library and add some entries to it
  2. make some changes to the entries you added and then save the changes
  3. Go to commit dialog then click on Show Diff button, a new dialog will pop up and the all the changes can be seen there

Related issues and pull requests

Closes #16341

AI usage

Most of my brain is used but for some testing ans errors i was getting during implementation i used gpt

AI CHECKLIST.md walkthrough

Checklist

  • I own the copyright of the code submitted and I license it under the MIT license
  • If AI tools were used, I disclosed them in the "AI usage" section and reviewed, understood, and take full ownership of all AI-generated code
  • I manually tested my changes in running JabRef (always required)
  • [/] I added JUnit tests for changes (if applicable)
  • I added screenshots in the PR description (if change is visible to the user)
  • [/] I added a screenshot in the PR description showing a library with a single entry with me as author and as title the issue number
  • [/] I described the change in CHANGELOG.md in a way that can be understood by the average user (if change is visible to the user)
  • [/] I checked the user documentation for up to dateness and submitted a pull request to our user documentation repository

@github-actions github-actions Bot added status: changes-required Pull requests that are not yet complete good first issue An issue intended for project-newcomers. Varies in difficulty. component: ui labels Aug 14, 2026
@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Add per-library Git diff preview dialog to Git Commit workflow

✨ Enhancement ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Add “Show Diff” in Git Commit dialog to preview changes for the active library file.
• Compute diffs against HEAD, using entry-level diffs for .bib and line diffs otherwise.
• Introduce a dedicated Git Diff dialog UI with file list and before/after diff table.
Diagram

graph TD
  A["Git Commit dialog"] --> B["Commit ViewModel"] --> C["GitDiffChecker"] --> D{{"JGit repo"}}
  C --> E["BibTeX diff"]
  C --> F{{"java-diff-utils"}}
  A --> G["Git Diff dialog"]
  subgraph Legend
    direction LR
    _ui["UI"] ~~~ _mod["Module"] ~~~ _ext{{"External"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use JGit DiffFormatter for unified/file diffs
  • ➕ Avoids adding/depending on a second diff library for non-.bib files
  • ➕ Produces standard, well-understood patch output
  • ➕ Potentially simpler correctness story for line-number handling
  • ➖ Harder to map into a side-by-side table model without additional parsing
  • ➖ Less tailored for BibTeX entry-level summaries
2. Embed diff preview directly in the commit dialog (no separate modal)
  • ➕ Fewer windows; faster review loop before committing
  • ➕ Can keep commit message and diff visible simultaneously
  • ➖ Commit dialog becomes significantly more complex and crowded
  • ➖ More layout work across screen sizes
3. Compute diffs for all changed files in the repo (not just active .bib)
  • ➕ Aligns closer with typical Git commit expectations
  • ➕ Helps catch accidental changes outside the library file
  • ➖ More computation and UI complexity (staging/selection, larger result sets)
  • ➖ Conflicts with the stated scope of 'current library only'

Recommendation: The chosen approach (on-demand diff for the active library file, with BibTeX-aware summaries) fits the stated UX goal well and keeps scope contained. Consider a follow-up cleanup to remove the unused ImportFormatPreferences constructor parameter in GitCommitDialogViewModel (it is derived from GuiPreferences anyway) and/or add basic tests around GitDiffChecker (e.g., HEAD-missing/new-file cases and .bib vs non-.bib selection).

Files changed (12) +595 / -4

Enhancement (11) +593 / -3
GitCommitDialogView.javaWire “Show Diff” button into Git commit dialog +27/-2

Wire “Show Diff” button into Git commit dialog

• Adds a Show Diff button and handler that triggers an async diff computation via the view model. Displays results in a custom GitDiffDialogView and shows an error dialog on failures.

jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogView.java

GitCommitDialogViewModel.javaAdd diffTask() for active library file vs HEAD +64/-1

Add diffTask() for active library file vs HEAD

• Introduces diffTask() and supporting logic to locate the active library’s .bib path, resolve the Git repository root, and compute a diff against the last commit. Adds user-facing error conditions for missing library/path/repo.

jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogViewModel.java

GitDiffDialogView.javaImplement Git diff preview dialog UI controller +194/-0

Implement Git diff preview dialog UI controller

• Adds a new dialog that lists diffed files and shows a before/after table. For BibTeX entry diffs, it summarizes changes at entry/field/comment level and styles rows by diff type.

jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java

GitCommitDialog.fxmlAdd “Show Diff” button to commit dialog layout +6/-0

Add “Show Diff” button to commit dialog layout

• Introduces an HBox with a Show Diff button above the commit message input and binds it to the view’s showDiff handler.

jabgui/src/main/resources/org/jabref/gui/git/GitCommitDialog.fxml

GitDiffDialog.fxmlAdd FXML layout for Git diff dialog +50/-0

Add FXML layout for Git diff dialog

• Defines a split-pane layout with a changed-files list on the left and a diff table on the right, plus a close button type.

jabgui/src/main/resources/org/jabref/gui/git/GitDiffDialog.fxml

DiffFiles.javaIntroduce sealed DiffFiles abstraction +5/-0

Introduce sealed DiffFiles abstraction

• Adds a sealed interface representing a diff result per file, implemented by line-based and entry-based variants.

jablib/src/main/java/org/jabref/logic/git/diff/DiffFiles.java

DiffLine.javaAdd DiffLine model for table-friendly diff rows +27/-0

Add DiffLine model for table-friendly diff rows

• Defines a DiffLine record with optional old/new line numbers and texts, plus factory methods for context/changed/added/deleted rows.

jablib/src/main/java/org/jabref/logic/git/diff/DiffLine.java

DiffLineType.javaDefine diff row types for rendering +8/-0

Define diff row types for rendering

• Adds an enum to classify diff rows (context/changed/added/deleted) for styling and display logic.

jablib/src/main/java/org/jabref/logic/git/diff/DiffLineType.java

EntryDiffFiles.javaAdd entry-diff result type for .bib files +8/-0

Add entry-diff result type for .bib files

• Introduces a DiffFiles implementation that carries BibEntryDiff lists for BibTeX-aware diff rendering.

jablib/src/main/java/org/jabref/logic/git/diff/EntryDiffFiles.java

GitDiffChecker.javaCompute per-file diff against HEAD with BibTeX-aware mode +198/-0

Compute per-file diff against HEAD with BibTeX-aware mode

• Implements diff computation by reading HEAD content via JGit and comparing against working tree content. Uses BibtexImporter + BibDatabaseDiff for .bib files and java-diff-utils DiffRowGenerator for line-based diffs, producing DiffLine models with line numbers.

jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java

LineDiffFiles.javaAdd line-diff result type for non-.bib diffs +6/-0

Add line-diff result type for non-.bib diffs

• Introduces a DiffFiles implementation containing line-oriented DiffLine rows for display in the diff dialog.

jablib/src/main/java/org/jabref/logic/git/diff/LineDiffFiles.java

Other (1) +2 / -1
module-info.javaExport git.diff package and add java-diff-utils module requirement +2/-1

Export git.diff package and add java-diff-utils module requirement

• Exports org.jabref.logic.git.diff for GUI consumption and adds a module requirement for io.github.javadiffutils.

jablib/src/main/java/module-info.java

@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (4) 📜 Skill insights (0)

Grey Divider


Action required

1. Hard-coded diff summary strings 📘 Rule violation ≡ Correctness
Description
GitDiffDialogView builds user-visible diff labels using hard-coded English strings and string
concatenation (for example " - entry type" and "(no citation key)"). This breaks localization
expectations and prevents translators from reordering/formatting text correctly.
Code

jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[R121-122]

+            String typeLabel = label + " - entry type";
+            summary.add(DiffLine.changed(row, row, typeLabel + ": " + originalEntry.getType().getName(), typeLabel + ": " + newEntry.getType().getName()));
Evidence
PR Compliance requires user-facing strings to be localized and placeholder-based. The dialog
currently constructs visible row labels with hard-coded English fragments and concatenation, and
uses a hard-coded fallback citation key string.

AGENTS.md: User-Facing Strings Must Be Localized; Logging Strings Must Remain English
jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[118-123]
jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[163-165]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
User-facing text in the diff dialog is currently hard-coded and composed via string concatenation.

## Issue Context
The diff dialog is a GUI feature; all visible strings should be localized and (when dynamic values are involved) use placeholder-based localization keys.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[118-123]
- jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[138-145]
- jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[151-165]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Blank line diff miscount 🐞 Bug ≡ Correctness
Description
GitDiffChecker.toDiffLines() treats empty-string lines as “missing”, so changes involving blank
lines can be misclassified as INSERT/DELETE and can desynchronize displayed line numbers. This
produces incorrect diff output for files with blank lines in changed hunks.
Code

jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java[R161-163]

+            boolean hasOld = !row.getOldLine().isEmpty();
+            boolean hasNew = !row.getNewLine().isEmpty();
+
Evidence
The diff conversion uses isEmpty() on the line text to infer whether that side exists, which
collapses a real blank line into “no line”. DiffLine encodes missing sides via Optional.empty(),
so this heuristic loses information and can produce the wrong DiffLineType/line numbering.

jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java[155-193]
jablib/src/main/java/org/jabref/logic/git/diff/DiffLine.java[5-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`GitDiffChecker.toDiffLines` uses `row.getOldLine().isEmpty()` / `row.getNewLine().isEmpty()` to decide whether the old/new side exists. An actual blank line is also an empty string, so blank-line changes get interpreted as a missing side, producing wrong `DiffLineType` and skewed line counters.

### Issue Context
`DiffLine` uses `Optional.empty()` to represent an absent side (added/deleted), so the conversion step must not conflate "absent" with "present but empty".

### Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java[155-194]
- jablib/src/main/java/org/jabref/logic/git/diff/DiffLine.java[5-26]

### Suggested fix
- Derive side presence from `row.getTag()` rather than string emptiness:
 - `EQUAL`/`CHANGE`: treat both sides as present and increment both line counters.
 - `DELETE`: old present only.
 - `INSERT`: new present only.
- Always pass line text through (including empty strings) using `Optional.of(...)` for present sides.
- Add a regression test covering blank-line changes (e.g., "" -> "x" and "x" -> "").

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. GUI contains diff summarization logic 📘 Rule violation ⚙ Maintainability
Description
GitDiffDialogView implements non-trivial diff summarization/business logic (iterating entry diffs,
computing field diffs, and generating summary rows) directly in the GUI layer. This violates the
layered architecture guideline that non-GUI logic should live in org.jabref.logic.
Code

jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[R94-97]

+    private static List<DiffLine> summarize(List<BibEntryDiff> entryDiffs) {
+        List<DiffLine> summary = new ArrayList<>();
+        int row = 0;
+        for (BibEntryDiff entryDiff : entryDiffs) {
Evidence
The compliance checklist requires keeping complex/non-UI operations out of org.jabref.gui. The GUI
class contains summarization functions (summarize, appendFieldDiffs, describe) that transform
model diffs into display rows.

AGENTS.md: Layered GUI Architecture: GUI Is a Gateway; Non-GUI Logic Belongs in org.jabref.logic
jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[94-165]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Non-GUI diff summarization is implemented inside a GUI class (`GitDiffDialogView`), increasing coupling and making the logic harder to test/reuse.

## Issue Context
The project architecture expects GUI classes to act as gateways/controllers, while substantial logic should be in `org.jabref.logic`.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[85-165]
- jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java[1-198]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Unused importFormatPreferences parameter 📘 Rule violation ≡ Correctness
Description
GitCommitDialogViewModel accepts an ImportFormatPreferences/importFormatPreferences
constructor parameter but ignores it, overwriting/deriving the field from guiPreferences instead,
while GitCommitDialogView passes an uninitialized field for that parameter. This creates confusing
and misleading dependency wiring that can hide mistakes now and become brittle or null-prone if
future code starts relying on the constructor argument.
Code

jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogViewModel.java[R63-66]

        this.gitHandlerRegistry = gitHandlerRegistry;
+        this.guiPreferences = guiPreferences;
+        this.importFormatPreferences = guiPreferences.getImportFormatPreferences();
+        this.fileUpdateMonitor = fileUpdateMonitor;
Evidence
The cited code shows that GitCommitDialogView forwards an importFormatPreferences field into the
GitCommitDialogViewModel constructor even though that field is never initialized/injected in the
view, and that the view model constructor does not use the passed parameter, instead obtaining the
preferences via guiPreferences.getImportFormatPreferences(). Together, this demonstrates
inconsistent/unused dependency wiring: the API suggests a meaningful constructor dependency, but the
implementation ignores it and the caller provides a value that is effectively meaningless,
undermining clarity and future safety.

AGENTS.md: Follow Existing Formatting, Naming Conventions, and Keep Code Small/Focused (SRP)
jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogViewModel.java[52-66]
jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogView.java[32-66]
jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogView.java[32-36]
jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogView.java[58-62]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`GitCommitDialogViewModel` declares a constructor dependency on `ImportFormatPreferences importFormatPreferences` but does not use it (it derives the value from `guiPreferences` instead), and `GitCommitDialogView` passes an `importFormatPreferences` field that is never initialized/injected. This dead/incorrect wiring is confusing and can mask wiring mistakes today or turn into a null/brittle contract later if the constructor argument is ever used.

## Issue Context
Currently the ViewModel uses `guiPreferences.getImportFormatPreferences()` rather than the constructor argument, while the View still passes an uninitialized `importFormatPreferences` field into that constructor. Choose one consistent approach: either remove the constructor parameter and the unused view field (keeping `GuiPreferences` as the single source), or properly initialize/inject `ImportFormatPreferences` in the View and have the ViewModel assign and use the constructor argument.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogViewModel.java[52-66]
- jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogView.java[32-36]
- jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogView.java[59-66]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Two requires on one line 📘 Rule violation ⚙ Maintainability
Description
module-info.java places two requires directives on the same line, deviating from the surrounding
formatting pattern and reducing diff readability. This should be split into separate lines to match
the project’s conventions.
Code

jablib/src/main/java/module-info.java[308]

+    requires transitive org.jspecify; requires io.github.javadiffutils;
Evidence
The compliance checklist requires following existing formatting conventions. The modified
module-info.java line combines two separate requires statements into one line, unlike adjacent
entries.

AGENTS.md: Follow Existing Formatting, Naming Conventions, and Keep Code Small/Focused (SRP)
jablib/src/main/java/module-info.java[304-309]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Two JPMS `requires` directives are written on a single line, inconsistent with the rest of the module declaration.

## Issue Context
Maintaining consistent formatting keeps diffs reviewable and avoids style drift in critical configuration files.

## Fix Focus Areas
- jablib/src/main/java/module-info.java[304-309]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View review recommended (1)
6. Diff fails for missing file 🐞 Bug ☼ Reliability
Description
GitCommitDialogViewModel.computeDiff() resolves the library path with toRealPath(), which throws
if the .bib file is missing on disk, preventing the diff dialog from opening. This contradicts
GitDiffChecker, which already handles missing working-tree files by treating them as empty
content/database.
Code

jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogViewModel.java[R108-111]

+                                   .toRealPath();
+
+        Path relativePath = repoRoot.relativize(
+                trackedFile.bibFilePath().toRealPath()
Evidence
computeDiff() requires bibFilePath.toRealPath(), which fails when the file does not exist.
Meanwhile, GitDiffChecker is implemented to gracefully handle a non-existent working-tree file via
Files.exists(trackedFile) checks, meaning the pre-toRealPath() failure is avoidable.

jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogViewModel.java[102-113]
jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java[103-107]
jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java[122-125]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`computeDiff()` calls `trackedFile.bibFilePath().toRealPath()`. If the file was deleted/moved externally while the library is still open (or otherwise missing), `toRealPath()` throws and the diff cannot be computed.

### Issue Context
`GitDiffChecker` explicitly supports missing working-tree files by checking `Files.exists(trackedFile)` and returning empty content/empty database context.

### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogViewModel.java[102-120]
- jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java[103-106]
- jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java[122-125]

### Suggested fix
- Don’t call `toRealPath()` on the bib file path. Use `toAbsolutePath().normalize()` (or similar) and allow non-existent paths.
- Compute the repository-relative path from normalized absolute paths.
- Optionally catch `NoSuchFileException` and fall back to non-real path handling so the dialog can still show a diff (e.g., treated as deleted).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can describe a rule in plain language on the Rules page and Qodo drafts it for you

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment on lines +121 to +122
String typeLabel = label + " - entry type";
summary.add(DiffLine.changed(row, row, typeLabel + ": " + originalEntry.getType().getName(), typeLabel + ": " + newEntry.getType().getName()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Action required

1. Hard-coded diff summary strings 📘 Rule violation ≡ Correctness

GitDiffDialogView builds user-visible diff labels using hard-coded English strings and string
concatenation (for example " - entry type" and "(no citation key)"). This breaks localization
expectations and prevents translators from reordering/formatting text correctly.
Agent Prompt
## Issue description
User-facing text in the diff dialog is currently hard-coded and composed via string concatenation.

## Issue Context
The diff dialog is a GUI feature; all visible strings should be localized and (when dynamic values are involved) use placeholder-based localization keys.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[118-123]
- jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[138-145]
- jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[151-165]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +94 to +97
private static List<DiffLine> summarize(List<BibEntryDiff> entryDiffs) {
List<DiffLine> summary = new ArrayList<>();
int row = 0;
for (BibEntryDiff entryDiff : entryDiffs) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Remediation recommended

2. Gui contains diff summarization logic 📘 Rule violation ⚙ Maintainability

GitDiffDialogView implements non-trivial diff summarization/business logic (iterating entry diffs,
computing field diffs, and generating summary rows) directly in the GUI layer. This violates the
layered architecture guideline that non-GUI logic should live in org.jabref.logic.
Agent Prompt
## Issue description
Non-GUI diff summarization is implemented inside a GUI class (`GitDiffDialogView`), increasing coupling and making the logic harder to test/reuse.

## Issue Context
The project architecture expects GUI classes to act as gateways/controllers, while substantial logic should be in `org.jabref.logic`.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/git/GitDiffDialogView.java[85-165]
- jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java[1-198]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines 63 to +66
this.gitHandlerRegistry = gitHandlerRegistry;
this.guiPreferences = guiPreferences;
this.importFormatPreferences = guiPreferences.getImportFormatPreferences();
this.fileUpdateMonitor = fileUpdateMonitor;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Remediation recommended

3. Unused importformatpreferences parameter 📘 Rule violation ≡ Correctness

GitCommitDialogViewModel accepts an ImportFormatPreferences/importFormatPreferences
constructor parameter but ignores it, overwriting/deriving the field from guiPreferences instead,
while GitCommitDialogView passes an uninitialized field for that parameter. This creates confusing
and misleading dependency wiring that can hide mistakes now and become brittle or null-prone if
future code starts relying on the constructor argument.
Agent Prompt
## Issue description
`GitCommitDialogViewModel` declares a constructor dependency on `ImportFormatPreferences importFormatPreferences` but does not use it (it derives the value from `guiPreferences` instead), and `GitCommitDialogView` passes an `importFormatPreferences` field that is never initialized/injected. This dead/incorrect wiring is confusing and can mask wiring mistakes today or turn into a null/brittle contract later if the constructor argument is ever used.

## Issue Context
Currently the ViewModel uses `guiPreferences.getImportFormatPreferences()` rather than the constructor argument, while the View still passes an uninitialized `importFormatPreferences` field into that constructor. Choose one consistent approach: either remove the constructor parameter and the unused view field (keeping `GuiPreferences` as the single source), or properly initialize/inject `ImportFormatPreferences` in the View and have the ViewModel assign and use the constructor argument.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogViewModel.java[52-66]
- jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogView.java[32-36]
- jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogView.java[59-66]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

requires org.jooq.jool;
requires transitive org.libreoffice.uno;
requires transitive org.jspecify;
requires transitive org.jspecify; requires io.github.javadiffutils;

@qodo-free-for-open-source-projects qodo-free-for-open-source-projects Bot Aug 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Remediation recommended

4. Two requires on one line 📘 Rule violation ⚙ Maintainability


module-info.java places two requires directives on the same line, deviating from the surrounding
formatting pattern and reducing diff readability. This should be split into separate lines to match
the project’s conventions.
Agent Prompt
## Issue description
Two JPMS `requires` directives are written on a single line, inconsistent with the rest of the module declaration.

## Issue Context
Maintaining consistent formatting keeps diffs reviewable and avoids style drift in critical configuration files.

## Fix Focus Areas
- jablib/src/main/java/module-info.java[304-309]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah, should be addressed

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is not addressed, please don't strikethrough or resolve @qodo

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Understood. The finding remains active and I won’t strikethrough or resolve it. The required change is still to place requires io.github.javadiffutils; on its own line.

Comment on lines +161 to +163
boolean hasOld = !row.getOldLine().isEmpty();
boolean hasNew = !row.getNewLine().isEmpty();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Action required

5. Blank line diff miscount 🐞 Bug ≡ Correctness

GitDiffChecker.toDiffLines() treats empty-string lines as “missing”, so changes involving blank
lines can be misclassified as INSERT/DELETE and can desynchronize displayed line numbers. This
produces incorrect diff output for files with blank lines in changed hunks.
Agent Prompt
### Issue description
`GitDiffChecker.toDiffLines` uses `row.getOldLine().isEmpty()` / `row.getNewLine().isEmpty()` to decide whether the old/new side exists. An actual blank line is also an empty string, so blank-line changes get interpreted as a missing side, producing wrong `DiffLineType` and skewed line counters.

### Issue Context
`DiffLine` uses `Optional.empty()` to represent an absent side (added/deleted), so the conversion step must not conflate "absent" with "present but empty".

### Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java[155-194]
- jablib/src/main/java/org/jabref/logic/git/diff/DiffLine.java[5-26]

### Suggested fix
- Derive side presence from `row.getTag()` rather than string emptiness:
  - `EQUAL`/`CHANGE`: treat both sides as present and increment both line counters.
  - `DELETE`: old present only.
  - `INSERT`: new present only.
- Always pass line text through (including empty strings) using `Optional.of(...)` for present sides.
- Add a regression test covering blank-line changes (e.g., "" -> "x" and "x" -> "").

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +108 to +111
.toRealPath();

Path relativePath = repoRoot.relativize(
trackedFile.bibFilePath().toRealPath()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Remediation recommended

6. Diff fails for missing file 🐞 Bug ☼ Reliability

GitCommitDialogViewModel.computeDiff() resolves the library path with toRealPath(), which throws
if the .bib file is missing on disk, preventing the diff dialog from opening. This contradicts
GitDiffChecker, which already handles missing working-tree files by treating them as empty
content/database.
Agent Prompt
### Issue description
`computeDiff()` calls `trackedFile.bibFilePath().toRealPath()`. If the file was deleted/moved externally while the library is still open (or otherwise missing), `toRealPath()` throws and the diff cannot be computed.

### Issue Context
`GitDiffChecker` explicitly supports missing working-tree files by checking `Files.exists(trackedFile)` and returning empty content/empty database context.

### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/git/GitCommitDialogViewModel.java[102-120]
- jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java[103-106]
- jablib/src/main/java/org/jabref/logic/git/diff/GitDiffChecker.java[122-125]

### Suggested fix
- Don’t call `toRealPath()` on the bib file path. Use `toAbsolutePath().normalize()` (or similar) and allow non-existent paths.
- Compute the repository-relative path from normalized absolute paths.
- Optionally catch `NoSuchFileException` and fall back to non-real path handling so the dialog can still show a diff (e.g., treated as deleted).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@pluto-han
pluto-han requested a review from wanling0000 August 14, 2026 15:32
@Inject
private GuiPreferences preferences;

private ImportFormatPreferences importFormatPreferences;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How is this initalized?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

When i was doing @Inject for for Importpreference it was not working as it was not registered so inject GuiPrefrence and using this i passed Importpreference

commitMessage.textProperty().bindBidirectional(viewModel.commitMessageProperty());
commitMessage.setPromptText(Localization.lang("Enter commit message here"));

showDiffButton.setOnAction(_ -> showDiff());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There is no need, as you already have onAction="#showDiff" in FXML

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Okay i will test this and will do the changes accordingly

GitHandlerRegistry gitHandlerRegistry) {
GitHandlerRegistry gitHandlerRegistry,
GuiPreferences guiPreferences,
ImportFormatPreferences importFormatPreferences,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

you can already get it from guiPreferences via getImportFormatPreferences()


import org.jabref.logic.bibtex.comparator.BibEntryDiff;

public record EntryDiffFiles(String fileName, List<BibEntryDiff> entryDiffs) implements DiffFiles {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

But since we work only with 1 .bib file, is there a need for String fileName?

Ping @wanling0000 , for more information. Because if yes, I think we can remove the fileName

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yesss we can later i realised i can remove it in later commit i will remove this

requires org.jooq.jool;
requires transitive org.libreoffice.uno;
requires transitive org.jspecify;
requires transitive org.jspecify; requires io.github.javadiffutils;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah, should be addressed

@subhramit

subhramit commented Aug 14, 2026

Copy link
Copy Markdown
Member

The screenshots seem very different from the conventions used in the issue:
image

Here it shows deletions/additions with red/green respectively, and it's mentioned "blue" for changed.

@subhramit

Copy link
Copy Markdown
Member

Here it shows deletions/additions with red/green respectively, and it's mentioned "blue" for changed.

Internal discussion: The current view is fine as well.

@koppor koppor left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The diff needs to use the view provided in the issue

Image

Not invent another view. Reuse!

JabRef has a Library diff since 10+ years

"SEMANTIC Diff"

JabRef is more advanced than text comparison!

@github-actions

Copy link
Copy Markdown
Contributor

Your pull request conflicts with the target branch.

Please merge upstream/main with your code. For a step-by-step guide to resolve merge conflicts, see https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line.

@thesauravpoddar

Copy link
Copy Markdown
Contributor Author

The diff needs to use the view provided in the issue

Image **Not invent another view. Reuse!**

JabRef has a Library diff since 10+ years

"SEMANTIC Diff"

JabRef is more advanced than text comparison!

okay I will change the view the way given in issue actually i was doing what given in issue but in midway i changed it thinking it is good but i should not have done that i will update the view to the way given in issue

@InAnYan

InAnYan commented Aug 15, 2026

Copy link
Copy Markdown
Member

Is it okay for organisational reasons to mark this PR as draft?

@InAnYan
InAnYan marked this pull request as draft August 15, 2026 16:05

@ThinkerDesigns ThinkerDesigns left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Summary

Nice addition -- a "Show Diff" button in the Git commit dialog for the current .bib file. Clean UI work with proper reuse of existing infrastructure.

Comments

Dependency injection bloat
The ViewModel constructor gained 3 new params (GuiPreferences, ImportFormatPreferences, FileUpdateMonitor) when only importFormatPreferences and fileUpdateMonitor are actually needed. Pass those two directly instead of the wrapper + deriving -- fewer parameters and more explicit dependencies.

Stale diff caveat (non-blocking)
The diff is computed against HEAD at button-click time, not at commit-time. If the file was modified externally between clicking "Show Diff" and "Commit", the user sees a stale diff worth noting in the PR description so users are aware.


Verdict: LGTM with above comments

@subhramit

Copy link
Copy Markdown
Member

Summary

Nice addition -- a "Show Diff" button in the Git commit dialog for the current .bib file. Clean UI work with proper reuse of existing infrastructure.

Comments

Dependency injection bloat
The ViewModel constructor gained 3 new params (GuiPreferences, ImportFormatPreferences, FileUpdateMonitor) when only importFormatPreferences and fileUpdateMonitor are actually needed. Pass those two directly instead of the wrapper + deriving -- fewer parameters and more explicit dependencies.

Stale diff caveat (non-blocking)
The diff is computed against HEAD at button-click time, not at commit-time. If the file was modified externally between clicking "Show Diff" and "Commit", the user sees a stale diff worth noting in the PR description so users are aware.


Verdict: LGTM with above comments

@ThinkerDesigns note that this is a public platform, everyone knows what you're doing - it won't help you. Anywhere else you are seen spamming in this project again using AI generated reviews to get GitHub activity, we'll make sure it is made even more public before we ban you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: git component: ui good first issue An issue intended for project-newcomers. Varies in difficulty. status: changes-required Pull requests that are not yet complete

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Diff View Before Comitting

5 participants