Bug 580412 - core.symlinks Option Ignored By AddCommand
Summary: core.symlinks Option Ignored By AddCommand
Status: RESOLVED FIXED
Alias: None
Product: JGit
Classification: Technology
Component: JGit (show other bugs)
Version: 6.2   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 6.3   Edit
Assignee: Project Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-07-20 05:53 EDT by Dave Hawkins CLA
Modified: 2022-08-13 09:30 EDT (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dave Hawkins CLA 2022-07-20 05:53:25 EDT
When core.symlinks = false, add operations should preserve the file mode of symlinks. However they are actually being changed to regular files.

The correct behaviour can be seen in git using the following steps:

 1. git init repo
 2. cd repo
 3. ln -s target link
 4. git add link
 5. git commit -m "Initial"
 6. echo "symlinks = false " >>.git/config
 7. rm link
 8. git reset --hard
 9. git ls-tree HEAD
10. git add link
11. git commit --allow-empty -m "Updated"
12. git ls-tree HEAD

Both ls-tree steps will show the file mode to be 120000.

If the equivalent steps are done in JGit, the add step causes the file mode to change to 100644, ie a regular file:

@Test
public void testSymlinkAdd() throws Exception {
  Path gitPath = Files.createTempDirectory(null);
  InitCommand initCommand = Git.init();
  initCommand.setDirectory(gitPath.toFile());
  initCommand.setInitialBranch(MASTER);
  git = initCommand.call();

  String linkName = "link";
  Path link = gitPath.resolve(linkName);
  Path target = Paths.get("target");
  Files.createSymbolicLink(link, target);
  git.add().addFilepattern(".").call();
  git.commit().setMessage("Initial").call();

  StoredConfig config = git.getRepository().getConfig();
  config.setBoolean(CONFIG_CORE_SECTION, null, CONFIG_KEY_SYMLINKS, false);
  config.save();

  Files.delete(link);
  git.reset().setMode(ResetCommand.ResetType.HARD).call();
  assertTrue(Files.isRegularFile(link));

  checkLinkIsSymlink();

  git.add().addFilepattern(linkName).call();
  git.commit().setAllowEmpty(true).setMessage("Updated").call();

  // The following fails
  checkLinkIsSymlink();
}

private void checkLinkIsSymlink() throws Exception {
  Repository repository = git.getRepository();
  ObjectId headCommit = repository.findRef(HEAD).getLeaf().getObjectId();
  RevTree tree = repository.parseCommit(headCommit).getTree();
  TreeWalk walk = new TreeWalk(repository);
  walk.addTree(tree);
  walk.setRecursive(false);
  walk.next();
  assertEquals(linkName, walk.getNameString());
  assertEquals(FileMode.SYMLINK, walk.getFileMode());
}

I believe the problem is due to WorkingTreeIterator::getIndexFileMode not taking into account the core.symlinks option. It can be worked around by subclassing FileTreeIterator, overriding the problematic method and using that with the AddCommand. Note that the symlinks option is taken into account in the isModeDifferent method.
Comment 1 Eclipse Genie CLA 2022-07-20 12:34:18 EDT
New Gerrit change created: https://git.eclipse.org/r/c/jgit/jgit/+/194808