Fix out-of-bounds exception in RepoCommand#relative

Change-Id: I9c91aa2ff037bff27a8131fba54be22f5f27d80d
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
index 24b5ad7..6ed2c21 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
@@ -1120,6 +1120,7 @@ public void relative() {
 		testRelative("a/", "a/b", "b");
 		testRelative("/a/b/c", "/b/c", "../../b/c");
 		testRelative("/abc", "bcd", "bcd");
+		testRelative("abc", "def", "def");
 		testRelative("abc", "/bcd", "/bcd");
 		testRelative("http://a", "a/b", "a/b");
 		testRelative("http://base.com/a/", "http://child.com/a/b", "http://child.com/a/b");
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
index 6669c9c..1de8a0b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -731,7 +731,9 @@ private void addSubmodule(String url, String path, String revision,
 	 * Returns the child if either base or child is not a bare path. This provides a missing feature in
 	 * java.net.URI (see http://bugs.java.com/view_bug.do?bug_id=6226081).
 	 */
+	private static final String SLASH = "/"; //$NON-NLS-1$
 	static URI relativize(URI current, URI target) {
+
 		// We only handle bare paths for now.
 		if (!target.toString().equals(target.getPath())) {
 			return target;
@@ -744,37 +746,46 @@ static URI relativize(URI current, URI target) {
 		String dest = target.normalize().getPath();
 
 		// TODO(hanwen): maybe (absolute, relative) should throw an exception.
-		if (cur.startsWith("/") != dest.startsWith("/")) { //$NON-NLS-1$//$NON-NLS-2$
+		if (cur.startsWith(SLASH) != dest.startsWith(SLASH)) {
 			return target;
 		}
 
-		while (cur.startsWith("/")) { //$NON-NLS-1$
+		while (cur.startsWith(SLASH)) {
 			cur = cur.substring(1);
 		}
-		while (dest.startsWith("/")) { //$NON-NLS-1$
+		while (dest.startsWith(SLASH)) {
 			dest = dest.substring(1);
 		}
 
-		if (!cur.endsWith("/")) { //$NON-NLS-1$
+		if (cur.indexOf('/') == -1 || dest.indexOf('/') == -1) {
+			// Avoid having to special-casing in the next two ifs.
+			String prefix = "prefix/"; //$NON-NLS-1$
+			cur = prefix + cur;
+			dest = prefix + dest;
+		}
+
+		if (!cur.endsWith(SLASH)) {
 			// The current file doesn't matter.
-			cur = cur.substring(0, cur.lastIndexOf('/'));
+			int lastSlash = cur.lastIndexOf('/');
+			cur = cur.substring(0, lastSlash);
 		}
 		String destFile = ""; //$NON-NLS-1$
-		if (!dest.endsWith("/")) { //$NON-NLS-1$
+		if (!dest.endsWith(SLASH)) {
 			// We always have to provide the destination file.
-			destFile = dest.substring(dest.lastIndexOf('/') + 1, dest.length());
+			int lastSlash = dest.lastIndexOf('/');
+			destFile = dest.substring(lastSlash + 1, dest.length());
 			dest = dest.substring(0, dest.lastIndexOf('/'));
 		}
 
-		String[] cs = cur.split("/"); //$NON-NLS-1$
-		String[] ds = dest.split("/"); //$NON-NLS-1$
+		String[] cs = cur.split(SLASH);
+		String[] ds = dest.split(SLASH);
 
 		int common = 0;
 		while (common < cs.length && common < ds.length && cs[common].equals(ds[common])) {
 			common++;
 		}
 
-		StringJoiner j = new StringJoiner("/"); //$NON-NLS-1$
+		StringJoiner j = new StringJoiner(SLASH);
 		for (int i = common; i < cs.length; i++) {
 			j.add(".."); //$NON-NLS-1$
 		}