diff --git a/jcheck/src/test/java/org/openjdk/skara/jcheck/TestRepository.java b/jcheck/src/test/java/org/openjdk/skara/jcheck/TestRepository.java index 8308fa521..cc2b76995 100644 --- a/jcheck/src/test/java/org/openjdk/skara/jcheck/TestRepository.java +++ b/jcheck/src/test/java/org/openjdk/skara/jcheck/TestRepository.java @@ -216,4 +216,8 @@ public Optional upstreamFor(Branch b) throws IOException { public List status(Hash from, Hash to) throws IOException { return Collections.emptyList(); } + + public boolean contains(Branch b, Hash h) throws IOException { + return false; + } } diff --git a/vcs/src/main/java/org/openjdk/skara/vcs/ReadOnlyRepository.java b/vcs/src/main/java/org/openjdk/skara/vcs/ReadOnlyRepository.java index 8b4cdbdb7..4bd46a098 100644 --- a/vcs/src/main/java/org/openjdk/skara/vcs/ReadOnlyRepository.java +++ b/vcs/src/main/java/org/openjdk/skara/vcs/ReadOnlyRepository.java @@ -55,6 +55,7 @@ public interface ReadOnlyRepository { Hash mergeBase(Hash first, Hash second) throws IOException; boolean isAncestor(Hash ancestor, Hash descendant) throws IOException; Optional resolve(String ref) throws IOException; + boolean contains(Branch b, Hash h) throws IOException; Optional username() throws IOException; Optional show(Path p, Hash h) throws IOException; default Optional> lines(Path p, Hash h) throws IOException { diff --git a/vcs/src/main/java/org/openjdk/skara/vcs/git/GitRepository.java b/vcs/src/main/java/org/openjdk/skara/vcs/git/GitRepository.java index ebee913c9..3e0165d87 100644 --- a/vcs/src/main/java/org/openjdk/skara/vcs/git/GitRepository.java +++ b/vcs/src/main/java/org/openjdk/skara/vcs/git/GitRepository.java @@ -1019,4 +1019,18 @@ public void pull(String remote, String refspec) throws IOException { await(p); } } + + @Override + public boolean contains(Branch b, Hash h) throws IOException { + try (var p = capture("git", "for-each-ref", "--contains", h.hex(), "--format", "%(refname:short)")) { + var res = await(p); + for (var line : res.stdout()) { + if (line.equals(b.name())) { + return true; + } + } + } + + return false; + } } diff --git a/vcs/src/main/java/org/openjdk/skara/vcs/hg/HgRepository.java b/vcs/src/main/java/org/openjdk/skara/vcs/hg/HgRepository.java index 86aef3bc1..dda3998aa 100644 --- a/vcs/src/main/java/org/openjdk/skara/vcs/hg/HgRepository.java +++ b/vcs/src/main/java/org/openjdk/skara/vcs/hg/HgRepository.java @@ -997,4 +997,16 @@ public void pull(String remote, String refspec) throws IOException { await(p); } } + + @Override + public boolean contains(Branch b, Hash h) throws IOException { + try (var p = capture("hg", "log", "--template", "{branch}", "-r", h.hex())) { + var res = await(p); + if (res.stdout().size() != 1) { + throw new IOException("Unexpected output: " + String.join("\n", res.stdout())); + } + var line = res.stdout().get(0); + return line.equals(b.name()); + } + } } diff --git a/vcs/src/test/java/org/openjdk/skara/vcs/RepositoryTests.java b/vcs/src/test/java/org/openjdk/skara/vcs/RepositoryTests.java index 8ba538a45..41e10ca07 100644 --- a/vcs/src/test/java/org/openjdk/skara/vcs/RepositoryTests.java +++ b/vcs/src/test/java/org/openjdk/skara/vcs/RepositoryTests.java @@ -1737,4 +1737,26 @@ void testTrackLineEndings(VCS vcs) throws IOException, InterruptedException { hunk.target().lines()); } } + + @ParameterizedTest + @EnumSource(VCS.class) + void testContains(VCS vcs) throws IOException { + try (var dir = new TemporaryDirectory()) { + var r = Repository.init(dir.path(), vcs); + assertTrue(r.isClean()); + + var f = dir.path().resolve("README"); + Files.writeString(f, "Hello\n"); + r.add(f); + var initial = r.commit("Initial commit", "duke", "duke@openjdk.org"); + + assertTrue(r.contains(r.defaultBranch(), initial)); + + Files.writeString(f, "Hello again\n"); + r.add(f); + var second = r.commit("Second commit", "duke", "duke@openjdk.org"); + + assertTrue(r.contains(r.defaultBranch(), initial)); + } + } }