Merge "Compute time differences with Duration"
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index f3e1fe3..c116437 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -294,6 +294,7 @@
 usage_StopTrackingAFile=Stop tracking a file
 usage_TextHashFunctions=Scan repository to compute maximum number of collisions for hash functions
 usage_UpdateRemoteRepositoryFromLocalRefs=Update remote repository from local refs
+usage_UseAll=Use all refs found in refs/
 usage_UseTags=Use any tag including lightweight tags
 usage_WriteDirCache=Write the DirCache
 usage_abbrevCommits=abbreviate commits to N + 1 digits
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
index 610b647..8aa119a 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
@@ -32,6 +32,9 @@
 	@Option(name = "--long", usage = "usage_LongFormat")
 	private boolean longDesc;
 
+	@Option(name = "--all", usage = "usage_UseTags")
+	private boolean useAll;
+
 	@Option(name = "--tags", usage = "usage_UseTags")
 	private boolean useTags;
 
@@ -50,6 +53,7 @@
 				cmd.setTarget(tree);
 			}
 			cmd.setLong(longDesc);
+			cmd.setAll(useAll);
 			cmd.setTags(useTags);
 			cmd.setAlways(always);
 			cmd.setMatch(patterns.toArray(new String[0]));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
index 7ba7c8d..b460e3f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
@@ -310,7 +310,7 @@
 			assertEquals(
 					"2 commits for describe commit increment expected since lightweight tag: c4 and c3",
 					"t2-2-g119892b", describe(c4)); // 2 commits: c4 and c3
-		} else if (!useAnnotatedTags && !describeUseAllTags) {
+		} else if (!useAnnotatedTags) {
 			assertEquals("no matching commits expected", null, describe(c4));
 		} else {
 			assertEquals(
@@ -405,6 +405,46 @@
 		}
 	}
 
+	@Test
+	public void testDescribeUseAllRefsMaster() throws Exception {
+		final ObjectId c1 = modify("aaa");
+		tag("t1");
+
+		if (useAnnotatedTags || describeUseAllTags) {
+			assertEquals("t1", describe(c1));
+		} else {
+			assertEquals(null, describe(c1));
+		}
+		assertEquals("heads/master", describeAll(c1));
+	}
+
+	/**
+	 * Branch off from master and then tag
+	 *
+	 * <pre>
+	 * c1 -+ -> c2
+	 *     |
+	 *     +-> t1
+	 * </pre>
+	 * @throws Exception
+	 * */
+	@Test
+	public void testDescribeUseAllRefsBranch() throws Exception {
+		final ObjectId c1 = modify("aaa");
+		modify("bbb");
+
+		branch("b", c1);
+		final ObjectId c3 = modify("ccc");
+		tag("t1");
+
+		if (!useAnnotatedTags && !describeUseAllTags) {
+			assertEquals(null, describe(c3));
+		} else {
+			assertEquals("t1", describe(c3));
+		}
+		assertEquals("heads/b", describeAll(c3));
+	}
+
 	private ObjectId merge(ObjectId c2) throws GitAPIException {
 		return git.merge().include(c2).call().getNewHead();
 	}
@@ -444,6 +484,11 @@
 		return describe(c1, false, false);
 	}
 
+	private String describeAll(ObjectId c1) throws GitAPIException, IOException {
+		return git.describe().setTarget(c1).setTags(describeUseAllTags)
+				.setLong(false).setAlways(false).setAll(true).call();
+	}
+
 	private String describe(ObjectId c1, String... patterns) throws Exception {
 		return git.describe().setTarget(c1).setTags(describeUseAllTags)
 				.setMatch(patterns).call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpConfigTest.java
index a5f98ee..5336dd7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpConfigTest.java
@@ -13,7 +13,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import org.eclipse.jgit.junit.MockSystemReader;
 import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.util.SystemReader;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -96,7 +98,8 @@
 	@Test
 	public void testMatchWithInvalidUriInConfig() throws Exception {
 		config.fromText(
-				DEFAULT + "[http \"///\"]\n" + "\tpostBuffer = 1024\n");
+				DEFAULT + "[http \"///#expectedWarning\"]\n"
+						+ "\tpostBuffer = 1024\n");
 		HttpConfig http = new HttpConfig(config,
 				new URIish("http://example.com/path/repo.git"));
 		assertEquals(1, http.getPostBuffer());
@@ -104,7 +107,8 @@
 
 	@Test
 	public void testMatchWithInvalidAndValidUriInConfig() throws Exception {
-		config.fromText(DEFAULT + "[http \"///\"]\n" + "\tpostBuffer = 1024\n"
+		config.fromText(DEFAULT + "[http \"///#expectedWarning\"]\n"
+				+ "\tpostBuffer = 1024\n"
 				+ "[http \"http://example.com\"]\n" + "\tpostBuffer = 2048\n");
 		HttpConfig http = new HttpConfig(config,
 				new URIish("http://example.com/path/repo.git"));
@@ -232,6 +236,31 @@
 	}
 
 	@Test
+	public void testUserAgentEnvOverride() throws Exception {
+		String mockAgent = "jgit-test/5.10.0";
+		SystemReader originalReader = SystemReader.getInstance();
+		SystemReader.setInstance(new MockSystemReader() {
+
+			@Override
+			public String getenv(String variable) {
+				if ("GIT_HTTP_USER_AGENT".equals(variable)) {
+					return mockAgent;
+				}
+				return super.getenv(variable);
+			}
+		});
+		try {
+			config.fromText(DEFAULT + "[http \"http://example.com\"]\n"
+					+ "\tuserAgent=DummyAgent/4.0\n");
+			HttpConfig http = new HttpConfig(config,
+					new URIish("http://example.com/"));
+			assertEquals(mockAgent, http.getUserAgent());
+		} finally {
+			SystemReader.setInstance(originalReader);
+		}
+	}
+
+	@Test
 	public void testUserAgentNonAscii() throws Exception {
 		config.fromText(DEFAULT + "[http \"http://example.com\"]\n"
 				+ "\tuserAgent= d ümmy Agent -5.10\n");
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
index 8d42738..6a9fbd4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
@@ -9,6 +9,7 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.eclipse.jgit.lib.Constants.R_REFS;
 import static org.eclipse.jgit.lib.Constants.R_TAGS;
 
 import java.io.IOException;
@@ -73,6 +74,11 @@
 	private List<FileNameMatcher> matchers = new ArrayList<>();
 
 	/**
+	 * Whether to use all refs in the refs/ namespace
+	 */
+	private boolean useAll;
+
+	/**
 	 * Whether to use all tags (incl. lightweight) or not.
 	 */
 	private boolean useTags;
@@ -153,6 +159,22 @@
 	}
 
 	/**
+	 * Instead of using only the annotated tags, use any ref found in refs/
+	 * namespace. This option enables matching any known branch,
+	 * remote-tracking branch, or lightweight tag.
+	 *
+	 * @param all
+	 *            <code>true</code> enables matching any ref found in refs/
+	 *            like setting option --all in c git
+	 * @return {@code this}
+	 * @since 5.10
+	 */
+	public DescribeCommand setAll(boolean all) {
+		this.useAll = all;
+		return this;
+	}
+
+	/**
 	 * Instead of using only the annotated tags, use any tag found in refs/tags
 	 * namespace. This option enables matching lightweight (non-annotated) tags
 	 * or not.
@@ -186,7 +208,7 @@
 	private String longDescription(Ref tag, int depth, ObjectId tip)
 			throws IOException {
 		return String.format(
-				"%s-%d-g%s", tag.getName().substring(R_TAGS.length()), //$NON-NLS-1$
+				"%s-%d-g%s", formatRefName(tag.getName()), //$NON-NLS-1$
 				Integer.valueOf(depth), w.getObjectReader().abbreviate(tip)
 						.name());
 	}
@@ -244,8 +266,7 @@
 			for (FileNameMatcher matcher : matchers) {
 				Stream<Ref> m = tags.stream().filter(
 						tag -> {
-							matcher.append(
-									tag.getName().substring(R_TAGS.length()));
+							matcher.append(formatRefName(tag.getName()));
 							boolean result = matcher.isMatch();
 							matcher.reset();
 							return result;
@@ -283,7 +304,7 @@
 			}
 
 			Collection<Ref> tagList = repo.getRefDatabase()
-					.getRefsByPrefix(R_TAGS);
+					.getRefsByPrefix(useAll ? R_REFS : R_TAGS);
 			Map<ObjectId, List<Ref>> tags = tagList.stream()
 					.filter(this::filterLightweightTags)
 					.collect(Collectors.groupingBy(this::getObjectIdFromRef));
@@ -336,7 +357,7 @@
 			Optional<Ref> bestMatch = getBestMatch(tags.get(target));
 			if (bestMatch.isPresent()) {
 				return longDesc ? longDescription(bestMatch.get(), 0, target) :
-						bestMatch.get().getName().substring(R_TAGS.length());
+						formatRefName(bestMatch.get().getName());
 			}
 
 			w.markStart(target);
@@ -408,6 +429,16 @@
 	}
 
 	/**
+	 * Removes the refs/ or refs/tags prefix from tag names
+	 * @param name the name of the tag
+	 * @return the tag name with its prefix removed
+	 */
+	private String formatRefName(String name) {
+		return name.startsWith(R_TAGS) ? name.substring(R_TAGS.length()) :
+				name.substring(R_REFS.length());
+	}
+
+	/**
 	 * Whether we use lightweight tags or not for describe Candidates
 	 *
 	 * @param ref
@@ -419,7 +450,7 @@
 	private boolean filterLightweightTags(Ref ref) {
 		ObjectId id = ref.getObjectId();
 		try {
-			return this.useTags || (id != null && (w.parseTag(id) != null));
+			return this.useAll || this.useTags || (id != null && (w.parseTag(id) != null));
 		} catch (IOException e) {
 			return false;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java
index 58fc250..dc82f46 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java
@@ -121,6 +121,8 @@
 		}
 	}).get().intValue();
 
+	private static final String ENV_HTTP_USER_AGENT = "GIT_HTTP_USER_AGENT"; //$NON-NLS-1$
+
 	/**
 	 * Config values for http.followRedirect.
 	 */
@@ -364,6 +366,11 @@
 			saveCookies = config.getBoolean(HTTP, match, SAVE_COOKIES_KEY,
 					saveCookies);
 		}
+		// Environment overrides config
+		agent = SystemReader.getInstance().getenv(ENV_HTTP_USER_AGENT);
+		if (!StringUtils.isEmptyOrNull(agent)) {
+			userAgent = UserAgent.clean(agent);
+		}
 		postBuffer = postBufferSize;
 		sslVerify = sslVerifyFlag;
 		followRedirects = followRedirectsMode;