This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new f2527ef036 fix git diff and overall experience of Git info window,
fixes #6051 (#6349)
f2527ef036 is described below
commit f2527ef03656c2a223d4365b64f3ad2437c378ed
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Mon Jan 12 17:08:11 2026 +0100
fix git diff and overall experience of Git info window, fixes #6051 (#6349)
---
.../git/info/GitInfoExplorerFileTypeHandler.java | 208 ++++++++++++++++++---
.../main/java/org/apache/hop/git/model/UIGit.java | 149 +++++++++++----
2 files changed, 294 insertions(+), 63 deletions(-)
diff --git
a/plugins/misc/git/src/main/java/org/apache/hop/git/info/GitInfoExplorerFileTypeHandler.java
b/plugins/misc/git/src/main/java/org/apache/hop/git/info/GitInfoExplorerFileTypeHandler.java
index bd9663958a..8a25092da9 100644
---
a/plugins/misc/git/src/main/java/org/apache/hop/git/info/GitInfoExplorerFileTypeHandler.java
+++
b/plugins/misc/git/src/main/java/org/apache/hop/git/info/GitInfoExplorerFileTypeHandler.java
@@ -195,20 +195,34 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
ColumnInfo[] revisionColumns = {
new ColumnInfo(
BaseMessages.getString(PKG,
"GitInfoDialog.Revisions.ColumnRevision.Label"),
- ColumnInfo.COLUMN_TYPE_TEXT),
+ ColumnInfo.COLUMN_TYPE_TEXT,
+ false,
+ true),
new ColumnInfo(
BaseMessages.getString(PKG,
"GitInfoDialog.Revisions.ColumnCreation.Label"),
- ColumnInfo.COLUMN_TYPE_TEXT),
+ ColumnInfo.COLUMN_TYPE_TEXT,
+ false,
+ true),
new ColumnInfo(
BaseMessages.getString(PKG,
"GitInfoDialog.Revisions.ColumnLogin.Label"),
- ColumnInfo.COLUMN_TYPE_TEXT),
+ ColumnInfo.COLUMN_TYPE_TEXT,
+ false,
+ true),
new ColumnInfo(
BaseMessages.getString(PKG,
"GitInfoDialog.Revisions.ColumnComment.Label"),
- ColumnInfo.COLUMN_TYPE_TEXT),
+ ColumnInfo.COLUMN_TYPE_TEXT,
+ false,
+ true),
};
wRevisions =
new TableView(
- hopGui.getVariables(), composite, SWT.BORDER, revisionColumns, 1,
null, props);
+ hopGui.getVariables(),
+ composite,
+ SWT.BORDER | SWT.SINGLE,
+ revisionColumns,
+ 1,
+ null,
+ props);
wRevisions.setReadonly(true);
PropsUi.setLook(wRevisions);
FormData fdRevisions = new FormData();
@@ -217,7 +231,18 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
fdRevisions.right = new FormAttachment(100, 0);
fdRevisions.bottom = new FormAttachment(40, 0);
wRevisions.setLayoutData(fdRevisions);
- wRevisions.table.addListener(SWT.Selection, e -> refreshChangedFiles());
+ // Use MouseDown event instead of Selection to ensure the click is fully
processed
+ wRevisions.table.addListener(
+ SWT.MouseDown,
+ e ->
+ // Delay slightly to ensure selection is registered
+
wRevisions.table.getDisplay().asyncExec(this::refreshChangedFiles));
+ // Also handle keyboard navigation (arrow keys, etc.)
+ wRevisions.table.addListener(
+ SWT.KeyDown,
+ e ->
+ // Delay slightly to ensure selection is registered
+
wRevisions.table.getDisplay().asyncExec(this::refreshChangedFiles));
lastControl = wRevisions;
Label wlFiles = new Label(composite, SWT.LEFT | SWT.SINGLE);
@@ -244,20 +269,37 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
ColumnInfo[] filesColumns = {
new ColumnInfo(
BaseMessages.getString(PKG,
"GitInfoDialog.ChangedFiles.Filename.Label"),
- ColumnInfo.COLUMN_TYPE_TEXT),
+ ColumnInfo.COLUMN_TYPE_TEXT,
+ false,
+ true), // not numeric, read-only
new ColumnInfo(
BaseMessages.getString(PKG,
"GitInfoDialog.ChangedFiles.Status.Label"),
- ColumnInfo.COLUMN_TYPE_TEXT),
+ ColumnInfo.COLUMN_TYPE_TEXT,
+ false,
+ true), // not numeric, read-only
new ColumnInfo(
BaseMessages.getString(PKG,
"GitInfoDialog.ChangedFiles.Staged.Label"),
- ColumnInfo.COLUMN_TYPE_CCOMBO,
- new String[] {"Y", "N"}),
+ ColumnInfo.COLUMN_TYPE_TEXT,
+ false,
+ true), // not numeric, read-only - use TEXT not CCOMBO for true
read-only
};
wFiles =
- new TableView(hopGui.getVariables(), sashForm, SWT.BORDER,
filesColumns, 1, null, props);
+ new TableView(
+ hopGui.getVariables(), sashForm, SWT.BORDER | SWT.SINGLE,
filesColumns, 1, null, props);
wFiles.setReadonly(true);
PropsUi.setLook(wFiles);
- wFiles.table.addListener(SWT.Selection, e -> fileSelected());
+ // Use MouseDown event instead of Selection to ensure the click is fully
processed
+ wFiles.table.addListener(
+ SWT.MouseDown,
+ e ->
+ // Delay slightly to ensure selection is registered
+ wFiles.table.getDisplay().asyncExec(this::fileSelected));
+ // Also handle keyboard navigation (arrow keys, etc.)
+ wFiles.table.addListener(
+ SWT.KeyDown,
+ e ->
+ // Delay slightly to ensure selection is registered
+ wFiles.table.getDisplay().asyncExec(this::fileSelected));
Composite wDiffComposite = new Composite(sashForm, SWT.NONE);
PropsUi.setLook(wDiffComposite);
@@ -291,7 +333,7 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
fdDiff.bottom = new FormAttachment(100, 0);
wDiff.setLayoutData(fdDiff);
- sashForm.setWeights(new int[] {40, 60});
+ sashForm.setWeights(40, 60);
refresh();
@@ -527,8 +569,20 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
UIGit git = guiPlugin.getGit();
List<ObjectRevision> revisions = new ArrayList<>();
try {
- String relativePath =
- calculateRelativePath(perspective.getRootFolder(),
explorerFile.getFilename());
+ // Use the git repository root, not the perspective root folder
+ // The git repository root is what JGit needs for relative paths
+ String gitRoot = git.getDirectory();
+ String relativePath = calculateRelativePath(gitRoot,
explorerFile.getFilename());
+ LogChannel.UI.logDebug(
+ "GitInfo refresh - gitRoot: '"
+ + gitRoot
+ + "', perspectiveRoot: '"
+ + perspective.getRootFolder()
+ + "', file: '"
+ + explorerFile.getFilename()
+ + "', relative: '"
+ + relativePath
+ + "'");
revisions = git.getRevisions(relativePath);
} catch (Exception e) {
LogChannel.UI.logError(
@@ -548,13 +602,30 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
item.setText(4, Const.NVL(revision.getComment(), ""));
}
wRevisions.optimizeTableView();
- if (!revisions.isEmpty()) {
- // Select the first line
- wRevisions.setSelection(new int[] {0});
- }
wbDiff.setEnabled(false);
+ // Refresh changed files first, before selecting a revision
refreshChangedFiles();
+
+ // Select the first revision after the UI is fully rendered
+ // Use asyncExec to ensure the table is ready to handle the selection
+ if (!revisions.isEmpty()) {
+ parentComposite
+ .getDisplay()
+ .asyncExec(
+ () -> {
+ if (!wRevisions.isDisposed() &&
wRevisions.table.getItemCount() > 0) {
+ wRevisions.table.setSelection(0);
+ wRevisions.table.showSelection();
+ LogChannel.UI.logDebug(
+ "GitInfo refresh: Auto-selected first revision (index 0)
after UI render");
+
+ // Refresh changed files now that a revision is selected
+ // This will trigger auto-selection of the file if there's
only one
+ refreshChangedFiles();
+ }
+ });
+ }
}
private String calculateRelativePath(String rootFolder, String filename)
@@ -562,10 +633,21 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
FileObject root = HopVfs.getFileObject(rootFolder);
FileObject file = HopVfs.getFileObject(filename);
- return root.getName().getRelativeName(file.getName());
+ String relativePath = root.getName().getRelativeName(file.getName());
+
+ // Normalize for JGit: forward slashes, no leading slash
+ if (relativePath != null && !".".equals(relativePath)) {
+ relativePath = relativePath.replace("\\", "/");
+ if (relativePath.startsWith("/")) {
+ relativePath = relativePath.substring(1);
+ }
+ }
+
+ return relativePath;
}
private void fileSelected() {
+ LogChannel.UI.logDebug("fileSelected: File clicked in changed files list");
String filename = showFileDiff();
wbDiff.setEnabled(false);
@@ -573,10 +655,11 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
// Enable visual diff button?
//
if (filename != null) {
+ LogChannel.UI.logDebug("fileSelected: Diff generated for file: " +
filename);
// if a folder is selected in the left pane then return
ExplorerPerspective perspective = HopGui.getExplorerPerspective();
if
(!perspective.getPipelineFileType().isHandledBy(explorerFile.getFilename(),
false)
- &
!perspective.getWorkflowFileType().isHandledBy(explorerFile.getFilename(),
false)) {
+ &&
!perspective.getWorkflowFileType().isHandledBy(explorerFile.getFilename(),
false)) {
return;
}
@@ -603,10 +686,12 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
GitGuiPlugin guiPlugin = GitGuiPlugin.getInstance();
UIGit git = guiPlugin.getGit();
- if (wRevisions.getSelectionIndices().length == 0) {
+ if (wRevisions.table.getSelectionCount() == 0) {
+ LogChannel.UI.logDebug("showFileDiff: No revision selected");
return null;
}
- if (wFiles.getSelectionIndices().length == 0) {
+ if (wFiles.table.getSelectionCount() == 0) {
+ LogChannel.UI.logDebug("showFileDiff: No file selected");
return null;
}
@@ -614,7 +699,12 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
// A revision/commit was selected...
//
- TableItem revisionItem = wRevisions.table.getSelection()[0];
+ TableItem[] revisionSelection = wRevisions.table.getSelection();
+ if (revisionSelection.length == 0) {
+ LogChannel.UI.logDebug("showFileDiff: Revision selection array is
empty");
+ return null;
+ }
+ TableItem revisionItem = revisionSelection[0];
String revisionId = revisionItem.getText(1);
boolean workingTree = VCS.WORKINGTREE.equals(revisionId);
@@ -648,13 +738,21 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
String rootFolder = git.getDirectory();
boolean showStaged = true;
- // Cleanup the diff text field
+ // Clear the diff text field and disable the visual diff button
wDiff.setText("");
+ wbDiff.setEnabled(false);
// Pick up the revision ID...
//
if (wRevisions.table.getSelectionCount() == 0) {
- changedFiles = new ArrayList<>(guiPlugin.getChangedFiles().values());
+ // No revision selected yet (during initial load)
+ // Still filter by the selected file/folder
+ changedFiles = new ArrayList<>();
+ for (UIFile changedFile : guiPlugin.getChangedFiles().values()) {
+ if (isFilteredPath(rootFolder, changedFile.getName(), selectedFile)) {
+ changedFiles.add(changedFile);
+ }
+ }
} else {
String revisionId = wRevisions.table.getSelection()[0].getText(1);
String parentRevisionId =
@@ -720,6 +818,40 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
}
}
wFiles.optimizeTableView();
+
+ // Auto-select file and show diff in certain cases
+ boolean shouldAutoSelect = false;
+
+ if (changedFiles.size() == 1 && wRevisions.table.getSelectionCount() > 0) {
+ // Single file mode - always auto-select
+ shouldAutoSelect = true;
+ } else if (!changedFiles.isEmpty() && wFiles.table.getSelectionCount() >
0) {
+ // Multiple files but one was previously selected - try to keep that
selection or select first
+ shouldAutoSelect = true;
+ }
+
+ if (shouldAutoSelect) {
+ wFiles
+ .table
+ .getDisplay()
+ .asyncExec(
+ () -> {
+ if (!wFiles.isDisposed() && wFiles.table.getItemCount() > 0) {
+ // If no selection, or single file mode, select the first
file
+ if (wFiles.table.getSelectionCount() == 0 ||
wFiles.table.getItemCount() == 1) {
+ wFiles.table.setSelection(0);
+ wFiles.table.showSelection();
+ LogChannel.UI.logDebug("refreshChangedFiles: Auto-selected
file at index 0");
+ }
+ // Show the diff for the selected file
+ if (wFiles.table.getSelectionCount() > 0) {
+ fileSelected();
+ LogChannel.UI.logDebug(
+ "refreshChangedFiles: Triggered diff display for
selected file");
+ }
+ }
+ });
+ }
}
/**
@@ -733,11 +865,33 @@ public class GitInfoExplorerFileTypeHandler extends
BaseExplorerFileTypeHandler
private boolean isFilteredPath(String root, String path, String
selectedFile) {
try {
String relativeSelected = calculateRelativePath(root, selectedFile);
+ LogChannel.UI.logDebug(
+ "isFilteredPath: path='"
+ + path
+ + "', relativeSelected='"
+ + relativeSelected
+ + "', selectedFile='"
+ + selectedFile
+ + "'");
+
if (".".equals(relativeSelected)) {
return true; // path is whole project
}
- return path.startsWith(relativeSelected);
+
+ // Check if the selected file is a directory
+ FileObject selectedFileObject = HopVfs.getFileObject(selectedFile);
+ boolean isDirectory = selectedFileObject.isFolder();
+
+ if (isDirectory) {
+ // For a folder, check if the path is in that folder or subfolder
+ // Use startsWith with a trailing slash to avoid false matches
+ return path.equals(relativeSelected) ||
path.startsWith(relativeSelected + "/");
+ } else {
+ // For a file, only exact match
+ return path.equals(relativeSelected);
+ }
} catch (Exception e) {
+ LogChannel.UI.logError("Error in isFilteredPath", e);
return false;
}
}
diff --git a/plugins/misc/git/src/main/java/org/apache/hop/git/model/UIGit.java
b/plugins/misc/git/src/main/java/org/apache/hop/git/model/UIGit.java
index 7e85c7cddc..e7129ee44b 100644
--- a/plugins/misc/git/src/main/java/org/apache/hop/git/model/UIGit.java
+++ b/plugins/misc/git/src/main/java/org/apache/hop/git/model/UIGit.java
@@ -331,15 +331,55 @@ public class UIGit extends VCS {
public List<ObjectRevision> getRevisions(String path) {
List<ObjectRevision> revisions = new ArrayList<>();
try {
+ // Normalize the path for JGit (forward slashes, no leading slash)
+ String normalizedPath = normalizePathForJGit(path);
+ if (path != null && !".".equals(path)) {
+ LogChannel.UI.logDebug(
+ "Getting revisions for path - original: '"
+ + path
+ + "', normalized: '"
+ + normalizedPath
+ + "'");
+ }
+
+ // Check if there are working tree changes for the specific path
+ boolean hasWorkingTreeChanges = false;
if (!isClean()
|| git.getRepository().getRepositoryState() ==
RepositoryState.MERGING_RESOLVED) {
- GitObjectRevision rev =
- new GitObjectRevision(WORKINGTREE, "*", new Date(), " // " +
VCS.WORKINGTREE);
- revisions.add(rev);
+ // If a specific path is provided, check if that path has changes
+ if (normalizedPath != null && !".".equals(normalizedPath)) {
+ List<UIFile> stagedFiles = getStagedFiles();
+ List<UIFile> unstagedFiles = getUnstagedFiles();
+ for (UIFile file : stagedFiles) {
+ if (file.getName().equals(normalizedPath)
+ || file.getName().startsWith(normalizedPath + "/")) {
+ hasWorkingTreeChanges = true;
+ break;
+ }
+ }
+ if (!hasWorkingTreeChanges) {
+ for (UIFile file : unstagedFiles) {
+ if (file.getName().equals(normalizedPath)
+ || file.getName().startsWith(normalizedPath + "/")) {
+ hasWorkingTreeChanges = true;
+ break;
+ }
+ }
+ }
+ } else {
+ // No specific path, so there are working tree changes
+ hasWorkingTreeChanges = true;
+ }
+
+ if (hasWorkingTreeChanges) {
+ GitObjectRevision rev =
+ new GitObjectRevision(WORKINGTREE, "*", new Date(), " // " +
VCS.WORKINGTREE);
+ revisions.add(rev);
+ }
}
LogCommand logCommand = git.log();
- if (path != null && !".".equals(path)) {
- logCommand = logCommand.addPath(path);
+ if (normalizedPath != null && !".".equals(normalizedPath)) {
+ logCommand = logCommand.addPath(normalizedPath);
}
Iterable<RevCommit> iterable = logCommand.call();
for (RevCommit commit : iterable) {
@@ -352,7 +392,7 @@ public class UIGit extends VCS {
revisions.add(rev);
}
} catch (Exception e) {
- // Do nothing
+ LogChannel.UI.logError("Error getting git revisions for path: " + path,
e);
}
return revisions;
}
@@ -365,9 +405,10 @@ public class UIGit extends VCS {
List<UIFile> files = new ArrayList<>();
Status status = null;
try {
+ String normalizedPath = normalizePathForJGit(path);
StatusCommand statusCommand = git.status();
- if (path != null && !".".equals(path)) {
- statusCommand = statusCommand.addPath(path);
+ if (normalizedPath != null && !".".equals(normalizedPath)) {
+ statusCommand = statusCommand.addPath(normalizedPath);
}
status = statusCommand.call();
@@ -445,18 +486,19 @@ public class UIGit extends VCS {
public void add(String filePattern) throws HopException {
try {
- if (filePattern.endsWith(CONST_OURS) ||
filePattern.endsWith(CONST_THEIRS)) {
+ String normalizedPattern = normalizePathForJGit(filePattern);
+ if (normalizedPattern.endsWith(CONST_OURS) ||
normalizedPattern.endsWith(CONST_THEIRS)) {
FileUtils.rename(
- new File(directory, filePattern),
- new File(directory, FilenameUtils.removeExtension(filePattern)),
+ new File(directory, normalizedPattern),
+ new File(directory,
FilenameUtils.removeExtension(normalizedPattern)),
StandardCopyOption.REPLACE_EXISTING);
- filePattern = FilenameUtils.removeExtension(filePattern);
+ normalizedPattern = FilenameUtils.removeExtension(normalizedPattern);
org.apache.commons.io.FileUtils.deleteQuietly(
- new File(directory, filePattern + CONST_OURS));
+ new File(directory, normalizedPattern + CONST_OURS));
org.apache.commons.io.FileUtils.deleteQuietly(
- new File(directory, filePattern + CONST_THEIRS));
+ new File(directory, normalizedPattern + CONST_THEIRS));
}
- git.add().addFilepattern(filePattern).call();
+ git.add().addFilepattern(normalizedPattern).call();
} catch (Exception e) {
throw new HopException("Error adding '" + filePattern + "'to git", e);
}
@@ -464,7 +506,8 @@ public class UIGit extends VCS {
public void rm(String filepattern) {
try {
- git.rm().addFilepattern(filepattern).call();
+ String normalizedPattern = normalizePathForJGit(filepattern);
+ git.rm().addFilepattern(normalizedPattern).call();
} catch (Exception e) {
showMessageBox(BaseMessages.getString(PKG, CONST_DIALOG_ERROR),
e.getMessage());
}
@@ -482,7 +525,8 @@ public class UIGit extends VCS {
/** Reset a file to HEAD (mixed) */
public void resetPath(String path) {
try {
- git.reset().addPath(path).call();
+ String normalizedPath = normalizePathForJGit(path);
+ git.reset().addPath(normalizedPath).call();
} catch (Exception e) {
showMessageBox(BaseMessages.getString(PKG, CONST_DIALOG_ERROR),
e.getMessage());
}
@@ -689,9 +733,11 @@ public class UIGit extends VCS {
public String diff(String oldCommitId, String newCommitId, String file) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
+ String normalizedFile = normalizePathForJGit(file);
getDiffCommand(oldCommitId, newCommitId)
.setOutputStream(out)
- .setPathFilter(file == null ? TreeFilter.ALL :
PathFilter.create(file))
+ .setPathFilter(
+ normalizedFile == null ? TreeFilter.ALL :
PathFilter.create(normalizedFile))
.call();
return out.toString(StandardCharsets.UTF_8);
} catch (Exception e) {
@@ -700,9 +746,10 @@ public class UIGit extends VCS {
}
public InputStream open(String file, String commitId) throws HopException {
+ String normalizedFile = normalizePathForJGit(file);
if (commitId.equals(WORKINGTREE)) {
String baseDirectory = getDirectory();
- String filePath = baseDirectory + Const.FILE_SEPARATOR + file;
+ String filePath = baseDirectory + Const.FILE_SEPARATOR + normalizedFile;
try {
return HopVfs.getInputStream(filePath);
} catch (HopFileException e) {
@@ -713,23 +760,29 @@ public class UIGit extends VCS {
RevTree tree = commit.getTree();
try (TreeWalk tw = new TreeWalk(git.getRepository())) {
tw.addTree(tree);
- tw.setFilter(PathFilter.create(file));
+ tw.setFilter(PathFilter.create(normalizedFile));
tw.setRecursive(true);
tw.next();
ObjectLoader loader = git.getRepository().open(tw.getObjectId(0));
return loader.openStream();
} catch (MissingObjectException e) {
throw new HopException(
- "Unable to find file '" + file + CONST_FOR_COMMIT_ID + commitId +
"", e);
+ "Unable to find file '" + normalizedFile + CONST_FOR_COMMIT_ID +
commitId + "", e);
} catch (IncorrectObjectTypeException e) {
throw new HopException(
- "Incorrect object type error for file '" + file +
CONST_FOR_COMMIT_ID + commitId + "", e);
+ "Incorrect object type error for file '"
+ + normalizedFile
+ + CONST_FOR_COMMIT_ID
+ + commitId
+ + "",
+ e);
} catch (CorruptObjectException e) {
throw new HopException(
- "Corrupt object error for file '" + file + CONST_FOR_COMMIT_ID +
commitId + "", e);
+ "Corrupt object error for file '" + normalizedFile +
CONST_FOR_COMMIT_ID + commitId + "",
+ e);
} catch (IOException e) {
throw new HopException(
- "Error reading git file '" + file + CONST_FOR_COMMIT_ID + commitId +
"", e);
+ "Error reading git file '" + normalizedFile + CONST_FOR_COMMIT_ID +
commitId + "", e);
}
}
@@ -776,20 +829,21 @@ public class UIGit extends VCS {
public void revertPath(String path) throws HopException {
try {
+ String normalizedPath = normalizePathForJGit(path);
// Revert files to HEAD state
- Status status = git.status().addPath(path).call();
+ Status status = git.status().addPath(normalizedPath).call();
if (!status.getUntracked().isEmpty() || !status.getAdded().isEmpty()) {
- resetPath(path);
- org.apache.commons.io.FileUtils.deleteQuietly(new File(directory,
path));
+ resetPath(normalizedPath);
+ org.apache.commons.io.FileUtils.deleteQuietly(new File(directory,
normalizedPath));
}
/*
* This is a work-around to discard changes of conflicting files
* Git CLI `git checkout -- conflicted.txt` discards the changes, but
jgit does not
*/
- git.add().addFilepattern(path).call();
+ git.add().addFilepattern(normalizedPath).call();
- git.checkout().setStartPoint(Constants.HEAD).addPath(path).call();
+
git.checkout().setStartPoint(Constants.HEAD).addPath(normalizedPath).call();
org.apache.commons.io.FileUtils.deleteQuietly(new File(directory, path +
CONST_OURS));
org.apache.commons.io.FileUtils.deleteQuietly(new File(directory, path +
CONST_THEIRS));
} catch (Exception e) {
@@ -806,9 +860,10 @@ public class UIGit extends VCS {
public List<String> getRevertPathFiles(String path) throws HopException {
try {
Set<String> files = new HashSet<>();
+ String normalizedPath = normalizePathForJGit(path);
StatusCommand statusCommand = git.status();
- if (path != null && !".".equals(path)) {
- statusCommand = statusCommand.addPath(path);
+ if (normalizedPath != null && !".".equals(normalizedPath)) {
+ statusCommand = statusCommand.addPath(normalizedPath);
}
// Get files to be reverted to HEAD state
@@ -898,15 +953,16 @@ public class UIGit extends VCS {
}
private void checkout(String path, String commitId, String postfix) throws
HopException {
- InputStream stream = open(path, commitId);
- File file = new File(directory + Const.FILE_SEPARATOR + path + postfix);
+ String normalizedPath = normalizePathForJGit(path);
+ InputStream stream = open(normalizedPath, commitId);
+ File file = new File(directory + Const.FILE_SEPARATOR + normalizedPath +
postfix);
try {
org.apache.commons.io.FileUtils.copyInputStreamToFile(stream, file);
stream.close();
} catch (IOException e) {
throw new HopException(
"Error checking out file '"
- + path
+ + normalizedPath
+ CONST_FOR_COMMIT_ID
+ commitId
+ "' and postfix "
@@ -946,6 +1002,26 @@ public class UIGit extends VCS {
}
}
+ /**
+ * Normalize a file path for JGit operations. JGit requires paths to: - Use
forward slashes (/) as
+ * separators - Be relative to the repository root - Not start with a slash
+ *
+ * @param path The path to normalize (can be null)
+ * @return The normalized path, or the original if it's null or "."
+ */
+ private String normalizePathForJGit(String path) {
+ if (path == null || ".".equals(path)) {
+ return path;
+ }
+ // Convert backslashes to forward slashes
+ String normalized = path.replace("\\", "/");
+ // Remove leading slash if present
+ if (normalized.startsWith("/")) {
+ normalized = normalized.substring(1);
+ }
+ return normalized;
+ }
+
public String getShortenedName(String name) {
if (name.length() == Constants.OBJECT_ID_STRING_LENGTH) {
return name.substring(0, 7);
@@ -1041,9 +1117,10 @@ public class UIGit extends VCS {
public Set<String> getIgnored(String path) {
try {
+ String normalizedPath = normalizePathForJGit(path);
StatusCommand statusCommand = git.status();
- if (path != null && !".".equals(path)) {
- statusCommand = statusCommand.addPath(path);
+ if (normalizedPath != null && !".".equals(normalizedPath)) {
+ statusCommand = statusCommand.addPath(normalizedPath);
}
Status status = statusCommand.call();
return status.getIgnoredNotInIndex();