-
Notifications
You must be signed in to change notification settings - Fork 23
Description
Problem
-
When I call
GitDir.fromExisting(path)wherepathis a symlink that points directly to the root of the work tree...ACTUAL: The operation succeeds, but the resulting
gitDir.pathcontains the unresolved symlink path.EXPECTED: The operation succeeds, and
gitDir.pathcontains the absolutized, canonicalized path with all symlinks resolved.REASONING: All paths returned by
git rev-parseare canonicalized, and have symlinks resolved. This is true for both relative and absolute paths it returns. This is a required piece of the way git works, because it's the only way to reliably manipulate and compare paths on the scale git needs to. It makes sense that GitDir would work the same way -- canonicalizing and removing symlinks so that the worktree path stored in GitDir matches the path that git reports. Judging from the code, I believe this is exactly what it was intended to do. So I'd classify this as a minor issue, currently causing inconsistent behavior when working with symlinks. -
When I call
GitDir.fromExisting(path, allowSubdirectory: true)wherepathis a symlink that points down into a sub-directory within the work tree (not the root of the work tree)...ACTUAL: The operation fails with an exception indicating that "The provided value 'my-repo/path/to/some/dir' is not the root of a git directory". The failure and message is non-sensical since
allowSubdirectory: truewas set, and we intentionally passed a sub-directory, not the root. The same operation succeeds if we resolve all symlinks in our path and try again.EXPECTED: The operation should succeed and work the same way, for both the symlink path, and the target path with symlinks resolved.
REASONING: For consistency, GitDir should produce the same result whether constructed with a symlink or a fully resolved path, as long as the target directory is the same in both cases. Also, all of the reasoning above, from
#1, also applies here.
Example
These test cases cover both situations described above.
import 'dart:io';
import 'package:git/git.dart';
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
import 'package:test_descriptor/test_descriptor.dart' as d;
Future<void> main() async {
group('creating GitDir with a symlink', () {
late GitDir repo;
setUp(() async {
// create a regular directory, and create a GitDir there.
Directory.current = Directory(d.sandbox);
final dir = await Directory('repo').create(recursive: true);
repo = await GitDir.init(dir.path);
});
test('calling fromExisting() with a link to worktree root', () async {
// create a symlink that points to worktree's root
Directory.current = Directory(d.sandbox);
final linkToRepoDir = await Link('link-to-root').create(repo.path);
final repoFromLink = await GitDir.fromExisting(linkToRepoDir.path);
expect(repo.path, repoFromLink.path, // <------------------------------------------- FAIL 1
reason: 'GitDir should resolve symlinks');
});
test('calling fromExisting() with a link to inside worktree', () async {
// create a directory tree within worktree
Directory.current = Directory(repo.path);
await Directory('path/within/work/tree').create(recursive: true);
// create a symlink that points inside the worktree below the root
Directory.current = Directory(d.sandbox);
final linkDestinationPath = p.join(repo.path, 'path/within/work');
final linkToRepoDir =
await Link('link-to-child').create(linkDestinationPath);
// make sure this path works correctly when it's not a symlink
final repoFromDirectPath = await GitDir.fromExisting(linkDestinationPath, // <------- FAIL 2
allowSubdirectory: true);
expect(
repo.path,
repoFromDirectPath.path,
reason: 'GitDir should point to the tree\'s root',
);
// now try the same thing using a symlink to the same location
final repoFromLink = await GitDir.fromExisting(linkToRepoDir.path,
allowSubdirectory: true);
expect(
repo.path,
repoFromLink.path,
reason: 'GitDir should resolve symlinks, and point to the tree\'s root',
);
});
});
}OUTPUT
00:01 +0 -1: creating GitDir with a symlink calling fromExisting() with a link to worktree root [E]
Expected: '/private/var/folders/pm/74183vl91990j7tbzgtcvn7r0000gn/T/dart_test_dadLYd/link-to-root'
Actual: '/private/var/folders/pm/74183vl91990j7tbzgtcvn7r0000gn/T/dart_test_dadLYd/repo'
Which: is different.
Expected: ... st_dadLYd/link-to-ro ...
Actual: ... st_dadLYd/repo
^
Differ at offset 74
GitDir should resolve symlinks
package:matcher expect
test/_symlink.dart 25:7 main.<fn>.<fn>
00:01 +0 -2: creating GitDir with a symlink calling fromExisting() with a link to inside worktree [E]
Invalid argument(s): The provided value "link-to-child" is not the root of a git directory
package:git/src/git_dir.dart 481:5 GitDir.fromExisting