git@vger.kernel.org mailing list mirror (one of many)
 help / Atom feed
* [JGIT PATCH 1/2] Close a forgotten reference to the HEAD ref.
       [not found] <y>
@ 2008-12-02 21:20 ` Robin Rosenberg
  2008-12-02 21:20   ` [JGIT PATCH 2/2] Improve closing of files in error situations Robin Rosenberg
  2009-06-07 20:19 ` [EGIT PATCH 0/3] Ref log reader Robin Rosenberg
                   ` (24 subsequent siblings)
  25 siblings, 1 reply; 95+ messages in thread
From: Robin Rosenberg @ 2008-12-02 21:20 UTC (permalink / raw)
  To: spearce; +Cc: git, Robin Rosenberg

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../src/org/spearce/jgit/lib/Repository.java       |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index c953531..b54afd5 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -989,9 +989,10 @@ public Ref peel(final Ref ref) {
 	 * @return true if HEAD points to a StGit patch.
 	 */
 	public boolean isStGitMode() {
+		File file = new File(getDirectory(), "HEAD");
+		BufferedReader reader = null;
 		try {
-			File file = new File(getDirectory(), "HEAD");
-			BufferedReader reader = new BufferedReader(new FileReader(file));
+			reader = new BufferedReader(new FileReader(file));
 			String string = reader.readLine();
 			if (!string.startsWith("ref: refs/heads/"))
 				return false;
@@ -1007,6 +1008,13 @@ public boolean isStGitMode() {
 		} catch (IOException e) {
 			e.printStackTrace();
 			return false;
+		} finally {
+			try {
+				if (reader != null)
+					reader.close();
+			} catch (IOException e1) {
+				// nothing to do here
+			}
 		}
 	}
 
-- 
1.6.0.3.640.g6331a

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [JGIT PATCH 2/2] Improve closing of files in error situations.
  2008-12-02 21:20 ` [JGIT PATCH 1/2] Close a forgotten reference to the HEAD ref Robin Rosenberg
@ 2008-12-02 21:20   ` Robin Rosenberg
  2008-12-02 21:41     ` [JGIT PATCH 2/2 v2] " Robin Rosenberg
  0 siblings, 1 reply; 95+ messages in thread
From: Robin Rosenberg @ 2008-12-02 21:20 UTC (permalink / raw)
  To: spearce; +Cc: git, Robin Rosenberg

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../exttst/org/spearce/jgit/lib/SpeedTestBase.java |   12 +++++--
 .../src/org/spearce/jgit/lib/Repository.java       |   31 +++++++++++++-------
 2 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/org.spearce.jgit.test/exttst/org/spearce/jgit/lib/SpeedTestBase.java b/org.spearce.jgit.test/exttst/org/spearce/jgit/lib/SpeedTestBase.java
index 11f7439..36a5e0e 100644
--- a/org.spearce.jgit.test/exttst/org/spearce/jgit/lib/SpeedTestBase.java
+++ b/org.spearce.jgit.test/exttst/org/spearce/jgit/lib/SpeedTestBase.java
@@ -72,10 +72,14 @@
 	protected void prepare(String[] refcmd) throws Exception {
 		try {
 			BufferedReader bufferedReader = new BufferedReader(new FileReader("kernel.ref"));
-			kernelrepo = bufferedReader.readLine();
-			bufferedReader.close();
-			timeNativeGit(kernelrepo, refcmd);
-			nativeTime = timeNativeGit(kernelrepo, refcmd);
+			try {
+				kernelrepo = bufferedReader.readLine();
+				bufferedReader.close();
+				timeNativeGit(kernelrepo, refcmd);
+				nativeTime = timeNativeGit(kernelrepo, refcmd);
+			} finally {
+				bufferedReader.close();
+			}
 		} catch (Exception e) {
 			System.out.println("Create a file named kernel.ref and put the path to the Linux kernels repository there");
 			throw e;
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index b54afd5..da1494f 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -144,10 +144,13 @@ public Repository(final File d) throws IOException {
 		final File altFile = FS.resolve(objectsDir, "info/alternates");
 		if (altFile.exists()) {
 			BufferedReader ar = new BufferedReader(new FileReader(altFile));
-			for (String alt=ar.readLine(); alt!=null; alt=ar.readLine()) {
-				readObjectsDirs(FS.resolve(objectsDir, alt), ret);
+			try {
+				for (String alt=ar.readLine(); alt!=null; alt=ar.readLine()) {
+					readObjectsDirs(FS.resolve(objectsDir, alt), ret);
+				}
+			} catch (Exception e) {
+				ar.close();
 			}
-			ar.close();
 		}
 		return ret;
 	}
@@ -1027,15 +1030,21 @@ public boolean isStGitMode() {
 		if (isStGitMode()) {
 			File patchDir = new File(new File(getDirectory(),"patches"),getBranch());
 			BufferedReader apr = new BufferedReader(new FileReader(new File(patchDir,"applied")));
-			for (String patchName=apr.readLine(); patchName!=null; patchName=apr.readLine()) {
-				File topFile = new File(new File(new File(patchDir,"patches"), patchName), "top");
-				BufferedReader tfr = new BufferedReader(new FileReader(topFile));
-				String objectId = tfr.readLine();
-				ObjectId id = ObjectId.fromString(objectId);
-				ret.put(id, new StGitPatch(patchName, id));
-				tfr.close();
+			try {
+				for (String patchName=apr.readLine(); patchName!=null; patchName=apr.readLine()) {
+					File topFile = new File(new File(new File(patchDir,"patches"), patchName), "top");
+					BufferedReader tfr = new BufferedReader(new FileReader(topFile));
+					try {
+						String objectId = tfr.readLine();
+						ObjectId id = ObjectId.fromString(objectId);
+						ret.put(id, new StGitPatch(patchName, id));
+					} finally {
+						tfr.close();
+					}
+				}
+			} finally {
+				apr.close();
 			}
-			apr.close();
 		}
 		return ret;
 	}
-- 
1.6.0.3.640.g6331a

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [JGIT PATCH 2/2 v2] Improve closing of files in error situations.
  2008-12-02 21:20   ` [JGIT PATCH 2/2] Improve closing of files in error situations Robin Rosenberg
@ 2008-12-02 21:41     ` " Robin Rosenberg
  0 siblings, 0 replies; 95+ messages in thread
From: Robin Rosenberg @ 2008-12-02 21:41 UTC (permalink / raw)
  To: spearce; +Cc: git, Robin Rosenberg

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../exttst/org/spearce/jgit/lib/SpeedTestBase.java |   12 +++++--
 .../dircache/DirCacheCGitCompatabilityTest.java    |   24 ++++++++++-----
 .../org/spearce/jgit/lib/RepositoryTestCase.java   |   27 +++++++++++------
 .../src/org/spearce/jgit/lib/GitIndex.java         |    2 +-
 .../src/org/spearce/jgit/lib/Repository.java       |   31 +++++++++++++-------
 5 files changed, 63 insertions(+), 33 deletions(-)

I was a bit quick there. This is an extended version of patch 2/2.

-- robin

diff --git a/org.spearce.jgit.test/exttst/org/spearce/jgit/lib/SpeedTestBase.java b/org.spearce.jgit.test/exttst/org/spearce/jgit/lib/SpeedTestBase.java
index 11f7439..36a5e0e 100644
--- a/org.spearce.jgit.test/exttst/org/spearce/jgit/lib/SpeedTestBase.java
+++ b/org.spearce.jgit.test/exttst/org/spearce/jgit/lib/SpeedTestBase.java
@@ -72,10 +72,14 @@
 	protected void prepare(String[] refcmd) throws Exception {
 		try {
 			BufferedReader bufferedReader = new BufferedReader(new FileReader("kernel.ref"));
-			kernelrepo = bufferedReader.readLine();
-			bufferedReader.close();
-			timeNativeGit(kernelrepo, refcmd);
-			nativeTime = timeNativeGit(kernelrepo, refcmd);
+			try {
+				kernelrepo = bufferedReader.readLine();
+				bufferedReader.close();
+				timeNativeGit(kernelrepo, refcmd);
+				nativeTime = timeNativeGit(kernelrepo, refcmd);
+			} finally {
+				bufferedReader.close();
+			}
 		} catch (Exception e) {
 			System.out.println("Create a file named kernel.ref and put the path to the Linux kernels repository there");
 			throw e;
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheCGitCompatabilityTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheCGitCompatabilityTest.java
index b052686..42832fe 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheCGitCompatabilityTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheCGitCompatabilityTest.java
@@ -146,10 +146,14 @@ private File pathOf(final String name) {
 		final LinkedHashMap<String, CGitIndexRecord> r = new LinkedHashMap<String, CGitIndexRecord>();
 		final BufferedReader br = new BufferedReader(new InputStreamReader(
 				new FileInputStream(pathOf("gitgit.lsfiles")), "UTF-8"));
-		String line;
-		while ((line = br.readLine()) != null) {
-			final CGitIndexRecord cr = new CGitIndexRecord(line);
-			r.put(cr.path, cr);
+		try {
+			String line;
+			while ((line = br.readLine()) != null) {
+				final CGitIndexRecord cr = new CGitIndexRecord(line);
+				r.put(cr.path, cr);
+			}
+		} finally {
+			br.close();
 		}
 		return r;
 	}
@@ -158,10 +162,14 @@ private File pathOf(final String name) {
 		final LinkedHashMap<String, CGitLsTreeRecord> r = new LinkedHashMap<String, CGitLsTreeRecord>();
 		final BufferedReader br = new BufferedReader(new InputStreamReader(
 				new FileInputStream(pathOf("gitgit.lstree")), "UTF-8"));
-		String line;
-		while ((line = br.readLine()) != null) {
-			final CGitLsTreeRecord cr = new CGitLsTreeRecord(line);
-			r.put(cr.path, cr);
+		try {
+			String line;
+			while ((line = br.readLine()) != null) {
+				final CGitLsTreeRecord cr = new CGitLsTreeRecord(line);
+				r.put(cr.path, cr);
+			}
+		} finally {
+			br.close();
 		}
 		return r;
 	}
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryTestCase.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryTestCase.java
index 22bf395..8937145 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryTestCase.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryTestCase.java
@@ -152,14 +152,20 @@ private static void reportDeleteFailure(final String name,
 	protected static void copyFile(final File src, final File dst)
 			throws IOException {
 		final FileInputStream fis = new FileInputStream(src);
-		final FileOutputStream fos = new FileOutputStream(dst);
-		final byte[] buf = new byte[4096];
-		int r;
-		while ((r = fis.read(buf)) > 0) {
-			fos.write(buf, 0, r);
+		try {
+			final FileOutputStream fos = new FileOutputStream(dst);
+			try {
+				final byte[] buf = new byte[4096];
+				int r;
+				while ((r = fis.read(buf)) > 0) {
+					fos.write(buf, 0, r);
+				}
+			} finally {
+				fos.close();
+			}
+		} finally {
+			fis.close();
 		}
-		fis.close();
-		fos.close();
 	}
 
 	protected File writeTrashFile(final String name, final String data)
@@ -170,8 +176,11 @@ protected File writeTrashFile(final String name, final String data)
 			throw new Error("Could not create directory " + tf.getParentFile());
 		final OutputStreamWriter fw = new OutputStreamWriter(
 				new FileOutputStream(tf), "UTF-8");
-		fw.write(data);
-		fw.close();
+		try {
+			fw.write(data);
+		} finally {
+			fw.close();
+		}
 		return tf;
 	}
 
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/GitIndex.java b/org.spearce.jgit/src/org/spearce/jgit/lib/GitIndex.java
index bafddef..7ff6754 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/GitIndex.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/GitIndex.java
@@ -547,8 +547,8 @@ public boolean isModified(File wd, boolean forceContentCheck) {
 
 				try {
 					InputStream is = new FileInputStream(file);
-					ObjectWriter objectWriter = new ObjectWriter(db);
 					try {
+						ObjectWriter objectWriter = new ObjectWriter(db);
 						ObjectId newId = objectWriter.computeBlobSha1(file
 								.length(), is);
 						boolean ret = !newId.equals(sha1);
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index b54afd5..da1494f 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -144,10 +144,13 @@ public Repository(final File d) throws IOException {
 		final File altFile = FS.resolve(objectsDir, "info/alternates");
 		if (altFile.exists()) {
 			BufferedReader ar = new BufferedReader(new FileReader(altFile));
-			for (String alt=ar.readLine(); alt!=null; alt=ar.readLine()) {
-				readObjectsDirs(FS.resolve(objectsDir, alt), ret);
+			try {
+				for (String alt=ar.readLine(); alt!=null; alt=ar.readLine()) {
+					readObjectsDirs(FS.resolve(objectsDir, alt), ret);
+				}
+			} catch (Exception e) {
+				ar.close();
 			}
-			ar.close();
 		}
 		return ret;
 	}
@@ -1027,15 +1030,21 @@ public boolean isStGitMode() {
 		if (isStGitMode()) {
 			File patchDir = new File(new File(getDirectory(),"patches"),getBranch());
 			BufferedReader apr = new BufferedReader(new FileReader(new File(patchDir,"applied")));
-			for (String patchName=apr.readLine(); patchName!=null; patchName=apr.readLine()) {
-				File topFile = new File(new File(new File(patchDir,"patches"), patchName), "top");
-				BufferedReader tfr = new BufferedReader(new FileReader(topFile));
-				String objectId = tfr.readLine();
-				ObjectId id = ObjectId.fromString(objectId);
-				ret.put(id, new StGitPatch(patchName, id));
-				tfr.close();
+			try {
+				for (String patchName=apr.readLine(); patchName!=null; patchName=apr.readLine()) {
+					File topFile = new File(new File(new File(patchDir,"patches"), patchName), "top");
+					BufferedReader tfr = new BufferedReader(new FileReader(topFile));
+					try {
+						String objectId = tfr.readLine();
+						ObjectId id = ObjectId.fromString(objectId);
+						ret.put(id, new StGitPatch(patchName, id));
+					} finally {
+						tfr.close();
+					}
+				}
+			} finally {
+				apr.close();
 			}
-			apr.close();
 		}
 		return ret;
 	}
-- 
1.6.0.3.640.g6331a

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [EGIT PATCH 0/3] Ref log reader
       [not found] <y>
  2008-12-02 21:20 ` [JGIT PATCH 1/2] Close a forgotten reference to the HEAD ref Robin Rosenberg
@ 2009-06-07 20:19 ` Robin Rosenberg
  2009-06-07 20:19   ` [EGIT PATCH 1/3] Assert the name and origName properties of Ref objects Robin Rosenberg
  2009-06-22 11:49 ` [BUG] apply: test for trailing whitespace & no new line bug y
                   ` (23 subsequent siblings)
  25 siblings, 1 reply; 95+ messages in thread
From: Robin Rosenberg @ 2009-06-07 20:19 UTC (permalink / raw)
  To: spearce; +Cc: git, Robin Rosenberg

Initially this is needed to the next revised set of rename tests. I have
not optimized much for performance.

-- robin

Robin Rosenberg (3):
  Assert the name and origName properties of Ref objects
  Add methods to RawParseUtils for scanning backwards.
  Add a ref log reader class

 .../tst/org/spearce/jgit/lib/RefTest.java          |   11 ++
 .../tst/org/spearce/jgit/lib/ReflogReaderTest.java |  153 ++++++++++++++++
 .../src/org/spearce/jgit/lib/ReflogReader.java     |  186 ++++++++++++++++++++
 .../src/org/spearce/jgit/lib/Repository.java       |    9 +
 .../src/org/spearce/jgit/util/RawParseUtils.java   |   84 +++++++++-
 5 files changed, 442 insertions(+), 1 deletions(-)
 create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [EGIT PATCH 1/3] Assert the name and origName properties of Ref objects
  2009-06-07 20:19 ` [EGIT PATCH 0/3] Ref log reader Robin Rosenberg
@ 2009-06-07 20:19   ` Robin Rosenberg
  2009-06-07 20:19     ` [EGIT PATCH 2/3] Add methods to RawParseUtils for scanning backwards Robin Rosenberg
  0 siblings, 1 reply; 95+ messages in thread
From: Robin Rosenberg @ 2009-06-07 20:19 UTC (permalink / raw)
  To: spearce; +Cc: git, Robin Rosenberg

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../tst/org/spearce/jgit/lib/RefTest.java          |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RefTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RefTest.java
index 440686d..fabbe7e 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RefTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RefTest.java
@@ -144,4 +144,15 @@ public void testReadSimplePackedRefSameRepo() throws IOException {
 		assertEquals(Storage.LOOSE_PACKED, ref.getStorage());
 	}
 
+	public void testOrigResolvedNamesBranch() throws IOException {
+		Ref ref = db.getRef("a");
+		assertEquals("refs/heads/a", ref.getName());
+		assertEquals("refs/heads/a", ref.getOrigName());
+	}
+
+	public void testOrigResolvedNamesSymRef() throws IOException {
+		Ref ref = db.getRef("HEAD");
+		assertEquals("refs/heads/master", ref.getName());
+		assertEquals("HEAD", ref.getOrigName());
+	}
 }
-- 
1.6.3.2.199.g7340d

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [EGIT PATCH 2/3] Add methods to RawParseUtils for scanning backwards.
  2009-06-07 20:19   ` [EGIT PATCH 1/3] Assert the name and origName properties of Ref objects Robin Rosenberg
@ 2009-06-07 20:19     ` Robin Rosenberg
  2009-06-07 20:19       ` [EGIT PATCH 3/3] Add a ref log reader class Robin Rosenberg
  0 siblings, 1 reply; 95+ messages in thread
From: Robin Rosenberg @ 2009-06-07 20:19 UTC (permalink / raw)
  To: spearce; +Cc: git, Robin Rosenberg

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../src/org/spearce/jgit/util/RawParseUtils.java   |   84 +++++++++++++++++++-
 1 files changed, 83 insertions(+), 1 deletions(-)

diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
index 79ebe41..bdd6a11 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
@@ -321,6 +321,67 @@ public static final int nextLF(final byte[] b, int ptr, final char chrA) {
 	}
 
 	/**
+	 * Locate the first position before a given character.
+	 * 
+	 * @param b
+	 *            buffer to scan.
+	 * @param ptr
+	 *            position within buffer to start looking for chrA at.
+	 * @param chrA
+	 *            character to find.
+	 * @return new position just before chrA, -1 for not found
+	 */
+	public static final int prev(final byte[] b, int ptr, final char chrA) {
+		if (ptr == b.length)
+			--ptr;
+		while (ptr >= 0) {
+			if (b[ptr--] == chrA)
+				return ptr;
+		}
+		return ptr;
+	}
+
+	/**
+	 * Locate the first position before the previous LF.
+	 * <p>
+	 * This method stops on the first '\n' it finds.
+	 * 
+	 * @param b
+	 *            buffer to scan.
+	 * @param ptr
+	 *            position within buffer to start looking for LF at.
+	 * @return new position just before the first LF found, -1 for not found
+	 */
+	public static final int prevLF(final byte[] b, int ptr) {
+		return prev(b, ptr, '\n');
+	}
+
+	/**
+	 * Locate the previous position before either the given character or LF.
+	 * <p>
+	 * This method stops on the first match it finds from either chrA or '\n'.
+	 * 
+	 * @param b
+	 *            buffer to scan.
+	 * @param ptr
+	 *            position within buffer to start looking for chrA or LF at.
+	 * @param chrA
+	 *            character to find.
+	 * @return new position just before the first chrA or LF to be found, -1 for
+	 *         not found
+	 */
+	public static final int prevLF(final byte[] b, int ptr, final char chrA) {
+		if (ptr == b.length)
+			--ptr;
+		while (ptr >= 0) {
+			final byte c = b[ptr--];
+			if (c == chrA || c == '\n')
+				return ptr;
+		}
+		return ptr;
+	}
+
+	/**
 	 * Index the region between <code>[ptr, end)</code> to find line starts.
 	 * <p>
 	 * The returned list is 1 indexed. Index 0 contains
@@ -519,7 +580,28 @@ public static PersonIdent parsePersonIdent(final byte[] raw, final int nameB) {
 	 *         after decoding the region through the specified character set.
 	 */
 	public static String decode(final byte[] buffer) {
-		return decode(Constants.CHARSET, buffer, 0, buffer.length);
+		return decode(buffer, 0, buffer.length);
+	}
+
+	/**
+	 * Decode a buffer under UTF-8, if possible.
+	 * 
+	 * If the byte stream cannot be decoded that way, the platform default is
+	 * tried and if that too fails, the fail-safe ISO-8859-1 encoding is tried.
+	 * 
+	 * @param buffer
+	 *            buffer to pull raw bytes from.
+	 * @param start
+	 *            start position in buffer
+	 * @param end
+	 *            one position past the last location within the buffer to take
+	 *            data from.
+	 * @return a string representation of the range <code>[start,end)</code>,
+	 *         after decoding the region through the specified character set.
+	 */
+	public static String decode(final byte[] buffer, final int start,
+			final int end) {
+		return decode(Constants.CHARSET, buffer, start, end);
 	}
 
 	/**
-- 
1.6.3.2.199.g7340d

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [EGIT PATCH 3/3] Add a ref log reader class
  2009-06-07 20:19     ` [EGIT PATCH 2/3] Add methods to RawParseUtils for scanning backwards Robin Rosenberg
@ 2009-06-07 20:19       ` Robin Rosenberg
  2009-06-07 22:21         ` Shawn O. Pearce
  0 siblings, 1 reply; 95+ messages in thread
From: Robin Rosenberg @ 2009-06-07 20:19 UTC (permalink / raw)
  To: spearce; +Cc: git, Robin Rosenberg

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../tst/org/spearce/jgit/lib/ReflogReaderTest.java |  153 ++++++++++++++++
 .../src/org/spearce/jgit/lib/ReflogReader.java     |  186 ++++++++++++++++++++
 .../src/org/spearce/jgit/lib/Repository.java       |    9 +
 3 files changed, 348 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java

diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java
new file mode 100644
index 0000000..1919477
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2009, Robin Rosenberg
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.spearce.jgit.lib;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import org.spearce.jgit.lib.ReflogReader.Entry;
+
+public class ReflogReaderTest extends RepositoryTestCase {
+
+	static byte[] oneLine = "da85355dfc525c9f6f3927b876f379f46ccf826e 3e7549db262d1e836d9bf0af7e22355468f1717c Robin Rosenberg <robin.rosenberg@dewire.com> 1243028200 +0200\tcommit: Add a toString for debugging to RemoteRefUpdate\n"
+			.getBytes();
+
+	static byte[] twoLine = ("0000000000000000000000000000000000000000 c6734895958052a9dbc396cff4459dc1a25029ab A U Thor <thor@committer.au> 1243028201 -0100\tbranch: Created from rr/renamebranchv4\n"
+			+ "c6734895958052a9dbc396cff4459dc1a25029ab 54794942a18a237c57a80719afed44bb78172b10 Same A U Thor <same.author@example.com> 1243028202 +0100\trebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d\n")
+			.getBytes();
+
+	static byte[] aLine = "1111111111111111111111111111111111111111 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to a\n"
+			.getBytes();
+
+	static byte[] masterLine = "2222222222222222222222222222222222222222 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to master\n"
+			.getBytes();
+
+	static byte[] headLine = "3333333333333333333333333333333333333333 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to HEAD\n"
+			.getBytes();
+
+	public void testReadOneLine() throws Exception {
+		setupReflog("logs/refs/heads/master", oneLine);
+
+		ReflogReader reader = new ReflogReader(db, "refs/heads/master");
+		Entry e = reader.getLastEntry();
+		assertEquals(ObjectId
+				.fromString("da85355dfc525c9f6f3927b876f379f46ccf826e"), e
+				.getOldId());
+		assertEquals(ObjectId
+				.fromString("3e7549db262d1e836d9bf0af7e22355468f1717c"), e
+				.getNewId());
+		assertEquals("Robin Rosenberg", e.getWho().getName());
+		assertEquals("robin.rosenberg@dewire.com", e.getWho().getEmailAddress());
+		assertEquals(120, e.getWho().getTimeZoneOffset());
+		assertEquals("2009-05-22T23:36:40", iso(e.getWho().getWhen()));
+		assertEquals("commit", e.getAction());
+		assertEquals("Add a toString for debugging to RemoteRefUpdate", e
+				.getComment());
+	}
+
+	private String iso(Date d) {
+		return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(d);
+	}
+
+	public void testReadTwoLine() throws Exception {
+		setupReflog("logs/refs/heads/master", twoLine);
+
+		ReflogReader reader = new ReflogReader(db, "refs/heads/master");
+		List<Entry> reverseEntries = reader.getReverseEntries();
+		Entry e = reverseEntries.get(0);
+		assertEquals(ObjectId
+				.fromString("c6734895958052a9dbc396cff4459dc1a25029ab"), e
+				.getOldId());
+		assertEquals(ObjectId
+				.fromString("54794942a18a237c57a80719afed44bb78172b10"), e
+				.getNewId());
+		assertEquals("Same A U Thor", e.getWho().getName());
+		assertEquals("same.author@example.com", e.getWho().getEmailAddress());
+		assertEquals(60, e.getWho().getTimeZoneOffset());
+		assertEquals("2009-05-22T23:36:42", iso(e.getWho().getWhen()));
+		assertEquals("rebase finished", e.getAction());
+		assertEquals(
+				"refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d",
+				e.getComment());
+
+		e = reverseEntries.get(1);
+		assertEquals(ObjectId
+				.fromString("0000000000000000000000000000000000000000"), e
+				.getOldId());
+		assertEquals(ObjectId
+				.fromString("c6734895958052a9dbc396cff4459dc1a25029ab"), e
+				.getNewId());
+		assertEquals("A U Thor", e.getWho().getName());
+		assertEquals("thor@committer.au", e.getWho().getEmailAddress());
+		assertEquals(-60, e.getWho().getTimeZoneOffset());
+		assertEquals("2009-05-22T23:36:41", iso(e.getWho().getWhen()));
+		assertEquals("branch", e.getAction());
+		assertEquals("Created from rr/renamebranchv4", e.getComment());
+	}
+
+	public void testReadRightLog() throws Exception {
+		setupReflog("logs/refs/heads/a", aLine);
+		setupReflog("logs/refs/heads/master", masterLine);
+		setupReflog("logs/HEAD", headLine);
+		assertEquals("change to master", db.getReflogReader("master")
+				.getLastEntry().getComment());
+		assertEquals("change to a", db.getReflogReader("a").getLastEntry()
+				.getComment());
+		assertEquals("change to HEAD", db.getReflogReader("HEAD").getLastEntry()
+				.getComment());
+	}
+
+	public void testNoLog() throws Exception {
+		assertEquals(0, db.getReflogReader("master").getReverseEntries().size());
+		assertNull(db.getReflogReader("master").getLastEntry());
+	}
+
+	private void setupReflog(String logName, byte[] data)
+			throws FileNotFoundException, IOException {
+		File logfile = new File(db.getDirectory(), logName);
+		logfile.getParentFile().mkdirs();
+		FileOutputStream fileOutputStream = new FileOutputStream(logfile);
+		fileOutputStream.write(data);
+		fileOutputStream.close();
+
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java
new file mode 100644
index 0000000..15591af
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2009, Robin Rosenberg
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.spearce.jgit.lib;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.spearce.jgit.util.NB;
+import org.spearce.jgit.util.RawParseUtils;
+
+/**
+ * Utility for reading reflog entries
+ */
+public class ReflogReader {
+	/**
+	 * Parsed reflog entry
+	 */
+	static public class Entry {
+		Entry(byte[] raw, int pos) {
+			oldId = ObjectId.fromString(raw, pos);
+			if (raw[pos + Constants.OBJECT_ID_LENGTH * 2] != ' ')
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			newId = ObjectId.fromString(raw, pos + Constants.OBJECT_ID_LENGTH
+					* 2 + 1);
+			if (raw[pos + Constants.OBJECT_ID_LENGTH * 2 * 2 + 1] != ' ')
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			who = RawParseUtils.parsePersonIdent(raw, pos
+					+ Constants.OBJECT_ID_LENGTH * 2 * 2 + 2);
+			int p0 = RawParseUtils.next(raw, pos + Constants.OBJECT_ID_LENGTH
+					* 2 * 2 + 2, '\t');
+			if (p0 == -1)
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			int p1 = RawParseUtils.next(raw, p0 + 1, ':');
+			if (p1 == -1)
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			action = RawParseUtils.decode(raw, p0, p1-1).trim();
+			int p2 = RawParseUtils.nextLF(raw, p1 + 1);
+			if (p2 == -1)
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			comment = RawParseUtils.decode(raw, p1, p2).trim();
+		}
+
+		/**
+		 * @return the commit id before the change
+		 */
+		public ObjectId getOldId() {
+			return oldId;
+		}
+
+		/**
+		 * @return the commit id after the change
+		 */
+		public ObjectId getNewId() {
+			return newId;
+		}
+
+		/**
+		 * @return user performin the change
+		 */
+		public PersonIdent getWho() {
+			return who;
+		}
+
+		/**
+		 * @return some kind of textual indication of the change made
+		 */
+		public String getAction() {
+			return action;
+		}
+
+		/**
+		 * @return textual description of the change
+		 */
+		public String getComment() {
+			return comment;
+		}
+
+		private ObjectId oldId;
+
+		private ObjectId newId;
+
+		private PersonIdent who;
+
+		private String action;
+
+		private String comment;
+	}
+
+	private File logName;
+
+	ReflogReader(Repository db, String refname) {
+		logName = new File(db.getDirectory(), "logs/" + refname);
+	}
+
+	/**
+	 * Get the last entry in the reflog
+	 * 
+	 * @return the latest reflog entry, or null if no log
+	 * @throws IOException
+	 */
+	public Entry getLastEntry() throws IOException {
+		List<Entry> entries = getReverseEntries(1);
+		return entries.size() > 0 ? entries.get(0) : null;
+	}
+
+	/**
+	 * @return all reflog entries in reverse order
+	 * @throws IOException
+	 */
+	public List<Entry> getReverseEntries() throws IOException {
+		return getReverseEntries(Integer.MAX_VALUE);
+	}
+
+	/**
+	 * @param max
+	 *            max numer of entries to read
+	 * @return all reglog entries in reverse order
+	 * @throws IOException
+	 */
+	public List<Entry> getReverseEntries(int max) throws IOException {
+		FileInputStream fileInputStream;
+		try {
+			fileInputStream = new FileInputStream(logName);
+		} catch (FileNotFoundException e) {
+			return Collections.emptyList();
+		}
+		if (logName.length() > Integer.MAX_VALUE)
+			// implementation limit, will suck with smaller files too
+			throw new IOException("Cannot handle reflog larger than "
+					+ Integer.MAX_VALUE + " bytes");
+		byte[] log = new byte[(int) logName.length()];
+		NB.readFully(fileInputStream, log, 0, log.length);
+		int rs = log.length - 2; // skip terminating \n
+		List<Entry> ret = new ArrayList<Entry>();
+		while (rs >= 0 && max-- > 0) {
+			rs = RawParseUtils.prevLF(log, rs);
+			Entry entry = new Entry(log, rs < 0 ? 0 : rs + 2);
+			ret.add(entry);
+		}
+		return ret;
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index 5def5d3..89dc044 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -1089,4 +1089,13 @@ public String shortenRefName(String refName) {
 			return refName.substring(Constants.R_REMOTES.length());
 		return refName;
 	}
+
+	/**
+	 * @param refName
+	 * @return a {@link ReflogReader} for the refname
+	 * @throws IOException 
+	 */
+	public ReflogReader getReflogReader(String refName) throws IOException {
+		return new ReflogReader(this, getRef(refName).getOrigName());
+	}
 }
-- 
1.6.3.2.199.g7340d

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [EGIT PATCH 3/3] Add a ref log reader class
  2009-06-07 20:19       ` [EGIT PATCH 3/3] Add a ref log reader class Robin Rosenberg
@ 2009-06-07 22:21         ` Shawn O. Pearce
  2009-06-07 22:45           ` Robin Rosenberg
  0 siblings, 1 reply; 95+ messages in thread
From: Shawn O. Pearce @ 2009-06-07 22:21 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

Robin Rosenberg <robin.rosenberg@dewire.com> wrote:
> diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java
> new file mode 100644
> index 0000000..15591af
> --- /dev/null
> +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java
> @@ -0,0 +1,186 @@
...
> +public class ReflogReader {
> +	/**
> +	 * Parsed reflog entry
> +	 */
> +	static public class Entry {
> +		Entry(byte[] raw, int pos) {
> +			oldId = ObjectId.fromString(raw, pos);
> +			if (raw[pos + Constants.OBJECT_ID_LENGTH * 2] != ' ')
> +				throw new IllegalArgumentException(
> +						"Raw log message does not parse as log entry");

Please, for the sake of everyone's sanity, increment pos after you
read oldId.  Then its just raw[pos++] != ' ' here, and the next
line for newId is even shorter.

> +			int p1 = RawParseUtils.next(raw, p0 + 1, ':');
> +			if (p1 == -1)
> +				throw new IllegalArgumentException(
> +						"Raw log message does not parse as log entry");

Technically, missing a ':' is legal.  Everything after the '\t'
is the comment.  It may be splittable into an action/comment,
it might not be.

> +			action = RawParseUtils.decode(raw, p0, p1-1).trim();
> +			int p2 = RawParseUtils.nextLF(raw, p1 + 1);
> +			if (p2 == -1)
> +				throw new IllegalArgumentException(
> +						"Raw log message does not parse as log entry");
> +			comment = RawParseUtils.decode(raw, p1, p2).trim();

trim() on these shouldn't be necessary.  If you parse the line
right, you can avoid handing the '\t' and the '\n' to the decode,
and then whatever is left is what was given to the logger, and we
should faithfully return that to the caller.  Its unlikely to have
unncessary whitespace, so the trim is just wasting CPU looking
for it.

> +		private ObjectId oldId;
> +
> +		private ObjectId newId;
> +
> +		private PersonIdent who;
> +
> +		private String action;
> +
> +		private String comment;

Style nit: I much prefer fields to appear before the constructor.

> +	}
...
> +	public List<Entry> getReverseEntries(int max) throws IOException {
> +		FileInputStream fileInputStream;
> +		try {
> +			fileInputStream = new FileInputStream(logName);
> +		} catch (FileNotFoundException e) {
> +			return Collections.emptyList();
> +		}

Please ensure fileInputStream doesn't leak and is closed before
this method block returns.

> +		if (logName.length() > Integer.MAX_VALUE)
> +			// implementation limit, will suck with smaller files too
> +			throw new IOException("Cannot handle reflog larger than "
> +					+ Integer.MAX_VALUE + " bytes");

Style nit: Please wrap this huge block in {}, its easier to read
when there are more than one line dangling below.

> +		byte[] log = new byte[(int) logName.length()];

Please use fileInputStream.getChannel().size() as it does an fstat()
rather than a stat() on the path.

But I'd rather just read the file backwards, with a RandomAccessFile
and what amounts to a reverse version of BufferedInputStream.

> +		NB.readFully(fileInputStream, log, 0, log.length);
> +		int rs = log.length - 2; // skip terminating \n

If the file is currently being appended to, it might not end in
'\n'.  Something to keep in mind.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [EGIT PATCH 3/3] Add a ref log reader class
  2009-06-07 22:21         ` Shawn O. Pearce
@ 2009-06-07 22:45           ` Robin Rosenberg
  2009-06-07 22:47             ` Shawn O. Pearce
  0 siblings, 1 reply; 95+ messages in thread
From: Robin Rosenberg @ 2009-06-07 22:45 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git

måndag 08 juni 2009 00:21:54 skrev "Shawn O. Pearce" <spearce@spearce.org>:
> Robin Rosenberg <robin.rosenberg@dewire.com> wrote:
...
> > +			int p1 = RawParseUtils.next(raw, p0 + 1, ':');
> > +			if (p1 == -1)
> > +				throw new IllegalArgumentException(
> > +						"Raw log message does not parse as log entry");
> 
> Technically, missing a ':' is legal.  Everything after the '\t'
> is the comment.  It may be splittable into an action/comment,
> it might not be.

Do you think I should just skip parsing out action? I don't really need it. I can
go with everything after tab as one string for my purposes, i.e. reading reflogs
in JUnit tests.

As for optimized reading, I'd rather spend my time on something else. Reading
reflogs won't likely be a real problem and I think the interface will be stable
even if it needs to be optimized.

The other stuff I'll fix.

-- robin

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [EGIT PATCH 3/3] Add a ref log reader class
  2009-06-07 22:45           ` Robin Rosenberg
@ 2009-06-07 22:47             ` Shawn O. Pearce
  2009-06-08 17:28               ` [EGIT PATCH 1/2] Add methods to RawParseUtils for scanning backwards Robin Rosenberg
  0 siblings, 1 reply; 95+ messages in thread
From: Shawn O. Pearce @ 2009-06-07 22:47 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

Robin Rosenberg <robin.rosenberg.lists@dewire.com> wrote:
> m?ndag 08 juni 2009 00:21:54 skrev "Shawn O. Pearce" <spearce@spearce.org>:
> > Robin Rosenberg <robin.rosenberg@dewire.com> wrote:
> ...
> > > +			int p1 = RawParseUtils.next(raw, p0 + 1, ':');
> > > +			if (p1 == -1)
> > > +				throw new IllegalArgumentException(
> > > +						"Raw log message does not parse as log entry");
> > 
> > Technically, missing a ':' is legal.  Everything after the '\t'
> > is the comment.  It may be splittable into an action/comment,
> > it might not be.
> 
> Do you think I should just skip parsing out action? I don't really need it. I can
> go with everything after tab as one string for my purposes, i.e. reading reflogs
> in JUnit tests.

Yea, just skip it.
 
> As for optimized reading, I'd rather spend my time on something else. Reading
> reflogs won't likely be a real problem and I think the interface will be stable
> even if it needs to be optimized.
> 
> The other stuff I'll fix.

OK, sounds fine to me.

Maybe we should cap the limit at say 20 MiB of log or something, and
refuse to read anything more than that, rather than allowing 2 GiB.

Or, since we most likely only care about the tail, if its over 5
MiB, skip through to the end and then read the last 5 MiB, and if we
have a partial entry left over at the start of the buffer, ignore it.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [EGIT PATCH 1/2] Add methods to RawParseUtils for scanning backwards.
  2009-06-07 22:47             ` Shawn O. Pearce
@ 2009-06-08 17:28               ` Robin Rosenberg
  2009-06-08 17:28                 ` [EGIT PATCH 2/2] Add a ref log reader class Robin Rosenberg
  0 siblings, 1 reply; 95+ messages in thread
From: Robin Rosenberg @ 2009-06-08 17:28 UTC (permalink / raw)
  To: spearce; +Cc: git, Robin Rosenberg

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../src/org/spearce/jgit/util/RawParseUtils.java   |   84 +++++++++++++++++++-
 1 files changed, 83 insertions(+), 1 deletions(-)

diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
index 79ebe41..bdd6a11 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
@@ -321,6 +321,67 @@ public static final int nextLF(final byte[] b, int ptr, final char chrA) {
 	}
 
 	/**
+	 * Locate the first position before a given character.
+	 * 
+	 * @param b
+	 *            buffer to scan.
+	 * @param ptr
+	 *            position within buffer to start looking for chrA at.
+	 * @param chrA
+	 *            character to find.
+	 * @return new position just before chrA, -1 for not found
+	 */
+	public static final int prev(final byte[] b, int ptr, final char chrA) {
+		if (ptr == b.length)
+			--ptr;
+		while (ptr >= 0) {
+			if (b[ptr--] == chrA)
+				return ptr;
+		}
+		return ptr;
+	}
+
+	/**
+	 * Locate the first position before the previous LF.
+	 * <p>
+	 * This method stops on the first '\n' it finds.
+	 * 
+	 * @param b
+	 *            buffer to scan.
+	 * @param ptr
+	 *            position within buffer to start looking for LF at.
+	 * @return new position just before the first LF found, -1 for not found
+	 */
+	public static final int prevLF(final byte[] b, int ptr) {
+		return prev(b, ptr, '\n');
+	}
+
+	/**
+	 * Locate the previous position before either the given character or LF.
+	 * <p>
+	 * This method stops on the first match it finds from either chrA or '\n'.
+	 * 
+	 * @param b
+	 *            buffer to scan.
+	 * @param ptr
+	 *            position within buffer to start looking for chrA or LF at.
+	 * @param chrA
+	 *            character to find.
+	 * @return new position just before the first chrA or LF to be found, -1 for
+	 *         not found
+	 */
+	public static final int prevLF(final byte[] b, int ptr, final char chrA) {
+		if (ptr == b.length)
+			--ptr;
+		while (ptr >= 0) {
+			final byte c = b[ptr--];
+			if (c == chrA || c == '\n')
+				return ptr;
+		}
+		return ptr;
+	}
+
+	/**
 	 * Index the region between <code>[ptr, end)</code> to find line starts.
 	 * <p>
 	 * The returned list is 1 indexed. Index 0 contains
@@ -519,7 +580,28 @@ public static PersonIdent parsePersonIdent(final byte[] raw, final int nameB) {
 	 *         after decoding the region through the specified character set.
 	 */
 	public static String decode(final byte[] buffer) {
-		return decode(Constants.CHARSET, buffer, 0, buffer.length);
+		return decode(buffer, 0, buffer.length);
+	}
+
+	/**
+	 * Decode a buffer under UTF-8, if possible.
+	 * 
+	 * If the byte stream cannot be decoded that way, the platform default is
+	 * tried and if that too fails, the fail-safe ISO-8859-1 encoding is tried.
+	 * 
+	 * @param buffer
+	 *            buffer to pull raw bytes from.
+	 * @param start
+	 *            start position in buffer
+	 * @param end
+	 *            one position past the last location within the buffer to take
+	 *            data from.
+	 * @return a string representation of the range <code>[start,end)</code>,
+	 *         after decoding the region through the specified character set.
+	 */
+	public static String decode(final byte[] buffer, final int start,
+			final int end) {
+		return decode(Constants.CHARSET, buffer, start, end);
 	}
 
 	/**
-- 
1.6.3.2.199.g7340d

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [EGIT PATCH 2/2] Add a ref log reader class
  2009-06-08 17:28               ` [EGIT PATCH 1/2] Add methods to RawParseUtils for scanning backwards Robin Rosenberg
@ 2009-06-08 17:28                 ` Robin Rosenberg
  2009-06-12 19:52                   ` Shawn O. Pearce
  0 siblings, 1 reply; 95+ messages in thread
From: Robin Rosenberg @ 2009-06-08 17:28 UTC (permalink / raw)
  To: spearce; +Cc: git, Robin Rosenberg

This reader allows the caller to the reflog entries for a given ref.

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../tst/org/spearce/jgit/lib/ReflogReaderTest.java |  187 ++++++++++++++++++++
 .../src/org/spearce/jgit/lib/ReflogReader.java     |  181 +++++++++++++++++++
 .../src/org/spearce/jgit/lib/Repository.java       |    9 +
 3 files changed, 377 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java

diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java
new file mode 100644
index 0000000..3e1946e
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2009, Robin Rosenberg
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.spearce.jgit.lib;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import org.spearce.jgit.lib.ReflogReader.Entry;
+
+public class ReflogReaderTest extends RepositoryTestCase {
+
+	static byte[] oneLine = "da85355dfc525c9f6f3927b876f379f46ccf826e 3e7549db262d1e836d9bf0af7e22355468f1717c Robin Rosenberg <robin.rosenberg@dewire.com> 1243028200 +0200\tcommit: Add a toString for debugging to RemoteRefUpdate\n"
+			.getBytes();
+
+	static byte[] twoLine = ("0000000000000000000000000000000000000000 c6734895958052a9dbc396cff4459dc1a25029ab A U Thor <thor@committer.au> 1243028201 -0100\tbranch: Created from rr/renamebranchv4\n"
+			+ "c6734895958052a9dbc396cff4459dc1a25029ab 54794942a18a237c57a80719afed44bb78172b10 Same A U Thor <same.author@example.com> 1243028202 +0100\trebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d\n")
+			.getBytes();
+
+	static byte[] twoLineWithAppendInProgress = ("0000000000000000000000000000000000000000 c6734895958052a9dbc396cff4459dc1a25029ab A U Thor <thor@committer.au> 1243028201 -0100\tbranch: Created from rr/renamebranchv4\n"
+			+ "c6734895958052a9dbc396cff4459dc1a25029ab 54794942a18a237c57a80719afed44bb78172b10 Same A U Thor <same.author@example.com> 1243028202 +0100\trebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d\n"
+			+ "54794942a18a237c57a80719afed44bb78172b10 ")
+			.getBytes();
+
+	static byte[] aLine = "1111111111111111111111111111111111111111 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to a\n"
+			.getBytes();
+
+	static byte[] masterLine = "2222222222222222222222222222222222222222 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to master\n"
+			.getBytes();
+
+	static byte[] headLine = "3333333333333333333333333333333333333333 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to HEAD\n"
+			.getBytes();
+
+	public void testReadOneLine() throws Exception {
+		setupReflog("logs/refs/heads/master", oneLine);
+
+		ReflogReader reader = new ReflogReader(db, "refs/heads/master");
+		Entry e = reader.getLastEntry();
+		assertEquals(ObjectId
+				.fromString("da85355dfc525c9f6f3927b876f379f46ccf826e"), e
+				.getOldId());
+		assertEquals(ObjectId
+				.fromString("3e7549db262d1e836d9bf0af7e22355468f1717c"), e
+				.getNewId());
+		assertEquals("Robin Rosenberg", e.getWho().getName());
+		assertEquals("robin.rosenberg@dewire.com", e.getWho().getEmailAddress());
+		assertEquals(120, e.getWho().getTimeZoneOffset());
+		assertEquals("2009-05-22T23:36:40", iso(e.getWho().getWhen()));
+		assertEquals("commit: Add a toString for debugging to RemoteRefUpdate",
+				e.getComment());
+	}
+
+	private String iso(Date d) {
+		return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(d);
+	}
+
+	public void testReadTwoLine() throws Exception {
+		setupReflog("logs/refs/heads/master", twoLine);
+
+		ReflogReader reader = new ReflogReader(db, "refs/heads/master");
+		List<Entry> reverseEntries = reader.getReverseEntries();
+		assertEquals(2, reverseEntries.size());
+		Entry e = reverseEntries.get(0);
+		assertEquals(ObjectId
+				.fromString("c6734895958052a9dbc396cff4459dc1a25029ab"), e
+				.getOldId());
+		assertEquals(ObjectId
+				.fromString("54794942a18a237c57a80719afed44bb78172b10"), e
+				.getNewId());
+		assertEquals("Same A U Thor", e.getWho().getName());
+		assertEquals("same.author@example.com", e.getWho().getEmailAddress());
+		assertEquals(60, e.getWho().getTimeZoneOffset());
+		assertEquals("2009-05-22T23:36:42", iso(e.getWho().getWhen()));
+		assertEquals(
+				"rebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d",
+				e.getComment());
+
+		e = reverseEntries.get(1);
+		assertEquals(ObjectId
+				.fromString("0000000000000000000000000000000000000000"), e
+				.getOldId());
+		assertEquals(ObjectId
+				.fromString("c6734895958052a9dbc396cff4459dc1a25029ab"), e
+				.getNewId());
+		assertEquals("A U Thor", e.getWho().getName());
+		assertEquals("thor@committer.au", e.getWho().getEmailAddress());
+		assertEquals(-60, e.getWho().getTimeZoneOffset());
+		assertEquals("2009-05-22T23:36:41", iso(e.getWho().getWhen()));
+		assertEquals("branch: Created from rr/renamebranchv4", e.getComment());
+	}
+
+	public void testReadWhileAppendIsInProgress() throws Exception {
+		setupReflog("logs/refs/heads/master", twoLineWithAppendInProgress);
+		ReflogReader reader = new ReflogReader(db, "refs/heads/master");
+		List<Entry> reverseEntries = reader.getReverseEntries();
+		assertEquals(2, reverseEntries.size());
+		Entry e = reverseEntries.get(0);
+		assertEquals(ObjectId
+				.fromString("c6734895958052a9dbc396cff4459dc1a25029ab"), e
+				.getOldId());
+		assertEquals(ObjectId
+				.fromString("54794942a18a237c57a80719afed44bb78172b10"), e
+				.getNewId());
+		assertEquals("Same A U Thor", e.getWho().getName());
+		assertEquals("same.author@example.com", e.getWho().getEmailAddress());
+		assertEquals(60, e.getWho().getTimeZoneOffset());
+		assertEquals("2009-05-22T23:36:42", iso(e.getWho().getWhen()));
+		assertEquals(
+				"rebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d",
+				e.getComment());
+		// while similar to testReadTwoLine, we can assume that if we get the last entry
+		// right, everything else is too
+	}
+
+
+	public void testReadRightLog() throws Exception {
+		setupReflog("logs/refs/heads/a", aLine);
+		setupReflog("logs/refs/heads/master", masterLine);
+		setupReflog("logs/HEAD", headLine);
+		assertEquals("branch: change to master", db.getReflogReader("master")
+				.getLastEntry().getComment());
+		assertEquals("branch: change to a", db.getReflogReader("a")
+				.getLastEntry().getComment());
+		assertEquals("branch: change to HEAD", db.getReflogReader("HEAD")
+				.getLastEntry().getComment());
+	}
+
+	public void testNoLog() throws Exception {
+		assertEquals(0, db.getReflogReader("master").getReverseEntries().size());
+		assertNull(db.getReflogReader("master").getLastEntry());
+	}
+
+	private void setupReflog(String logName, byte[] data)
+			throws FileNotFoundException, IOException {
+		File logfile = new File(db.getDirectory(), logName);
+		if (!logfile.getParentFile().mkdirs()
+				&& !logfile.getParentFile().isDirectory()) {
+			throw new IOException(
+					"oops, cannot create the directory for the test reflog file"
+							+ logfile);
+		}
+		FileOutputStream fileOutputStream = new FileOutputStream(logfile);
+		try {
+			fileOutputStream.write(data);
+		} finally {
+			fileOutputStream.close();
+		}
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java
new file mode 100644
index 0000000..73a5e0c
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2009, Robin Rosenberg
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.spearce.jgit.lib;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.spearce.jgit.util.NB;
+import org.spearce.jgit.util.RawParseUtils;
+
+/**
+ * Utility for reading reflog entries
+ */
+public class ReflogReader {
+	/**
+	 * Parsed reflog entry
+	 */
+	static public class Entry {
+		private ObjectId oldId;
+
+		private ObjectId newId;
+
+		private PersonIdent who;
+
+		private String comment;
+
+		Entry(byte[] raw, int pos) {
+			oldId = ObjectId.fromString(raw, pos);
+			pos += Constants.OBJECT_ID_LENGTH * 2;
+			if (raw[pos++] != ' ')
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			newId = ObjectId.fromString(raw, pos);
+			pos += Constants.OBJECT_ID_LENGTH * 2;
+			if (raw[pos++] != ' ') {
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			}
+			who = RawParseUtils.parsePersonIdent(raw, pos);
+			int p0 = RawParseUtils.next(raw, pos, '\t'); // personident has no
+															// \t
+			if (p0 == -1) {
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			}
+			int p1 = RawParseUtils.nextLF(raw, p0);
+			if (p1 == -1) {
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			}
+			comment = RawParseUtils.decode(raw, p0, p1 - 1);
+		}
+
+		/**
+		 * @return the commit id before the change
+		 */
+		public ObjectId getOldId() {
+			return oldId;
+		}
+
+		/**
+		 * @return the commit id after the change
+		 */
+		public ObjectId getNewId() {
+			return newId;
+		}
+
+		/**
+		 * @return user performin the change
+		 */
+		public PersonIdent getWho() {
+			return who;
+		}
+
+		/**
+		 * @return textual description of the change
+		 */
+		public String getComment() {
+			return comment;
+		}
+	}
+
+	private File logName;
+
+	ReflogReader(Repository db, String refname) {
+		logName = new File(db.getDirectory(), "logs/" + refname);
+	}
+
+	/**
+	 * Get the last entry in the reflog
+	 * 
+	 * @return the latest reflog entry, or null if no log
+	 * @throws IOException
+	 */
+	public Entry getLastEntry() throws IOException {
+		List<Entry> entries = getReverseEntries(1);
+		return entries.size() > 0 ? entries.get(0) : null;
+	}
+
+	/**
+	 * @return all reflog entries in reverse order
+	 * @throws IOException
+	 */
+	public List<Entry> getReverseEntries() throws IOException {
+		return getReverseEntries(Integer.MAX_VALUE);
+	}
+
+	/**
+	 * @param max
+	 *            max numer of entries to read
+	 * @return all reflog entries in reverse order
+	 * @throws IOException
+	 */
+	public List<Entry> getReverseEntries(int max) throws IOException {
+		FileInputStream fileInputStream;
+		try {
+			fileInputStream = new FileInputStream(logName);
+		} catch (FileNotFoundException e) {
+			return Collections.emptyList();
+		}
+		try {
+			long logSize = fileInputStream.getChannel().size();
+			if (logSize > Integer.MAX_VALUE) {
+				// implementation limit, will suck with smaller files too
+				throw new IOException("Cannot handle reflog larger than "
+						+ Integer.MAX_VALUE + " bytes");
+			}
+			byte[] log = new byte[(int) logSize];
+			NB.readFully(fileInputStream, log, 0, log.length);
+			int rs = RawParseUtils.prevLF(log, log.length);
+			List<Entry> ret = new ArrayList<Entry>();
+			while (rs >= 0 && max-- > 0) {
+				rs = RawParseUtils.prevLF(log, rs);
+				Entry entry = new Entry(log, rs < 0 ? 0 : rs + 2);
+				ret.add(entry);
+			}
+			return ret;
+		} finally {
+			fileInputStream.close();
+		}
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index 5def5d3..89dc044 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -1089,4 +1089,13 @@ public String shortenRefName(String refName) {
 			return refName.substring(Constants.R_REMOTES.length());
 		return refName;
 	}
+
+	/**
+	 * @param refName
+	 * @return a {@link ReflogReader} for the refname
+	 * @throws IOException 
+	 */
+	public ReflogReader getReflogReader(String refName) throws IOException {
+		return new ReflogReader(this, getRef(refName).getOrigName());
+	}
 }
-- 
1.6.3.2.199.g7340d

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [EGIT PATCH 2/2] Add a ref log reader class
  2009-06-08 17:28                 ` [EGIT PATCH 2/2] Add a ref log reader class Robin Rosenberg
@ 2009-06-12 19:52                   ` Shawn O. Pearce
  2009-06-15 21:25                     ` [EGIT PATCH 1/2] Use a UTC relative time zone for PersonIdent Robin Rosenberg
  0 siblings, 1 reply; 95+ messages in thread
From: Shawn O. Pearce @ 2009-06-12 19:52 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

Robin Rosenberg <robin.rosenberg@dewire.com> wrote:
> This reader allows the caller to the reflog entries for a given ref.
> 
> Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
> ---
>  .../tst/org/spearce/jgit/lib/ReflogReaderTest.java |  187 ++++++++++++++++++++
>  .../src/org/spearce/jgit/lib/ReflogReader.java     |  181 +++++++++++++++++++
>  .../src/org/spearce/jgit/lib/Repository.java       |    9 +
>  3 files changed, 377 insertions(+), 0 deletions(-)
>  create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java
>  create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java

Tests fail, I suspect time zone failure (I am in PST):

  ComparisonFailure: expected:<2009-05-22T[23]:36:40> but was:<2009-05-22T[14]:36:40>
  at org.spearce.jgit.lib.ReflogReaderTest.testReadOneLine(ReflogReaderTest.java:86)

Otherwise, it looks sane to me.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [EGIT PATCH 1/2] Use a UTC relative time zone for PersonIdent
  2009-06-12 19:52                   ` Shawn O. Pearce
@ 2009-06-15 21:25                     ` Robin Rosenberg
  2009-06-15 21:25                       ` [EGIT PATCH 2/2] Add a ref log reader class Robin Rosenberg
  0 siblings, 1 reply; 95+ messages in thread
From: Robin Rosenberg @ 2009-06-15 21:25 UTC (permalink / raw)
  To: spearce; +Cc: git, Robin Rosenberg

The timezone used in Git objects is not the user's preferred
timezone, but rather a numeric form stating the offset relative to
UTC in hours and minuutes. Any special rules like daylight savings
is already accounted for and cannot be deduced from the time
zone part of the git timestamp.

As an example, a committer in Sweden will have +0100 as
his/her timezone in winter and +0200 in summer.

We hereby abandon the attempts to guess a real timezone
from the UTC offset. When creating a person ident a real
timezone can be used, but it's identifty will be lost when externalizing
and only the UTC offset will be left.

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../src/org/spearce/jgit/lib/PersonIdent.java      |   54 ++++++++++++-------
 1 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/PersonIdent.java b/org.spearce.jgit/src/org/spearce/jgit/lib/PersonIdent.java
index 85435b5..4ed2f71 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/PersonIdent.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/PersonIdent.java
@@ -39,7 +39,9 @@
 
 package org.spearce.jgit.lib;
 
+import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.Locale;
 import java.util.TimeZone;
 
 /**
@@ -228,24 +230,24 @@ public String getEmailAddress() {
 	}
 
 	/**
-	 * @return timestamp
+	 * @return timestamp in the person's local time
 	 */
 	public Date getWhen() {
 		return new Date(when);
 	}
 
 	/**
-	 * @return this person's preferred time zone; null if time zone is unknown.
+	 * @return this person's declared time zone; null if time zone is unknown.
 	 */
 	public TimeZone getTimeZone() {
-		final String[] ids = TimeZone.getAvailableIDs(tzOffset * 60 * 1000);
-		if (ids.length == 0)
-			return null;
-		return TimeZone.getTimeZone(ids[0]);
+		StringBuffer tzId = new StringBuffer(8);
+		tzId.append("GMT");
+		appendTimezone(tzId);
+		return TimeZone.getTimeZone(tzId.toString());
 	}
 
 	/**
-	 * @return this person's preferred time zone as minutes east of UTC. If the
+	 * @return this person's declared time zone as minutes east of UTC. If the
 	 *         timezone is to the west of UTC it is negative.
 	 */
 	public int getTimeZoneOffset() {
@@ -273,6 +275,17 @@ public boolean equals(final Object o) {
 	 */
 	public String toExternalString() {
 		final StringBuffer r = new StringBuffer();
+		r.append(getName());
+		r.append(" <");
+		r.append(getEmailAddress());
+		r.append("> ");
+		r.append(when / 1000);
+		r.append(' ');
+		appendTimezone(r);
+		return r.toString();
+	}
+
+	private void appendTimezone(final StringBuffer r) {
 		int offset = tzOffset;
 		final char sign;
 		final int offsetHours;
@@ -288,12 +301,6 @@ public String toExternalString() {
 		offsetHours = offset / 60;
 		offsetMins = offset % 60;
 
-		r.append(getName());
-		r.append(" <");
-		r.append(getEmailAddress());
-		r.append("> ");
-		r.append(when / 1000);
-		r.append(' ');
 		r.append(sign);
 		if (offsetHours < 10) {
 			r.append('0');
@@ -303,25 +310,32 @@ public String toExternalString() {
 			r.append('0');
 		}
 		r.append(offsetMins);
-		return r.toString();
 	}
 
 	public String toString() {
 		final StringBuffer r = new StringBuffer();
-		int minutes;
-
-		minutes = tzOffset < 0 ? -tzOffset : tzOffset;
-		minutes = (minutes / 100) * 60 + (minutes % 100);
-		minutes = tzOffset < 0 ? -minutes : minutes;
 
 		r.append("PersonIdent[");
 		r.append(getName());
 		r.append(", ");
 		r.append(getEmailAddress());
 		r.append(", ");
-		r.append(new Date(when + minutes * 60));
+		r.append(formatTime(new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy Z", Locale.US)));
 		r.append("]");
 
 		return r.toString();
 	}
+
+	/**
+	 * Format the time represented by this object using the give
+	 * SimpleDateFormat.
+	 * 
+	 * @param simpleDateFormat
+	 * @return a formatted time stamp.
+	 */
+	@SuppressWarnings("boxing")
+	public String formatTime(SimpleDateFormat simpleDateFormat) {
+		simpleDateFormat.setTimeZone(getTimeZone());
+		return simpleDateFormat.format(when);
+	}
 }
-- 
1.6.3.2.199.g7340d

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [EGIT PATCH 2/2] Add a ref log reader class
  2009-06-15 21:25                     ` [EGIT PATCH 1/2] Use a UTC relative time zone for PersonIdent Robin Rosenberg
@ 2009-06-15 21:25                       ` Robin Rosenberg
  2009-06-15 22:21                         ` Robin Rosenberg
  0 siblings, 1 reply; 95+ messages in thread
From: Robin Rosenberg @ 2009-06-15 21:25 UTC (permalink / raw)
  To: spearce; +Cc: git, Robin Rosenberg

This reader allows the caller to the reflog entries for a given ref.

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 ...pearce.jgit--All-External-Tests (Java 6).launch |   27 ++--
 .../tst/org/spearce/jgit/lib/ReflogReaderTest.java |  165 +++++++++++++++++
 .../org/spearce/jgit/lib/RepositoryTestCase.java   |   18 ++
 .../src/org/spearce/jgit/lib/ReflogReader.java     |  187 ++++++++++++++++++++
 .../src/org/spearce/jgit/lib/Repository.java       |   14 ++
 .../src/org/spearce/jgit/util/RawParseUtils.java   |   46 +++++
 6 files changed, 445 insertions(+), 12 deletions(-)
 create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java

diff --git a/org.spearce.jgit.test/org.spearce.jgit--All-External-Tests (Java 6).launch b/org.spearce.jgit.test/org.spearce.jgit--All-External-Tests (Java 6).launch
index 73a2f63..1e16df2 100644
--- a/org.spearce.jgit.test/org.spearce.jgit--All-External-Tests (Java 6).launch	
+++ b/org.spearce.jgit.test/org.spearce.jgit--All-External-Tests (Java 6).launch	
@@ -1,21 +1,24 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
-<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
-<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.spearce.jgit.test/exttst"/>
+</listAttribute>
 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="4"/>
+<listEntry value="2"/>
 </listAttribute>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.spearce.jgit.test"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+<mapAttribute key="org.eclipse.debug.core.environmentVariables">
+<mapEntry key="TZ" value="America/Los_Angeles"/>
+</mapAttribute>
 <listAttribute key="org.eclipse.debug.ui.favoriteGroups">
-<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
 <listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/org.spearce.jgit.test"/>
+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
 </listAttribute>
 <stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.spearce.jgit.test/exttst"/>
-<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
 <stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.spearce.jgit.test"/>
 </launchConfiguration>
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java
new file mode 100644
index 0000000..93fcf9d
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/ReflogReaderTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2009, Robin Rosenberg
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.spearce.jgit.lib;
+
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+import org.spearce.jgit.lib.ReflogReader.Entry;
+
+public class ReflogReaderTest extends RepositoryTestCase {
+
+	static byte[] oneLine = "da85355dfc525c9f6f3927b876f379f46ccf826e 3e7549db262d1e836d9bf0af7e22355468f1717c A O Thor Too <authortoo@wri.tr> 1243028200 +0200\tcommit: Add a toString for debugging to RemoteRefUpdate\n"
+			.getBytes();
+
+	static byte[] twoLine = ("0000000000000000000000000000000000000000 c6734895958052a9dbc396cff4459dc1a25029ab A U Thor <thor@committer.au> 1243028201 -0100\tbranch: Created from rr/renamebranchv4\n"
+			+ "c6734895958052a9dbc396cff4459dc1a25029ab 54794942a18a237c57a80719afed44bb78172b10 Same A U Thor <same.author@example.com> 1243028202 +0100\trebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d\n")
+			.getBytes();
+
+	static byte[] twoLineWithAppendInProgress = ("0000000000000000000000000000000000000000 c6734895958052a9dbc396cff4459dc1a25029ab A U Thor <thor@committer.au> 1243028201 -0100\tbranch: Created from rr/renamebranchv4\n"
+			+ "c6734895958052a9dbc396cff4459dc1a25029ab 54794942a18a237c57a80719afed44bb78172b10 Same A U Thor <same.author@example.com> 1243028202 +0100\trebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d\n"
+			+ "54794942a18a237c57a80719afed44bb78172b10 ")
+			.getBytes();
+
+	static byte[] aLine = "1111111111111111111111111111111111111111 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to a\n"
+			.getBytes();
+
+	static byte[] masterLine = "2222222222222222222222222222222222222222 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to master\n"
+			.getBytes();
+
+	static byte[] headLine = "3333333333333333333333333333333333333333 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to HEAD\n"
+			.getBytes();
+
+	public void testReadOneLine() throws Exception {
+		setupReflog("logs/refs/heads/master", oneLine);
+
+		ReflogReader reader = new ReflogReader(db, "refs/heads/master");
+		Entry e = reader.getLastEntry();
+		assertEquals(ObjectId
+				.fromString("da85355dfc525c9f6f3927b876f379f46ccf826e"), e
+				.getOldId());
+		assertEquals(ObjectId
+				.fromString("3e7549db262d1e836d9bf0af7e22355468f1717c"), e
+				.getNewId());
+		assertEquals("A O Thor Too", e.getWho().getName());
+		assertEquals("authortoo@wri.tr", e.getWho().getEmailAddress());
+		assertEquals(120, e.getWho().getTimeZoneOffset());
+		assertEquals("2009-05-22T23:36:40", iso(e.getWho()));
+		assertEquals("commit: Add a toString for debugging to RemoteRefUpdate",
+				e.getComment());
+	}
+
+	private String iso(PersonIdent id) {
+		return id.formatTime(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"));
+	}
+
+	public void testReadTwoLine() throws Exception {
+		setupReflog("logs/refs/heads/master", twoLine);
+
+		ReflogReader reader = new ReflogReader(db, "refs/heads/master");
+		List<Entry> reverseEntries = reader.getReverseEntries();
+		assertEquals(2, reverseEntries.size());
+		Entry e = reverseEntries.get(0);
+		assertEquals(ObjectId
+				.fromString("c6734895958052a9dbc396cff4459dc1a25029ab"), e
+				.getOldId());
+		assertEquals(ObjectId
+				.fromString("54794942a18a237c57a80719afed44bb78172b10"), e
+				.getNewId());
+		assertEquals("Same A U Thor", e.getWho().getName());
+		assertEquals("same.author@example.com", e.getWho().getEmailAddress());
+		assertEquals(60, e.getWho().getTimeZoneOffset());
+		assertEquals("2009-05-22T22:36:42", iso(e.getWho()));
+		assertEquals(
+				"rebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d",
+				e.getComment());
+
+		e = reverseEntries.get(1);
+		assertEquals(ObjectId
+				.fromString("0000000000000000000000000000000000000000"), e
+				.getOldId());
+		assertEquals(ObjectId
+				.fromString("c6734895958052a9dbc396cff4459dc1a25029ab"), e
+				.getNewId());
+		assertEquals("A U Thor", e.getWho().getName());
+		assertEquals("thor@committer.au", e.getWho().getEmailAddress());
+		assertEquals(-60, e.getWho().getTimeZoneOffset());
+		assertEquals("2009-05-22T20:36:41", iso(e.getWho()));
+		assertEquals("branch: Created from rr/renamebranchv4", e.getComment());
+	}
+
+	public void testReadWhileAppendIsInProgress() throws Exception {
+		setupReflog("logs/refs/heads/master", twoLineWithAppendInProgress);
+		ReflogReader reader = new ReflogReader(db, "refs/heads/master");
+		List<Entry> reverseEntries = reader.getReverseEntries();
+		assertEquals(2, reverseEntries.size());
+		Entry e = reverseEntries.get(0);
+		assertEquals(ObjectId
+				.fromString("c6734895958052a9dbc396cff4459dc1a25029ab"), e
+				.getOldId());
+		assertEquals(ObjectId
+				.fromString("54794942a18a237c57a80719afed44bb78172b10"), e
+				.getNewId());
+		assertEquals("Same A U Thor", e.getWho().getName());
+		assertEquals("same.author@example.com", e.getWho().getEmailAddress());
+		assertEquals(60, e.getWho().getTimeZoneOffset());
+		assertEquals("2009-05-22T22:36:42", iso(e.getWho()));
+		assertEquals(
+				"rebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d",
+				e.getComment());
+		// while similar to testReadTwoLine, we can assume that if we get the last entry
+		// right, everything else is too
+	}
+
+
+	public void testReadRightLog() throws Exception {
+		setupReflog("logs/refs/heads/a", aLine);
+		setupReflog("logs/refs/heads/master", masterLine);
+		setupReflog("logs/HEAD", headLine);
+		assertEquals("branch: change to master", db.getReflogReader("master")
+				.getLastEntry().getComment());
+		assertEquals("branch: change to a", db.getReflogReader("a")
+				.getLastEntry().getComment());
+		assertEquals("branch: change to HEAD", db.getReflogReader("HEAD")
+				.getLastEntry().getComment());
+	}
+
+	public void testNoLog() throws Exception {
+		assertEquals(0, db.getReflogReader("master").getReverseEntries().size());
+		assertNull(db.getReflogReader("master").getLastEntry());
+	}
+}
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryTestCase.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryTestCase.java
index 3b03ac1..3837ea9 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryTestCase.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryTestCase.java
@@ -40,6 +40,7 @@
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -348,4 +349,21 @@ public void run() {
 		return newRepo;
 	}
 
+	protected void setupReflog(String logName, byte[] data)
+			throws FileNotFoundException, IOException {
+				File logfile = new File(db.getDirectory(), logName);
+				if (!logfile.getParentFile().mkdirs()
+						&& !logfile.getParentFile().isDirectory()) {
+					throw new IOException(
+							"oops, cannot create the directory for the test reflog file"
+									+ logfile);
+				}
+				FileOutputStream fileOutputStream = new FileOutputStream(logfile);
+				try {
+					fileOutputStream.write(data);
+				} finally {
+					fileOutputStream.close();
+				}
+			}
+
 }
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java
new file mode 100644
index 0000000..081b52c
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ReflogReader.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2009, Robin Rosenberg
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.spearce.jgit.lib;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.spearce.jgit.util.NB;
+import org.spearce.jgit.util.RawParseUtils;
+
+/**
+ * Utility for reading reflog entries
+ */
+public class ReflogReader {
+	/**
+	 * Parsed reflog entry
+	 */
+	static public class Entry {
+		private ObjectId oldId;
+
+		private ObjectId newId;
+
+		private PersonIdent who;
+
+		private String comment;
+
+		Entry(byte[] raw, int pos) {
+			oldId = ObjectId.fromString(raw, pos);
+			pos += Constants.OBJECT_ID_LENGTH * 2;
+			if (raw[pos++] != ' ')
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			newId = ObjectId.fromString(raw, pos);
+			pos += Constants.OBJECT_ID_LENGTH * 2;
+			if (raw[pos++] != ' ') {
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			}
+			who = RawParseUtils.parsePersonIdentOnly(raw, pos);
+			int p0 = RawParseUtils.next(raw, pos, '\t'); // personident has no
+															// \t
+			if (p0 == -1) {
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			}
+			int p1 = RawParseUtils.nextLF(raw, p0);
+			if (p1 == -1) {
+				throw new IllegalArgumentException(
+						"Raw log message does not parse as log entry");
+			}
+			comment = RawParseUtils.decode(raw, p0, p1 - 1);
+		}
+
+		/**
+		 * @return the commit id before the change
+		 */
+		public ObjectId getOldId() {
+			return oldId;
+		}
+
+		/**
+		 * @return the commit id after the change
+		 */
+		public ObjectId getNewId() {
+			return newId;
+		}
+
+		/**
+		 * @return user performin the change
+		 */
+		public PersonIdent getWho() {
+			return who;
+		}
+
+		/**
+		 * @return textual description of the change
+		 */
+		public String getComment() {
+			return comment;
+		}
+		
+		@Override
+		public String toString() {
+			return "Entry[" + oldId.name() + ", " + newId.name() + ", " + getWho() + ", "
+					+ getComment() + "]";
+		}
+	}
+
+	private File logName;
+
+	ReflogReader(Repository db, String refname) {
+		logName = new File(db.getDirectory(), "logs/" + refname);
+	}
+
+	/**
+	 * Get the last entry in the reflog
+	 * 
+	 * @return the latest reflog entry, or null if no log
+	 * @throws IOException
+	 */
+	public Entry getLastEntry() throws IOException {
+		List<Entry> entries = getReverseEntries(1);
+		return entries.size() > 0 ? entries.get(0) : null;
+	}
+
+	/**
+	 * @return all reflog entries in reverse order
+	 * @throws IOException
+	 */
+	public List<Entry> getReverseEntries() throws IOException {
+		return getReverseEntries(Integer.MAX_VALUE);
+	}
+
+	/**
+	 * @param max
+	 *            max numer of entries to read
+	 * @return all reflog entries in reverse order
+	 * @throws IOException
+	 */
+	public List<Entry> getReverseEntries(int max) throws IOException {
+		FileInputStream fileInputStream;
+		try {
+			fileInputStream = new FileInputStream(logName);
+		} catch (FileNotFoundException e) {
+			return Collections.emptyList();
+		}
+		try {
+			long logSize = fileInputStream.getChannel().size();
+			if (logSize > Integer.MAX_VALUE) {
+				// implementation limit, will suck with smaller files too
+				throw new IOException("Cannot handle reflog larger than "
+						+ Integer.MAX_VALUE + " bytes");
+			}
+			byte[] log = new byte[(int) logSize];
+			NB.readFully(fileInputStream, log, 0, log.length);
+			int rs = RawParseUtils.prevLF(log, log.length);
+			List<Entry> ret = new ArrayList<Entry>();
+			while (rs >= 0 && max-- > 0) {
+				rs = RawParseUtils.prevLF(log, rs);
+				Entry entry = new Entry(log, rs < 0 ? 0 : rs + 2);
+				ret.add(entry);
+			}
+			return ret;
+		} finally {
+			fileInputStream.close();
+		}
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index 5def5d3..971215c 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -1089,4 +1089,18 @@ public String shortenRefName(String refName) {
 			return refName.substring(Constants.R_REMOTES.length());
 		return refName;
 	}
+
+	/**
+	 * @param refName
+	 * @return a {@link ReflogReader} for the refname, or null if the names ref
+	 *         does not exist.
+	 * @throws IOException 
+	 */
+	public ReflogReader getReflogReader(String refName) throws IOException {
+		Ref ref = getRef(refName);
+		if (ref != null)
+			return new ReflogReader(this, ref.getOrigName());
+		else
+			return null;
+	}
 }
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
index bdd6a11..df24190 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
@@ -569,6 +569,52 @@ public static PersonIdent parsePersonIdent(final byte[] raw, final int nameB) {
 	}
 
 	/**
+	 * Parse a name data (e.g. as within a reflog) into a PersonIdent.
+	 * <p>
+	 * When passing in a value for <code>nameB</code> callers should use the
+	 * return value of {@link #author(byte[], int)} or
+	 * {@link #committer(byte[], int)}, as these methods provide the proper
+	 * position within the buffer.
+	 * 
+	 * @param raw
+	 *            the buffer to parse character data from.
+	 * @param nameB
+	 *            first position of the identity information. This should be the
+	 *            first position after the space which delimits the header field
+	 *            name (e.g. "author" or "committer") from the rest of the
+	 *            identity line.
+	 * @return the parsed identity. Never null.
+	 */
+	public static PersonIdent parsePersonIdentOnly(final byte[] raw, final int nameB) {
+		int stop = nextLF(raw, nameB);
+		int emailB = nextLF(raw, nameB, '<');
+		int emailE = nextLF(raw, emailB, '>');
+		final String name;
+		final String email;
+		if (emailE < stop) {
+			email = decode(raw, emailB, emailE - 1);
+		} else {
+			email = "invalid";
+		}
+		if (emailB < stop)
+			name = decode(raw, nameB, emailB - 2);
+		else
+			name = decode(raw, nameB, stop);
+
+		final MutableInteger ptrout = new MutableInteger();
+		long when;
+		int tz;
+		if (emailE < stop) {
+			when = parseLongBase10(raw, emailE + 1, ptrout);
+			tz = parseTimeZoneOffset(raw, ptrout.value);
+		} else {
+			when = 0;
+			tz = 0;
+		}
+		return new PersonIdent(name, email, when * 1000L, tz);
+	}
+
+	/**
 	 * Decode a buffer under UTF-8, if possible.
 	 *
 	 * If the byte stream cannot be decoded that way, the platform default is tried
-- 
1.6.3.2.199.g7340d

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [EGIT PATCH 2/2] Add a ref log reader class
  2009-06-15 21:25                       ` [EGIT PATCH 2/2] Add a ref log reader class Robin Rosenberg
@ 2009-06-15 22:21                         ` Robin Rosenberg
  0 siblings, 0 replies; 95+ messages in thread
From: Robin Rosenberg @ 2009-06-15 22:21 UTC (permalink / raw)
  To: spearce; +Cc: git

måndag 15 juni 2009 23:25:36 skrev Robin Rosenberg <robin.rosenberg@dewire.com>:
> This reader allows the caller to the reflog entries for a given ref.

Oops a typo.

This reader allows the caller to read the reflog entries for a given ref.. I also noted 
two missing comments in UIText.java. If you want to I can resend the whole
series(es).

-- robin

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [BUG] apply: test for trailing whitespace & no new line bug
       [not found] <y>
  2008-12-02 21:20 ` [JGIT PATCH 1/2] Close a forgotten reference to the HEAD ref Robin Rosenberg
  2009-06-07 20:19 ` [EGIT PATCH 0/3] Ref log reader Robin Rosenberg
@ 2009-06-22 11:49 ` y
  2009-06-22 11:49 ` y
                   ` (22 subsequent siblings)
  25 siblings, 0 replies; 95+ messages in thread
From: y @ 2009-06-22 11:49 UTC (permalink / raw)
  To: git; +Cc: SZEDER Gábor

From: SZEDER Gábor <szeder@ira.uka.de>

If a patch adds a new line to the end of a file and this line ends
with trailing whitespace but has no newline, then 'git apply
--whitespace=fix' does not remove the trailing whitespace from that
line.

Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
---

Noticed last week, but couldn't fix it myself during the weekend.

 t/t4124-apply-ws-rule.sh |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh
index f83322e..0db9b59 100755
--- a/t/t4124-apply-ws-rule.sh
+++ b/t/t4124-apply-ws-rule.sh
@@ -148,4 +148,22 @@ do
 	done
 done
 
+create_patch () {
+	sed -e "s/_/ /" <<-\EOF
+		diff --git a/target b/target
+		index e69de29..8bd6648 100644
+		--- a/target
+		+++ b/target
+		@@ -0,0 +1 @@
+		+A line with trailing whitespace and no newline_
+		\ No newline at end of file
+	EOF
+}
+
+test_expect_failure 'trailing whitespace & no newline at the end of file' '
+	>target &&
+	create_patch | git apply --whitespace=fix - &&
+	git diff --check -- target
+'
+
 test_done
-- 
1.6.3.2.370.g6bb4.dirty


^ permalink raw reply	[flat|nested] 95+ messages in thread

* [BUG] apply: test for trailing whitespace & no new line bug
       [not found] <y>
                   ` (2 preceding siblings ...)
  2009-06-22 11:49 ` [BUG] apply: test for trailing whitespace & no new line bug y
@ 2009-06-22 11:49 ` y
  2010-07-08 15:12 ` [PATCH] diff.c: fix a graph output " struggleyb.nku
                   ` (21 subsequent siblings)
  25 siblings, 0 replies; 95+ messages in thread
From: y @ 2009-06-22 11:49 UTC (permalink / raw)
  To: git; +Cc: SZEDER Gábor

From: SZEDER Gábor <szeder@ira.uka.de>

If a patch adds a new line to the end of a file and this line ends
with trailing whitespace but has no newline, then 'git apply
--whitespace=fix' does not remove the trailing whitespace from that
line.

Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
---

Noticed last week, but couldn't fix it myself during the weekend.

 t/t4124-apply-ws-rule.sh |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh
index f83322e..0db9b59 100755
--- a/t/t4124-apply-ws-rule.sh
+++ b/t/t4124-apply-ws-rule.sh
@@ -148,4 +148,22 @@ do
 	done
 done
 
+create_patch () {
+	sed -e "s/_/ /" <<-\EOF
+		diff --git a/target b/target
+		index e69de29..8bd6648 100644
+		--- a/target
+		+++ b/target
+		@@ -0,0 +1 @@
+		+A line with trailing whitespace and no newline_
+		\ No newline at end of file
+	EOF
+}
+
+test_expect_failure 'trailing whitespace & no newline at the end of file' '
+	>target &&
+	create_patch | git apply --whitespace=fix - &&
+	git diff --check -- target
+'
+
 test_done
-- 
1.6.3.2.370.g6bb4.dirty

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH] diff.c: fix a graph output bug
       [not found] <y>
                   ` (3 preceding siblings ...)
  2009-06-22 11:49 ` y
@ 2010-07-08 15:12 ` " struggleyb.nku
  2010-07-09  0:15   ` Junio C Hamano
  2010-10-07  4:46 ` [PATCH 1/2] setup.c: add enter_work_tree() pclouds
                   ` (20 subsequent siblings)
  25 siblings, 1 reply; 95+ messages in thread
From: struggleyb.nku @ 2010-07-08 15:12 UTC (permalink / raw)
  To: git; +Cc: gitster

From: Bo Yang <struggleyb.nku@gmail.com>

Ouput the line_prefix ahead of color sequence.

Signed-off-by: Bo Yang <struggleyb.nku@gmail.com>
---
 diff.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/diff.c b/diff.c
index 3aa695d..17873f3 100644
--- a/diff.c
+++ b/diff.c
@@ -2627,8 +2627,7 @@ static void fill_metainfo(struct strbuf *msg,
 			    (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
 				abbrev = 40;
 		}
-		strbuf_addf(msg, "%s%sindex %s..", set,
-			    line_prefix,
+		strbuf_addf(msg, "%s%sindex %s..", line_prefix, set,
 			    find_unique_abbrev(one->sha1, abbrev));
 		strbuf_addstr(msg, find_unique_abbrev(two->sha1, abbrev));
 		if (one->mode == two->mode)
-- 
1.7.0.2.273.gc2413.dirty

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH] diff.c: fix a graph output bug
  2010-07-08 15:12 ` [PATCH] diff.c: fix a graph output " struggleyb.nku
@ 2010-07-09  0:15   ` Junio C Hamano
  2010-07-09  0:57     ` Junio C Hamano
  0 siblings, 1 reply; 95+ messages in thread
From: Junio C Hamano @ 2010-07-09  0:15 UTC (permalink / raw)
  To: struggleyb.nku; +Cc: git, gitster

struggleyb.nku@gmail.com writes:

> From: Bo Yang <struggleyb.nku@gmail.com>
>
> Ouput the line_prefix ahead of color sequence.

Justification for the patch, and/or a better bug description ("when run
with this combination of options, X gets painted in that color that is not
meant to be used for X") please?

>
> Signed-off-by: Bo Yang <struggleyb.nku@gmail.com>
> ---
>  diff.c |    3 +--
>  1 files changed, 1 insertions(+), 2 deletions(-)
>
> diff --git a/diff.c b/diff.c
> index 3aa695d..17873f3 100644
> --- a/diff.c
> +++ b/diff.c
> @@ -2627,8 +2627,7 @@ static void fill_metainfo(struct strbuf *msg,
>  			    (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
>  				abbrev = 40;
>  		}
> -		strbuf_addf(msg, "%s%sindex %s..", set,
> -			    line_prefix,
> +		strbuf_addf(msg, "%s%sindex %s..", line_prefix, set,
>  			    find_unique_abbrev(one->sha1, abbrev));
>  		strbuf_addstr(msg, find_unique_abbrev(two->sha1, abbrev));
>  		if (one->mode == two->mode)
> -- 
> 1.7.0.2.273.gc2413.dirty
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH] diff.c: fix a graph output bug
  2010-07-09  0:15   ` Junio C Hamano
@ 2010-07-09  0:57     ` Junio C Hamano
  2010-07-09  1:04       ` Nazri Ramliy
  2010-07-11  6:10       ` Bo Yang
  0 siblings, 2 replies; 95+ messages in thread
From: Junio C Hamano @ 2010-07-09  0:57 UTC (permalink / raw)
  To: struggleyb.nku; +Cc: git

Junio C Hamano <gitster@pobox.com> writes:

> struggleyb.nku@gmail.com writes:
>
>> From: Bo Yang <struggleyb.nku@gmail.com>
>>
>> Ouput the line_prefix ahead of color sequence.
>
> Justification for the patch, and/or a better bug description ("when run
> with this combination of options, X gets painted in that color that is not
> meant to be used for X") please?
>>
>> Signed-off-by: Bo Yang <struggleyb.nku@gmail.com>

Perhaps something like this?

From: Bo Yang <struggleyb.nku@gmail.com>
Date: Thu, 8 Jul 2010 23:12:34 +0800
Subject: [PATCH] diff.c: fix a graph output bug

When --graph is in effect, the line-prefix typically has colored graph
line segments and ends with reset.  The color sequence "set" given to
this function is for showing the metainfo part of the patch text and
(1) it should not be applied to the graph lines, and (2) it will be
reset at the end of line_prefix so it won't be effect anyway.

Signed-off-by: Bo Yang <struggleyb.nku@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 diff.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)
 ...

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH] diff.c: fix a graph output bug
  2010-07-09  0:57     ` Junio C Hamano
@ 2010-07-09  1:04       ` Nazri Ramliy
  2010-07-09  1:09         ` Junio C Hamano
  2010-07-11  6:10       ` Bo Yang
  1 sibling, 1 reply; 95+ messages in thread
From: Nazri Ramliy @ 2010-07-09  1:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: struggleyb.nku, git

On Fri, Jul 9, 2010 at 8:57 AM, Junio C Hamano <gitster@pobox.com> wrote:
> reset at the end of line_prefix so it won't be effect anyway.

s/effect/affected/  ?

nazri

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH] diff.c: fix a graph output bug
  2010-07-09  1:04       ` Nazri Ramliy
@ 2010-07-09  1:09         ` Junio C Hamano
  0 siblings, 0 replies; 95+ messages in thread
From: Junio C Hamano @ 2010-07-09  1:09 UTC (permalink / raw)
  To: Nazri Ramliy; +Cc: Junio C Hamano, struggleyb.nku, git

Nazri Ramliy <ayiehere@gmail.com> writes:

> On Fri, Jul 9, 2010 at 8:57 AM, Junio C Hamano <gitster@pobox.com> wrote:
>> reset at the end of line_prefix so it won't be effect anyway.
>
> s/effect/affected/  ?

Thanks for spotting.  I meant to say "won't be in effect".

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH] diff.c: fix a graph output bug
  2010-07-09  0:57     ` Junio C Hamano
  2010-07-09  1:04       ` Nazri Ramliy
@ 2010-07-11  6:10       ` Bo Yang
  1 sibling, 0 replies; 95+ messages in thread
From: Bo Yang @ 2010-07-11  6:10 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Hi Junio,

On Fri, Jul 9, 2010 at 8:57 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Perhaps something like this?
>
> From: Bo Yang <struggleyb.nku@gmail.com>
> Date: Thu, 8 Jul 2010 23:12:34 +0800
> Subject: [PATCH] diff.c: fix a graph output bug
>
> When --graph is in effect, the line-prefix typically has colored graph
> line segments and ends with reset.  The color sequence "set" given to
> this function is for showing the metainfo part of the patch text and
> (1) it should not be applied to the graph lines, and (2) it will be
> reset at the end of line_prefix so it won't be effect anyway.
>
> Signed-off-by: Bo Yang <struggleyb.nku@gmail.com>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>  diff.c |    3 +--
>  1 files changed, 1 insertions(+), 2 deletions(-)
>  ...
>

Hmm, your description is great, thanks a lot! And please apply this
patch, thanks!

-- 
Regards!
Bo
----------------------------
My blog: http://blog.morebits.org
Why Git: http://www.whygitisbetterthanx.com/

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH 1/2] setup.c: add enter_work_tree()
       [not found] <y>
                   ` (4 preceding siblings ...)
  2010-07-08 15:12 ` [PATCH] diff.c: fix a graph output " struggleyb.nku
@ 2010-10-07  4:46 ` pclouds
  2010-10-07  4:46 ` [PATCH 2/2] worktree: provide better prefix to go back to original cwd pclouds
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 95+ messages in thread
From: pclouds @ 2010-10-07  4:46 UTC (permalink / raw)
  To: git, judge.packham; +Cc: Jens.Lehmann, Junio C Hamano, jrnieder, Nguyễn Thái Ngọc Duy

From: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>

This function, apart from chdir() to worktree topdir, also invalidates
inside_work_tree so is_inside_work_tree() should reflect the new
situation correctly.

This function may be used when cwd is outside worktree and the running
command supports this case.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 To be used by builtin/grep.c when cwd is outside worktree.
 More explanation in the next patch.

 cache.h |    1 +
 setup.c |    7 +++++++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/cache.h b/cache.h
index 2ef2fa3..e71db23 100644
--- a/cache.h
+++ b/cache.h
@@ -414,6 +414,7 @@ extern int set_git_dir(const char *path);
 extern const char *get_git_work_tree(void);
 extern const char *read_gitfile_gently(const char *path);
 extern void set_git_work_tree(const char *tree);
+extern void enter_work_tree();
 
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
diff --git a/setup.c b/setup.c
index a3b76de..3fbe928 100644
--- a/setup.c
+++ b/setup.c
@@ -208,6 +208,13 @@ int is_inside_work_tree(void)
 	return inside_work_tree;
 }
 
+void enter_work_tree(void)
+{
+	if (chdir(get_git_work_tree()))
+		die("Could not chdir to %s", get_git_work_tree());
+	inside_work_tree = -1;
+}
+
 /*
  * set_work_tree() is only ever called if you set GIT_DIR explicitly.
  * The old behaviour (which we retain here) is to set the work tree root
-- 
1.7.1.rc1.70.g788ca

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH 2/2] worktree: provide better prefix to go back to original cwd
       [not found] <y>
                   ` (5 preceding siblings ...)
  2010-10-07  4:46 ` [PATCH 1/2] setup.c: add enter_work_tree() pclouds
@ 2010-10-07  4:46 ` pclouds
  2010-10-07  5:53   ` Nguyen Thai Ngoc Duy
  2010-10-07  5:54   ` Junio C Hamano
  2010-11-23  2:32 ` [PATCH] Corrected cmitmode set in the right lower window when initiating a diff Michał Pomorski
                   ` (18 subsequent siblings)
  25 siblings, 2 replies; 95+ messages in thread
From: pclouds @ 2010-10-07  4:46 UTC (permalink / raw)
  To: git, judge.packham; +Cc: Jens.Lehmann, Junio C Hamano, jrnieder, Nguyễn Thái Ngọc Duy

From: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>

When both GIT_DIR and GIT_WORK_TREE are set, if cwd is outside
worktree, prefix (the one passed to every builtin commands) will be
set to NULL, which means "user stays at worktree topdir", but cwd is
not moved to worktree topdir.

As a consequence, command line arguments will be interpreted
differently. Assume there is a file named "bar" in foo/.git. A command
can expect command line arguments to be "path in repository":

$ GIT_DIR=foo/.git GIT_WORK_TREE=foo git blah bar

or "path in file system":

$ GIT_DIR=foo/.git GIT_WORK_TREE=foo git blah foo/bar

Some commands may want "path in repository" and "path in file system"
to be identical. Moreover, output from commands in such situations are
relative to worktree topdir (because prefix is NULL), not what users
expect. It's just confusing.

This patch does not address that. Instead it prepares some variables
to ease access to original cwd in this case. Commands that work well
outside worktree should:

 - detect this case, via is_inside_work_tree()

 - enter_work_tree() (not strictly needed, but I believe it would
   less work this way)

 - prepend startup_info->cwd_to_worktree to output so it becomes
   relative to original cwd

 - prepend startup_info->worktree_to_cwd to command line arguments
   if they are meant to access file system

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 I don't care Windows UNC path. And I did not test the case
 where cwd is on C:\ while worktree is on another drive.

 As stated elsewhere, I neglect other cases where cwd may be
 outside worktree. The goal of these patches is to help
 Chris' grep series. If it works out, I'll fix the rest.

 Sorry Chris, I think I have dragged you into worktree setup
 mess.

 builtin/rev-parse.c        |   10 ++++
 cache.h                    |    2 +
 setup.c                    |  119 ++++++++++++++++++++++++++++++++++++++++++--
 t/t1510-worktree-prefix.sh |   52 +++++++++++++++++++
 4 files changed, 179 insertions(+), 4 deletions(-)
 create mode 100755 t/t1510-worktree-prefix.sh

diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index a5a1c86..525610e 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -623,6 +623,16 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 					puts(prefix);
 				continue;
 			}
+			if (!strcmp(arg, "--cwd-to-worktree")) {
+				if (startup_info->cwd_to_worktree)
+					puts(startup_info->cwd_to_worktree);
+				continue;
+			}
+			if (!strcmp(arg, "--worktree-to-cwd")) {
+				if (startup_info->worktree_to_cwd)
+					puts(startup_info->worktree_to_cwd);
+				continue;
+			}
 			if (!strcmp(arg, "--show-cdup")) {
 				const char *pfx = prefix;
 				if (!is_inside_work_tree()) {
diff --git a/cache.h b/cache.h
index e71db23..be35b8f 100644
--- a/cache.h
+++ b/cache.h
@@ -1111,6 +1111,8 @@ const char *split_cmdline_strerror(int cmdline_errno);
 /* git.c */
 struct startup_info {
 	int have_repository;
+	char *cwd_to_worktree; /* path from original cwd to worktree */
+	char *worktree_to_cwd; /* path from worktree to original cwd */
 };
 extern struct startup_info *startup_info;
 
diff --git a/setup.c b/setup.c
index 3fbe928..1f5117a 100644
--- a/setup.c
+++ b/setup.c
@@ -320,10 +320,120 @@ const char *read_gitfile_gently(const char *path)
 	return path;
 }
 
+/*
+ * Given "foo/bar" and "hey/hello/world", return "../../hey/hello/world/"
+ * Either path1 or path2 can be NULL. All must be canonical.
+ */
+static char *make_path_to_path(const char *path1, const char *path2)
+{
+	int nr_back = 0;
+	int i, pathlen = path2 ? strlen(path2) : 0;
+	char *buf, *p;
+
+	if (path1 && *path1) {
+		nr_back = 1;
+		while (*path1) {
+			if (is_dir_sep(*path1))
+				nr_back++;
+			path1++;
+		}
+	}
+
+	if (!nr_back && !pathlen)
+		return NULL;
+
+	p = buf = xmalloc(3*nr_back + pathlen + 2); /* "../"^nr_back + path2 + '/' + NULL */
+	for (i = 0; i < nr_back; i++) {
+		memcpy(p, "../", 3);
+		p += 3;
+	}
+	if (pathlen) {
+		memcpy(p, path2, pathlen);
+		p += pathlen;
+		if (p[-1] != '/') /* path2 may be c:/, don't put another slash  */
+			*p++ = '/';
+	}
+	*p = '\0';
+	return buf;
+}
+
+/*
+ * Return a prefix if cwd inside worktree, or NULL otherwise.
+ * Also fill startup_info struct.
+ */
+static const char *setup_prefix(const char *cwd)
+{
+	const char *worktree = get_git_work_tree();
+	int len = 0, cwd_len = strlen(cwd), worktree_len = strlen(worktree);
+
+	while (worktree[len] && worktree[len] == cwd[len])
+		len++;
+
+	if (!worktree[len] && !cwd[len]) {
+		if (startup_info) {
+			startup_info->cwd_to_worktree = NULL;
+			startup_info->worktree_to_cwd = NULL;
+		}
+		return NULL;
+	}
+	/* get /foo/, not /foo/baa if /foo/baa1 and /foo/baa2 are given */
+	else if (worktree[len] && cwd[len]) {
+		while (len && !is_dir_sep(worktree[len]))
+			len--;
+		len++;
+
+		/* Worktree and cwd are on different drives? */
+		if (len == 3 && has_dos_drive_prefix(cwd)) {
+			if (startup_info) {
+				/* make_path_to_path will add the trailing slash */
+				startup_info->cwd_to_worktree = make_path_to_path(NULL, worktree);
+				startup_info->worktree_to_cwd = make_path_to_path(NULL, cwd);
+			}
+			return NULL;
+		}
+	}
+	else {
+		if (worktree[len]) {
+			if (!is_dir_sep(worktree[len])) {
+				while (len && !is_dir_sep(worktree[len]))
+					len--;
+			}
+		}
+		else {
+			if (!is_dir_sep(cwd[len])) {
+				while (len && !is_dir_sep(cwd[len]))
+					len--;
+			}
+		}
+		len++;		/* must be a slash here, skip it */
+	}
+
+	if (len < cwd_len && len < worktree_len) {
+		if (startup_info) {
+			startup_info->cwd_to_worktree = make_path_to_path(cwd+len, worktree+len);
+			startup_info->worktree_to_cwd = make_path_to_path(worktree+len, cwd+len);
+		}
+		return NULL;
+	}
+
+	if (startup_info) {
+		if (len < cwd_len) { /* cwd inside worktree */
+			startup_info->cwd_to_worktree = make_path_to_path(cwd+len, NULL);
+			startup_info->worktree_to_cwd = make_path_to_path(NULL, cwd+len);
+		}
+		else {
+			startup_info->cwd_to_worktree = make_path_to_path(NULL, worktree+len);
+			startup_info->worktree_to_cwd = make_path_to_path(worktree+len, NULL);
+		}
+	}
+
+	return len < cwd_len ? cwd+len : NULL;
+}
+
 static const char *setup_explicit_git_dir(const char *gitdirenv,
 				const char *work_tree_env, int *nongit_ok)
 {
-	static char buffer[1024 + 1];
+	static char buffer[PATH_MAX];
 	const char *retval;
 
 	if (PATH_MAX - 40 < strlen(gitdirenv))
@@ -344,9 +454,10 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
 	}
 	if (check_repository_format_gently(nongit_ok))
 		return NULL;
-	retval = get_relative_cwd(buffer, sizeof(buffer) - 1,
-			get_git_work_tree());
-	if (!retval || !*retval)
+	if (!getcwd(buffer, sizeof(buffer)))
+		die_errno("can't find the current directory");
+	retval = setup_prefix(buffer);
+	if (!retval)
 		return NULL;
 	set_git_dir(make_absolute_path(gitdirenv));
 	if (chdir(work_tree_env) < 0)
diff --git a/t/t1510-worktree-prefix.sh b/t/t1510-worktree-prefix.sh
new file mode 100755
index 0000000..3839493
--- /dev/null
+++ b/t/t1510-worktree-prefix.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+test_description='test rev-parse --cwd-to-worktree and --worktree-to-cwd'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	mkdir foo bar &&
+	mv .git foo &&
+	mkdir foo/bar &&
+	GIT_DIR=`pwd`/foo/.git &&
+	GIT_WORK_TREE=`pwd`/foo &&
+	export GIT_DIR GIT_WORK_TREE
+'
+
+test_expect_success 'at root' '
+	(
+	cd foo &&
+	git rev-parse --cwd-to-worktree --worktree-to-cwd >result &&
+	: >expected &&
+	test_cmp expected result
+	)
+'
+
+test_expect_success 'cwd inside worktree' '
+	(
+	cd foo/bar &&
+	git rev-parse --cwd-to-worktree --worktree-to-cwd >result &&
+	echo ../ >expected &&
+	echo bar/ >>expected &&
+	test_cmp expected result
+	)
+'
+
+test_expect_success 'cwd outside worktree' '
+	git rev-parse --cwd-to-worktree --worktree-to-cwd >result &&
+	echo foo/ >expected &&
+	echo ../ >>expected &&
+	test_cmp expected result
+'
+
+test_expect_success 'cwd outside worktree (2)' '
+	(
+	cd bar &&
+	git rev-parse --cwd-to-worktree --worktree-to-cwd >result &&
+	echo ../foo/ >expected &&
+	echo ../bar/ >>expected &&
+	test_cmp expected result
+	)
+'
+
+test_done
-- 
1.7.1.rc1.70.g788ca

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 2/2] worktree: provide better prefix to go back to original cwd
  2010-10-07  4:46 ` [PATCH 2/2] worktree: provide better prefix to go back to original cwd pclouds
@ 2010-10-07  5:53   ` Nguyen Thai Ngoc Duy
  2010-10-07  5:54   ` Junio C Hamano
  1 sibling, 0 replies; 95+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2010-10-07  5:53 UTC (permalink / raw)
  To: git, judge.packham; +Cc: Jens.Lehmann, Junio C Hamano, jrnieder, Nguyễn Thái Ngọc Duy

On Thu, Oct 7, 2010 at 11:46 AM,  <pclouds@gmail.com> wrote:
> +               /* Worktree and cwd are on different drives? */
> +               if (len == 3 && has_dos_drive_prefix(cwd)) {
> +                       if (startup_info) {
> +                               /* make_path_to_path will add the trailing slash */
> +                               startup_info->cwd_to_worktree = make_path_to_path(NULL, worktree);
> +                               startup_info->worktree_to_cwd = make_path_to_path(NULL, cwd);
> +                       }
> +                       return NULL;
> +               }

Went for lunch and realized this code is just wrong. Gaahh..
-- 
Duy

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 2/2] worktree: provide better prefix to go back to original cwd
  2010-10-07  4:46 ` [PATCH 2/2] worktree: provide better prefix to go back to original cwd pclouds
  2010-10-07  5:53   ` Nguyen Thai Ngoc Duy
@ 2010-10-07  5:54   ` Junio C Hamano
  2010-10-07  7:20     ` Nguyen Thai Ngoc Duy
  1 sibling, 1 reply; 95+ messages in thread
From: Junio C Hamano @ 2010-10-07  5:54 UTC (permalink / raw)
  To: pclouds; +Cc: git, judge.packham, Jens.Lehmann, jrnieder

pclouds@gmail.com writes:

> From: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
>
> When both GIT_DIR and GIT_WORK_TREE are set, if cwd is outside
> worktree, prefix (the one passed to every builtin commands) will be
> set to NULL, which means "user stays at worktree topdir", but cwd is
> not moved to worktree topdir.

Well, NULL traditionally meant "_if_ the cwd is inside the working tree,
it is at the top", not "stays at worktree topdir" if you started from
elsewhere.

And when cwd is inside the working tree, we do want to feed paths given
from the command line after adding the prefix, so that we will see the
paths relative to the cwd after we do cd-to-topdir.

Obviously when you run git command that requires you to be in a working
tree from outside the working tree, relative or full paths would not make
any difference.  The command should simply fail.

I suspect that you are introducing a new semantics on top of that
traditional semantics; if so, you may want to state it more clearly.

For example:

    When you run git command that requires you to be in a working tree
    from outside the working tree, the command should simply fail.

    When GIT_WORK_TREE is in use, however, it could be argued that we do
    not necessarily have to be in anywhere in the working tree to perform
    a whole-tree operation.  Instead, we could just say the operation
    always runs as if the command was started at the root level of the
    working tree.

    To support this new mode of operation, however, prefix needs to be
    adjusted to allow the program, after running chdir(2) to the root of
    the working tree, to refer to non-absolute paths originally given from
    the command line as relative to the original cwd.  This patch adds a
    mechanism to support that.

I have a queasy feeling about the idea of the second paragraph above,
though.

If the original cwd is inside GIT_WORK_TREE, limiting ourselves inside
prefix naturally limits the operation to the subdirectory we started from
(if the original cwd is at GIT_WORK_TREE, that would make it a whole-tree
operation).  A natural extension of this idea to limit the operation to
the part of the subtree of the working tree we started from is to refuse
to work in the case where the original cwd is outside GIT_WORK_TREE (the
current implementation of GIT_WORK_TREE may or may not correctly implement
it, though---I never use it myself).

Futzing with the prefix that is not a prefix to reach into the working
tree from sideways may make the relative paths given from the command line
mean something to the current implementation, but it doesn't change the
fundamental fact that you are introducing a funny special case where your
cwd does _not_ mean anything with respect to which part of the working
tree should be affected.

> Some commands may want "path in repository" and "path in file system"
> to be identical. Moreover, output from commands in such situations are
> relative to worktree topdir (because prefix is NULL), not what users
> expect. It's just confusing.

My gut feeling is that this is probably made more confusing, not less,
with the change.  Perhaps we should instead make sure this fails?

    $ cd /srv/git/git.git
    $ export GIT_DIR=$(pwd)/.git GIT_WORK_TREE=$(pwd)
    $ cd /var/tmp ;# no git stuff there
    $ git status

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 2/2] worktree: provide better prefix to go back to original cwd
  2010-10-07  5:54   ` Junio C Hamano
@ 2010-10-07  7:20     ` Nguyen Thai Ngoc Duy
  2010-10-07 14:56       ` Junio C Hamano
  0 siblings, 1 reply; 95+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2010-10-07  7:20 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, judge.packham, Jens.Lehmann, jrnieder

On Thu, Oct 7, 2010 at 12:54 PM, Junio C Hamano <gitster@pobox.com> wrote:
> pclouds@gmail.com writes:
>
>> From: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
>>
>> When both GIT_DIR and GIT_WORK_TREE are set, if cwd is outside
>> worktree, prefix (the one passed to every builtin commands) will be
>> set to NULL, which means "user stays at worktree topdir", but cwd is
>> not moved to worktree topdir.
>
> Well, NULL traditionally meant "_if_ the cwd is inside the working tree,
> it is at the top", not "stays at worktree topdir" if you started from
> elsewhere.
>
> And when cwd is inside the working tree, we do want to feed paths given
> from the command line after adding the prefix, so that we will see the
> paths relative to the cwd after we do cd-to-topdir.
>
> Obviously when you run git command that requires you to be in a working
> tree from outside the working tree, relative or full paths would not make
> any difference.  The command should simply fail.
>
> I suspect that you are introducing a new semantics on top of that
> traditional semantics; if so, you may want to state it more clearly.

Yes. The better semantics _when_ cwd is outside worktree.

> For example:
>
>    When you run git command that requires you to be in a working tree
>    from outside the working tree, the command should simply fail.
>
>    When GIT_WORK_TREE is in use, however, it could be argued that we do
>    not necessarily have to be in anywhere in the working tree to perform
>    a whole-tree operation.  Instead, we could just say the operation
>    always runs as if the command was started at the root level of the
>    working tree.
>
>    To support this new mode of operation, however, prefix needs to be
>    adjusted to allow the program, after running chdir(2) to the root of
>    the working tree, to refer to non-absolute paths originally given from
>    the command line as relative to the original cwd.  This patch adds a
>    mechanism to support that.
>
> I have a queasy feeling about the idea of the second paragraph above,
> though.
>
> If the original cwd is inside GIT_WORK_TREE, limiting ourselves inside
> prefix naturally limits the operation to the subdirectory we started from
> (if the original cwd is at GIT_WORK_TREE, that would make it a whole-tree
> operation).  A natural extension of this idea to limit the operation to
> the part of the subtree of the working tree we started from is to refuse
> to work in the case where the original cwd is outside GIT_WORK_TREE (the
> current implementation of GIT_WORK_TREE may or may not correctly implement
> it, though---I never use it myself).

I tend to think that as we go up to worktree's root, prefix is shorten
and the operation area is widen. When cwd is at worktree's, we operate
on full worktree. If it goes up one level higher, the operation area
remains full worktree (but not everything under cwd because cwd now
can have non-worktree directories).

> Futzing with the prefix that is not a prefix to reach into the working
> tree from sideways may make the relative paths given from the command line
> mean something to the current implementation, but it doesn't change the
> fundamental fact that you are introducing a funny special case where your
> cwd does _not_ mean anything with respect to which part of the working
> tree should be affected.

It would mean full worktree is affected. But not full cwd. In other
words, in set theory, it's a union of cwd and worktree.

>> Some commands may want "path in repository" and "path in file system"
>> to be identical. Moreover, output from commands in such situations are
>> relative to worktree topdir (because prefix is NULL), not what users
>> expect. It's just confusing.
>
> My gut feeling is that this is probably made more confusing, not less,
> with the change.  Perhaps we should instead make sure this fails?
>
>    $ cd /srv/git/git.git

Err.. you did not mean bare repo, did you?

>    $ export GIT_DIR=$(pwd)/.git GIT_WORK_TREE=$(pwd)
>    $ cd /var/tmp ;# no git stuff there
>    $ git status

I think it used to fail some time ago. Though I see nothing wrong if
that command works. And it'd be better if it outputs relative to
/var/tmp rather than /srv/git/git.git. I don't use this a lot but
sometimes I export GIT_DIR/GIT_WORK_TREE, cd around then do "git add
/srv/git/git.git/blah". To me, it should work. I may stand outside
worktree, but I give input inside worktree.
-- 
Duy

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 2/2] worktree: provide better prefix to go back to original cwd
  2010-10-07  7:20     ` Nguyen Thai Ngoc Duy
@ 2010-10-07 14:56       ` Junio C Hamano
  2010-10-07 15:11         ` Nguyen Thai Ngoc Duy
  0 siblings, 1 reply; 95+ messages in thread
From: Junio C Hamano @ 2010-10-07 14:56 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: git, judge.packham, Jens.Lehmann, jrnieder

Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:

> On Thu, Oct 7, 2010 at 12:54 PM, Junio C Hamano <gitster@pobox.com> wrote:
>> pclouds@gmail.com writes:
>> ...
>> If the original cwd is inside GIT_WORK_TREE, limiting ourselves inside
>> prefix naturally limits the operation to the subdirectory we started from
>> (if the original cwd is at GIT_WORK_TREE, that would make it a whole-tree
>> operation).  A natural extension of this idea to limit the operation to
>> the part of the subtree of the working tree we started from is to refuse
>> to work in the case where the original cwd is outside GIT_WORK_TREE (the
>> current implementation of GIT_WORK_TREE may or may not correctly implement
>> it, though---I never use it myself).
>
> I tend to think that as we go up to worktree's root, prefix is shorten
> and the operation area is widen. When cwd is at worktree's, we operate
> on full worktree. If it goes up one level higher, the operation area
> remains full worktree (but not everything under cwd because cwd now
> can have non-worktree directories).

I have a feeling that you did not understand my /srv/git/git.git (no, it
is not a bare repository) vs /var/tmp example.

I think it makes the new semantics much less yucky if the special case is
limited to "the working tree is a subdirectory somewhere under cwd".  But
does your patch check and notice that /var/tmp is not above the working
tree and they are completely unrelated?

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 2/2] worktree: provide better prefix to go back to original cwd
  2010-10-07 14:56       ` Junio C Hamano
@ 2010-10-07 15:11         ` Nguyen Thai Ngoc Duy
  0 siblings, 0 replies; 95+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2010-10-07 15:11 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, judge.packham, Jens.Lehmann, jrnieder

On Thu, Oct 7, 2010 at 9:56 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
>
>> On Thu, Oct 7, 2010 at 12:54 PM, Junio C Hamano <gitster@pobox.com> wrote:
>>> pclouds@gmail.com writes:
>>> ...
>>> If the original cwd is inside GIT_WORK_TREE, limiting ourselves inside
>>> prefix naturally limits the operation to the subdirectory we started from
>>> (if the original cwd is at GIT_WORK_TREE, that would make it a whole-tree
>>> operation).  A natural extension of this idea to limit the operation to
>>> the part of the subtree of the working tree we started from is to refuse
>>> to work in the case where the original cwd is outside GIT_WORK_TREE (the
>>> current implementation of GIT_WORK_TREE may or may not correctly implement
>>> it, though---I never use it myself).
>>
>> I tend to think that as we go up to worktree's root, prefix is shorten
>> and the operation area is widen. When cwd is at worktree's, we operate
>> on full worktree. If it goes up one level higher, the operation area
>> remains full worktree (but not everything under cwd because cwd now
>> can have non-worktree directories).
>
> I have a feeling that you did not understand my /srv/git/git.git (no, it
> is not a bare repository) vs /var/tmp example.
>
> I think it makes the new semantics much less yucky if the special case is
> limited to "the working tree is a subdirectory somewhere under cwd".  But
> does your patch check and notice that /var/tmp is not above the working
> tree and they are completely unrelated?
>

OK I see it now. I think my patch deals with completely unrelated
worktree/cwd just fine (both cwd-to-worktree and worktree-to-cwd
contain a few "../").

There is however a case where "git status" on separate cwd/worktree
might make sense. Suppose a master repo a/.git has two submodules
a/b/.git and a/c/.git. If user stands in a/c and want to do git-status
on all repos (let's skip how it finds out a/.git is the master repo),
it would make sense to display paths, including ones from a/b/.git,
relative to a/c (which is cwd and completely unrelated to a/b/.git).
-- 
Duy

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH] Corrected cmitmode set in the right lower window when initiating a diff.
       [not found] <y>
                   ` (6 preceding siblings ...)
  2010-10-07  4:46 ` [PATCH 2/2] worktree: provide better prefix to go back to original cwd pclouds
@ 2010-11-23  2:32 ` Michał Pomorski
  2011-04-07  6:01 ` [PATCH] git-p4: replace each tab with 8 spaces for consistency Andrew Garber
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 95+ messages in thread
From: Michał Pomorski @ 2010-11-23  2:32 UTC (permalink / raw)
  To: git; +Cc: Michał Pomorski

Under certain circumstances it caused an error: bad text index "a:_number_" in treeopendir:
-Start gitk;
-Select the tree radio button in the lower right window;
-Choose a diff from the context menu in the main window (this->selected or vice versa)
-Observe the lower right window: a file list is displayed, but the radio button 'tree' remains selected
-Select one of the files listed. This should cause the error.

Because the variable cmitmode remains in the 'tree' setting, gitk is trying to calculate a tree view selection.
This patch corrects this by setting the cmitmode variable to 'patch' each time a diff is selected.
---
 gitk-git/gitk |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 1b0e09a..5d76de4 100644
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7330,8 +7330,9 @@ proc mergediff {id} {
 }
 
 proc startdiff {ids} {
-    global treediffs diffids treepending diffmergeid nullid nullid2
+    global treediffs diffids treepending diffmergeid nullid nullid2 cmitmode
 
+    set cmitmode patch
     settabs 1
     set diffids $ids
     catch {unset diffmergeid}
-- 
1.7.3.2

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH] git-p4: replace each tab with 8 spaces for consistency
       [not found] <y>
                   ` (7 preceding siblings ...)
  2010-11-23  2:32 ` [PATCH] Corrected cmitmode set in the right lower window when initiating a diff Michał Pomorski
@ 2011-04-07  6:01 ` Andrew Garber
  2011-04-07  7:36   ` Junio C Hamano
  2011-04-07  6:01 ` Andrew Garber
                   ` (16 subsequent siblings)
  25 siblings, 1 reply; 95+ messages in thread
From: Andrew Garber @ 2011-04-07  6:01 UTC (permalink / raw)
  To: git, gitster; +Cc: Andrew Garber

Note that the majority of git-p4 uses spaces, not tabs, for indentation.
Consistent indentation is critical to the functionality of Python
scripts: mixing tabs and spaces in Python can lead to hard-to-find bugs.

Andrew Garber (1):
  git-p4: replace each tab with 8 spaces for consistency

 contrib/fast-import/git-p4 |   64 ++++++++++++++++++++++----------------------
 1 files changed, 32 insertions(+), 32 deletions(-)

-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH] git-p4: replace each tab with 8 spaces for consistency
       [not found] <y>
                   ` (8 preceding siblings ...)
  2011-04-07  6:01 ` [PATCH] git-p4: replace each tab with 8 spaces for consistency Andrew Garber
@ 2011-04-07  6:01 ` Andrew Garber
  2012-06-04 19:15 ` [PATCH/RFC] file import functionality for git-remote-mw Pavel Volek
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 95+ messages in thread
From: Andrew Garber @ 2011-04-07  6:01 UTC (permalink / raw)
  To: git, gitster; +Cc: Andrew Garber

Note that the majority of git-p4 uses spaces, not tabs, for indentation.
Consistent indentation is critical to the functionality of Python
scripts: mixing tabs and spaces in Python can lead to hard-to-find bugs.

Signed-off-by: Andrew Garber <andrew@andrewgarber.com>
---
 contrib/fast-import/git-p4 |   64 ++++++++++++++++++++++----------------------
 1 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index 3881515..78e5b3a 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -222,10 +222,10 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None):
     try:
         while True:
             entry = marshal.load(p4.stdout)
-	    if cb is not None:
-		cb(entry)
-	    else:
-		result.append(entry)
+            if cb is not None:
+                cb(entry)
+            else:
+                result.append(entry)
     except EOFError:
         pass
     exitCode = p4.wait()
@@ -449,8 +449,8 @@ def p4ChangesForPaths(depotPaths, changeRange):
 
     changes = {}
     for line in output:
-	changeNum = int(line.split(" ")[1])
-	changes[changeNum] = True
+        changeNum = int(line.split(" ")[1])
+        changes[changeNum] = True
 
     changelist = changes.keys()
     changelist.sort()
@@ -1033,10 +1033,10 @@ class P4Sync(Command):
     # - helper for streamP4Files
 
     def streamOneP4File(self, file, contents):
-	if file["type"] == "apple":
-	    print "\nfile %s is a strange apple file that forks. Ignoring" % \
-		file['depotFile']
-	    return
+        if file["type"] == "apple":
+            print "\nfile %s is a strange apple file that forks. Ignoring" % \
+                file['depotFile']
+            return
 
         relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
         relPath = self.wildcard_decode(relPath)
@@ -1085,22 +1085,22 @@ class P4Sync(Command):
     # handle another chunk of streaming data
     def streamP4FilesCb(self, marshalled):
 
-	if marshalled.has_key('depotFile') and self.stream_have_file_info:
-	    # start of a new file - output the old one first
-	    self.streamOneP4File(self.stream_file, self.stream_contents)
-	    self.stream_file = {}
-	    self.stream_contents = []
-	    self.stream_have_file_info = False
+        if marshalled.has_key('depotFile') and self.stream_have_file_info:
+            # start of a new file - output the old one first
+            self.streamOneP4File(self.stream_file, self.stream_contents)
+            self.stream_file = {}
+            self.stream_contents = []
+            self.stream_have_file_info = False
 
-	# pick up the new file information... for the
-	# 'data' field we need to append to our array
-	for k in marshalled.keys():
-	    if k == 'data':
-		self.stream_contents.append(marshalled['data'])
-	    else:
-		self.stream_file[k] = marshalled[k]
+        # pick up the new file information... for the
+        # 'data' field we need to append to our array
+        for k in marshalled.keys():
+            if k == 'data':
+                self.stream_contents.append(marshalled['data'])
+            else:
+                self.stream_file[k] = marshalled[k]
 
-	self.stream_have_file_info = True
+        self.stream_have_file_info = True
 
     # Stream directly from "p4 files" into "git fast-import"
     def streamP4Files(self, files):
@@ -1132,14 +1132,14 @@ class P4Sync(Command):
             self.stream_contents = []
             self.stream_have_file_info = False
 
-	    # curry self argument
-	    def streamP4FilesCbSelf(entry):
-		self.streamP4FilesCb(entry)
+            # curry self argument
+            def streamP4FilesCbSelf(entry):
+                self.streamP4FilesCb(entry)
 
-	    p4CmdList("-x - print",
-		'\n'.join(['%s#%s' % (f['path'], f['rev'])
+            p4CmdList("-x - print",
+                '\n'.join(['%s#%s' % (f['path'], f['rev'])
                                                   for f in filesToRead]),
-	        cb=streamP4FilesCbSelf)
+                cb=streamP4FilesCbSelf)
 
             # do the last chunk
             if self.stream_file.has_key('depotFile'):
@@ -1148,7 +1148,7 @@ class P4Sync(Command):
     def commit(self, details, files, branch, branchPrefixes, parent = ""):
         epoch = details["time"]
         author = details["user"]
-	self.branchPrefixes = branchPrefixes
+        self.branchPrefixes = branchPrefixes
 
         if self.verbose:
             print "commit into %s" % branch
@@ -1253,7 +1253,7 @@ class P4Sync(Command):
 
         s = ''
         for (key, val) in self.users.items():
-	    s += "%s\t%s\n" % (key.expandtabs(1), val.expandtabs(1))
+            s += "%s\t%s\n" % (key.expandtabs(1), val.expandtabs(1))
 
         open(self.getUserCacheFilename(), "wb").write(s)
         self.userMapFromPerforceServer = True
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH] git-p4: replace each tab with 8 spaces for consistency
  2011-04-07  6:01 ` [PATCH] git-p4: replace each tab with 8 spaces for consistency Andrew Garber
@ 2011-04-07  7:36   ` Junio C Hamano
  2011-04-07 16:35     ` Phil Hord
  0 siblings, 1 reply; 95+ messages in thread
From: Junio C Hamano @ 2011-04-07  7:36 UTC (permalink / raw)
  To: Andrew Garber; +Cc: git

Andrew Garber <andrew@andrewgarber.com> writes:

> Note that the majority of git-p4 uses spaces, not tabs, for indentation.
> Consistent indentation is critical to the functionality of Python
> scripts: mixing tabs and spaces in Python can lead to hard-to-find bugs.

Mixing tabs and spaces can lead to hard-to-find bugs, I agree.

I just threw this in to my .git/info/attributes:

    contrib/fast-import/git-p4 whitespace=!indent,tail,tab-in-indent

and then did this:

    $ >contrib/fast-import/git-p4
    $ git diff -R | git apply --whitespace=fix
    $ git diff

The changes I get out of the last step seem to exactly match your patch.

Thanks.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH] git-p4: replace each tab with 8 spaces for consistency
  2011-04-07  7:36   ` Junio C Hamano
@ 2011-04-07 16:35     ` Phil Hord
  2011-04-07 18:45       ` Junio C Hamano
  0 siblings, 1 reply; 95+ messages in thread
From: Phil Hord @ 2011-04-07 16:35 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Andrew Garber, git

On 04/07/2011 03:36 AM, Junio C Hamano wrote:
> Mixing tabs and spaces can lead to hard-to-find bugs, I agree.
>
> I just threw this in to my .git/info/attributes:
>
>     contrib/fast-import/git-p4 whitespace=!indent,tail,tab-in-indent
>
> and then did this:
>
>     $ >contrib/fast-import/git-p4
>     $ git diff -R | git apply --whitespace=fix
>     $ git diff
>
> The changes I get out of the last step seem to exactly match your patch.

Junio!  Thanks for that recipe.

I suspected there must be some way to employ git-apply's whitespace=fix
feature to ws-normalize my code, but I was clueless how to do that.  I
wound up cobbling together a python script that reimplements the same
fixes (hopefully).

I wish this (the git-apply trick) was documented somewhere and/or made
more prominent.  Is it, and I have also overlooked it?

This is what I want:

   git fix-whitespace             # fix new ws errors in workdir
   git fix-whitespace --all       # fix all ws errors in workdir
   git fix-whitespace foo         # fix new ws errors since foo
   git fix-whitespace --cached    # fix new ws errors in the index
   etc.

Is this already implemented somewhere in the git porcelain?

Phil

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH] git-p4: replace each tab with 8 spaces for consistency
  2011-04-07 16:35     ` Phil Hord
@ 2011-04-07 18:45       ` Junio C Hamano
  0 siblings, 0 replies; 95+ messages in thread
From: Junio C Hamano @ 2011-04-07 18:45 UTC (permalink / raw)
  To: Phil Hord; +Cc: git

Phil Hord <hordp@cisco.com> writes:

> This is what I want:
>
>    git fix-whitespace             # fix new ws errors in workdir
>    git fix-whitespace --all       # fix all ws errors in workdir
>    git fix-whitespace foo         # fix new ws errors since foo
>    git fix-whitespace --cached    # fix new ws errors in the index
>    etc.

If you understood the example I gave, you should be able to figure all of
these out.  In the most general case, you would come up with a way to
generate a diff that represents the change you want to fix (e.g. "new
errors" would be comparing the HEAD and the working tree), reverse apply
the diff and then forward apply the same diff with --whitespace=fix, but
often you can omit "reverse apply the diff" step by finding an appropriate
combination between HEAD/index/working tree.

I long time wrote this alias

[alias]
        wsadd = "!sh -c 'git diff -- \"$@\" | git apply --cached --whitespace=fix;\
                git co -- ${1-.} \"$@\"' -"

that acts as if you are saying "git add $path" while fixing the whitespace
errors I introduced in the working tree version.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH/RFC] file import functionality for git-remote-mw
       [not found] <y>
                   ` (9 preceding siblings ...)
  2011-04-07  6:01 ` Andrew Garber
@ 2012-06-04 19:15 ` Pavel Volek
  2012-06-04 20:54   ` Matthieu Moy
  2012-06-04 20:49 ` [PATCH/RFC] Export file attachements in git-remote-mediawiki NGUYEN Kim Thuat
                   ` (14 subsequent siblings)
  25 siblings, 1 reply; 95+ messages in thread
From: Pavel Volek @ 2012-06-04 19:15 UTC (permalink / raw)
  To: git; +Cc: Volek Pavel, Pavel Volek, NGUYEN Kim Thuat, ROUCHER IGLESIAS Javier, Matthieu Moy

From: Volek Pavel <me@pavelvolek.cz>

The current version of the git-remote-mediawiki supports only import and export of the pages, doesn't support import and export of file attachements which are also exposed by MediaWiki API. This patch adds the functionality to import the last versions of the files and all versions of description pages for these files.

Signed-off-by: Pavel Volek <Pavel.Volek@ensimag.imag.fr>
Signed-off-by: NGUYEN Kim Thuat <Kim-Thuat.Nguyen@ensimag.imag.fr>
Signed-off-by: ROUCHER IGLESIAS Javier <roucherj@ensimag.imag.fr>
Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
---
 contrib/mw-to-git/git-remote-mediawiki | 128 +++++++++++++++++++++++++++++++--
 1 file changed, 123 insertions(+), 5 deletions(-)

diff --git a/contrib/mw-to-git/git-remote-mediawiki b/contrib/mw-to-git/git-remote-mediawiki
index c18bfa1..4168218 100755
--- a/contrib/mw-to-git/git-remote-mediawiki
+++ b/contrib/mw-to-git/git-remote-mediawiki
@@ -267,6 +267,39 @@ sub get_mw_pages {
 	return values(%pages);
 }
 
+sub get_mw_media_pages {
+	mw_connect_maybe();
+
+	my %pages; # hash on page titles to avoid duplicates
+
+	# get all pages for mediafiles (they are in different namespace)
+	# only one namespace can be queried at the same moment
+	my $mw_pages = $mediawiki->list({
+		action => 'query',
+		list => 'allpages',
+		apnamespace => get_mw_namespace_id("File"),
+		aplimit => 500,
+	});
+	if (!defined($mw_pages)) {
+		print STDERR "fatal: could not get the list of media file pages.\n";
+		print STDERR "fatal: '$url' does not appear to be a mediawiki\n";
+		print STDERR "fatal: make sure '$url/api.php' is a valid page.\n";
+		exit 1;
+	}
+	foreach my $page (@{$mw_pages}) {
+		$pages{$page->{title}} = $page;
+	}
+	return values(%pages);
+}
+
+sub get_all_mw_pages() {
+	my @pages = get_mw_pages();
+	my @media_pages = get_mw_media_pages();
+	push(@pages,@media_pages);
+
+	return @pages;
+}
+
 sub run_git {
 	open(my $git, "-|:encoding(UTF-8)", "git " . $_[0]);
 	my $res = do { local $/; <$git> };
@@ -300,7 +333,7 @@ my %basetimestamps;
 sub get_last_remote_revision {
 	mw_connect_maybe();
 
-	my @pages = get_mw_pages();
+	my @pages = get_all_mw_pages();
 
 	my $max_rev_num = 0;
 
@@ -403,6 +436,25 @@ sub mw_option {
 	print STDOUT "unsupported\n";
 }
 
+# Returns MediaWiki id for a canonical namespace name. Ex.: "File", "Project".
+sub get_mw_namespace_id() {
+	mw_connect_maybe();
+	my $name = shift;
+	my $query = {
+		action => 'query',
+		meta => 'siteinfo',
+		siprop => 'namespaces',
+	};
+	my $result = $mediawiki->api($query);
+
+	while (my ($id, $ns) = each(%{$result->{query}->{namespaces}})) {
+		if (defined($ns->{canonical}) && ($ns->{canonical} eq $name)) {
+			return $ns->{id};
+		}
+	}
+	die "Namespace $name was not found on MediaWiki.";
+}
+
 sub fetch_mw_revisions_for_page {
 	my $page = shift;
 	my $id = shift;
@@ -461,11 +513,37 @@ sub fetch_mw_revisions {
 	return ($n, @revisions);
 }
 
+sub download_mw_mediafile {
+	my $filename = shift;
+
+	$mediawiki->{config}->{files_url} = $url;
+
+	my $file = $mediawiki->download( { title => $filename } )
+			|| die 'Fatal: Error ' .
+				$mediawiki->{error}->{code} .
+				' from mediwiki: ' . $mediawiki->{error}->{details};
+	if (!defined($file)){
+		print STDERR "\tFile \'$filename\' could not be downloaded.\n";
+		exit 1;
+	} elsif ($file eq "") {
+		print STDERR "\tFile \'$filename\' does not exist on the wiki.\n";
+		exit 1;
+	} else {
+		return $file;
+	}
+}
+
 sub import_file_revision {
 	my $commit = shift;
 	my %commit = %{$commit};
 	my $full_import = shift;
 	my $n = shift;
+	my $mediafile_import = shift;
+	my $mediafile;my %mediafile;
+	if ($mediafile_import) {
+		$mediafile = shift;
+		%mediafile = %{$mediafile};
+	}
 
 	my $title = $commit{title};
 	my $comment = $commit{comment};
@@ -485,6 +563,10 @@ sub import_file_revision {
 	if ($content ne DELETED_CONTENT) {
 		print STDOUT "M 644 inline $title.mw\n";
 		literal_data($content);
+		if ($mediafile_import) {
+			print STDOUT "M 644 inline $mediafile{title}\n";
+			literal_data($mediafile{content});
+		}
 		print STDOUT "\n\n";
 	} else {
 		print STDOUT "D $title.mw\n";
@@ -547,7 +629,7 @@ sub mw_import_ref {
 
 	mw_connect_maybe();
 
-	my @pages = get_mw_pages();
+	my @pages = get_all_mw_pages();
 
 	print STDERR "Searching revisions...\n";
 	my $last_local = get_last_local_revision();
@@ -580,6 +662,7 @@ sub mw_import_ref {
 
 		$n++;
 
+		my $page_title = $result->{query}->{pages}->{$pagerevid->{pageid}}->{title};
 		my %commit;
 		$commit{author} = $rev->{user} || 'Anonymous';
 		$commit{comment} = $rev->{comment} || '*Empty MediaWiki Message*';
@@ -596,9 +679,44 @@ sub mw_import_ref {
 		}
 		$commit{date} = DateTime::Format::ISO8601->parse_datetime($last_timestamp);
 
-		print STDERR "$n/", scalar(@revisions), ": Revision #$pagerevid->{revid} of $commit{title}\n";
-
-		import_file_revision(\%commit, ($fetch_from == 1), $n);
+		# differentiates classic pages and media pages
+		my @prefix = split (":",$page_title);
+		if ($prefix[0] eq "File" || $prefix[0] eq "Image") {
+			# check if there is a corresponding mediafile with the same timestamp => it is page
+			# for new verion of the file (not only for new version of the description of the file)
+			# => download corresponding file version
+			$query = {
+				action => 'query',
+				prop => 'imageinfo',
+				titles => $page_title,
+				iistart => $rev->{timestamp},
+				iiend => $rev->{timestamp},
+				iiprop => 'timestamp|archivename',
+				iilimit => 1,
+			};
+			$result = $mediawiki->api($query);
+
+			my ($imageid,$imageinfo) = each ( %{$result->{query}->{pages}} );
+			# page has a related version of the file
+			if (defined($imageinfo->{imageinfo})) {
+				foreach ( @{$imageinfo->{imageinfo}} ) {
+					my %mediafile;
+					if ($prefix[0] eq "File") { $mediafile{title} = substr $page_title, 5; }
+					else { $mediafile{title} = substr $page_title, 6; }
+
+					$mediafile{content} = download_mw_mediafile("File:".$mediafile{title});
+					print STDERR "$n/", scalar(@revisions), ": Revision #$pagerevid->{revid} of $commit{title}\n";
+					import_file_revision(\%commit, ($fetch_from == 1), $n, 1, \%mediafile);
+				}
+			# page has no related version of the file, do commit only for the page
+			} else {
+				print STDERR "$n/", scalar(@revisions), ": Revision #$pagerevid->{revid} of $commit{title}\n";
+				import_file_revision(\%commit, ($fetch_from == 1), $n, 0);
+			}
+		} else {
+			print STDERR "$n/", scalar(@revisions), ": Revision #$pagerevid->{revid} of $commit{title}\n";
+			import_file_revision(\%commit, ($fetch_from == 1), $n, 0);
+		}
 	}
 
 	if ($fetch_from == 1 && $n == 0) {
-- 
1.7.10.2.552.gaa3bb87

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH/RFC] Export file attachements in git-remote-mediawiki
       [not found] <y>
                   ` (10 preceding siblings ...)
  2012-06-04 19:15 ` [PATCH/RFC] file import functionality for git-remote-mw Pavel Volek
@ 2012-06-04 20:49 ` NGUYEN Kim Thuat
  2012-06-04 21:34   ` Matthieu Moy
  2012-06-08 13:27 ` [PATCHv1] Export file " Kim Thuat NGUYEN
                   ` (13 subsequent siblings)
  25 siblings, 1 reply; 95+ messages in thread
From: NGUYEN Kim Thuat @ 2012-06-04 20:49 UTC (permalink / raw)
  To: git; +Cc: nguyenkimthuat, Pavel Volek, NGUYEN Kim Thuat, ROUCHER IGLESIAS Javier, Matthieu Moy

From: nguyenkimthuat <nguyenkimthuat@gmail.com>

The current version of the git-remote-mediawiki supports only import and export of the pages, doesn't support import and export of file attachements which are also exposed by MediaWiki API. This patch add the functionnality to export the file attachements from the local git's repository using the API of mediawiki.
 For the moment, i removed the line: "use enconding 'utf8'" because it's broken, especially when reding a binary file for exemple .pdf or .jpg.

Signed-off-by: Pavel Volek <Pavel.Volek@ensimag.imag.fr>
Signed-off-by: NGUYEN Kim Thuat <Kim-Thuat.Nguyen@ensimag.imag.fr>
Signed-off-by: ROUCHER IGLESIAS Javier <roucherj@ensimag.imag.fr>
Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
---
 contrib/mw-to-git/git-remote-mediawiki | 90 ++++++++++++++++++++++++++++++++--
 1 file changed, 87 insertions(+), 3 deletions(-)

diff --git a/contrib/mw-to-git/git-remote-mediawiki b/contrib/mw-to-git/git-remote-mediawiki
index c18bfa1..830e2d0 100755
--- a/contrib/mw-to-git/git-remote-mediawiki
+++ b/contrib/mw-to-git/git-remote-mediawiki
@@ -36,7 +36,6 @@
 use strict;
 use MediaWiki::API;
 use DateTime::Format::ISO8601;
-use encoding 'utf8';
 
 # use encoding 'utf8' doesn't change STDERROR
 # but we're going to output UTF-8 filenames to STDERR
@@ -114,6 +113,9 @@ $wiki_name =~ s/[^\/]*:\/\///;
 # and '@' sign, to avoid author like MWUser@HTTPUser@host.com
 $wiki_name =~ s/^.*@//;
 
+# Get the list of file extensions supported by the current version of mediawiki 
+my @list_file_extensions = get_file_extensions();
+
 # Commands parser
 my $entry;
 my @cmd;
@@ -275,6 +277,13 @@ sub run_git {
 	return $res;
 }
 
+sub run_git_raw {
+        open(my $g,"-|","git " . $_[0]);   
+        my $r = do { local $/; <$g> };
+        close($g);
+
+        return $r;
+}
 
 sub get_last_local_revision {
 	# Get note regarding last mediawiki revision
@@ -642,8 +651,14 @@ sub mw_push_file {
 	my $old_sha1 = $diff_info_split[2];
 	my $page_created = ($old_sha1 eq NULL_SHA1);
 	my $page_deleted = ($new_sha1 eq NULL_SHA1);
+	my $file_deleted = ($new_sha1 eq NULL_SHA1);
 	$complete_file_name = mediawiki_clean_filename($complete_file_name);
 
+	my %hashFiles = map {$_ => 1}@list_file_extensions;
+	my $path = "File:".$complete_file_name;
+	my @extensions = split(/\./,$complete_file_name);
+	my $extension = pop(@extensions);
+
 	if (substr($complete_file_name,-3) eq ".mw") {
 		my $title = substr($complete_file_name,0,-3);
 
@@ -686,8 +701,34 @@ sub mw_push_file {
 		}
 		$newrevid = $result->{edit}->{newrevid};
 		print STDERR "Pushed file: $new_sha1 - $title\n";
-	} else {
-		print STDERR "$complete_file_name not a mediawiki file (Not pushable on this version of git-remote-mediawiki).\n"
+	} elsif (exists($hashFiles{$extension})) {
+		# Deleting and uploading a file require the priviledge of the user
+		if ($file_deleted) {
+			mw_connect_maybe();
+			my $res = $mediawiki->edit( {
+			action => 'delete',
+			title => $path,
+			reason => $summary } )
+			|| die $mediawiki-> {error}->{code} . ':' . $mediawiki->{error}->{details};
+
+		} else {
+			my $content = run_git_raw("cat-file blob $new_sha1");
+			mw_connect_maybe();
+				$mediawiki->{config}->{upload_url} = "$url/index.php/Special:Upload";
+
+				$mediawiki->upload( {
+				title => $complete_file_name,
+				summary => $summary,
+				data => $content,
+				ignorewarnings=>1
+                                  }, {
+					skip_encoding => 1 # Helps with names with accentuated characters
+			} ) || die $mediawiki-> {error}->{code} . ':' . $mediawiki->{error}->{details};
+			$newrevid = get_reviId_filepage();
+			print STDERR "Pushed file: $new_sha1 - $complete_file_name\n";
+			 }
+	else {
+		print STDERR "$complete_file_name is not supported on this version of Mediawiki.\n"
 	}
 	return ($newrevid, "ok");
 }
@@ -825,3 +866,46 @@ sub mw_push_revision {
 	print STDOUT "ok $remote\n";
 	return 1;
 }
+
+sub get_reviId_filepage() {
+	mw_connect_maybe();
+
+	my $max_rev_num_file = 0;
+
+	my @list_file_pages = get_mw_media_pages();
+
+	foreach my $file_page (@list_file_pages) {
+	my $id = $file_page->{pageid};
+        
+	my $query = {
+		action => 'query',
+		prop => 'revisions',
+		rvprop => 'ids',
+		pageids => $id,
+		};
+
+		my $result = $mediawiki->api($query);
+
+		my $lastrev = pop(@{$result->{query}->{pages}->{$id}->{revisions}});
+	}
+}
+
+sub get_file_extensions {
+	mw_connect_maybe();
+
+	my $query = {
+	action => 'query',
+	meta => 'siteinfo',
+	siprop => 'fileextensions'
+	};
+
+	my $result = $mediawiki->api($query);
+
+	my @file_extensions = map $_->{ext},@{$result->{query}->{fileextensions}};
+
+	return @file_extensions;
+}
+
+
+
+
-- 
1.7.10.2.552.gaa3bb87

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH/RFC] file import functionality for git-remote-mw
  2012-06-04 19:15 ` [PATCH/RFC] file import functionality for git-remote-mw Pavel Volek
@ 2012-06-04 20:54   ` Matthieu Moy
  0 siblings, 0 replies; 95+ messages in thread
From: Matthieu Moy @ 2012-06-04 20:54 UTC (permalink / raw)
  To: Pavel Volek; +Cc: git, Volek Pavel, NGUYEN Kim Thuat, ROUCHER IGLESIAS Javier

Pavel Volek <Pavel.Volek@ensimag.imag.fr> writes:

> +sub get_mw_media_pages {
> +	mw_connect_maybe();
> +
> +	my %pages; # hash on page titles to avoid duplicates
> +
> +	# get all pages for mediafiles (they are in different namespace)
> +	# only one namespace can be queried at the same moment
> +	my $mw_pages = $mediawiki->list({
> +		action => 'query',
> +		list => 'allpages',
> +		apnamespace => get_mw_namespace_id("File"),
> +		aplimit => 500,
> +	});

This seems to be done unconditionally. Is this reasonable if the user
has explicitely set remote.origin.pages or remote.origin.categories?

Actually, shouldn't this be added to get_mw_pages, next to the code
dealing with these two variables? Perhaps the function should be
split into multiple functions, along the lines of:

sub get_mw_pages {
	mw_connect_maybe();

        my %pages;
	if (@tracked_pages) {
		$user_defined = 1;
		get_mw_tracked_pages(\%pages);
	}
	if (@tracked_categories) {
		$user_defined = 1;
		get_mw_tracked_categories(\%pages);
	}
	if (!$user_defined) {
		get_mw_all_pages(\%pages);
	}
	return values(%pages);
}

And your code would need to take these 3 options into account.

> +sub get_all_mw_pages() {
> +	my @pages = get_mw_pages();
> +	my @media_pages = get_mw_media_pages();
> +	push(@pages,@media_pages);

Space after comma.

> +# Returns MediaWiki id for a canonical namespace name. Ex.: "File", "Project".
> +sub get_mw_namespace_id() {
> +	mw_connect_maybe();
> +	my $name = shift;
> +	my $query = {
> +		action => 'query',
> +		meta => 'siteinfo',
> +		siprop => 'namespaces',
> +	};
> +	my $result = $mediawiki->api($query);

It may make sense to cache the result, to avoid querying the API
multiple times if you call the function more than once. We can even
cache this in a configuration variable as the namespace identifiers are
unlikely to change for a given wiki.

> +	if (!defined($file)){

Space between ) and { please.

> +		my @prefix = split (":",$page_title);

Space after , please.

> +		if ($prefix[0] eq "File" || $prefix[0] eq "Image") {
> +			# check if there is a corresponding mediafile with the same timestamp => it is page
> +			# for new verion of the file (not only for new version of the description of the file)

> +			# => download corresponding file version

Don't make long lines like this. In general, we avoid lines longer than
80 characters (or even a bit less), these are >100 and the following are
worse.

Long lines are usually an indication that you did not structure your
code into functions, and this diagnosis seems to apply here.

> +			my ($imageid,$imageinfo) = each ( %{$result->{query}->{pages}} );

Space after ",".

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH/RFC] Export file attachements in git-remote-mediawiki
  2012-06-04 20:49 ` [PATCH/RFC] Export file attachements in git-remote-mediawiki NGUYEN Kim Thuat
@ 2012-06-04 21:34   ` Matthieu Moy
  2012-06-05 17:00     ` nguyenki
  2012-06-05 17:11     ` nguyenki
  0 siblings, 2 replies; 95+ messages in thread
From: Matthieu Moy @ 2012-06-04 21:34 UTC (permalink / raw)
  To: NGUYEN Kim Thuat; +Cc: git, nguyenkimthuat, Pavel Volek, ROUCHER IGLESIAS Javier

NGUYEN Kim Thuat <kim-thuat.nguyen@ensimag.imag.fr> writes:

> +# Get the list of file extensions supported by the current version of mediawiki 
> +my @list_file_extensions = get_file_extensions();

You should do it only on demand (like $mediawiki is created lazily).

> +        open(my $g,"-|","git " . $_[0]);   

Space after ",".

> @@ -642,8 +651,14 @@ sub mw_push_file {
>  	my $old_sha1 = $diff_info_split[2];
>  	my $page_created = ($old_sha1 eq NULL_SHA1);
>  	my $page_deleted = ($new_sha1 eq NULL_SHA1);
> +	my $file_deleted = ($new_sha1 eq NULL_SHA1);

This line looks suspiciously similar to the previous one. Do you need
another variable for the same value?

> +	my @extensions = split(/\./,$complete_file_name);

Space after "," (many more instances after).

> -	} else {
> -		print STDERR "$complete_file_name not a mediawiki file (Not pushable on this version of git-remote-mediawiki).\n"
> +	} elsif (exists($hashFiles{$extension})) {
> +		# Deleting and uploading a file require the priviledge of the user
> +		if ($file_deleted) {
> +			mw_connect_maybe();
> +			my $res = $mediawiki->edit( {
> +			action => 'delete',
> +			title => $path,
> +			reason => $summary } )

Indent the body of {} please.

> +		} else {
> +			my $content = run_git_raw("cat-file blob $new_sha1");
> +			mw_connect_maybe();
> +				$mediawiki->{config}->{upload_url} = "$url/index.php/Special:Upload";

Broken indentation.

Does this work on wiki configured in foreign languages, like french that
has Spécial:Téléverser instead?

> +			} ) || die $mediawiki-> {error}->{code} . ':' . $mediawiki->{error}->{details};
> +			$newrevid = get_reviId_filepage();

This queries the wiki to get the last revision id. The existing code (to
deal with page) could get this from the response of the API to the edit
request, like this:

		$newrevid = $result->{edit}->{newrevid};

Your version is much more inefficient (many requests each time you
upload a file), and has a race condition (what happens if someone else
creates a revision at the same time?). Isn't there a better way?

> +			print STDERR "Pushed file: $new_sha1 - $complete_file_name\n";
> +			 }

Broken indentation.

> +	else {
> +		print STDERR "$complete_file_name is not supported on this version of Mediawiki.\n"

It's not a matter of version, it's a matter of configuration.

> +sub get_reviId_filepage() {

Strange name (two consecutive i?). If this function fetches the last
wiki revision, why not call it get_last_mw_revid or something like this?

> +	mw_connect_maybe();
> +
> +	my $max_rev_num_file = 0;
> +
> +	my @list_file_pages = get_mw_media_pages();
> +
> +	foreach my $file_page (@list_file_pages) {
> +	my $id = $file_page->{pageid};

Broken indentation.

> +	my $query = {
> +		action => 'query',
> +		prop => 'revisions',
> +		rvprop => 'ids',
> +		pageids => $id,
> +		};
> +
> +		my $result = $mediawiki->api($query);

Broken indentation.

> +sub get_file_extensions {
> +	mw_connect_maybe();
> +
> +	my $query = {
> +	action => 'query',
> +	meta => 'siteinfo',
> +	siprop => 'fileextensions'
> +	};

Broken indentation.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH/RFC] Export file attachements in git-remote-mediawiki
  2012-06-04 21:34   ` Matthieu Moy
@ 2012-06-05 17:00     ` nguyenki
  2012-06-05 17:05       ` Matthieu Moy
  2012-06-05 17:11     ` nguyenki
  1 sibling, 1 reply; 95+ messages in thread
From: nguyenki @ 2012-06-05 17:00 UTC (permalink / raw)
  To: Matthieu.Moy; +Cc: git, roucherj, Pavel.Volek

On Mon, 04 Jun 2012 23:34:29 +0200, Matthieu Moy wrote:
> NGUYEN Kim Thuat <kim-thuat.nguyen@ensimag.imag.fr> writes:
>
>> +# Get the list of file extensions supported by the current version 
>> of mediawiki
>> +my @list_file_extensions = get_file_extensions();
>
> You should do it only on demand (like $mediawiki is created lazily).
yeah, i changed the code in this part, it look like:

@@ -113,9 +113,6 @@ $wiki_name =~ s/[^\/]*:\/\///;
  # and '@' sign, to avoid author like MWUser@HTTPUser@host.com
  $wiki_name =~ s/^.*@//;

-# Get the list of file extensions supported by the current version of 
mediawiki
-my @list_file_extensions = get_file_extensions();
-
  # Commands parser
  my $entry;
  my @cmd;
@@ -654,7 +651,7 @@ sub mw_push_file {
  	my $file_deleted = ($new_sha1 eq NULL_SHA1);
  	$complete_file_name = mediawiki_clean_filename($complete_file_name);

-	my %hashFiles = map {$_ => 1}@list_file_extensions;
+	my %hashFiles = get_file_extensions_maybe($complete_file_name);
  	my $path = "File:".$complete_file_name;
  	my @extensions = split(/\./,$complete_file_name);
  	my $extension = pop(@extensions);

-sub get_file_extensions {
-	mw_connect_maybe();
-
-	my $query = {
-	action => 'query',
-	meta => 'siteinfo',
-	siprop => 'fileextensions'
-	};
+sub get_file_extensions_maybe {
+	my $file_name = shift;
+	my $est_mw_page = substr($file_name,-3) eq ".mw";
+	if(!$est_mw_page) {
+		mw_connect_maybe();

-	my $result = $mediawiki->api($query);
+		my $query = {
+			action => 'query',
+			meta => 'siteinfo',
+			siprop => 'fileextensions'
+			};

-	my @file_extensions = map 
$_->{ext},@{$result->{query}->{fileextensions}};
+		my $result = $mediawiki->api($query);
+		my @file_extensions = map 
$_->{ext},@{$result->{query}->{fileextensions}};
+		my %hashFile = map {$_ => 1}@file_extensions;

-	return @file_extensions;
+		return %hashFile;
+	} else {
+		return ;
+	}
  }

  Now, the function will list the file extensions on demand.


>> @@ -642,8 +651,14 @@ sub mw_push_file {
>>  	my $old_sha1 = $diff_info_split[2];
>>  	my $page_created = ($old_sha1 eq NULL_SHA1);
>>  	my $page_deleted = ($new_sha1 eq NULL_SHA1);
>> +	my $file_deleted = ($new_sha1 eq NULL_SHA1);
>
> This line looks suspiciously similar to the previous one. Do you need
> another variable for the same value?
Yes, it's true. I just want the code to be more visible. Because, when 
we delete a file attachment, it's not a page wiki.

> Does this work on wiki configured in foreign languages, like french 
> that
> has Spécial:Téléverser instead?
>

>> +	else {
>> +		print STDERR "$complete_file_name is not supported on this 
>> version of Mediawiki.\n"
>
> It's not a matter of version, it's a matter of configuration.
What do you think if i change it like:
         else {
	print STDERR "$complete_file_name is not a permitted file type. Check 
your configuration for more information\n"

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH/RFC] Export file attachements in git-remote-mediawiki
  2012-06-05 17:00     ` nguyenki
@ 2012-06-05 17:05       ` Matthieu Moy
  2012-06-06 22:25         ` nguyenki
  0 siblings, 1 reply; 95+ messages in thread
From: Matthieu Moy @ 2012-06-05 17:05 UTC (permalink / raw)
  To: nguyenki; +Cc: git, roucherj, Pavel.Volek

nguyenki <nguyenki@ensibm.imag.fr> writes:

>>> @@ -642,8 +651,14 @@ sub mw_push_file {
>>>  	my $old_sha1 = $diff_info_split[2];
>>>  	my $page_created = ($old_sha1 eq NULL_SHA1);
>>>  	my $page_deleted = ($new_sha1 eq NULL_SHA1);
>>> +	my $file_deleted = ($new_sha1 eq NULL_SHA1);
>>
>> This line looks suspiciously similar to the previous one. Do you need
>> another variable for the same value?
> Yes, it's true. I just want the code to be more visible. Because, when
> we delete a file attachment, it's not a page wiki.

I still don't see a reason to have two variables for the same thing. If
$page_deleted is not a good name, then rename the variable to
something more general (e.g. $path_deleted ?)

>>> +	else {
>>> +		print STDERR "$complete_file_name is not supported on
>>> this version of Mediawiki.\n"
>>
>> It's not a matter of version, it's a matter of configuration.
> What do you think if i change it like:
>         else {
> 	print STDERR "$complete_file_name is not a permitted file
> type. Check your configuration for more information\n"

That's better, but it doesn't tell the user which configuration to
check (Git's one, or the wiki's one).

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH/RFC] Export file attachements in git-remote-mediawiki
  2012-06-04 21:34   ` Matthieu Moy
  2012-06-05 17:00     ` nguyenki
@ 2012-06-05 17:11     ` nguyenki
  1 sibling, 0 replies; 95+ messages in thread
From: nguyenki @ 2012-06-05 17:11 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: git

On Mon, 04 Jun 2012 23:34:29 +0200, Matthieu Moy wrote:
> NGUYEN Kim Thuat <kim-thuat.nguyen@ensimag.imag.fr> writes:
>

>> +		} else {
>> +			my $content = run_git_raw("cat-file blob $new_sha1");
>> +			mw_connect_maybe();
>> +				$mediawiki->{config}->{upload_url} = 
>> "$url/index.php/Special:Upload";
>
> Broken indentation.
>
> Does this work on wiki configured in foreign languages, like french 
> that
> has Spécial:Téléverser instead?
>

[[Special:Upload]] will work on any wiki, since the English names 
(known
internally as the "canonical" page) will work regardless of the wiki's
language.

For example, if you go to http://fr.wikipedia.org/wiki/Special:Upload, 
you'll
see that it redirects automatically.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH/RFC] Export file attachements in git-remote-mediawiki
  2012-06-05 17:05       ` Matthieu Moy
@ 2012-06-06 22:25         ` nguyenki
  0 siblings, 0 replies; 95+ messages in thread
From: nguyenki @ 2012-06-06 22:25 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: git

On Tue, 05 Jun 2012 19:05:44 +0200, Matthieu Moy wrote:
> nguyenki <nguyenki@ensibm.imag.fr> writes:
>
>>>> @@ -642,8 +651,14 @@ sub mw_push_file {
>>>>  	my $old_sha1 = $diff_info_split[2];
>>>>  	my $page_created = ($old_sha1 eq NULL_SHA1);
>>>>  	my $page_deleted = ($new_sha1 eq NULL_SHA1);
>>>> +	my $file_deleted = ($new_sha1 eq NULL_SHA1);
>>>
>>> This line looks suspiciously similar to the previous one. Do you 
>>> need
>>> another variable for the same value?
>> Yes, it's true. I just want the code to be more visible. Because, 
>> when
>> we delete a file attachment, it's not a page wiki.
>
> I still don't see a reason to have two variables for the same thing. 
> If
> $page_deleted is not a good name, then rename the variable to
> something more general (e.g. $path_deleted ?)
>

>>>> +	else {
>>>> +		print STDERR "$complete_file_name is not supported on
>>>> this version of Mediawiki.\n"
>>>
>>> It's not a matter of version, it's a matter of configuration.
>> What do you think if i change it like:
>>         else {
>> 	print STDERR "$complete_file_name is not a permitted file
>> type. Check your configuration for more information\n"
>
> That's better, but it doesn't tell the user which configuration to
> check (Git's one, or the wiki's one).
Thank for your advices, i changed the code from your suggestions, now 
it look like:
@@ -36,6 +36,7 @@
  use strict;
  use MediaWiki::API;
  use DateTime::Format::ISO8601;
+use encoding 'utf8';

  # use encoding 'utf8' doesn't change STDERROR
  # but we're going to output UTF-8 filenames to STDERR
@@ -275,7 +276,8 @@ sub run_git {
  }

  sub run_git_raw {
-        open(my $g,"-|","git " . $_[0]);
+	no encoding 'utf8';
+        open(my $g, "-|:utf8", "git " . $_[0]);
          my $r = do { local $/; <$g> };
          close($g);

@@ -648,7 +650,6 @@ sub mw_push_file {
  	my $old_sha1 = $diff_info_split[2];
  	my $page_created = ($old_sha1 eq NULL_SHA1);
  	my $page_deleted = ($new_sha1 eq NULL_SHA1);
-	my $file_deleted = ($new_sha1 eq NULL_SHA1);
  	$complete_file_name = mediawiki_clean_filename($complete_file_name);

  	my %hashFiles = get_file_extensions_maybe($complete_file_name);
@@ -700,28 +701,29 @@ sub mw_push_file {
  		print STDERR "Pushed file: $new_sha1 - $title\n";
  	} elsif (exists($hashFiles{$extension})) {
  		# Deleting and uploading a file require the priviledge of the user
-		if ($file_deleted) {
+		if ($page_deleted) {
  			mw_connect_maybe();
  			my $res = $mediawiki->edit( {
-			action => 'delete',
-			title => $path,
-			reason => $summary } )
+				action => 'delete',
+				title => $path,
+				reason => $summary } )
  			|| die $mediawiki-> {error}->{code} . ':' . 
$mediawiki->{error}->{details};

  		} else {
  			my $content = run_git_raw("cat-file blob $new_sha1");
  			mw_connect_maybe();
-				$mediawiki->{config}->{upload_url} = 
"$url/index.php/Special:Upload";
+			$mediawiki->{config}->{upload_url} = 
"$url/index.php/Special:Upload";

-				$mediawiki->upload( {
+			$mediawiki->upload( {
  				title => $complete_file_name,
  				summary => $summary,
  				data => $content,
  				ignorewarnings=>1
-                                  }, {
-					skip_encoding => 1 # Helps with names with accentuated characters
-			} ) || die $mediawiki-> {error}->{code} . ':' . 
$mediawiki->{error}->{details};
-			$newrevid = get_reviId_filepage();
+					}, {
+						skip_encoding => 1 # Helps with names with accentuated 
characters
+					} ) || die $mediawiki-> {error}->{code} . ':' . 
$mediawiki->{error}->{details};
+			my $last_file_page = $mediawiki->get_page({title =>$path});
+			$newrevid = $last_file_page->{revid};
  			print STDERR "Pushed file: $new_sha1 - $complete_file_name\n";
  			 }
  	else {
@@ -864,29 +866,6 @@ sub mw_push_revision {
  	return 1;
  }

-sub get_reviId_filepage() {
-	mw_connect_maybe();
-
-	my $max_rev_num_file = 0;
-
-	my @list_file_pages = get_mw_media_pages();
-
-	foreach my $file_page (@list_file_pages) {
-	my $id = $file_page->{pageid};
-
-	my $query = {
-		action => 'query',
-		prop => 'revisions',
-		rvprop => 'ids',
-		pageids => $id,
-		};
-
-	my $result = $mediawiki->api($query);
-
-	my $lastrev = pop(@{$result->{query}->{pages}->{$id}->{revisions}});
-	}
-}
-

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCHv1] Export file in git-remote-mediawiki
       [not found] <y>
                   ` (11 preceding siblings ...)
  2012-06-04 20:49 ` [PATCH/RFC] Export file attachements in git-remote-mediawiki NGUYEN Kim Thuat
@ 2012-06-08 13:27 ` " Kim Thuat NGUYEN
  2012-06-08 14:07   ` Matthieu Moy
  2012-06-12 12:46 ` [PATCHv2] git-remote-mediawiki: export File: attachments Kim Thuat NGUYEN
                   ` (12 subsequent siblings)
  25 siblings, 1 reply; 95+ messages in thread
From: Kim Thuat NGUYEN @ 2012-06-08 13:27 UTC (permalink / raw)
  To: git; +Cc: nguyenkimthuat, VOLEK Pavel, NGUYEN Kim Thuat, ROUCHER IGLESIAS Javier, Matthieu Moy

From: nguyenkimthuat <nguyenkimthuat@gmail.com>

This patch adds the functionnality to export the file attachements from the local git's repository using the API of mediawiki. It also provides the possibility for
an user to delete a page in the local repository Git which means the page  will be deleted in the wiki site after user do the 'push'.

Signed-off-by: VOLEK Pavel <Pavel.Volek@ensimag.imag.fr>
Signed-off-by: NGUYEN Kim Thuat <Kim-Thuat.Nguyen@ensimag.imag.fr>
Signed-off-by: ROUCHER IGLESIAS Javier <roucherj@ensimag.imag.fr>
Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
---
 contrib/mw-to-git/git-remote-mediawiki | 126 +++++++++++++++++++++++++--------
 1 file changed, 98 insertions(+), 28 deletions(-)

diff --git a/contrib/mw-to-git/git-remote-mediawiki b/contrib/mw-to-git/git-remote-mediawiki
index c18bfa1..2fd0e5b 100755
--- a/contrib/mw-to-git/git-remote-mediawiki
+++ b/contrib/mw-to-git/git-remote-mediawiki
@@ -275,6 +275,14 @@ sub run_git {
 	return $res;
 }
 
+sub run_git_raw {
+	no encoding 'utf8';
+	open(my $g,"-|","git " . $_[0]); 
+	my $r = do { local $/; <$g> };
+	close($g);
+
+	return $r;
+}
 
 sub get_last_local_revision {
 	# Get note regarding last mediawiki revision
@@ -644,6 +652,11 @@ sub mw_push_file {
 	my $page_deleted = ($new_sha1 eq NULL_SHA1);
 	$complete_file_name = mediawiki_clean_filename($complete_file_name);
 
+	my %hashFiles = get_file_extensions_maybe($complete_file_name);
+	my $path = "File:".$complete_file_name;
+	my @extensions = split(/\./, $complete_file_name);
+	my $extension = pop(@extensions);
+
 	if (substr($complete_file_name,-3) eq ".mw") {
 		my $title = substr($complete_file_name,0,-3);
 
@@ -653,39 +666,74 @@ sub mw_push_file {
 			# special priviledges. A common
 			# convention is to replace the page
 			# with this content instead:
-			$file_content = DELETED_CONTENT;
+			mw_connect_maybe();
+			my $re = $mediawiki->edit( {
+				action => 'delete',
+				title => $title,
+				reason => $summary 
+				} )|| die $mediawiki-> {error}->{code} . ':' . $mediawiki->{error}->{details};
 		} else {
 			$file_content = run_git("cat-file blob $new_sha1");
-		}
-
-		mw_connect_maybe();
 
-		my $result = $mediawiki->edit( {
-			action => 'edit',
-			summary => $summary,
-			title => $title,
-			basetimestamp => $basetimestamps{$newrevid},
-			text => mediawiki_clean($file_content, $page_created),
-				  }, {
-					  skip_encoding => 1 # Helps with names with accentuated characters
-				  });
-		if (!$result) {
-			if ($mediawiki->{error}->{code} == 3) {
-				# edit conflicts, considered as non-fast-forward
-				print STDERR 'Warning: Error ' .
-				    $mediawiki->{error}->{code} .
-				    ' from mediwiki: ' . $mediawiki->{error}->{details} .
-				    ".\n";
-				return ($newrevid, "non-fast-forward");
-			} else {
-				# Other errors. Shouldn't happen => just die()
-				die 'Fatal: Error ' .
-				    $mediawiki->{error}->{code} .
-				    ' from mediwiki: ' . $mediawiki->{error}->{details};
+			mw_connect_maybe();
+	
+			my $result = $mediawiki->edit( {
+				action => 'edit',
+				summary => $summary,
+				title => $title,
+				basetimestamp => $basetimestamps{$newrevid},
+				text => mediawiki_clean($file_content, $page_created),
+					  }, {
+						  skip_encoding => 1 # Helps with names with accentuated characters
+					  });
+			if (!$result) {
+				if ($mediawiki->{error}->{code} == 3) {
+					# edit conflicts, considered as non-fast-forward
+					print STDERR 'Warning: Error ' .
+					    $mediawiki->{error}->{code} .
+				   	 ' from mediwiki: ' . $mediawiki->{error}->{details} .".\n";
+					return ($newrevid, "non-fast-forward");
+				} else {
+					# Other errors. Shouldn't happen => just die()
+					die 'Fatal: Error ' .
+					    $mediawiki->{error}->{code} . ' from mediwiki: ' . $mediawiki->{error}->{details};
+				}
 			}
+			$newrevid = $result->{edit}->{newrevid};
+			print STDERR "Pushed file: $new_sha1 - $title\n";
+		}
+	elsif (exists($hashFiles{$extension}))      
+	{		
+		# Deleting and uploading a file require the priviledge of the user
+		if ($page_deleted) {       
+			mw_connect_maybe();
+			my $res = $mediawiki->edit( {
+				action => 'delete',
+				title => $path,
+				reason => $summary
+				} )|| die $mediawiki-> {error}->{code} . ':' . $mediawiki->{error}->{details};	
+		} else {
+			my $content = run_git_raw("cat-file blob $new_sha1");	
+			if ($content ne "") { 
+				mw_connect_maybe();	
+				$mediawiki->{config}->{upload_url} = "$url/index.php/Special:Upload";
+			
+				my $res = $mediawiki->edit ( {
+					action => 'upload',
+					filename => $complete_file_name,
+					comment => $summary,
+					file => [undef, $complete_file_name, Content => $content ],
+					ignorewarnings=>1,
+					}, {
+						  skip_encoding => 1 # Helps with names with accentuated characters
+						} ) || die $mediawiki-> {error}->{code} . ':' . $mediawiki->{error}->{details};
+				my $last_file_page = $mediawiki->get_page({title =>$path});
+				$newrevid = $last_file_page->{revid};
+				print STDERR "Pushed file: $new_sha1 - $complete_file_name\n";
+			} else {
+				print STDERR "Empty file. Can not upload \n ";
+				}
 		}
-		$newrevid = $result->{edit}->{newrevid};
-		print STDERR "Pushed file: $new_sha1 - $title\n";
 	} else {
 		print STDERR "$complete_file_name not a mediawiki file (Not pushable on this version of git-remote-mediawiki).\n"
 	}
@@ -825,3 +873,25 @@ sub mw_push_revision {
 	print STDOUT "ok $remote\n";
 	return 1;
 }
+
+sub get_file_extensions_maybe {
+	my $file_name = shift;
+	my $est_mw_page = substr($file_name,-3) eq ".mw";
+	if(!$est_mw_page) {
+		mw_connect_maybe();
+
+        	my $query = {
+			action => 'query',
+			meta => 'siteinfo',
+			siprop => 'fileextensions'
+			};
+
+		my $result = $mediawiki->api($query);
+		my @file_extensions= map $_->{ext},@{$result->{query}->{fileextensions}};
+		my %hashFile = map {$_ => 1}@file_extensions;
+
+		return %hashFile;
+	} else {
+		return ;
+	}
+}
-- 
1.7.10.2.552.gaa3bb87

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCHv1] Export file in git-remote-mediawiki
  2012-06-08 13:27 ` [PATCHv1] Export file " Kim Thuat NGUYEN
@ 2012-06-08 14:07   ` Matthieu Moy
  2012-06-08 22:59     ` nguyenki
  0 siblings, 1 reply; 95+ messages in thread
From: Matthieu Moy @ 2012-06-08 14:07 UTC (permalink / raw)
  To: Kim Thuat NGUYEN; +Cc: git, nguyenkimthuat, VOLEK Pavel, ROUCHER IGLESIAS Javier

> Subject: Re: [PATCHv1] Export file in git-remote-mediawiki

We usually write commit subject lines as "subsystem: description", hence

git-remote-mediawiki: export "File:" attachments

Kim Thuat NGUYEN <kim-thuat.nguyen@ensimag.imag.fr> writes:

> From: nguyenkimthuat <nguyenkimthuat@gmail.com>
>
> This patch adds the functionnality to export the file attachements from the local git's repository using the API of mediawiki. It also provides the possibility for
> an user to delete a page in the local repository Git which means the page  will be deleted in the wiki site after user do the 'push'.

Please, avoid long lines (> 80 characters).

> +	open(my $g,"-|","git " . $_[0]); 

Space after , please.

> +	my %hashFiles = get_file_extensions_maybe($complete_file_name);

What does this function do? My first understanding was that it queried
the wiki for allowed file extensions, but why does it need the file
name? It does nothing if $complete_file_name ends with .mw, but then why
do you run it before entering the following if() statement?

>  	if (substr($complete_file_name,-3) eq ".mw") {
>  		my $title = substr($complete_file_name,0,-3);

> @@ -653,39 +666,74 @@ sub mw_push_file {
>  			# special priviledges. A common
>  			# convention is to replace the page
>  			# with this content instead:
> -			$file_content = DELETED_CONTENT;
> +			mw_connect_maybe();
> +			my $re = $mediawiki->edit( {
> +				action => 'delete',
> +				title => $title,
> +				reason => $summary 
> +				} )|| die $mediawiki-> {error}->{code} . ':' . $mediawiki->{error}->{details};

This is an unrelated topic, and should not appear in this patch.

If you want to propagate page deletions, then you also need to deal with
the case where the user is not allowed to do so (very common on
MediaWiki). Also, if you change the code corresponding to the comment
right above, you should update the comment too.

> +	elsif (exists($hashFiles{$extension}))      
> +	{

Brace on the same line as else please.

> +			} else {
> +				print STDERR "Empty file. Can not upload \n ";
> +				}

Broken indentation.

>  	} else {
>  		print STDERR "$complete_file_name not a mediawiki file (Not pushable on this version of git-remote-mediawiki).\n"
>  	}

Isn't the very point of this patch to remove this error message?

> @@ -825,3 +873,25 @@ sub mw_push_revision {
>  	print STDOUT "ok $remote\n";
>  	return 1;
>  }
> +
> +sub get_file_extensions_maybe {
> +	my $file_name = shift;
> +	my $est_mw_page = substr($file_name,-3) eq ".mw";

English please. "est" is french ;-).

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCHv1] Export file in git-remote-mediawiki
  2012-06-08 14:07   ` Matthieu Moy
@ 2012-06-08 22:59     ` nguyenki
  2012-06-10 13:01       ` Matthieu Moy
  0 siblings, 1 reply; 95+ messages in thread
From: nguyenki @ 2012-06-08 22:59 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: git

On Fri, 08 Jun 2012 16:07:23 +0200, Matthieu Moy wrote:
>> Subject: Re: [PATCHv1] Export file in git-remote-mediawiki
>
> We usually write commit subject lines as "subsystem: description", 
> hence
>
> git-remote-mediawiki: export "File:" attachments
>
Yes, it will be corrected in the next version.

> Kim Thuat NGUYEN <kim-thuat.nguyen@ensimag.imag.fr> writes:
>
>> From: nguyenkimthuat <nguyenkimthuat@gmail.com>
>>
>> This patch adds the functionnality to export the file attachements 
>> from the local git's repository using the API of mediawiki. It also 
>> provides the possibility for
>> an user to delete a page in the local repository Git which means the 
>> page  will be deleted in the wiki site after user do the 'push'.
>
> Please, avoid long lines (> 80 characters).
>
>> +	open(my $g,"-|","git " . $_[0]);
>
> Space after , please.
>
>> +	my %hashFiles = get_file_extensions_maybe($complete_file_name);
>
> What does this function do? My first understanding was that it 
> queried
> the wiki for allowed file extensions, but why does it need the file
> name? It does nothing if $complete_file_name ends with .mw, but then 
> why
> do you run it before entering the following if() statement?
>
>>  	if (substr($complete_file_name,-3) eq ".mw") {
>>  		my $title = substr($complete_file_name,0,-3);
>
  This function will get a list of allowed file extensions. It need the 
file name to verify if this name begins with .mw or not. If not, it does 
nothing like
you said. But if $complete_file_name is not a wiki page (end with .mw), 
the function will return the list of file extensions %hashFiles to 
verify if this file is allowed in this condition:

                              } elsif (exists($hashFiles{$extension})) {


>> @@ -653,39 +666,74 @@ sub mw_push_file {
>>  			# special priviledges. A common
>>  			# convention is to replace the page
>>  			# with this content instead:
>> -			$file_content = DELETED_CONTENT;
>> +			mw_connect_maybe();
>> +			my $re = $mediawiki->edit( {
>> +				action => 'delete',
>> +				title => $title,
>> +				reason => $summary
>> +				} )|| die $mediawiki-> {error}->{code} . ':' . 
>> $mediawiki->{error}->{details};
>
> This is an unrelated topic, and should not appear in this patch.
>
> If you want to propagate page deletions, then you also need to deal 
> with
> the case where the user is not allowed to do so (very common on
> MediaWiki). Also, if you change the code corresponding to the comment
> right above, you should update the comment too.
>
>> +	elsif (exists($hashFiles{$extension}))
>> +	{
>
Yes, i'll correct it in the next patch.
For the moment, i added these lines to deal with the case similar - the 
case when an user tries to upload a file or pages but he doesn't have 
sufficient rights or he failed to login.

+sub error_insufficient_right {
+       print STDERR "Can not delete or upload file and wiki pages\n";
+       print STDERR "You don't have right to do it\n";
+       print STDOUT "error $_[0]\"right insufficient\"\n";
+       return 0;
+}
@@ -726,17 +1011,32 @@ sub mw_push_file {
                                         ignorewarnings=>1,
                                         }, {
                                                   skip_encoding => 1 # 
Helps with names with accentuated characters
-                                               } ) || die $mediawiki-> 
{error}->{code} . ':' . $mediawiki->{error}->{details};
+                                               } );
+                               if (!$res) {
+                                       if ($mediawiki->{error}->{code} 
== 3) {
+                                               # Failed to upload, 
user didn't login or he doesn't have sufficient rights
+                                               print STDERR 'Warning: 
Error ' .
+                                                   
$mediawiki->{error}->{code} .
+                                                   ' from mediwiki: ' 
. $mediawiki->{error}->{details} .
+                                                   ".\n";
+                                               return 
($newrevid,"insufficient-right");
+                                       } else {
+                                               # Other errors. 
Shouldn't happen => just die()
+                                               die 'Fatal: Error ' .
+                                                   
$mediawiki->{error}->{code} .
+                                                   ' from mediwiki: ' 
. $mediawiki->{error}->{details};
+                                       }
+                               }


@@ -860,6 +1161,9 @@ sub mw_push_revision {
                                 # accurate error message.
                                 return error_non_fast_forward($remote);
                         }
+                       if($status eq "insufficient-right") {
+                               return 
error_insufficient_right($remote);
+                       }
                         if ($status ne "ok") {
                                 die("Unknown error from 
mw_push_file()");
                         }



>
>>  	} else {
>>  		print STDERR "$complete_file_name not a mediawiki file (Not 
>> pushable on this version of git-remote-mediawiki).\n"
>>  	}
>
> Isn't the very point of this patch to remove this error message?
Now, the message is
+               print STDERR "$complete_file_name is not a permitted 
file. Check the configuration of file uploads in your mediawiki \n"
+       }


>
>> @@ -825,3 +873,25 @@ sub mw_push_revision {
>>  	print STDOUT "ok $remote\n";
>>  	return 1;
>>  }
>> +
>> +sub get_file_extensions_maybe {
>> +	my $file_name = shift;
>> +	my $est_mw_page = substr($file_name,-3) eq ".mw";
>
> English please. "est" is french ;-).
Corrected.
-       my $est_mw_page = substr($file_name,-3) eq ".mw";
-       if(!$est_mw_page) {
+       my $is_mw_page = substr($file_name,-3) eq ".mw";
+       if(!$is_mw_page) {

Thanks you so much for your advices.

Thuat.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCHv1] Export file in git-remote-mediawiki
  2012-06-08 22:59     ` nguyenki
@ 2012-06-10 13:01       ` Matthieu Moy
  0 siblings, 0 replies; 95+ messages in thread
From: Matthieu Moy @ 2012-06-10 13:01 UTC (permalink / raw)
  To: nguyenki; +Cc: git

nguyenki <nguyenki@ensibm.imag.fr> writes:

>>> +	my %hashFiles = get_file_extensions_maybe($complete_file_name);
>>
>> What does this function do? My first understanding was that it
>> queried
>> the wiki for allowed file extensions, but why does it need the file
>> name? It does nothing if $complete_file_name ends with .mw, but then
>> why
>> do you run it before entering the following if() statement?
>>
>>>  	if (substr($complete_file_name,-3) eq ".mw") {
>>>  		my $title = substr($complete_file_name,0,-3);
>>
>  This function will get a list of allowed file extensions. It need the
> file name to verify if this name begins with .mw or not. If not, it
> does nothing like
> you said. But if $complete_file_name is not a wiki page (end with
> .mw), the function will return the list of file extensions %hashFiles
> to verify if this file is allowed in this condition:

If $complete_file_name is not a wiki page, you basically don't need to
call this function. As I said, move the call to the function within the
next "if" statement, and you won't need this extra complexity.

> Yes, i'll correct it in the next patch.
> For the moment, i added these lines to deal with the case similar -
> the case when an user tries to upload a file or pages but he doesn't
> have sufficient rights or he failed to login.
>
> +sub error_insufficient_right {
> +       print STDERR "Can not delete or upload file and wiki pages\n";
> +       print STDERR "You don't have right to do it\n";
> +       print STDOUT "error $_[0]\"right insufficient\"\n";
> +       return 0;
> +}

This is still a regression. The previous version was propagating page
deletion as "replace content with [[Category:Deleted]]", which did work
with insufficient priviledge.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCHv2] git-remote-mediawiki: export File: attachments
       [not found] <y>
                   ` (12 preceding siblings ...)
  2012-06-08 13:27 ` [PATCHv1] Export file " Kim Thuat NGUYEN
@ 2012-06-12 12:46 ` Kim Thuat NGUYEN
  2012-06-12 12:52   ` Matthieu Moy
                     ` (2 more replies)
  2012-06-13  7:56 ` [PATCHv3] " kim-thuat.nguyen
                   ` (11 subsequent siblings)
  25 siblings, 3 replies; 95+ messages in thread
From: Kim Thuat NGUYEN @ 2012-06-12 12:46 UTC (permalink / raw)
  To: git; +Cc: nguyenkimthuat, VOLEK Pavel, NGUYEN Kim Thuat, ROUCHER IGLESIAS Javier, Matthieu Moy

From: nguyenkimthuat <nguyenkimthuat@gmail.com>

This patch adds the functionnality to export the 
file attachements from the local git's repository 
using the API of mediawiki.

Signed-off-by: VOLEK Pavel <Pavel.Volek@ensimag.imag.fr>
Signed-off-by: NGUYEN Kim Thuat <Kim-Thuat.Nguyen@ensimag.imag.fr>
Signed-off-by: ROUCHER IGLESIAS Javier <roucherj@ensimag.imag.fr>
Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
---
 contrib/mw-to-git/git-remote-mediawiki | 62 +++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/contrib/mw-to-git/git-remote-mediawiki b/contrib/mw-to-git/git-remote-mediawiki
index c18bfa1..8f711e2 100755
--- a/contrib/mw-to-git/git-remote-mediawiki
+++ b/contrib/mw-to-git/git-remote-mediawiki
@@ -275,6 +275,14 @@ sub run_git {
 	return $res;
 }
 
+sub run_git_raw {
+	no encoding 'utf8';
+	open(my $g, "-|", "git " . $_[0]);
+	my $r = do { local $/; <$g> };
+	close($g);
+
+	return $r;
+}
 
 sub get_last_local_revision {
 	# Get note regarding last mediawiki revision
@@ -644,6 +652,10 @@ sub mw_push_file {
 	my $page_deleted = ($new_sha1 eq NULL_SHA1);
 	$complete_file_name = mediawiki_clean_filename($complete_file_name);
 
+	my $path = "File:".$complete_file_name;
+	my @extensions = split(/\./, $complete_file_name);
+	my $extension = pop(@extensions);
+
 	if (substr($complete_file_name,-3) eq ".mw") {
 		my $title = substr($complete_file_name,0,-3);
 
@@ -687,7 +699,40 @@ sub mw_push_file {
 		$newrevid = $result->{edit}->{newrevid};
 		print STDERR "Pushed file: $new_sha1 - $title\n";
 	} else {
-		print STDERR "$complete_file_name not a mediawiki file (Not pushable on this version of git-remote-mediawiki).\n"
+		my %hashFiles = get_file_extensions();
+		if (exists($hashFiles{$extension})) {
+			# Deleting and uploading a file require the priviledge of the user
+			if ($page_deleted) {
+				mw_connect_maybe();
+				my $res = $mediawiki->edit( {
+					action => 'delete',
+					title => $path,
+					reason => $summary
+					} )|| die $mediawiki-> {error}->{code} . ':' . $mediawiki->{error}->{details};
+			} else {
+				my $content = run_git_raw("cat-file blob $new_sha1");
+				if ($content ne "") {
+					mw_connect_maybe();
+					$mediawiki->{config}->{upload_url} = "$url/index.php/Special:Upload";
+					my $res = $mediawiki->edit ( {
+						action => 'upload',
+						filename => $complete_file_name,
+						comment => $summary,
+						file => [undef, $complete_file_name, Content => $content ],
+						ignorewarnings=>1,
+						}, {
+								skip_encoding => 1 # Helps with names with accentuated characters
+							} )  || die $mediawiki-> {error}->{code} . ':' . $mediawiki->{error}->{details};
+					my $last_file_page = $mediawiki->get_page({title =>$path});
+					$newrevid = $last_file_page->{revid};
+					print STDERR "Pushed file: $new_sha1 - $complete_file_name\n";
+				} else {
+					print STDERR "Empty file. Can not upload \n ";
+				}
+			}
+		} else {
+			print STDERR "$complete_file_name not a mediawiki file (Not pushable on this version of git-remote-mediawiki).\n";
+		}
 	}
 	return ($newrevid, "ok");
 }
@@ -825,3 +870,18 @@ sub mw_push_revision {
 	print STDOUT "ok $remote\n";
 	return 1;
 }
+
+sub get_file_extensions {
+	mw_connect_maybe();
+
+	my $query = {
+		action => 'query',
+		meta => 'siteinfo',
+		siprop => 'fileextensions'
+		};
+	my $result = $mediawiki->api($query);
+	my @file_extensions= map $_->{ext},@{$result->{query}->{fileextensions}};
+	my %hashFile = map {$_ => 1}@file_extensions;
+
+	return %hashFile;
+}
-- 
1.7.10.GIT

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCHv2] git-remote-mediawiki: export File: attachments
  2012-06-12 12:46 ` [PATCHv2] git-remote-mediawiki: export File: attachments Kim Thuat NGUYEN
@ 2012-06-12 12:52   ` Matthieu Moy
  2012-06-12 12:54   ` nguyenki
  2012-06-12 13:51   ` Max Horn
  2 siblings, 0 replies; 95+ messages in thread
From: Matthieu Moy @ 2012-06-12 12:52 UTC (permalink / raw)
  To: Kim Thuat NGUYEN; +Cc: git, nguyenkimthuat, VOLEK Pavel, ROUCHER IGLESIAS Javier

Kim Thuat NGUYEN <kim-thuat.nguyen@ensimag.imag.fr> writes:

> From: nguyenkimthuat <nguyenkimthuat@gmail.com>

Please use your @ensimag email for Ensimag-related things. This adress
is the one used in the commit itself, i.e. ~/.gitconfig. "git commit
--reset-author" can help.

> @@ -644,6 +652,10 @@ sub mw_push_file {
>  	my $page_deleted = ($new_sha1 eq NULL_SHA1);
>  	$complete_file_name = mediawiki_clean_filename($complete_file_name);
>  
> +	my $path = "File:".$complete_file_name;
> +	my @extensions = split(/\./, $complete_file_name);
> +	my $extension = pop(@extensions);
> +
>  	if (substr($complete_file_name,-3) eq ".mw") {
>  		my $title = substr($complete_file_name,0,-3);

If you extract the extension explicitely, then you don't need these
"substr(...)" anymore.

> +		my %hashFiles = get_file_extensions();
> +		if (exists($hashFiles{$extension})) {
> +			# Deleting and uploading a file require the priviledge of the user
> +			if ($page_deleted) {
> +				mw_connect_maybe();
> +				my $res = $mediawiki->edit( {
> +					action => 'delete',
> +					title => $path,
> +					reason => $summary
> +					} )|| die $mediawiki-> {error}->{code} . ':' . $mediawiki->{error}->{details};

Here and below: you still have too long lines.

> +						ignorewarnings=>1,

Spaces around =>.

> +						}, {
> +								skip_encoding => 1 # Helps with names with accentuated characters
> +							} )  || die $mediawiki-> {error}->{code} . ':' . $mediawiki->{error}->{details};

Weird indentation.

> +				} else {
> +					print STDERR "Empty file. Can not upload \n ";
> +				}

No space, but a "." before \n.

> +		} else {
> +			print STDERR "$complete_file_name not a mediawiki file (Not pushable on this version of git-remote-mediawiki).\n";
> +		}

Why does this message keep reappearing?

> +sub get_file_extensions {
> +	mw_connect_maybe();
> +
> +	my $query = {
> +		action => 'query',
> +		meta => 'siteinfo',
> +		siprop => 'fileextensions'
> +		};
> +	my $result = $mediawiki->api($query);
> +	my @file_extensions= map $_->{ext},@{$result->{query}->{fileextensions}};
> +	my %hashFile = map {$_ => 1}@file_extensions;
> +
> +	return %hashFile;
> +}

I like the new function much more than the previous one.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCHv2] git-remote-mediawiki: export File: attachments
  2012-06-12 12:46 ` [PATCHv2] git-remote-mediawiki: export File: attachments Kim Thuat NGUYEN
  2012-06-12 12:52   ` Matthieu Moy
@ 2012-06-12 12:54   ` nguyenki
  2012-06-12 13:51   ` Max Horn
  2 siblings, 0 replies; 95+ messages in thread
From: nguyenki @ 2012-06-12 12:54 UTC (permalink / raw)
  To: git

On Tue, 12 Jun 2012 14:46:16 +0200, Kim Thuat NGUYEN wrote:

> +			print STDERR "$complete_file_name not a mediawiki file (Not
> pushable on this version of git-remote-mediawiki).\n";
> +		}
>  	}
>  	return ($newrevid, "ok");
>  }

I changed the comment like that, i'll be correct in the nex patch.

-			print STDERR "$complete_file_name not a mediawiki file (Not 
pushable on this version of git-remote-mediawiki).\n";
+			print STDERR "$complete_file_name is not a permitted file. Check 
the configuration of file uploads in your mediawiki \n";

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCHv2] git-remote-mediawiki: export File: attachments
  2012-06-12 12:46 ` [PATCHv2] git-remote-mediawiki: export File: attachments Kim Thuat NGUYEN
  2012-06-12 12:52   ` Matthieu Moy
  2012-06-12 12:54   ` nguyenki
@ 2012-06-12 13:51   ` Max Horn
  2 siblings, 0 replies; 95+ messages in thread
From: Max Horn @ 2012-06-12 13:51 UTC (permalink / raw)
  To: Kim Thuat NGUYEN; +Cc: git, nguyenkimthuat, VOLEK Pavel, ROUCHER IGLESIAS Javier, Matthieu Moy


Am 12.06.2012 um 14:46 schrieb Kim Thuat NGUYEN:

> From: nguyenkimthuat <nguyenkimthuat@gmail.com>
> 
> This patch adds the functionnality to export the 

Minor nitpick:
functionnality => functionality


Cheers,
Max

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCHv3] git-remote-mediawiki: export File: attachments
       [not found] <y>
                   ` (13 preceding siblings ...)
  2012-06-12 12:46 ` [PATCHv2] git-remote-mediawiki: export File: attachments Kim Thuat NGUYEN
@ 2012-06-13  7:56 ` " kim-thuat.nguyen
  2012-06-13 16:36   ` Matthieu Moy
       [not found] ` <1357885869-20815-1-git-send-email-cyliu@suse.com>
                   ` (10 subsequent siblings)
  25 siblings, 1 reply; 95+ messages in thread
From: kim-thuat.nguyen @ 2012-06-13  7:56 UTC (permalink / raw)
  To: git; +Cc: nguyenkimthuat, VOLEK Pavel, ROUCHER IGLESIAS Javier, Matthieu Moy

From: nguyenkimthuat <Kim-Thuat.Nguyen@ensimag.imag.fr>

This patch adds the functionality to export the 
file attachements from the local git's repository 
using the API of mediawiki.

Signed-off-by: VOLEK Pavel <Pavel.Volek@ensimag.imag.fr>
Signed-off-by: NGUYEN Kim Thuat <Kim-Thuat.Nguyen@ensimag.imag.fr>
Signed-off-by: ROUCHER IGLESIAS Javier <roucherj@ensimag.imag.fr>
Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
---
 contrib/mw-to-git/git-remote-mediawiki | 67 +++++++++++++++++++++++++++++++++-
 1 file changed, 65 insertions(+), 2 deletions(-)

diff --git a/contrib/mw-to-git/git-remote-mediawiki b/contrib/mw-to-git/git-remote-mediawiki
index c18bfa1..e6f8940 100755
--- a/contrib/mw-to-git/git-remote-mediawiki
+++ b/contrib/mw-to-git/git-remote-mediawiki
@@ -275,6 +275,14 @@ sub run_git {
 	return $res;
 }
 
+sub run_git_raw {
+	no encoding 'utf8';
+	open(my $g, "-|", "git " . $_[0]);
+	my $r = do { local $/; <$g> };
+	close($g);
+
+	return $r;
+}
 
 sub get_last_local_revision {
 	# Get note regarding last mediawiki revision
@@ -644,7 +652,11 @@ sub mw_push_file {
 	my $page_deleted = ($new_sha1 eq NULL_SHA1);
 	$complete_file_name = mediawiki_clean_filename($complete_file_name);
 
-	if (substr($complete_file_name,-3) eq ".mw") {
+	my $path = "File:".$complete_file_name;
+	my @extensions = split(/\./, $complete_file_name);
+	my $extension = pop(@extensions);
+
+	if ($extension eq "mw") {
 		my $title = substr($complete_file_name,0,-3);
 
 		my $file_content;
@@ -687,7 +699,43 @@ sub mw_push_file {
 		$newrevid = $result->{edit}->{newrevid};
 		print STDERR "Pushed file: $new_sha1 - $title\n";
 	} else {
-		print STDERR "$complete_file_name not a mediawiki file (Not pushable on this version of git-remote-mediawiki).\n"
+		my %hashFiles = get_file_extensions();
+		if (exists($hashFiles{$extension})) {
+			# Deleting and uploading a file require the priviledge of the user
+			if ($page_deleted) {
+				mw_connect_maybe();
+				my $res = $mediawiki->edit( {
+					action => 'delete',
+					title => $path,
+					reason => $summary
+					} )|| die $mediawiki-> {error}->{code} .
+						':' . $mediawiki->{error}->{details};
+			} else {
+				my $content = run_git_raw("cat-file blob $new_sha1");
+				if ($content ne "") {
+					mw_connect_maybe();
+					$mediawiki->{config}->{upload_url} = "$url/index.php/Special:Upload";
+
+					my $res = $mediawiki->edit ( {
+						action => 'upload',
+						filename => $complete_file_name,
+						comment => $summary,
+						file => [undef, $complete_file_name, Content => $content ],
+						ignorewarnings => 1,
+						}, {
+							skip_encoding => 1 # Helps with names with accentuated characters
+						} )  || die $mediawiki-> {error}->{code} .
+							':' . $mediawiki->{error}->{details};
+					my $last_file_page = $mediawiki->get_page({title =>$path});
+					$newrevid = $last_file_page->{revid};
+					print STDERR "Pushed file: $new_sha1 - $complete_file_name.\n";
+				} else {
+					print STDERR "Empty file. Can not upload.\n ";
+				}
+			}
+		} else {
+			print STDERR "$complete_file_name is not a permitted file. Check the configuration of file uploads in your mediawiki.\n";
+		}
 	}
 	return ($newrevid, "ok");
 }
@@ -825,3 +873,18 @@ sub mw_push_revision {
 	print STDOUT "ok $remote\n";
 	return 1;
 }
+
+sub get_file_extensions {
+	mw_connect_maybe();
+
+	my $query = {
+		action => 'query',
+		meta => 'siteinfo',
+		siprop => 'fileextensions'
+		};
+	my $result = $mediawiki->api($query);
+	my @file_extensions= map $_->{ext},@{$result->{query}->{fileextensions}};
+	my %hashFile = map {$_ => 1}@file_extensions;
+
+	return %hashFile;
+}
-- 
1.7.11.rc2.10.g9fb1faf

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCHv3] git-remote-mediawiki: export File: attachments
  2012-06-13  7:56 ` [PATCHv3] " kim-thuat.nguyen
@ 2012-06-13 16:36   ` Matthieu Moy
  0 siblings, 0 replies; 95+ messages in thread
From: Matthieu Moy @ 2012-06-13 16:36 UTC (permalink / raw)
  To: kim-thuat.nguyen; +Cc: git, VOLEK Pavel, ROUCHER IGLESIAS Javier

kim-thuat.nguyen@ensimag.imag.fr writes:

> From: nguyenkimthuat <Kim-Thuat.Nguyen@ensimag.imag.fr>

Please, use your real name, not your login name.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 95+ messages in thread

* git send-email should not allow 'y' for in-reply-to
       [not found]   ` <50EFD066.60501@redhat.com>
@ 2013-01-11 16:39     ` Eric Blake
  2013-01-11 16:47       ` Jeff King
  0 siblings, 1 reply; 95+ messages in thread
From: Eric Blake @ 2013-01-11 16:39 UTC (permalink / raw)
  To: git; +Cc: libvir-list

[-- Attachment #1: Type: text/plain, Size: 949 bytes --]

[raising this UI wart to the git list]

On 01/11/2013 01:42 AM, Peter Krempa wrote:
> On 01/11/13 07:31, Chunyan Liu wrote:
>> This patch series is to...
[snip]

> 
> Please don't answer "y" when git send email shows the following prompt:
> 
> "Message-ID to be used as In-Reply-To for the first email?"
> 
> you should respond with a message ID there. Unfortunately we have a
> growing thread that contains submissions with this mistake.

Anyone willing to patch upstream 'git send-email' to reject a simple 'y'
rather than blindly sending a bad messageID for the in-reply-to field,
to help future users avoid this mistake?  Obviously, it won't help until
the patch eventually percolates into distros, so it would be a few more
months before we see the benefits, but down the road it will prevent
confusing threads.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: git send-email should not allow 'y' for in-reply-to
  2013-01-11 16:39     ` git send-email should not allow 'y' for in-reply-to Eric Blake
@ 2013-01-11 16:47       ` Jeff King
  2013-01-11 17:51         ` Eric Blake
  2013-01-11 18:43         ` Hilco Wijbenga
  0 siblings, 2 replies; 95+ messages in thread
From: Jeff King @ 2013-01-11 16:47 UTC (permalink / raw)
  To: Eric Blake; +Cc: git, libvir-list

On Fri, Jan 11, 2013 at 09:39:06AM -0700, Eric Blake wrote:

> > Please don't answer "y" when git send email shows the following prompt:
> > 
> > "Message-ID to be used as In-Reply-To for the first email?"
> > 
> > you should respond with a message ID there. Unfortunately we have a
> > growing thread that contains submissions with this mistake.
> 
> Anyone willing to patch upstream 'git send-email' to reject a simple 'y'
> rather than blindly sending a bad messageID for the in-reply-to field,
> to help future users avoid this mistake?  Obviously, it won't help until
> the patch eventually percolates into distros, so it would be a few more
> months before we see the benefits, but down the road it will prevent
> confusing threads.

What version of git? Commit 51bbccf is in v1.7.12.1 and higher, and
says:

  $ git show 51bbccf
  commit 51bbccfd1b4a9e2807413022c56ab05c835164fb
  Author: Junio C Hamano <gitster@pobox.com>
  Date:   Tue Aug 14 15:15:53 2012 -0700

  send-email: validate & reconfirm interactive responses

  People answer 'y' to "Who should the emails appear to be from?"  and
  'n' to "Message-ID to be used as In-Reply-To for the first email?"
  for some unknown reason.  While it is possible that your local
  username really is "y" and you are sending the mail to your local
  colleagues, it is possible, and some might even say it is likely,
  that it is a user error.

  Fortunately, our interactive prompter already has input validation
  mechanism built-in.  Enhance it so that we can optionally reconfirm
  and allow the user to pass an input that does not validate, and
  "softly" require input to the sender, in-reply-to, and recipient to
  contain "@" and "." in this order, which would catch most cases of
  mistakes.

-Peff

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: git send-email should not allow 'y' for in-reply-to
  2013-01-11 16:47       ` Jeff King
@ 2013-01-11 17:51         ` Eric Blake
  2013-01-11 18:43         ` Hilco Wijbenga
  1 sibling, 0 replies; 95+ messages in thread
From: Eric Blake @ 2013-01-11 17:51 UTC (permalink / raw)
  To: Jeff King; +Cc: git, libvir-list

[-- Attachment #1: Type: text/plain, Size: 1390 bytes --]

On 01/11/2013 09:47 AM, Jeff King wrote:
> On Fri, Jan 11, 2013 at 09:39:06AM -0700, Eric Blake wrote:
> 
>>> Please don't answer "y" when git send email shows the following prompt:
>>>

>>
>> Anyone willing to patch upstream 'git send-email' to reject a simple 'y'

> What version of git? Commit 51bbccf is in v1.7.12.1 and higher, and
> says:
> 
>   $ git show 51bbccf
>   commit 51bbccfd1b4a9e2807413022c56ab05c835164fb
>   Author: Junio C Hamano <gitster@pobox.com>
>   Date:   Tue Aug 14 15:15:53 2012 -0700
> 
>   send-email: validate & reconfirm interactive responses
> 
>   People answer 'y' to "Who should the emails appear to be from?"  and
>   'n' to "Message-ID to be used as In-Reply-To for the first email?"
>   for some unknown reason.  While it is possible that your local
>   username really is "y" and you are sending the mail to your local
>   colleagues, it is possible, and some might even say it is likely,
>   that it is a user error.

Awesome!  Already implemented!  In the case that sparked this particular
email, the culprit was using 1.7.3.4; earlier this month, a separate
culprit to the same libvirt mailing list was using 1.7.11.7.

I was right about it needing to take a few months to percolate to the
actual users.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: git send-email should not allow 'y' for in-reply-to
  2013-01-11 16:47       ` Jeff King
  2013-01-11 17:51         ` Eric Blake
@ 2013-01-11 18:43         ` Hilco Wijbenga
  2013-01-11 18:54           ` Jeff King
  1 sibling, 1 reply; 95+ messages in thread
From: Hilco Wijbenga @ 2013-01-11 18:43 UTC (permalink / raw)
  To: Jeff King; +Cc: Eric Blake, git, libvir-list

On 11 January 2013 08:47, Jeff King <peff@peff.net> wrote:
> On Fri, Jan 11, 2013 at 09:39:06AM -0700, Eric Blake wrote:
>
>> > Please don't answer "y" when git send email shows the following prompt:
>> >
>> > "Message-ID to be used as In-Reply-To for the first email?"
>> >
>> > you should respond with a message ID there. Unfortunately we have a
>> > growing thread that contains submissions with this mistake.

<snip/>

>   People answer 'y' to "Who should the emails appear to be from?"  and
>   'n' to "Message-ID to be used as In-Reply-To for the first email?"
>   for some unknown reason.  While it is possible that your local
>   username really is "y" and you are sending the mail to your local
>   colleagues, it is possible, and some might even say it is likely,
>   that it is a user error.

I have never used Git's email support so this doesn't affect me one
way or another but it seems that checking the results is fixing the
symptoms, not the problem? I apologize if this was already discussed
but I couldn't find such a discussion.

I was wondering if it might be a better idea to change the wording of
the questions if they have proven so confusing? The first time (just
now) that I read "Message-ID to be used as In-Reply-To for the first
email?", it clearly seemed like a yes/no question to me. :-)

How about "What Message-ID to use as In-Reply-To for the first email?"
or "Provide the Message-ID to use as In-Reply-To for the first
email:". I'm a little surprised that "Who should the emails appear to
be from?" would be interpreted as a yes/no question but we could
rephrase that similarly as "Provide the name of the email sender:" (I
don't really like this particular version but you get the idea).

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: git send-email should not allow 'y' for in-reply-to
  2013-01-11 18:43         ` Hilco Wijbenga
@ 2013-01-11 18:54           ` Jeff King
  2013-02-24  9:03             ` Junio C Hamano
  0 siblings, 1 reply; 95+ messages in thread
From: Jeff King @ 2013-01-11 18:54 UTC (permalink / raw)
  To: Hilco Wijbenga; +Cc: Eric Blake, git, libvir-list

On Fri, Jan 11, 2013 at 10:43:39AM -0800, Hilco Wijbenga wrote:

> >   People answer 'y' to "Who should the emails appear to be from?"  and
> >   'n' to "Message-ID to be used as In-Reply-To for the first email?"
> >   for some unknown reason.  While it is possible that your local
> >   username really is "y" and you are sending the mail to your local
> >   colleagues, it is possible, and some might even say it is likely,
> >   that it is a user error.
> 
> I have never used Git's email support so this doesn't affect me one
> way or another but it seems that checking the results is fixing the
> symptoms, not the problem? I apologize if this was already discussed
> but I couldn't find such a discussion.

It depends on who you are. If you are the person running send-email,
then the symptom is your confusion. If you are somebody else, the
symptom is somebody else sending out a bogus email. That patch fixes
only the latter. :)

More seriously, I agree that re-wording the question is a reasonable
thing to do. I do not use send-email, either, so I don't have a strong
opinion on it. The suggestions you made:

> How about "What Message-ID to use as In-Reply-To for the first email?"
> or "Provide the Message-ID to use as In-Reply-To for the first
> email:".

seem fine to me. Maybe somebody who has been confused by it can offer
more. At any rate, patches welcome.

-Peff

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: git send-email should not allow 'y' for in-reply-to
  2013-01-11 18:54           ` Jeff King
@ 2013-02-24  9:03             ` Junio C Hamano
  0 siblings, 0 replies; 95+ messages in thread
From: Junio C Hamano @ 2013-02-24  9:03 UTC (permalink / raw)
  To: git; +Cc: Hilco Wijbenga, Eric Blake, libvir-list, Jeff King

Jeff King <peff@peff.net> writes:

> On Fri, Jan 11, 2013 at 10:43:39AM -0800, Hilco Wijbenga wrote:
> ...
> More seriously, I agree that re-wording the question is a reasonable
> thing to do. I do not use send-email, either, so I don't have a strong
> opinion on it. The suggestions you made:
>
>> How about "What Message-ID to use as In-Reply-To for the first email?"
>> or "Provide the Message-ID to use as In-Reply-To for the first
>> email:".
>
> seem fine to me. Maybe somebody who has been confused by it can offer
> more. At any rate, patches welcome.

Has anything come out of this discussion?  Is the current phrasing
fine as-is?

^ permalink raw reply	[flat|nested] 95+ messages in thread

* v3 [PATCH 1/2] status: introduce status.short to enable --short by default
       [not found] <y>
                   ` (16 preceding siblings ...)
  2013-06-10 15:13 ` v3 [PATCH 1/2] status: introduce status.short to enable --short by default y
@ 2013-06-10 15:13 ` y
  2014-01-29 13:33 ` [PATCH 3/3] builtin/blame.c: reduce scope of variables Elia Pinto
                   ` (7 subsequent siblings)
  25 siblings, 0 replies; 95+ messages in thread
From: y @ 2013-06-10 15:13 UTC (permalink / raw)
  To: git; +Cc: gitster, Jorge Juan Garcia Garcia, Mathieu Lienard--Mayor, Matthieu Moy

From: Jorge Juan Garcia Garcia <Jorge-Juan.Garcia-Garcia@ensimag.imag.fr>

Some people always run 'git status -s'.
The configuration variable status.short allows to set it by default.

Signed-off-by: Jorge Juan Garcia Garcia <Jorge-Juan.Garcia-Garcia@ensimag.imag.fr>
Signed-off-by: Mathieu Lienard--Mayor <Mathieu.Lienard--Mayor@ensimag.imag.fr>
Signed-off-by: Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>
---
 Changes to be commented:
- Cleaning test

 Documentation/config.txt |    4 ++++
 builtin/commit.c         |    5 +++++
 t/t7508-status.sh        |   35 +++++++++++++++++++++++++++++++++++
 3 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 6e53fc5..1983bf7 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -2066,6 +2066,10 @@ status.relativePaths::
 	relative to the repository root (this was the default for Git
 	prior to v1.5.4).
 
+status.short::
+	Set to true to enable --short by default in linkgit:git-status[1].
+	The option --no-short takes precedence over this variable.
+
 status.showUntrackedFiles::
 	By default, linkgit:git-status[1] and linkgit:git-commit[1] show
 	files which are not currently tracked by Git. Directories which
diff --git a/builtin/commit.c b/builtin/commit.c
index 1621dfc..287f1cb 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1112,6 +1112,11 @@ static int git_status_config(const char *k, const char *v, void *cb)
 			s->submodule_summary = -1;
 		return 0;
 	}
+	if (!strcmp(k, "status.short")) {
+		if (git_config_bool(k, v))
+			status_format = STATUS_FORMAT_SHORT;
+		return 0;
+	}
 	if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
 		s->use_color = git_config_colorbool(k, v);
 		return 0;
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index e2ffdac..9a07f15 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1335,4 +1335,39 @@ test_expect_failure '.git/config ignore=all suppresses submodule summary' '
 	git config -f .gitmodules  --remove-section submodule.subname
 '
 
+test_expect_success '"Setup of environment of test"' '
+	git config status.showUntrackedFiles no
+'
+
+test_expect_success '"status.short=true" same as "-s"' '
+	git -c status.short=true status >actual &&
+	git status -s >expected_short &&
+	test_cmp actual expected_short
+'
+
+test_expect_success '"status.short=true" different from "--no-short"' '
+	git status --no-short >expected_noshort &&
+	test_must_fail test_cmp actual expected_noshort
+'
+
+test_expect_success '"status.short=true" weaker than "--no-short"' '
+	git -c status.short=true status --no-short >actual &&
+	test_cmp actual expected_noshort
+'
+
+test_expect_success '"status.short=false" same as "--no-short"' '
+	git -c status.short=false status >actual &&
+	git status -s >expected_short &&
+	test_cmp actual expected_noshort
+'
+
+test_expect_success '"status.short=false" weaker than "-s"' '
+	git -c status.short=false status -s >actual &&
+	test_cmp actual expected_short
+'
+
+test_expect_success '"Back to environment of test by default"' '
+	git config status.showUntrackedFiles yes
+'
+
 test_done
-- 
1.7.8

^ permalink raw reply	[flat|nested] 95+ messages in thread

* v3 [PATCH 1/2] status: introduce status.short to enable --short by default
       [not found] <y>
                   ` (15 preceding siblings ...)
       [not found] ` <1357885869-20815-1-git-send-email-cyliu@suse.com>
@ 2013-06-10 15:13 ` y
  2013-06-10 15:13   ` v3 [PATCH 2/2] status:introduce status.branch to enable --branch " y
                     ` (2 more replies)
  2013-06-10 15:13 ` y
                   ` (8 subsequent siblings)
  25 siblings, 3 replies; 95+ messages in thread
From: y @ 2013-06-10 15:13 UTC (permalink / raw)
  To: git; +Cc: gitster, Jorge Juan Garcia Garcia, Mathieu Lienard--Mayor, Matthieu Moy

From: Jorge Juan Garcia Garcia <Jorge-Juan.Garcia-Garcia@ensimag.imag.fr>

Some people always run 'git status -s'.
The configuration variable status.short allows to set it by default.

Signed-off-by: Jorge Juan Garcia Garcia <Jorge-Juan.Garcia-Garcia@ensimag.imag.fr>
Signed-off-by: Mathieu Lienard--Mayor <Mathieu.Lienard--Mayor@ensimag.imag.fr>
Signed-off-by: Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>
---
 Changes to be commented:
- Cleaning test

 Documentation/config.txt |    4 ++++
 builtin/commit.c         |    5 +++++
 t/t7508-status.sh        |   35 +++++++++++++++++++++++++++++++++++
 3 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 6e53fc5..1983bf7 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -2066,6 +2066,10 @@ status.relativePaths::
 	relative to the repository root (this was the default for Git
 	prior to v1.5.4).
 
+status.short::
+	Set to true to enable --short by default in linkgit:git-status[1].
+	The option --no-short takes precedence over this variable.
+
 status.showUntrackedFiles::
 	By default, linkgit:git-status[1] and linkgit:git-commit[1] show
 	files which are not currently tracked by Git. Directories which
diff --git a/builtin/commit.c b/builtin/commit.c
index 1621dfc..287f1cb 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1112,6 +1112,11 @@ static int git_status_config(const char *k, const char *v, void *cb)
 			s->submodule_summary = -1;
 		return 0;
 	}
+	if (!strcmp(k, "status.short")) {
+		if (git_config_bool(k, v))
+			status_format = STATUS_FORMAT_SHORT;
+		return 0;
+	}
 	if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
 		s->use_color = git_config_colorbool(k, v);
 		return 0;
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index e2ffdac..9a07f15 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1335,4 +1335,39 @@ test_expect_failure '.git/config ignore=all suppresses submodule summary' '
 	git config -f .gitmodules  --remove-section submodule.subname
 '
 
+test_expect_success '"Setup of environment of test"' '
+	git config status.showUntrackedFiles no
+'
+
+test_expect_success '"status.short=true" same as "-s"' '
+	git -c status.short=true status >actual &&
+	git status -s >expected_short &&
+	test_cmp actual expected_short
+'
+
+test_expect_success '"status.short=true" different from "--no-short"' '
+	git status --no-short >expected_noshort &&
+	test_must_fail test_cmp actual expected_noshort
+'
+
+test_expect_success '"status.short=true" weaker than "--no-short"' '
+	git -c status.short=true status --no-short >actual &&
+	test_cmp actual expected_noshort
+'
+
+test_expect_success '"status.short=false" same as "--no-short"' '
+	git -c status.short=false status >actual &&
+	git status -s >expected_short &&
+	test_cmp actual expected_noshort
+'
+
+test_expect_success '"status.short=false" weaker than "-s"' '
+	git -c status.short=false status -s >actual &&
+	test_cmp actual expected_short
+'
+
+test_expect_success '"Back to environment of test by default"' '
+	git config status.showUntrackedFiles yes
+'
+
 test_done
-- 
1.7.8


^ permalink raw reply	[flat|nested] 95+ messages in thread

* v3 [PATCH 2/2] status:introduce status.branch to enable --branch by default
  2013-06-10 15:13 ` v3 [PATCH 1/2] status: introduce status.short to enable --short by default y
@ 2013-06-10 15:13   ` " y
  2013-06-10 15:13   ` y
  2013-06-10 15:20   ` v3 [PATCH 1/2] status: introduce status.short to enable --short " Matthieu Moy
  2 siblings, 0 replies; 95+ messages in thread
From: y @ 2013-06-10 15:13 UTC (permalink / raw)
  To: git; +Cc: gitster, Jorge Juan Garcia Garcia, Mathieu Lienard--Mayor, Matthieu Moy

From: Jorge Juan Garcia Garcia <Jorge-Juan.Garcia-Garcia@ensimag.imag.fr>

Some people often run 'git status -b'.
The config variable status.branch allows to set it by default.

Signed-off-by: Jorge Juan Garcia Garcia <Jorge-Juan.Garcia-Garcia@ensimag.imag.fr>
Signed-off-by: Mathieu Lienard--Mayor <Mathieu.Lienard--Mayor@ensimag.imag.fr>
Signed-off-by: Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>
--- 
Changes to be commented:
- Cleaning test

 Documentation/config.txt |    4 ++++
 builtin/commit.c         |    4 ++++
 t/t7508-status.sh        |   27 +++++++++++++++++++++++++++
 3 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 1983bf7..ecdcd6d 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -2070,6 +2070,10 @@ status.short::
 	Set to true to enable --short by default in linkgit:git-status[1].
 	The option --no-short takes precedence over this variable.
 
+status.branch::
+	Set to true to enable --branch by default in linkgit:git-status[1].
+	The option --no-branch takes precedence over this variable.
+
 status.showUntrackedFiles::
 	By default, linkgit:git-status[1] and linkgit:git-commit[1] show
 	files which are not currently tracked by Git. Directories which
diff --git a/builtin/commit.c b/builtin/commit.c
index 287f1cb..f2b5d44 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1117,6 +1117,10 @@ static int git_status_config(const char *k, const char *v, void *cb)
 			status_format = STATUS_FORMAT_SHORT;
 		return 0;
 	}
+	if (!strcmp(k, "status.branch")) {
+		s->show_branch = git_config_bool(k, v);
+		return 0;
+	}
 	if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
 		s->use_color = git_config_colorbool(k, v);
 		return 0;
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 9a07f15..958617a 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1366,6 +1366,33 @@ test_expect_success '"status.short=false" weaker than "-s"' '
 	test_cmp actual expected_short
 '
 
+test_expect_success '"status.branch=true" same as "-b"' '
+	git -c status.branch=true status -s >actual &&
+	git status -sb >expected_branch &&
+	test_cmp actual expected_branch
+'
+
+test_expect_success '"status.branch=true" different from "--no-branch"' '
+	git -c status.branch=true status -s >actual &&
+	git status -s --no-branch  >expected_nobranch &&
+	test_must_fail test_cmp actual expected_nobranch
+'
+
+test_expect_success '"status.branch=true" weaker than "--no-branch"' '
+	git -c status.branch=true status -s --no-branch >actual &&
+	test_cmp actual expected_nobranch
+'
+
+test_expect_success '"status.branch=false" same as "--no-branch"' '
+	git -c status.branch=false status -s >actual &&
+	test_cmp actual expected_nobranch
+'
+
+test_expect_success '"status.branch=false" weaker than "-b"' '
+	git -c status.branch=false status -sb >actual &&
+	test_cmp actual expected_branch
+'
+
 test_expect_success '"Back to environment of test by default"' '
 	git config status.showUntrackedFiles yes
 '
-- 
1.7.8

^ permalink raw reply	[flat|nested] 95+ messages in thread

* v3 [PATCH 2/2] status:introduce status.branch to enable --branch by default
  2013-06-10 15:13 ` v3 [PATCH 1/2] status: introduce status.short to enable --short by default y
  2013-06-10 15:13   ` v3 [PATCH 2/2] status:introduce status.branch to enable --branch " y
@ 2013-06-10 15:13   ` y
  2013-06-10 15:20   ` v3 [PATCH 1/2] status: introduce status.short to enable --short " Matthieu Moy
  2 siblings, 0 replies; 95+ messages in thread
From: y @ 2013-06-10 15:13 UTC (permalink / raw)
  To: git; +Cc: gitster, Jorge Juan Garcia Garcia, Mathieu Lienard--Mayor, Matthieu Moy

From: Jorge Juan Garcia Garcia <Jorge-Juan.Garcia-Garcia@ensimag.imag.fr>

Some people often run 'git status -b'.
The config variable status.branch allows to set it by default.

Signed-off-by: Jorge Juan Garcia Garcia <Jorge-Juan.Garcia-Garcia@ensimag.imag.fr>
Signed-off-by: Mathieu Lienard--Mayor <Mathieu.Lienard--Mayor@ensimag.imag.fr>
Signed-off-by: Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>
--- 
Changes to be commented:
- Cleaning test

 Documentation/config.txt |    4 ++++
 builtin/commit.c         |    4 ++++
 t/t7508-status.sh        |   27 +++++++++++++++++++++++++++
 3 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 1983bf7..ecdcd6d 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -2070,6 +2070,10 @@ status.short::
 	Set to true to enable --short by default in linkgit:git-status[1].
 	The option --no-short takes precedence over this variable.
 
+status.branch::
+	Set to true to enable --branch by default in linkgit:git-status[1].
+	The option --no-branch takes precedence over this variable.
+
 status.showUntrackedFiles::
 	By default, linkgit:git-status[1] and linkgit:git-commit[1] show
 	files which are not currently tracked by Git. Directories which
diff --git a/builtin/commit.c b/builtin/commit.c
index 287f1cb..f2b5d44 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1117,6 +1117,10 @@ static int git_status_config(const char *k, const char *v, void *cb)
 			status_format = STATUS_FORMAT_SHORT;
 		return 0;
 	}
+	if (!strcmp(k, "status.branch")) {
+		s->show_branch = git_config_bool(k, v);
+		return 0;
+	}
 	if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
 		s->use_color = git_config_colorbool(k, v);
 		return 0;
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 9a07f15..958617a 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1366,6 +1366,33 @@ test_expect_success '"status.short=false" weaker than "-s"' '
 	test_cmp actual expected_short
 '
 
+test_expect_success '"status.branch=true" same as "-b"' '
+	git -c status.branch=true status -s >actual &&
+	git status -sb >expected_branch &&
+	test_cmp actual expected_branch
+'
+
+test_expect_success '"status.branch=true" different from "--no-branch"' '
+	git -c status.branch=true status -s >actual &&
+	git status -s --no-branch  >expected_nobranch &&
+	test_must_fail test_cmp actual expected_nobranch
+'
+
+test_expect_success '"status.branch=true" weaker than "--no-branch"' '
+	git -c status.branch=true status -s --no-branch >actual &&
+	test_cmp actual expected_nobranch
+'
+
+test_expect_success '"status.branch=false" same as "--no-branch"' '
+	git -c status.branch=false status -s >actual &&
+	test_cmp actual expected_nobranch
+'
+
+test_expect_success '"status.branch=false" weaker than "-b"' '
+	git -c status.branch=false status -sb >actual &&
+	test_cmp actual expected_branch
+'
+
 test_expect_success '"Back to environment of test by default"' '
 	git config status.showUntrackedFiles yes
 '
-- 
1.7.8


^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: v3 [PATCH 1/2] status: introduce status.short to enable --short by default
  2013-06-10 15:13 ` v3 [PATCH 1/2] status: introduce status.short to enable --short by default y
  2013-06-10 15:13   ` v3 [PATCH 2/2] status:introduce status.branch to enable --branch " y
  2013-06-10 15:13   ` y
@ 2013-06-10 15:20   ` " Matthieu Moy
  2013-06-10 18:02     ` Junio C Hamano
  2 siblings, 1 reply; 95+ messages in thread
From: Matthieu Moy @ 2013-06-10 15:20 UTC (permalink / raw)
  To: Jorge Juan Garcia Garcia; +Cc: git, gitster, Mathieu Lienard--Mayor

y@ensimag.imag.fr writes:

> To: y@ensimag.imag.fr

Common mistake, but you're not supposed to answer "y" when you're
prompted for an email ;-).

set sendemail.from to avoid this.

> +test_expect_success '"Setup of environment of test"' '

Same problem as v2.

> +test_expect_success '"Back to environment of test by default"' '
> +	git config status.showUntrackedFiles yes

Same.

Probably something went wrong during your rebase.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: v3 [PATCH 1/2] status: introduce status.short to enable --short by default
  2013-06-10 15:20   ` v3 [PATCH 1/2] status: introduce status.short to enable --short " Matthieu Moy
@ 2013-06-10 18:02     ` Junio C Hamano
  0 siblings, 0 replies; 95+ messages in thread
From: Junio C Hamano @ 2013-06-10 18:02 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Jorge Juan Garcia Garcia, git, Mathieu Lienard--Mayor

Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:

> y@ensimag.imag.fr writes:
>
>> To: y@ensimag.imag.fr
>
> Common mistake, but you're not supposed to answer "y" when you're
> prompted for an email ;-).

Didn't we introduce safety against this in v1.7.12.1 and later?  Is
the new release taking more than 9 months to percolate, or are there
still other codepaths that allow this to happen that we need to add
further safety?

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH 3/3] builtin/blame.c: reduce scope of variables
       [not found] <y>
                   ` (17 preceding siblings ...)
  2013-06-10 15:13 ` y
@ 2014-01-29 13:33 ` Elia Pinto
  2014-03-05 19:29 ` [PATCH] use strchrnul() in place of strchr() and strlen() Rohit Mani
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 95+ messages in thread
From: Elia Pinto @ 2014-01-29 13:33 UTC (permalink / raw)
  To: git; +Cc: Elia Pinto

Signed-off-by: Elia Pinto <gitter.spiros@gmail.com>
---
 builtin/blame.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/builtin/blame.c b/builtin/blame.c
index e44a6bb..967a7c6 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1580,14 +1580,14 @@ static const char *format_time(unsigned long time, const char *tz_str,
 			       int show_raw_time)
 {
 	static char time_buf[128];
-	const char *time_str;
-	int time_len;
-	int tz;
 
 	if (show_raw_time) {
 		snprintf(time_buf, sizeof(time_buf), "%lu %s", time, tz_str);
 	}
 	else {
+		const char *time_str;
+		int time_len;
+		int tz;
 		tz = atoi(tz_str);
 		time_str = show_date(time, tz, blame_date_mode);
 		time_len = strlen(time_str);
-- 
1.7.10.4

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH] use strchrnul() in place of strchr() and strlen()
       [not found] <y>
                   ` (18 preceding siblings ...)
  2014-01-29 13:33 ` [PATCH 3/3] builtin/blame.c: reduce scope of variables Elia Pinto
@ 2014-03-05 19:29 ` Rohit Mani
  2014-03-06 20:54   ` Junio C Hamano
  2014-03-08  6:48 ` [GSoC][PATCH v2] " Rohit Mani
                   ` (5 subsequent siblings)
  25 siblings, 1 reply; 95+ messages in thread
From: Rohit Mani @ 2014-03-05 19:29 UTC (permalink / raw)
  To: git; +Cc: Rohit Mani

Avoid scanning strings twice, once with strchr() and then with
strlen(), by using strchrnul(). Update the conditional expressions
involving the return value of strchrnul() with a check for '\0'.

Signed-off-by: Rohit Mani <rohit.mani@outlook.com>
---
I plan to apply for the GSoC.

 archive.c        |    4 ++--
 cache-tree.c     |   16 +++++++---------
 diff.c           |    9 +++------
 fast-import.c    |   35 ++++++++++++++---------------------
 match-trees.c    |   11 ++++-------
 parse-options.c  |    5 +----
 pretty.c         |    5 ++---
 remote-testsvn.c |    4 ++--
 ws.c             |    7 ++-----
 9 files changed, 37 insertions(+), 59 deletions(-)

diff --git a/archive.c b/archive.c
index 346f3b2..d196215 100644
--- a/archive.c
+++ b/archive.c
@@ -259,8 +259,8 @@ static void parse_treeish_arg(const char **argv,
 	/* Remotes are only allowed to fetch actual refs */
 	if (remote) {
 		char *ref = NULL;
-		const char *colon = strchr(name, ':');
-		int refnamelen = colon ? colon - name : strlen(name);
+		const char *colon = strchrnul(name, ':');
+		int refnamelen = colon - name;
 
 		if (!dwim_ref(name, refnamelen, sha1, &ref))
 			die("no such ref: %.*s", refnamelen, name);
diff --git a/cache-tree.c b/cache-tree.c
index 0bbec43..21a13cf 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -121,11 +121,11 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
 
 	if (!it)
 		return;
-	slash = strchr(path, '/');
+	slash = strchrnul(path, '/');
 	it->entry_count = -1;
-	if (!slash) {
+	if (*slash == '\0') {
 		int pos;
-		namelen = strlen(path);
+		namelen = slash - path;
 		pos = subtree_pos(it, path, namelen);
 		if (0 <= pos) {
 			cache_tree_free(&it->down[pos]->cache_tree);
@@ -554,9 +554,7 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
 		const char *slash;
 		struct cache_tree_sub *sub;
 
-		slash = strchr(path, '/');
-		if (!slash)
-			slash = path + strlen(path);
+		slash = strchrnul(path, '/');
 		/* between path and slash is the name of the
 		 * subtree to look for.
 		 */
@@ -564,10 +562,10 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
 		if (!sub)
 			return NULL;
 		it = sub->cache_tree;
-		if (slash)
-			while (*slash && *slash == '/')
+		if (*slash != '\0')
+			while (*slash != '\0' && *slash == '/')
 				slash++;
-		if (!slash || !*slash)
+		if (*slash == '\0' || !*slash)
 			return it; /* prefix ended with slashes */
 		path = slash;
 	}
diff --git a/diff.c b/diff.c
index e800666..83a039b 100644
--- a/diff.c
+++ b/diff.c
@@ -3365,14 +3365,11 @@ static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *va
 	if (c != '-')
 		return 0;
 	arg++;
-	eq = strchr(arg, '=');
-	if (eq)
-		len = eq - arg;
-	else
-		len = strlen(arg);
+	eq = strchrnul(arg, '=');
+	len = eq - arg;
 	if (!len || strncmp(arg, arg_long, len))
 		return 0;
-	if (eq) {
+	if (*eq != '\0') {
 		int n;
 		char *end;
 		if (!isdigit(*++eq))
diff --git a/fast-import.c b/fast-import.c
index 4fd18a3..449595d 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1485,14 +1485,12 @@ static int tree_content_set(
 	unsigned int i, n;
 	struct tree_entry *e;
 
-	slash1 = strchr(p, '/');
-	if (slash1)
-		n = slash1 - p;
-	else
-		n = strlen(p);
+	slash1 = strchrnul(p, '/');
+	n = slash1 - p;
+
 	if (!n)
 		die("Empty path component found in input");
-	if (!slash1 && !S_ISDIR(mode) && subtree)
+	if (*slash1 == '\0' && !S_ISDIR(mode) && subtree)
 		die("Non-directories cannot have subtrees");
 
 	if (!root->tree)
@@ -1501,7 +1499,7 @@ static int tree_content_set(
 	for (i = 0; i < t->entry_count; i++) {
 		e = t->entries[i];
 		if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
-			if (!slash1) {
+			if (*slash1 == '\0') {
 				if (!S_ISDIR(mode)
 						&& e->versions[1].mode == mode
 						&& !hashcmp(e->versions[1].sha1, sha1))
@@ -1552,7 +1550,7 @@ static int tree_content_set(
 	e->versions[0].mode = 0;
 	hashclr(e->versions[0].sha1);
 	t->entries[t->entry_count++] = e;
-	if (slash1) {
+	if (*slash1 != '\0') {
 		e->tree = new_tree_content(8);
 		e->versions[1].mode = S_IFDIR;
 		tree_content_set(e, slash1 + 1, sha1, mode, subtree);
@@ -1576,11 +1574,8 @@ static int tree_content_remove(
 	unsigned int i, n;
 	struct tree_entry *e;
 
-	slash1 = strchr(p, '/');
-	if (slash1)
-		n = slash1 - p;
-	else
-		n = strlen(p);
+	slash1 = strchrnul(p, '/');
+	n = slash1 - p;
 
 	if (!root->tree)
 		load_tree(root);
@@ -1594,7 +1589,7 @@ static int tree_content_remove(
 	for (i = 0; i < t->entry_count; i++) {
 		e = t->entries[i];
 		if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
-			if (slash1 && !S_ISDIR(e->versions[1].mode))
+			if (*slash1 != '\0' && !S_ISDIR(e->versions[1].mode))
 				/*
 				 * If p names a file in some subdirectory, and a
 				 * file or symlink matching the name of the
@@ -1602,7 +1597,7 @@ static int tree_content_remove(
 				 * exist and need not be deleted.
 				 */
 				return 1;
-			if (!slash1 || !S_ISDIR(e->versions[1].mode))
+			if (*slash1 == '\0' || !S_ISDIR(e->versions[1].mode))
 				goto del_entry;
 			if (!e->tree)
 				load_tree(e);
@@ -1644,11 +1639,9 @@ static int tree_content_get(
 	unsigned int i, n;
 	struct tree_entry *e;
 
-	slash1 = strchr(p, '/');
-	if (slash1)
-		n = slash1 - p;
-	else
-		n = strlen(p);
+	slash1 = strchrnul(p, '/');
+	n = slash1 - p;
+
 	if (!n && !allow_root)
 		die("Empty path component found in input");
 
@@ -1664,7 +1657,7 @@ static int tree_content_get(
 	for (i = 0; i < t->entry_count; i++) {
 		e = t->entries[i];
 		if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
-			if (!slash1)
+			if (*slash1 == '\0')
 				goto found_entry;
 			if (!S_ISDIR(e->versions[1].mode))
 				return 0;
diff --git a/match-trees.c b/match-trees.c
index 7873cde..7cca0f6 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -182,13 +182,10 @@ static int splice_tree(const unsigned char *hash1,
 	enum object_type type;
 	int status;
 
-	subpath = strchr(prefix, '/');
-	if (!subpath)
-		toplen = strlen(prefix);
-	else {
-		toplen = subpath - prefix;
+	subpath = strchrnul(prefix, '/');
+	toplen = subpath - prefix;
+	if (*subpath != '\0')
 		subpath++;
-	}
 
 	buf = read_sha1_file(hash1, &type, &sz);
 	if (!buf)
@@ -215,7 +212,7 @@ static int splice_tree(const unsigned char *hash1,
 	if (!rewrite_here)
 		die("entry %.*s not found in tree %s",
 		    toplen, prefix, sha1_to_hex(hash1));
-	if (subpath) {
+	if (*subpath != '\0') {
 		status = splice_tree(rewrite_here, subpath, hash2, subtree);
 		if (status)
 			return status;
diff --git a/parse-options.c b/parse-options.c
index 7b8d3fa..a5fa0b8 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -223,13 +223,10 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
                           const struct option *options)
 {
 	const struct option *all_opts = options;
-	const char *arg_end = strchr(arg, '=');
+	const char *arg_end = strchrnul(arg, '=');
 	const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
 	int abbrev_flags = 0, ambiguous_flags = 0;
 
-	if (!arg_end)
-		arg_end = arg + strlen(arg);
-
 	for (; options->type != OPTION_END; options++) {
 		const char *rest, *long_name = options->long_name;
 		int flags = 0, opt_flags = 0;
diff --git a/pretty.c b/pretty.c
index 87db08b..b1f60f9 100644
--- a/pretty.c
+++ b/pretty.c
@@ -549,14 +549,13 @@ static char *get_header(const struct commit *commit, const char *msg,
 	const char *line = msg;
 
 	while (line) {
-		const char *eol = strchr(line, '\n'), *next;
+		const char *eol = strchrnul(line, '\n'), *next;
 
 		if (line == eol)
 			return NULL;
-		if (!eol) {
+		if (*eol == '\0') {
 			warning("malformed commit (header is missing newline): %s",
 				sha1_to_hex(commit->object.sha1));
-			eol = line + strlen(line);
 			next = NULL;
 		} else
 			next = eol + 1;
diff --git a/remote-testsvn.c b/remote-testsvn.c
index 078f1ff..6be55cb 100644
--- a/remote-testsvn.c
+++ b/remote-testsvn.c
@@ -78,8 +78,8 @@ static int parse_rev_note(const char *msg, struct rev_note *res)
 	size_t len;
 
 	while (*msg) {
-		end = strchr(msg, '\n');
-		len = end ? end - msg : strlen(msg);
+		end = strchrnul(msg, '\n');
+		len = end - msg;
 
 		key = "Revision-number: ";
 		if (starts_with(msg, key)) {
diff --git a/ws.c b/ws.c
index b498d75..ea4b2b1 100644
--- a/ws.c
+++ b/ws.c
@@ -33,11 +33,8 @@ unsigned parse_whitespace_rule(const char *string)
 		int negated = 0;
 
 		string = string + strspn(string, ", \t\n\r");
-		ep = strchr(string, ',');
-		if (!ep)
-			len = strlen(string);
-		else
-			len = ep - string;
+		ep = strchrnul(string, ',');
+		len = ep - string;
 
 		if (*string == '-') {
 			negated = 1;
-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH] use strchrnul() in place of strchr() and strlen()
  2014-03-05 19:29 ` [PATCH] use strchrnul() in place of strchr() and strlen() Rohit Mani
@ 2014-03-06 20:54   ` Junio C Hamano
  0 siblings, 0 replies; 95+ messages in thread
From: Junio C Hamano @ 2014-03-06 20:54 UTC (permalink / raw)
  To: Rohit Mani; +Cc: git

Rohit Mani <rohit.mani@outlook.com> writes:

> Avoid scanning strings twice, once with strchr() and then with
> strlen(), by using strchrnul(). Update the conditional expressions
> involving the return value of strchrnul() with a check for '\0'.
>
> Signed-off-by: Rohit Mani <rohit.mani@outlook.com>
> ---

Nicely done.  I am not sure if you need to say the "update the
conditional...", which is a logical consequence of such a conversion
and goes without saying, though.

>  cache-tree.c     |   16 +++++++---------

This part may overlap with other topics in flight, but I expect the
conflict resolution would be trivial.

> diff --git a/cache-tree.c b/cache-tree.c
> index 0bbec43..21a13cf 100644
> --- a/cache-tree.c
> +++ b/cache-tree.c
> @@ -121,11 +121,11 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
>  
>  	if (!it)
>  		return;
> -	slash = strchr(path, '/');
> +	slash = strchrnul(path, '/');
>  	it->entry_count = -1;
> -	if (!slash) {
> +	if (*slash == '\0') {

Let's just say

	if (!*slash)

instead; it is more idiomatic (I won't repeat this for other hunks).

>  		int pos;
> -		namelen = strlen(path);
> +		namelen = slash - path;

After this "if (!*slash)", we compute "namelen = slash-path".
Perhaps we can lose this assignment and the other one by hoisting it
up before "if (!*slash)"?

> @@ -564,10 +562,10 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
> +		if (*slash == '\0' || !*slash)

Huh?  "The byte pointed at by 'slash' is NUL, or it is NUL"???

Other than that, looks good to me.

Thanks.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [GSoC][PATCH v2] use strchrnul() in place of strchr() and strlen()
       [not found] <y>
                   ` (19 preceding siblings ...)
  2014-03-05 19:29 ` [PATCH] use strchrnul() in place of strchr() and strlen() Rohit Mani
@ 2014-03-08  6:48 ` " Rohit Mani
  2014-03-10 15:36   ` Junio C Hamano
  2014-03-10 19:04 ` [PATCH][GSOC2014] TamerTas
                   ` (4 subsequent siblings)
  25 siblings, 1 reply; 95+ messages in thread
From: Rohit Mani @ 2014-03-08  6:48 UTC (permalink / raw)
  To: git; +Cc: Rohit Mani

Avoid scanning strings twice, once with strchr() and then with
strlen(), by using strchrnul().

Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Rohit Mani <rohit.mani@outlook.com>
---
PATCH v2 Updated commit description
	Updated code according to suggestions [1]
[1]	http://article.gmane.org/gmane.comp.version-control.git/243550
	
 archive.c        |    4 ++--
 cache-tree.c     |   15 ++++++---------
 diff.c           |    9 +++------
 fast-import.c    |   35 +++++++++++++----------------------
 match-trees.c    |   11 ++++-------
 parse-options.c  |    5 +----
 pretty.c         |    5 ++---
 remote-testsvn.c |    4 ++--
 ws.c             |    7 ++-----
 9 files changed, 35 insertions(+), 60 deletions(-)

diff --git a/archive.c b/archive.c
index 346f3b2..d196215 100644
--- a/archive.c
+++ b/archive.c
@@ -259,8 +259,8 @@ static void parse_treeish_arg(const char **argv,
 	/* Remotes are only allowed to fetch actual refs */
 	if (remote) {
 		char *ref = NULL;
-		const char *colon = strchr(name, ':');
-		int refnamelen = colon ? colon - name : strlen(name);
+		const char *colon = strchrnul(name, ':');
+		int refnamelen = colon - name;
 
 		if (!dwim_ref(name, refnamelen, sha1, &ref))
 			die("no such ref: %.*s", refnamelen, name);
diff --git a/cache-tree.c b/cache-tree.c
index 0bbec43..2130f32 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -121,11 +121,11 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
 
 	if (!it)
 		return;
-	slash = strchr(path, '/');
+	slash = strchrnul(path, '/');
+	namelen = slash - path;
 	it->entry_count = -1;
-	if (!slash) {
+	if (!*slash) {
 		int pos;
-		namelen = strlen(path);
 		pos = subtree_pos(it, path, namelen);
 		if (0 <= pos) {
 			cache_tree_free(&it->down[pos]->cache_tree);
@@ -143,7 +143,6 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
 		}
 		return;
 	}
-	namelen = slash - path;
 	down = find_subtree(it, path, namelen, 0);
 	if (down)
 		cache_tree_invalidate_path(down->cache_tree, slash + 1);
@@ -554,9 +553,7 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
 		const char *slash;
 		struct cache_tree_sub *sub;
 
-		slash = strchr(path, '/');
-		if (!slash)
-			slash = path + strlen(path);
+		slash = strchrnul(path, '/');
 		/* between path and slash is the name of the
 		 * subtree to look for.
 		 */
@@ -564,10 +561,10 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
 		if (!sub)
 			return NULL;
 		it = sub->cache_tree;
-		if (slash)
+		if (*slash)
 			while (*slash && *slash == '/')
 				slash++;
-		if (!slash || !*slash)
+		if (!*slash)
 			return it; /* prefix ended with slashes */
 		path = slash;
 	}
diff --git a/diff.c b/diff.c
index e800666..cb6b98b 100644
--- a/diff.c
+++ b/diff.c
@@ -3365,14 +3365,11 @@ static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *va
 	if (c != '-')
 		return 0;
 	arg++;
-	eq = strchr(arg, '=');
-	if (eq)
-		len = eq - arg;
-	else
-		len = strlen(arg);
+	eq = strchrnul(arg, '=');
+	len = eq - arg;
 	if (!len || strncmp(arg, arg_long, len))
 		return 0;
-	if (eq) {
+	if (*eq) {
 		int n;
 		char *end;
 		if (!isdigit(*++eq))
diff --git a/fast-import.c b/fast-import.c
index 4fd18a3..dbbf6b0 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1485,14 +1485,11 @@ static int tree_content_set(
 	unsigned int i, n;
 	struct tree_entry *e;
 
-	slash1 = strchr(p, '/');
-	if (slash1)
-		n = slash1 - p;
-	else
-		n = strlen(p);
+	slash1 = strchrnul(p, '/');
+	n = slash1 - p;
 	if (!n)
 		die("Empty path component found in input");
-	if (!slash1 && !S_ISDIR(mode) && subtree)
+	if (!*slash1 && !S_ISDIR(mode) && subtree)
 		die("Non-directories cannot have subtrees");
 
 	if (!root->tree)
@@ -1501,7 +1498,7 @@ static int tree_content_set(
 	for (i = 0; i < t->entry_count; i++) {
 		e = t->entries[i];
 		if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
-			if (!slash1) {
+			if (!*slash1) {
 				if (!S_ISDIR(mode)
 						&& e->versions[1].mode == mode
 						&& !hashcmp(e->versions[1].sha1, sha1))
@@ -1552,7 +1549,7 @@ static int tree_content_set(
 	e->versions[0].mode = 0;
 	hashclr(e->versions[0].sha1);
 	t->entries[t->entry_count++] = e;
-	if (slash1) {
+	if (*slash1) {
 		e->tree = new_tree_content(8);
 		e->versions[1].mode = S_IFDIR;
 		tree_content_set(e, slash1 + 1, sha1, mode, subtree);
@@ -1576,12 +1573,9 @@ static int tree_content_remove(
 	unsigned int i, n;
 	struct tree_entry *e;
 
-	slash1 = strchr(p, '/');
-	if (slash1)
-		n = slash1 - p;
-	else
-		n = strlen(p);
-
+	slash1 = strchrnul(p, '/');
+	n = slash1 - p;
+	
 	if (!root->tree)
 		load_tree(root);
 
@@ -1594,7 +1588,7 @@ static int tree_content_remove(
 	for (i = 0; i < t->entry_count; i++) {
 		e = t->entries[i];
 		if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
-			if (slash1 && !S_ISDIR(e->versions[1].mode))
+			if (*slash1 && !S_ISDIR(e->versions[1].mode))
 				/*
 				 * If p names a file in some subdirectory, and a
 				 * file or symlink matching the name of the
@@ -1602,7 +1596,7 @@ static int tree_content_remove(
 				 * exist and need not be deleted.
 				 */
 				return 1;
-			if (!slash1 || !S_ISDIR(e->versions[1].mode))
+			if (!*slash1 || !S_ISDIR(e->versions[1].mode))
 				goto del_entry;
 			if (!e->tree)
 				load_tree(e);
@@ -1644,11 +1638,8 @@ static int tree_content_get(
 	unsigned int i, n;
 	struct tree_entry *e;
 
-	slash1 = strchr(p, '/');
-	if (slash1)
-		n = slash1 - p;
-	else
-		n = strlen(p);
+	slash1 = strchrnul(p, '/');
+	n = slash1 - p;
 	if (!n && !allow_root)
 		die("Empty path component found in input");
 
@@ -1664,7 +1655,7 @@ static int tree_content_get(
 	for (i = 0; i < t->entry_count; i++) {
 		e = t->entries[i];
 		if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
-			if (!slash1)
+			if (!*slash1)
 				goto found_entry;
 			if (!S_ISDIR(e->versions[1].mode))
 				return 0;
diff --git a/match-trees.c b/match-trees.c
index 7873cde..e80b4af 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -182,13 +182,10 @@ static int splice_tree(const unsigned char *hash1,
 	enum object_type type;
 	int status;
 
-	subpath = strchr(prefix, '/');
-	if (!subpath)
-		toplen = strlen(prefix);
-	else {
-		toplen = subpath - prefix;
+	subpath = strchrnul(prefix, '/');
+	toplen = subpath - prefix;
+	if (*subpath)
 		subpath++;
-	}
 
 	buf = read_sha1_file(hash1, &type, &sz);
 	if (!buf)
@@ -215,7 +212,7 @@ static int splice_tree(const unsigned char *hash1,
 	if (!rewrite_here)
 		die("entry %.*s not found in tree %s",
 		    toplen, prefix, sha1_to_hex(hash1));
-	if (subpath) {
+	if (*subpath) {
 		status = splice_tree(rewrite_here, subpath, hash2, subtree);
 		if (status)
 			return status;
diff --git a/parse-options.c b/parse-options.c
index 7b8d3fa..a5fa0b8 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -223,13 +223,10 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
                           const struct option *options)
 {
 	const struct option *all_opts = options;
-	const char *arg_end = strchr(arg, '=');
+	const char *arg_end = strchrnul(arg, '=');
 	const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
 	int abbrev_flags = 0, ambiguous_flags = 0;
 
-	if (!arg_end)
-		arg_end = arg + strlen(arg);
-
 	for (; options->type != OPTION_END; options++) {
 		const char *rest, *long_name = options->long_name;
 		int flags = 0, opt_flags = 0;
diff --git a/pretty.c b/pretty.c
index 87db08b..99ba8ae 100644
--- a/pretty.c
+++ b/pretty.c
@@ -549,14 +549,13 @@ static char *get_header(const struct commit *commit, const char *msg,
 	const char *line = msg;
 
 	while (line) {
-		const char *eol = strchr(line, '\n'), *next;
+		const char *eol = strchrnul(line, '\n'), *next;
 
 		if (line == eol)
 			return NULL;
-		if (!eol) {
+		if (!*eol) {
 			warning("malformed commit (header is missing newline): %s",
 				sha1_to_hex(commit->object.sha1));
-			eol = line + strlen(line);
 			next = NULL;
 		} else
 			next = eol + 1;
diff --git a/remote-testsvn.c b/remote-testsvn.c
index 078f1ff..6be55cb 100644
--- a/remote-testsvn.c
+++ b/remote-testsvn.c
@@ -78,8 +78,8 @@ static int parse_rev_note(const char *msg, struct rev_note *res)
 	size_t len;
 
 	while (*msg) {
-		end = strchr(msg, '\n');
-		len = end ? end - msg : strlen(msg);
+		end = strchrnul(msg, '\n');
+		len = end - msg;
 
 		key = "Revision-number: ";
 		if (starts_with(msg, key)) {
diff --git a/ws.c b/ws.c
index b498d75..ea4b2b1 100644
--- a/ws.c
+++ b/ws.c
@@ -33,11 +33,8 @@ unsigned parse_whitespace_rule(const char *string)
 		int negated = 0;
 
 		string = string + strspn(string, ", \t\n\r");
-		ep = strchr(string, ',');
-		if (!ep)
-			len = strlen(string);
-		else
-			len = ep - string;
+		ep = strchrnul(string, ',');
+		len = ep - string;
 
 		if (*string == '-') {
 			negated = 1;
-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [GSoC][PATCH v2] use strchrnul() in place of strchr() and strlen()
  2014-03-08  6:48 ` [GSoC][PATCH v2] " Rohit Mani
@ 2014-03-10 15:36   ` Junio C Hamano
  0 siblings, 0 replies; 95+ messages in thread
From: Junio C Hamano @ 2014-03-10 15:36 UTC (permalink / raw)
  To: Rohit Mani; +Cc: git

Rohit Mani <rohit.mani@outlook.com> writes:

> Avoid scanning strings twice, once with strchr() and then with
> strlen(), by using strchrnul().

Thanks. The patch looks good.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH][GSOC2014]
       [not found] <y>
                   ` (20 preceding siblings ...)
  2014-03-08  6:48 ` [GSoC][PATCH v2] " Rohit Mani
@ 2014-03-10 19:04 ` TamerTas
       [not found] ` <1394478262-17911-1-git-send-email-tamertas@outlook.com>
                   ` (3 subsequent siblings)
  25 siblings, 0 replies; 95+ messages in thread
From: TamerTas @ 2014-03-10 19:04 UTC (permalink / raw)
  To: git; +Cc: TamerTas

I inspected branch.c:install_branch_config() and since
the conditionals cover all the possibilities, I decided
that making the code table-driven would be much cleaner
and shorter. I've ran the tests and they all passed. 
Reimplementation using "git am" also didn't have any problems.
Please let me know if there is any problems that I missed.
I would also love to learn if you think that the code was better
before and why it was better.

TamerTas (1):
  changed logical chain in branch.c to lookup tables

 branch.c |   31 ++++++++-----------------------
 1 file changed, 8 insertions(+), 23 deletions(-)

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH][GSOC2014] changed logical chain in branch.c to lookup tables
       [not found] ` <1394478262-17911-1-git-send-email-tamertas@outlook.com>
@ 2014-03-10 19:04   ` TamerTas
  2014-03-10 21:05     ` Stefan Beller
  2014-03-10 21:25     ` Eric Sunshine
  0 siblings, 2 replies; 95+ messages in thread
From: TamerTas @ 2014-03-10 19:04 UTC (permalink / raw)
  To: git; +Cc: TamerTas


Signed-off-by: TamerTas <tamertas@outlook.com>
---
 branch.c |   31 ++++++++-----------------------
 1 file changed, 8 insertions(+), 23 deletions(-)

diff --git a/branch.c b/branch.c
index 723a36b..397edd3 100644
--- a/branch.c
+++ b/branch.c
@@ -50,6 +50,9 @@ static int should_setup_rebase(const char *origin)
 void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
 {
 	const char *shortname = remote + 11;
+	const char *location[] = {"local", "remote"};
+	const char *type[] = {"branch", "ref"};
+
 	int remote_is_branch = starts_with(remote, "refs/heads/");
 	struct strbuf key = STRBUF_INIT;
 	int rebasing = should_setup_rebase(origin);
@@ -77,29 +80,11 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
 	strbuf_release(&key);
 
 	if (flag & BRANCH_CONFIG_VERBOSE) {
-		if (remote_is_branch && origin)
-			printf_ln(rebasing ?
-				  _("Branch %s set up to track remote branch %s from %s by rebasing.") :
-				  _("Branch %s set up to track remote branch %s from %s."),
-				  local, shortname, origin);
-		else if (remote_is_branch && !origin)
-			printf_ln(rebasing ?
-				  _("Branch %s set up to track local branch %s by rebasing.") :
-				  _("Branch %s set up to track local branch %s."),
-				  local, shortname);
-		else if (!remote_is_branch && origin)
-			printf_ln(rebasing ?
-				  _("Branch %s set up to track remote ref %s by rebasing.") :
-				  _("Branch %s set up to track remote ref %s."),
-				  local, remote);
-		else if (!remote_is_branch && !origin)
-			printf_ln(rebasing ?
-				  _("Branch %s set up to track local ref %s by rebasing.") :
-				  _("Branch %s set up to track local ref %s."),
-				  local, remote);
-		else
-			die("BUG: impossible combination of %d and %p",
-			    remote_is_branch, origin);
+        
+        printf_ln(rebasing ?
+              _("Branch %s set up to track %s %s %s by rebasing.") :
+              _("Branch %s set up to track %s %s %s."),
+              local, location[!origin], type[remote_is_branch], remote);
 	}
 }
 
-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH][GSOC2014] changed logical chain in branch.c to lookup tables
  2014-03-10 19:04   ` [PATCH][GSOC2014] changed logical chain in branch.c to lookup tables TamerTas
@ 2014-03-10 21:05     ` Stefan Beller
  2014-03-10 21:25     ` Eric Sunshine
  1 sibling, 0 replies; 95+ messages in thread
From: Stefan Beller @ 2014-03-10 21:05 UTC (permalink / raw)
  To: TamerTas, git

On 10.03.2014 20:04, TamerTas wrote:
> 
> Signed-off-by: TamerTas <tamertas@outlook.com>
> ---
>  branch.c |   31 ++++++++-----------------------
>  1 file changed, 8 insertions(+), 23 deletions(-)
> 
> diff --git a/branch.c b/branch.c
> index 723a36b..397edd3 100644
> --- a/branch.c
> +++ b/branch.c
> @@ -50,6 +50,9 @@ static int should_setup_rebase(const char *origin)
>  void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
>  {
>  	const char *shortname = remote + 11;
> +	const char *location[] = {"local", "remote"};
> +	const char *type[] = {"branch", "ref"};
> +
>  	int remote_is_branch = starts_with(remote, "refs/heads/");
>  	struct strbuf key = STRBUF_INIT;
>  	int rebasing = should_setup_rebase(origin);
> @@ -77,29 +80,11 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
>  	strbuf_release(&key);
>  
>  	if (flag & BRANCH_CONFIG_VERBOSE) {
> -		if (remote_is_branch && origin)
> -			printf_ln(rebasing ?
> -				  _("Branch %s set up to track remote branch %s from %s by rebasing.") :
> -				  _("Branch %s set up to track remote branch %s from %s."),
> -				  local, shortname, origin);
> -		else if (remote_is_branch && !origin)
> -			printf_ln(rebasing ?
> -				  _("Branch %s set up to track local branch %s by rebasing.") :
> -				  _("Branch %s set up to track local branch %s."),
> -				  local, shortname);
> -		else if (!remote_is_branch && origin)
> -			printf_ln(rebasing ?
> -				  _("Branch %s set up to track remote ref %s by rebasing.") :
> -				  _("Branch %s set up to track remote ref %s."),
> -				  local, remote);
> -		else if (!remote_is_branch && !origin)
> -			printf_ln(rebasing ?
> -				  _("Branch %s set up to track local ref %s by rebasing.") :
> -				  _("Branch %s set up to track local ref %s."),
> -				  local, remote);
> -		else
> -			die("BUG: impossible combination of %d and %p",
> -			    remote_is_branch, origin);
> +        
> +        printf_ln(rebasing ?
> +              _("Branch %s set up to track %s %s %s by rebasing.") :
> +              _("Branch %s set up to track %s %s %s."),
> +              local, location[!origin], type[remote_is_branch], remote);
>  	}
>  }
>  
> 

This one is neat, I'd favor this one as opposed to the one posted
earlier today.

Acked-by: Stefan Beller <stefanbeller@googlemail.com>

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH][GSOC2014] changed logical chain in branch.c to lookup tables
  2014-03-10 19:04   ` [PATCH][GSOC2014] changed logical chain in branch.c to lookup tables TamerTas
  2014-03-10 21:05     ` Stefan Beller
@ 2014-03-10 21:25     ` Eric Sunshine
  2014-03-10 21:47       ` Tamer TAS
  1 sibling, 1 reply; 95+ messages in thread
From: Eric Sunshine @ 2014-03-10 21:25 UTC (permalink / raw)
  To: TamerTas; +Cc: Git List

On Mon, Mar 10, 2014 at 3:04 PM, TamerTas <tamertas@outlook.com> wrote:
> Signed-off-by: TamerTas <tamertas@outlook.com>

Thanks for the submission. It appears to be well executed. Read below
for a concern about the approach taken.

> ---
>  branch.c |   31 ++++++++-----------------------
>  1 file changed, 8 insertions(+), 23 deletions(-)
>
> diff --git a/branch.c b/branch.c
> index 723a36b..397edd3 100644
> --- a/branch.c
> +++ b/branch.c
> @@ -50,6 +50,9 @@ static int should_setup_rebase(const char *origin)
>  void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
>  {
>         const char *shortname = remote + 11;
> +       const char *location[] = {"local", "remote"};
> +       const char *type[] = {"branch", "ref"};
> +
>         int remote_is_branch = starts_with(remote, "refs/heads/");
>         struct strbuf key = STRBUF_INIT;
>         int rebasing = should_setup_rebase(origin);
> @@ -77,29 +80,11 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
>         strbuf_release(&key);
>
>         if (flag & BRANCH_CONFIG_VERBOSE) {
> -               if (remote_is_branch && origin)
> -                       printf_ln(rebasing ?
> -                                 _("Branch %s set up to track remote branch %s from %s by rebasing.") :
> -                                 _("Branch %s set up to track remote branch %s from %s."),
> -                                 local, shortname, origin);
> -               else if (remote_is_branch && !origin)
> -                       printf_ln(rebasing ?
> -                                 _("Branch %s set up to track local branch %s by rebasing.") :
> -                                 _("Branch %s set up to track local branch %s."),
> -                                 local, shortname);
> -               else if (!remote_is_branch && origin)
> -                       printf_ln(rebasing ?
> -                                 _("Branch %s set up to track remote ref %s by rebasing.") :
> -                                 _("Branch %s set up to track remote ref %s."),
> -                                 local, remote);
> -               else if (!remote_is_branch && !origin)
> -                       printf_ln(rebasing ?
> -                                 _("Branch %s set up to track local ref %s by rebasing.") :
> -                                 _("Branch %s set up to track local ref %s."),
> -                                 local, remote);
> -               else
> -                       die("BUG: impossible combination of %d and %p",
> -                           remote_is_branch, origin);
> +
> +        printf_ln(rebasing ?
> +              _("Branch %s set up to track %s %s %s by rebasing.") :
> +              _("Branch %s set up to track %s %s %s."),
> +              local, location[!origin], type[remote_is_branch], remote);

The GSoC microproject talks about the _() function used for
internationalization and the limitations it places on string
composition. This change assumes, probably incorrectly, that strings
"local", "remote", "branch" and "ref" do not need to be localized.
Even allowing internationalization of them (via N_() in the location[]
and type[] tables) might not be sufficient since grammatical rules
differ from language to language.

>         }
>  }
>
> --
> 1.7.9.5

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH][GSOC2014] changed logical chain in branch.c to lookup tables
  2014-03-10 21:25     ` Eric Sunshine
@ 2014-03-10 21:47       ` Tamer TAS
  2014-03-10 22:39         ` Eric Sunshine
  0 siblings, 1 reply; 95+ messages in thread
From: Tamer TAS @ 2014-03-10 21:47 UTC (permalink / raw)
  To: git

Eric Sunshine wrote
> Even allowing internationalization of them (via N_() in the location[]
> and type[] tables) might not be sufficient since grammatical rules
> differ from language to language.

I didn't fully understand what you meant by that. Since they were being
internationalized before using _() in the if-else bodies, wouldn't it
produce
the same output if I were to use the same method for location[] and type[]
tables?




--
View this message in context: http://git.661346.n2.nabble.com/PATCH-GSOC2014-changed-logical-chain-in-branch-c-to-lookup-tables-tp7605343p7605372.html
Sent from the git mailing list archive at Nabble.com.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH][GSOC2014] changed logical chain in branch.c to lookup tables
  2014-03-10 21:47       ` Tamer TAS
@ 2014-03-10 22:39         ` Eric Sunshine
  2014-03-11 11:33           ` Tamer TAS
  0 siblings, 1 reply; 95+ messages in thread
From: Eric Sunshine @ 2014-03-10 22:39 UTC (permalink / raw)
  To: Tamer TAS; +Cc: Git List

On Mon, Mar 10, 2014 at 5:47 PM, Tamer TAS <tamertas@outlook.com> wrote:
> Eric Sunshine wrote
>> Even allowing internationalization of them (via N_() in the location[]
>> and type[] tables) might not be sufficient since grammatical rules
>> differ from language to language.
>
> I didn't fully understand what you meant by that. Since they were being
> internationalized before using _() in the if-else bodies, wouldn't it
> produce
> the same output if I were to use the same method for location[] and type[]
> tables?

In the original code, the person translating the text has the full context:

    "Branch %s set up to track remote ref %s."

With your revision, the translator has to translate standalone words
"local", "remote", "branch", "ref" without context about how they are
used. He then has to translate:

    "Branch %s set up to track %s %s %s."

without context of the words being inserted, which, depending upon
grammatical rules of the language can result in a different (and
perhaps worse) translation than the original full-context translation.

Section 4.3 of the GNU gettext manual [1] explains the issues in more
detail. I urge you to read it. The upshot is that translators fare
best when handed full sentences.

Note also that your change effectively reverts d53a35032a67 [2], which
did away with the sort of string composition used in your patch.

[1]: http://www.gnu.org/software/gettext/manual/gettext.html#Preparing-Strings
[2]: https://github.com/git/git/commit/d53a35032a67fde5b59c8a6a66e0466837cbaf1e

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH][GSOC2014] changed logical chain in branch.c to lookup tables
  2014-03-10 22:39         ` Eric Sunshine
@ 2014-03-11 11:33           ` Tamer TAS
  2014-03-11 20:32             ` Eric Sunshine
  0 siblings, 1 reply; 95+ messages in thread
From: Tamer TAS @ 2014-03-11 11:33 UTC (permalink / raw)
  To: git

Eric Sunshine wrote
> On Mon, Mar 10, 2014 at 5:47 PM, Tamer TAS &lt;

> tamertas@

> &gt; wrote:
> 
> Section 4.3 of the GNU gettext manual [1] explains the issues in more
> detail. I urge you to read it. The upshot is that translators fare
> best when handed full sentences.
> 
> Note also that your change effectively reverts d53a35032a67 [2], which
> did away with the sort of string composition used in your patch.

Eric thank you for your constructive feedbacks.
I read the section 4.3 of GNU gettext manual and also checked the commit you
mentioned.
It seems like that my previous changes were not internationalization
compatible.
In order for a table-driven change to be compatible, the sentences has to be
meaningful and not tokenized.
I made the following change to the branch.c in order for the function to be
both table-driven and
internationalization compatible. Let me know if there are any oversights on
my part.

Signed-off-by: TamerTas <tamertas@outlook.com>
---
 branch.c |   39 ++++++++++++++++-----------------------
 1 file changed, 16 insertions(+), 23 deletions(-)

diff --git a/branch.c b/branch.c
index 723a36b..4c04638 100644
--- a/branch.c
+++ b/branch.c
@@ -50,10 +50,25 @@ static int should_setup_rebase(const char *origin)
 void install_branch_config(int flag, const char *local, const char *origin,
const char *remote)
 {
 	const char *shortname = remote + 11;
+    const char *setup_messages[] = {
+		_("Branch %s set up to track remote branch %s from %s."),
+		_("Branch %s set up to track local branch %s."),
+		_("Branch %s set up to track remote ref %s."),
+		_("Branch %s set up to track local ref %s."),
+		_("Branch %s set up to track remote branch %s from %s by rebasing."),
+		_("Branch %s set up to track local branch %s by rebasing."),
+		_("Branch %s set up to track remote ref %s by rebasing."),
+		_("Branch %s set up to track local ref %s by rebasing.")
+	}; 
+
 	int remote_is_branch = starts_with(remote, "refs/heads/");
 	struct strbuf key = STRBUF_INIT;
 	int rebasing = should_setup_rebase(origin);
 
+    int msg_index = (!!origin           >> 0) +
+					(!!remote_is_branch >> 1) +
+					(!!rebasing         >> 2);
+   
 	if (remote_is_branch
 	    && !strcmp(local, shortname)
 	    && !origin) {
@@ -77,29 +92,7 @@ void install_branch_config(int flag, const char *local,
const char *origin, cons
 	strbuf_release(&key);
 
 	if (flag & BRANCH_CONFIG_VERBOSE) {
-		if (remote_is_branch && origin)
-			printf_ln(rebasing ?
-				  _("Branch %s set up to track remote branch %s from %s by rebasing.")
:
-				  _("Branch %s set up to track remote branch %s from %s."),
-				  local, shortname, origin);
-		else if (remote_is_branch && !origin)
-			printf_ln(rebasing ?
-				  _("Branch %s set up to track local branch %s by rebasing.") :
-				  _("Branch %s set up to track local branch %s."),
-				  local, shortname);
-		else if (!remote_is_branch && origin)
-			printf_ln(rebasing ?
-				  _("Branch %s set up to track remote ref %s by rebasing.") :
-				  _("Branch %s set up to track remote ref %s."),
-				  local, remote);
-		else if (!remote_is_branch && !origin)
-			printf_ln(rebasing ?
-				  _("Branch %s set up to track local ref %s by rebasing.") :
-				  _("Branch %s set up to track local ref %s."),
-				  local, remote);
-		else
-			die("BUG: impossible combination of %d and %p",
-			    remote_is_branch, origin);
+		printf_ln(setup_messages[msg_index], local, remote);
 	}
 }
 
-- 
1.7.9.5



--
View this message in context: http://git.661346.n2.nabble.com/PATCH-GSOC2014-changed-logical-chain-in-branch-c-to-lookup-tables-tp7605343p7605407.html
Sent from the git mailing list archive at Nabble.com.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH][GSOC2014] changed logical chain in branch.c to lookup tables
  2014-03-11 11:33           ` Tamer TAS
@ 2014-03-11 20:32             ` Eric Sunshine
  0 siblings, 0 replies; 95+ messages in thread
From: Eric Sunshine @ 2014-03-11 20:32 UTC (permalink / raw)
  To: Tamer TAS; +Cc: Git List

Thanks for the resubmission. Comments below.

On Tue, Mar 11, 2014 at 7:33 AM, Tamer TAS <tamertas@outlook.com> wrote:
> Subject: changed logical chain in branch.c to lookup tables

Use imperative tone: "change" rather than "changed"

Prefix the message with the part of the project you are touching. So,
for instance, you might write:

    Subject: install_branch_config: change logical chain to lookup table

> Eric Sunshine wrote
>> On Mon, Mar 10, 2014 at 5:47 PM, Tamer TAS &lt;
>
>> tamertas@
>
>> &gt; wrote:
>>
>> Section 4.3 of the GNU gettext manual [1] explains the issues in more
>> detail. I urge you to read it. The upshot is that translators fare
>> best when handed full sentences.
>>
>> Note also that your change effectively reverts d53a35032a67 [2], which
>> did away with the sort of string composition used in your patch.
>
> Eric thank you for your constructive feedbacks.
> I read the section 4.3 of GNU gettext manual and also checked the commit you
> mentioned.
> It seems like that my previous changes were not internationalization
> compatible.
> In order for a table-driven change to be compatible, the sentences has to be
> meaningful and not tokenized.
> I made the following change to the branch.c in order for the function to be
> both table-driven and
> internationalization compatible. Let me know if there are any oversights on
> my part.

This commentary is relevant to the ongoing email thread but not
suitable for the permanent commit message. Place it below the "---"
line just under your sign-off.

> Signed-off-by: TamerTas <tamertas@outlook.com>
> ---

It's considerate to reviewers to provide a link to the previous
attempt, like this [1]. This area below the "---" line is the
appropriate place to do so. Likewise, explain how this version differs
from the previous one.

[1]: http://thread.gmane.org/gmane.comp.version-control.git/243793

>  branch.c |   39 ++++++++++++++++-----------------------
>  1 file changed, 16 insertions(+), 23 deletions(-)
>
> diff --git a/branch.c b/branch.c
> index 723a36b..4c04638 100644
> --- a/branch.c
> +++ b/branch.c
> @@ -50,10 +50,25 @@ static int should_setup_rebase(const char *origin)
>  void install_branch_config(int flag, const char *local, const char *origin,
> const char *remote)

Your patch is whitespace damaged, probably due to being pasted into
your email. "git send-email" avoids such problems.

Indentation is also broken. Use tabs for indentation, and set tab
width to 8 in your editor, as explained in
Documentation/CodingGuidelines.

>  {
>         const char *shortname = remote + 11;
> +    const char *setup_messages[] = {
> +               _("Branch %s set up to track remote branch %s from %s."),
> +               _("Branch %s set up to track local branch %s."),
> +               _("Branch %s set up to track remote ref %s."),
> +               _("Branch %s set up to track local ref %s."),
> +               _("Branch %s set up to track remote branch %s from %s by rebasing."),
> +               _("Branch %s set up to track local branch %s by rebasing."),
> +               _("Branch %s set up to track remote ref %s by rebasing."),
> +               _("Branch %s set up to track local ref %s by rebasing.")
> +       };

On this project, arrays are usually (though not consistently) named in
singular form (for instance setup_message[]) so that a reference to a
single item, such as setup_message[42], reads more grammatically
correct.

It's not correct to use _() inside the initializer list. Instead use
N_(). Read section 4.7 of the GNU gettext manual [2] for an
explanation. You will still need to use _() at the point where you
extract the message from the array.

[2]: http://www.gnu.org/software/gettext/manual/gettext.html#Special-cases

>         int remote_is_branch = starts_with(remote, "refs/heads/");
>         struct strbuf key = STRBUF_INIT;
>         int rebasing = should_setup_rebase(origin);
>
> +    int msg_index = (!!origin           >> 0) +
> +                                       (!!remote_is_branch >> 1) +
> +                                       (!!rebasing         >> 2);

Are you sure this is correct? As I read it, msg_index will only ever
have a value of 0 or 1, which is unlikely what you intended.

>         if (remote_is_branch
>             && !strcmp(local, shortname)
>             && !origin) {
> @@ -77,29 +92,7 @@ void install_branch_config(int flag, const char *local,
> const char *origin, cons
>         strbuf_release(&key);
>
>         if (flag & BRANCH_CONFIG_VERBOSE) {
> -               if (remote_is_branch && origin)
> -                       printf_ln(rebasing ?
> -                                 _("Branch %s set up to track remote branch %s from %s by rebasing.")
> :
> -                                 _("Branch %s set up to track remote branch %s from %s."),
> -                                 local, shortname, origin);
> -               else if (remote_is_branch && !origin)
> -                       printf_ln(rebasing ?
> -                                 _("Branch %s set up to track local branch %s by rebasing.") :
> -                                 _("Branch %s set up to track local branch %s."),
> -                                 local, shortname);
> -               else if (!remote_is_branch && origin)
> -                       printf_ln(rebasing ?
> -                                 _("Branch %s set up to track remote ref %s by rebasing.") :
> -                                 _("Branch %s set up to track remote ref %s."),
> -                                 local, remote);
> -               else if (!remote_is_branch && !origin)
> -                       printf_ln(rebasing ?
> -                                 _("Branch %s set up to track local ref %s by rebasing.") :
> -                                 _("Branch %s set up to track local ref %s."),
> -                                 local, remote);
> -               else
> -                       die("BUG: impossible combination of %d and %p",
> -                           remote_is_branch, origin);
> +               printf_ln(setup_messages[msg_index], local, remote);

This can't be correct.

In the original code, all of the printf_ln() invocations received
'local' as the first argument, but only two of them received 'remote',
yet you are passing 'remote' on every invocation.

Worse, the first and fifths items in your setup_messages[] table
expect three arguments (they have three %s's), but you're passing only
two, which will surely lead to a crash.

Also, wrap _() around setup_messages[msg_index], as noted above.

>         }
>  }
>
> --
> 1.7.9.5

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH][GSOC2014] add: Rewrite run_add_interactive to use struct argv_array
       [not found] <y>
                   ` (22 preceding siblings ...)
       [not found] ` <1394478262-17911-1-git-send-email-tamertas@outlook.com>
@ 2014-03-18 12:31 ` Movchan Pavel
  2014-03-18 19:47   ` Junio C Hamano
  2016-06-09 17:46 ` [PATCH] Use "working tree" instead of "working directory" for git status Lars Vogel
  2017-10-11 18:03 ` [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments Takahito Ogawa
  25 siblings, 1 reply; 95+ messages in thread
From: Movchan Pavel @ 2014-03-18 12:31 UTC (permalink / raw)
  To: git; +Cc: Movchan Pavel

Origin code are code with own realisation argv array editing.
It was changed, and code modified for using unified argv-array
realisation from argv-array.h.
Commit for Google Summer of Code 2014

Signed-off-by: Movchan Pavel <movchan.pv@gmail.com>
---
 builtin/add.c |   21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/builtin/add.c b/builtin/add.c
index 4b045ba..258b491 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -15,6 +15,7 @@
 #include "diffcore.h"
 #include "revision.h"
 #include "bulk-checkin.h"
+#include "argv-array.h"
 
 static const char * const builtin_add_usage[] = {
 	N_("git add [options] [--] <pathspec>..."),
@@ -141,23 +142,21 @@ static void refresh(int verbose, const struct pathspec *pathspec)
 int run_add_interactive(const char *revision, const char *patch_mode,
 			const struct pathspec *pathspec)
 {
-	int status, ac, i;
-	const char **args;
+	int status, i;
+	struct argv_array *argv = ARGV_ARRAY_INIT;
 
-	args = xcalloc(sizeof(const char *), (pathspec->nr + 6));
-	ac = 0;
-	args[ac++] = "add--interactive";
+	argv_array_push(argv, "add--interactive");
 	if (patch_mode)
-		args[ac++] = patch_mode;
+		argv_array_push(argv, patch_mode);
 	if (revision)
-		args[ac++] = revision;
-	args[ac++] = "--";
+		argv_array_push(argv, revision);
+	argv_array_push(argv, "--");
 	for (i = 0; i < pathspec->nr; i++)
 		/* pass original pathspec, to be re-parsed */
-		args[ac++] = pathspec->items[i].original;
+		argv_array_push(argv, pathspec->items[i].original);
 
-	status = run_command_v_opt(args, RUN_GIT_CMD);
-	free(args);
+	status = run_command_v_opt(argv->argv, RUN_GIT_CMD);
+	argv_array_clear(argv);
 	return status;
 }
 
-- 
1.7.10.4

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH][GSOC2014] add: Rewrite run_add_interactive to use struct argv_array
  2014-03-18 12:31 ` [PATCH][GSOC2014] add: Rewrite run_add_interactive to use struct argv_array Movchan Pavel
@ 2014-03-18 19:47   ` Junio C Hamano
  0 siblings, 0 replies; 95+ messages in thread
From: Junio C Hamano @ 2014-03-18 19:47 UTC (permalink / raw)
  To: Movchan Pavel; +Cc: git

Movchan Pavel <movchan.pv@gmail.com> writes:

> Origin code are code with own realisation argv array editing.
> It was changed, and code modified for using unified argv-array
> realisation from argv-array.h.
> Commit for Google Summer of Code 2014
>
> Signed-off-by: Movchan Pavel <movchan.pv@gmail.com>
> ---

Thanks.  "Commit for ..." is not something we would want to see in
"git log" output, though.

>  builtin/add.c |   21 ++++++++++-----------
>  1 file changed, 10 insertions(+), 11 deletions(-)
>
> diff --git a/builtin/add.c b/builtin/add.c
> index 4b045ba..258b491 100644
> --- a/builtin/add.c
> +++ b/builtin/add.c
> @@ -15,6 +15,7 @@
>  #include "diffcore.h"
>  #include "revision.h"
>  #include "bulk-checkin.h"
> +#include "argv-array.h"
>  
>  static const char * const builtin_add_usage[] = {
>  	N_("git add [options] [--] <pathspec>..."),
> @@ -141,23 +142,21 @@ static void refresh(int verbose, const struct pathspec *pathspec)
>  int run_add_interactive(const char *revision, const char *patch_mode,
>  			const struct pathspec *pathspec)
>  {
> -	int status, ac, i;
> -	const char **args;
> +	int status, i;
> +	struct argv_array *argv = ARGV_ARRAY_INIT;

Where does that pointer point at and who allocated the piece of
memory used by it?

See http://thread.gmane.org/gmane.comp.version-control.git/244151
for an example solution.

>  
> -	args = xcalloc(sizeof(const char *), (pathspec->nr + 6));
> -	ac = 0;
> -	args[ac++] = "add--interactive";
> +	argv_array_push(argv, "add--interactive");
>  	if (patch_mode)
> -		args[ac++] = patch_mode;
> +		argv_array_push(argv, patch_mode);
>  	if (revision)
> -		args[ac++] = revision;
> -	args[ac++] = "--";
> +		argv_array_push(argv, revision);
> +	argv_array_push(argv, "--");
>  	for (i = 0; i < pathspec->nr; i++)
>  		/* pass original pathspec, to be re-parsed */
> -		args[ac++] = pathspec->items[i].original;
> +		argv_array_push(argv, pathspec->items[i].original);
>  
> -	status = run_command_v_opt(args, RUN_GIT_CMD);
> -	free(args);
> +	status = run_command_v_opt(argv->argv, RUN_GIT_CMD);
> +	argv_array_clear(argv);
>  	return status;
>  }

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH] Use "working tree" instead of "working directory" for git status
       [not found] <y>
                   ` (23 preceding siblings ...)
  2014-03-18 12:31 ` [PATCH][GSOC2014] add: Rewrite run_add_interactive to use struct argv_array Movchan Pavel
@ 2016-06-09 17:46 ` Lars Vogel
  2016-06-09 17:55   ` Eric Sunshine
  2017-10-11 18:03 ` [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments Takahito Ogawa
  25 siblings, 1 reply; 95+ messages in thread
From: Lars Vogel @ 2016-06-09 17:46 UTC (permalink / raw)
  To: git; +Cc: Lars Vogel

Working directory can be easily confused with the current directory.
In one of my patches I already updated the usage of working directory
with working tree for the man page but I noticed that git status also
uses this incorrect term.
---
 po/bg.po    | 2 +-
 po/ca.po    | 2 +-
 po/de.po    | 2 +-
 po/fr.po    | 2 +-
 po/git.pot  | 2 +-
 po/ko.po    | 2 +-
 po/ru.po    | 2 +-
 po/sv.po    | 2 +-
 po/vi.po    | 2 +-
 po/zh_CN.po | 2 +-
 wt-status.c | 2 +-
 11 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/po/bg.po b/po/bg.po
index ac6f103..9390c81 100644
--- a/po/bg.po
+++ b/po/bg.po
@@ -2295,7 +2295,7 @@ msgstr ""
 
 #: wt-status.c:1535
 #, c-format
-msgid "nothing to commit, working directory clean\n"
+msgid "nothing to commit, working tree clean\n"
 msgstr "липсват каквито и да е промени, работното дърво е чисто\n"
 
 #: wt-status.c:1642
diff --git a/po/ca.po b/po/ca.po
index 46000d7..f54f137 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -2318,7 +2318,7 @@ msgstr ""
 
 #: wt-status.c:1535
 #, c-format
-msgid "nothing to commit, working directory clean\n"
+msgid "nothing to commit, working tree clean\n"
 msgstr "no hi ha res a cometre, directori de treball net\n"
 
 #: wt-status.c:1642
diff --git a/po/de.po b/po/de.po
index 0eadf34..a14fe92 100644
--- a/po/de.po
+++ b/po/de.po
@@ -2356,7 +2356,7 @@ msgstr ""
 
 #: wt-status.c:1535
 #, c-format
-msgid "nothing to commit, working directory clean\n"
+msgid "nothing to commit, working tree clean\n"
 msgstr "nichts zu committen, Arbeitsverzeichnis unverändert\n"
 
 #: wt-status.c:1642
diff --git a/po/fr.po b/po/fr.po
index 55ca387..627315c 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -2394,7 +2394,7 @@ msgstr "rien à valider (utilisez -u pour afficher les fichiers non suivis)\n"
 
 #: wt-status.c:1535
 #, c-format
-msgid "nothing to commit, working directory clean\n"
+msgid "nothing to commit, working tree clean\n"
 msgstr "rien à valider, la copie de travail est propre\n"
 
 #: wt-status.c:1642
diff --git a/po/git.pot b/po/git.pot
index 72ef798..2957091 100644
--- a/po/git.pot
+++ b/po/git.pot
@@ -2192,7 +2192,7 @@ msgstr ""
 
 #: wt-status.c:1535
 #, c-format
-msgid "nothing to commit, working directory clean\n"
+msgid "nothing to commit, working tree clean\n"
 msgstr ""
 
 #: wt-status.c:1642
diff --git a/po/ko.po b/po/ko.po
index 3ff3b9b..9520e04 100644
--- a/po/ko.po
+++ b/po/ko.po
@@ -2313,7 +2313,7 @@ msgstr ""
 
 #: wt-status.c:1535
 #, c-format
-msgid "nothing to commit, working directory clean\n"
+msgid "nothing to commit, working tree clean\n"
 msgstr "커밋할 사항 없음, 작업 폴더 깨끗함\n"
 
 #: wt-status.c:1642
diff --git a/po/ru.po b/po/ru.po
index c0a838b..6fe8c09 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -2233,7 +2233,7 @@ msgstr "нечего коммитить (используйте опцию «-u
 
 #: wt-status.c:1535
 #, c-format
-msgid "nothing to commit, working directory clean\n"
+msgid "nothing to commit, working tree clean\n"
 msgstr "нечего коммитить, нет изменений в рабочем каталоге\n"
 
 #: wt-status.c:1642
diff --git a/po/sv.po b/po/sv.po
index 32bcaba..801a816 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -2289,7 +2289,7 @@ msgstr "inget att checka in (använd -u för att visa ospårade filer)\n"
 
 #: wt-status.c:1535
 #, c-format
-msgid "nothing to commit, working directory clean\n"
+msgid "nothing to commit, working tree clean\n"
 msgstr "inget att checka in, arbetskatalogen ren\n"
 
 #: wt-status.c:1642
diff --git a/po/vi.po b/po/vi.po
index edd8e29..18fbdef 100644
--- a/po/vi.po
+++ b/po/vi.po
@@ -2306,7 +2306,7 @@ msgstr ""
 
 #: wt-status.c:1535
 #, c-format
-msgid "nothing to commit, working directory clean\n"
+msgid "nothing to commit, working tree clean\n"
 msgstr "không có gì để chuyển giao, thư mục làm việc sạch sẽ\n"
 
 #: wt-status.c:1642
diff --git a/po/zh_CN.po b/po/zh_CN.po
index a6b06f9..b76f2c0 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -2421,7 +2421,7 @@ msgstr "无文件要提交(使用 -u 显示未跟踪的文件)\n"
 #  译者:中文字符串拼接,可删除前导空格
 #: wt-status.c:1535
 #, c-format
-msgid "nothing to commit, working directory clean\n"
+msgid "nothing to commit, working tree clean\n"
 msgstr "无文件要提交,干净的工作区\n"
 
 #  译者:注意保持句尾空格
diff --git a/wt-status.c b/wt-status.c
index 4f27bd6..4ce4e35 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1554,7 +1554,7 @@ void wt_status_print(struct wt_status *s)
 			else
 				printf(_("nothing to commit\n"));
 		} else
-			printf(_("nothing to commit, working directory clean\n"));
+			printf(_("nothing to commit, working tree clean\n"));
 	}
 }
 
-- 
2.8.1

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH] Use "working tree" instead of "working directory" for git status
  2016-06-09 17:46 ` [PATCH] Use "working tree" instead of "working directory" for git status Lars Vogel
@ 2016-06-09 17:55   ` Eric Sunshine
  2016-06-09 18:21     ` Lars Vogel
  0 siblings, 1 reply; 95+ messages in thread
From: Eric Sunshine @ 2016-06-09 17:55 UTC (permalink / raw)
  To: Lars Vogel; +Cc: Git List, Lars Vogel

On Thu, Jun 9, 2016 at 1:46 PM, Lars Vogel <lars.vogel@gmail.com> wrote:
> Working directory can be easily confused with the current directory.
> In one of my patches I already updated the usage of working directory
> with working tree for the man page but I noticed that git status also
> uses this incorrect term.

Missing sign-off.

> ---
>  po/bg.po    | 2 +-
>  po/ca.po    | 2 +-
>  po/de.po    | 2 +-
>  po/fr.po    | 2 +-
>  po/git.pot  | 2 +-
>  po/ko.po    | 2 +-
>  po/ru.po    | 2 +-
>  po/sv.po    | 2 +-
>  po/vi.po    | 2 +-
>  po/zh_CN.po | 2 +-
>  wt-status.c | 2 +-

Don't bother updating the .po files; that's the job of the
translators. Your patch should touch only wt-status.c.

>  11 files changed, 11 insertions(+), 11 deletions(-)

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH] Use "working tree" instead of "working directory" for git status
  2016-06-09 17:55   ` Eric Sunshine
@ 2016-06-09 18:21     ` Lars Vogel
  0 siblings, 0 replies; 95+ messages in thread
From: Lars Vogel @ 2016-06-09 18:21 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Lars Vogel, Git List

Thanks updated patch on its way.

On Thu, Jun 9, 2016 at 7:55 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Thu, Jun 9, 2016 at 1:46 PM, Lars Vogel <lars.vogel@gmail.com> wrote:
>> Working directory can be easily confused with the current directory.
>> In one of my patches I already updated the usage of working directory
>> with working tree for the man page but I noticed that git status also
>> uses this incorrect term.
>
> Missing sign-off.
>
>> ---
>>  po/bg.po    | 2 +-
>>  po/ca.po    | 2 +-
>>  po/de.po    | 2 +-
>>  po/fr.po    | 2 +-
>>  po/git.pot  | 2 +-
>>  po/ko.po    | 2 +-
>>  po/ru.po    | 2 +-
>>  po/sv.po    | 2 +-
>>  po/vi.po    | 2 +-
>>  po/zh_CN.po | 2 +-
>>  wt-status.c | 2 +-
>
> Don't bother updating the .po files; that's the job of the
> translators. Your patch should touch only wt-status.c.
>
>>  11 files changed, 11 insertions(+), 11 deletions(-)



-- 
Eclipse Platform UI and e4 project co-lead
CEO vogella GmbH

Haindaalwisch 17a, 22395 Hamburg
Amtsgericht Hamburg: HRB 127058
Geschäftsführer: Lars Vogel, Jennifer Nerlich de Vogel
USt-IdNr.: DE284122352
Fax (040) 5247 6322, Email: lars.vogel@vogella.com, Web: http://www.vogella.com

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments
       [not found] <y>
                   ` (24 preceding siblings ...)
  2016-06-09 17:46 ` [PATCH] Use "working tree" instead of "working directory" for git status Lars Vogel
@ 2017-10-11 18:03 ` Takahito Ogawa
  2017-10-12  0:53   ` Junio C Hamano
  25 siblings, 1 reply; 95+ messages in thread
From: Takahito Ogawa @ 2017-10-11 18:03 UTC (permalink / raw)
  To: git; +Cc: Takahito Ogawa

"git stash" behavior without any arguments was changed in
1ada5020b ("stash: use stash_push for no verb form", 2017-02-28).
This is equivalent to "git stash push" but document says
"git stash save".

Correct it.

Signed-off-by: Takahito Ogawa <takahito.ogawa@datagrid.co.jp>
---
 Documentation/git-stash.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 00f95fee1..63642c145 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -33,7 +33,7 @@ and reverts the working directory to match the `HEAD` commit.
 The modifications stashed away by this command can be listed with
 `git stash list`, inspected with `git stash show`, and restored
 (potentially on top of a different commit) with `git stash apply`.
-Calling `git stash` without any arguments is equivalent to `git stash save`.
+Calling `git stash` without any arguments is equivalent to `git stash push`.
 A stash is by default listed as "WIP on 'branchname' ...", but
 you can give a more descriptive message on the command line when
 you create one.
-- 
2.13.1


^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments
       [not found] <n>
@ 2017-10-11 18:06 ` Takahito Ogawa
  2017-10-11 18:37 ` Takahito Ogawa
  2017-10-11 20:01 ` Takahito Ogawa
  2 siblings, 0 replies; 95+ messages in thread
From: Takahito Ogawa @ 2017-10-11 18:06 UTC (permalink / raw)
  To: git; +Cc: Takahito Ogawa

"git stash" behavior without any arguments was changed in
1ada5020b ("stash: use stash_push for no verb form", 2017-02-28).
This is equivalent to "git stash push" but document says
"git stash save".

Correct it.

Signed-off-by: Takahito Ogawa <takahito.ogawa@datagrid.co.jp>
---
 Documentation/git-stash.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 00f95fee1..63642c145 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -33,7 +33,7 @@ and reverts the working directory to match the `HEAD` commit.
 The modifications stashed away by this command can be listed with
 `git stash list`, inspected with `git stash show`, and restored
 (potentially on top of a different commit) with `git stash apply`.
-Calling `git stash` without any arguments is equivalent to `git stash save`.
+Calling `git stash` without any arguments is equivalent to `git stash push`.
 A stash is by default listed as "WIP on 'branchname' ...", but
 you can give a more descriptive message on the command line when
 you create one.
-- 
2.13.1


^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments
       [not found] <n>
  2017-10-11 18:06 ` Takahito Ogawa
@ 2017-10-11 18:37 ` Takahito Ogawa
  2017-10-11 19:09   ` Thomas Gummerer
  2017-10-11 20:01 ` Takahito Ogawa
  2 siblings, 1 reply; 95+ messages in thread
From: Takahito Ogawa @ 2017-10-11 18:37 UTC (permalink / raw)
  To: git; +Cc: Takahito Ogawa

"git stash" behavior without any arguments was changed in
1ada5020b ("stash: use stash_push for no verb form", 2017-02-28).
This is equivalent to "git stash push" but documents says
"git stash save".

Correct it.

Signed-off-by: Takahito Ogawa <aiueogawa217@gmail.com>
---
 Documentation/git-stash.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 00f95fee1..63642c145 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -33,7 +33,7 @@ and reverts the working directory to match the `HEAD` commit.
 The modifications stashed away by this command can be listed with
 `git stash list`, inspected with `git stash show`, and restored
 (potentially on top of a different commit) with `git stash apply`.
-Calling `git stash` without any arguments is equivalent to `git stash save`.
+Calling `git stash` without any arguments is equivalent to `git stash push`.
 A stash is by default listed as "WIP on 'branchname' ...", but
 you can give a more descriptive message on the command line when
 you create one.
-- 
2.13.1


^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments
  2017-10-11 18:37 ` Takahito Ogawa
@ 2017-10-11 19:09   ` Thomas Gummerer
  2017-10-11 19:12     ` Thomas Gummerer
  0 siblings, 1 reply; 95+ messages in thread
From: Thomas Gummerer @ 2017-10-11 19:09 UTC (permalink / raw)
  To: Takahito Ogawa; +Cc: git

On 10/12, Takahito Ogawa wrote:
> "git stash" behavior without any arguments was changed in
> 1ada5020b ("stash: use stash_push for no verb form", 2017-02-28).
> This is equivalent to "git stash push" but documents says
> "git stash save".
> 
> Correct it.

Thanks for fixing this!  I recently sent a patch that would advertise
git stash push more in general, which would also fix this occurrence [1], 
but it didn't seem like it got much interest.  However this is
obviously correct, and should definitely be fixed, while the other
places can still mention 'git stash save'.

For what it's worth this is

Reviewed-by: Thomas Gummerer <t.gummerer@gmail.com>


> Signed-off-by: Takahito Ogawa <aiueogawa217@gmail.com>
> ---
>  Documentation/git-stash.txt | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
> index 00f95fee1..63642c145 100644
> --- a/Documentation/git-stash.txt
> +++ b/Documentation/git-stash.txt
> @@ -33,7 +33,7 @@ and reverts the working directory to match the `HEAD` commit.
>  The modifications stashed away by this command can be listed with
>  `git stash list`, inspected with `git stash show`, and restored
>  (potentially on top of a different commit) with `git stash apply`.
> -Calling `git stash` without any arguments is equivalent to `git stash save`.
> +Calling `git stash` without any arguments is equivalent to `git stash push`.
>  A stash is by default listed as "WIP on 'branchname' ...", but
>  you can give a more descriptive message on the command line when
>  you create one.
> -- 
> 2.13.1
> 

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments
  2017-10-11 19:09   ` Thomas Gummerer
@ 2017-10-11 19:12     ` Thomas Gummerer
  0 siblings, 0 replies; 95+ messages in thread
From: Thomas Gummerer @ 2017-10-11 19:12 UTC (permalink / raw)
  To: Takahito Ogawa; +Cc: git

On 10/11, Thomas Gummerer wrote:
> On 10/12, Takahito Ogawa wrote:
> > "git stash" behavior without any arguments was changed in
> > 1ada5020b ("stash: use stash_push for no verb form", 2017-02-28).
> > This is equivalent to "git stash push" but documents says
> > "git stash save".
> > 
> > Correct it.
> 
> Thanks for fixing this!  I recently sent a patch that would advertise
> git stash push more in general, which would also fix this occurrence [1], 
> but it didn't seem like it got much interest.  However this is
> obviously correct, and should definitely be fixed, while the other
> places can still mention 'git stash save'.
> 
> For what it's worth this is
> 
> Reviewed-by: Thomas Gummerer <t.gummerer@gmail.com>

And I forgot to include the link, sorry.  Here it is:

[1]: https://public-inbox.org/git/20171005200049.GF30301@hank/

> 
> > Signed-off-by: Takahito Ogawa <aiueogawa217@gmail.com>
> > ---
> >  Documentation/git-stash.txt | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
> > index 00f95fee1..63642c145 100644
> > --- a/Documentation/git-stash.txt
> > +++ b/Documentation/git-stash.txt
> > @@ -33,7 +33,7 @@ and reverts the working directory to match the `HEAD` commit.
> >  The modifications stashed away by this command can be listed with
> >  `git stash list`, inspected with `git stash show`, and restored
> >  (potentially on top of a different commit) with `git stash apply`.
> > -Calling `git stash` without any arguments is equivalent to `git stash save`.
> > +Calling `git stash` without any arguments is equivalent to `git stash push`.
> >  A stash is by default listed as "WIP on 'branchname' ...", but
> >  you can give a more descriptive message on the command line when
> >  you create one.
> > -- 
> > 2.13.1
> > 

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments
       [not found] <n>
  2017-10-11 18:06 ` Takahito Ogawa
  2017-10-11 18:37 ` Takahito Ogawa
@ 2017-10-11 20:01 ` Takahito Ogawa
  2 siblings, 0 replies; 95+ messages in thread
From: Takahito Ogawa @ 2017-10-11 20:01 UTC (permalink / raw)
  To: gitster; +Cc: git, Takahito Ogawa

"git stash" behavior without any arguments was changed in
1ada5020b ("stash: use stash_push for no verb form", 2017-02-28).
This is equivalent to "git stash push" but documents says
"git stash save".

Correct it.

Reviewed-by: Thomas Gummerer <t.gummerer@gmail.com>
Signed-off-by: Takahito Ogawa <aiueogawa217@gmail.com>
---
 Documentation/git-stash.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 00f95fee1..63642c145 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -33,7 +33,7 @@ and reverts the working directory to match the `HEAD` commit.
 The modifications stashed away by this command can be listed with
 `git stash list`, inspected with `git stash show`, and restored
 (potentially on top of a different commit) with `git stash apply`.
-Calling `git stash` without any arguments is equivalent to `git stash save`.
+Calling `git stash` without any arguments is equivalent to `git stash push`.
 A stash is by default listed as "WIP on 'branchname' ...", but
 you can give a more descriptive message on the command line when
 you create one.
-- 
2.13.1


^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments
  2017-10-11 18:03 ` [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments Takahito Ogawa
@ 2017-10-12  0:53   ` Junio C Hamano
       [not found]     ` <CAC2Jkr+ZDUxd9JcKvVwZqCHVW+Bpp2CbdyehwgKV_Ru-Uqxo8A@mail.gmail.com>
  0 siblings, 1 reply; 95+ messages in thread
From: Junio C Hamano @ 2017-10-12  0:53 UTC (permalink / raw)
  To: Takahito Ogawa; +Cc: git, Takahito Ogawa

Takahito Ogawa <aiueogawa217@gmail.com> writes:

> @@ -33,7 +33,7 @@ and reverts the working directory to match the `HEAD` commit.
>  The modifications stashed away by this command can be listed with
>  `git stash list`, inspected with `git stash show`, and restored
>  (potentially on top of a different commit) with `git stash apply`.
> -Calling `git stash` without any arguments is equivalent to `git stash save`.
> +Calling `git stash` without any arguments is equivalent to `git stash push`.

Hmph.  Is there any difference between

	git stash save
	git stash push

without any other argument?  Aren't they equivalent to

	git stash

without any argument, which is what this sentence explains?


^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments
       [not found]     ` <CAC2Jkr+ZDUxd9JcKvVwZqCHVW+Bpp2CbdyehwgKV_Ru-Uqxo8A@mail.gmail.com>
@ 2017-10-12  3:52       ` 小川恭史
  2017-10-12  3:54         ` 小川恭史
  0 siblings, 1 reply; 95+ messages in thread
From: 小川恭史 @ 2017-10-12  3:52 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Takahito Ogawa

As you point,

    git stash

without any argument is equivalent to both of

    git stash save
    git stash push

. The original sentence is correct.

2017-10-12 12:31 GMT+09:00 小川恭史 <aiueogawa217@gmail.com>:
> As you point,
>
>     git stash
>
> without any argument is equivalent to both of
> git stash save and
>
>
> 2017-10-12 9:53 GMT+09:00 Junio C Hamano <gitster@pobox.com>:
>> Takahito Ogawa <aiueogawa217@gmail.com> writes:
>>
>>> @@ -33,7 +33,7 @@ and reverts the working directory to match the `HEAD`
>>> commit.
>>>  The modifications stashed away by this command can be listed with
>>>  `git stash list`, inspected with `git stash show`, and restored
>>>  (potentially on top of a different commit) with `git stash apply`.
>>> -Calling `git stash` without any arguments is equivalent to `git stash
>>> save`.
>>> +Calling `git stash` without any arguments is equivalent to `git stash
>>> push`.
>>
>> Hmph.  Is there any difference between
>>
>>         git stash save
>>         git stash push
>>
>> without any other argument?  Aren't they equivalent to
>>
>>         git stash
>>
>> without any argument, which is what this sentence explains?
>>
>

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments
  2017-10-12  3:52       ` 小川恭史
@ 2017-10-12  3:54         ` 小川恭史
  2017-10-12  9:56           ` Junio C Hamano
  0 siblings, 1 reply; 95+ messages in thread
From: 小川恭史 @ 2017-10-12  3:54 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Takahito Ogawa

As you point,

    git stash

without any argument is equivalent to both of

    git stash save
    git stash push

. The original sentence is correct.

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments
  2017-10-12  3:54         ` 小川恭史
@ 2017-10-12  9:56           ` Junio C Hamano
  0 siblings, 0 replies; 95+ messages in thread
From: Junio C Hamano @ 2017-10-12  9:56 UTC (permalink / raw)
  To: 小川恭史; +Cc: git, Takahito Ogawa

小川恭史 <aiueogawa217@gmail.com> writes:

> As you point,
>
>     git stash
>
> without any argument is equivalent to both of
>
>     git stash save
>     git stash push
>
> . The original sentence is correct.

OK.  

Note that I was merely reacting to "Correct it." in your
justification for the change, which made it sound like 'save' was
incorrect.

As a part of a move to deprecate 'save' and nudge users towards
'push', the change does make sense.  I just wanted to make sure the
change and its motivation are presented with honesty ;-).


^ permalink raw reply	[flat|nested] 95+ messages in thread

end of thread, back to index

Thread overview: 95+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <y>
2008-12-02 21:20 ` [JGIT PATCH 1/2] Close a forgotten reference to the HEAD ref Robin Rosenberg
2008-12-02 21:20   ` [JGIT PATCH 2/2] Improve closing of files in error situations Robin Rosenberg
2008-12-02 21:41     ` [JGIT PATCH 2/2 v2] " Robin Rosenberg
2009-06-07 20:19 ` [EGIT PATCH 0/3] Ref log reader Robin Rosenberg
2009-06-07 20:19   ` [EGIT PATCH 1/3] Assert the name and origName properties of Ref objects Robin Rosenberg
2009-06-07 20:19     ` [EGIT PATCH 2/3] Add methods to RawParseUtils for scanning backwards Robin Rosenberg
2009-06-07 20:19       ` [EGIT PATCH 3/3] Add a ref log reader class Robin Rosenberg
2009-06-07 22:21         ` Shawn O. Pearce
2009-06-07 22:45           ` Robin Rosenberg
2009-06-07 22:47             ` Shawn O. Pearce
2009-06-08 17:28               ` [EGIT PATCH 1/2] Add methods to RawParseUtils for scanning backwards Robin Rosenberg
2009-06-08 17:28                 ` [EGIT PATCH 2/2] Add a ref log reader class Robin Rosenberg
2009-06-12 19:52                   ` Shawn O. Pearce
2009-06-15 21:25                     ` [EGIT PATCH 1/2] Use a UTC relative time zone for PersonIdent Robin Rosenberg
2009-06-15 21:25                       ` [EGIT PATCH 2/2] Add a ref log reader class Robin Rosenberg
2009-06-15 22:21                         ` Robin Rosenberg
2009-06-22 11:49 ` [BUG] apply: test for trailing whitespace & no new line bug y
2009-06-22 11:49 ` y
2010-07-08 15:12 ` [PATCH] diff.c: fix a graph output " struggleyb.nku
2010-07-09  0:15   ` Junio C Hamano
2010-07-09  0:57     ` Junio C Hamano
2010-07-09  1:04       ` Nazri Ramliy
2010-07-09  1:09         ` Junio C Hamano
2010-07-11  6:10       ` Bo Yang
2010-10-07  4:46 ` [PATCH 1/2] setup.c: add enter_work_tree() pclouds
2010-10-07  4:46 ` [PATCH 2/2] worktree: provide better prefix to go back to original cwd pclouds
2010-10-07  5:53   ` Nguyen Thai Ngoc Duy
2010-10-07  5:54   ` Junio C Hamano
2010-10-07  7:20     ` Nguyen Thai Ngoc Duy
2010-10-07 14:56       ` Junio C Hamano
2010-10-07 15:11         ` Nguyen Thai Ngoc Duy
2010-11-23  2:32 ` [PATCH] Corrected cmitmode set in the right lower window when initiating a diff Michał Pomorski
2011-04-07  6:01 ` [PATCH] git-p4: replace each tab with 8 spaces for consistency Andrew Garber
2011-04-07  7:36   ` Junio C Hamano
2011-04-07 16:35     ` Phil Hord
2011-04-07 18:45       ` Junio C Hamano
2011-04-07  6:01 ` Andrew Garber
2012-06-04 19:15 ` [PATCH/RFC] file import functionality for git-remote-mw Pavel Volek
2012-06-04 20:54   ` Matthieu Moy
2012-06-04 20:49 ` [PATCH/RFC] Export file attachements in git-remote-mediawiki NGUYEN Kim Thuat
2012-06-04 21:34   ` Matthieu Moy
2012-06-05 17:00     ` nguyenki
2012-06-05 17:05       ` Matthieu Moy
2012-06-06 22:25         ` nguyenki
2012-06-05 17:11     ` nguyenki
2012-06-08 13:27 ` [PATCHv1] Export file " Kim Thuat NGUYEN
2012-06-08 14:07   ` Matthieu Moy
2012-06-08 22:59     ` nguyenki
2012-06-10 13:01       ` Matthieu Moy
2012-06-12 12:46 ` [PATCHv2] git-remote-mediawiki: export File: attachments Kim Thuat NGUYEN
2012-06-12 12:52   ` Matthieu Moy
2012-06-12 12:54   ` nguyenki
2012-06-12 13:51   ` Max Horn
2012-06-13  7:56 ` [PATCHv3] " kim-thuat.nguyen
2012-06-13 16:36   ` Matthieu Moy
     [not found] ` <1357885869-20815-1-git-send-email-cyliu@suse.com>
     [not found]   ` <50EFD066.60501@redhat.com>
2013-01-11 16:39     ` git send-email should not allow 'y' for in-reply-to Eric Blake
2013-01-11 16:47       ` Jeff King
2013-01-11 17:51         ` Eric Blake
2013-01-11 18:43         ` Hilco Wijbenga
2013-01-11 18:54           ` Jeff King
2013-02-24  9:03             ` Junio C Hamano
2013-06-10 15:13 ` v3 [PATCH 1/2] status: introduce status.short to enable --short by default y
2013-06-10 15:13   ` v3 [PATCH 2/2] status:introduce status.branch to enable --branch " y
2013-06-10 15:13   ` y
2013-06-10 15:20   ` v3 [PATCH 1/2] status: introduce status.short to enable --short " Matthieu Moy
2013-06-10 18:02     ` Junio C Hamano
2013-06-10 15:13 ` y
2014-01-29 13:33 ` [PATCH 3/3] builtin/blame.c: reduce scope of variables Elia Pinto
2014-03-05 19:29 ` [PATCH] use strchrnul() in place of strchr() and strlen() Rohit Mani
2014-03-06 20:54   ` Junio C Hamano
2014-03-08  6:48 ` [GSoC][PATCH v2] " Rohit Mani
2014-03-10 15:36   ` Junio C Hamano
2014-03-10 19:04 ` [PATCH][GSOC2014] TamerTas
     [not found] ` <1394478262-17911-1-git-send-email-tamertas@outlook.com>
2014-03-10 19:04   ` [PATCH][GSOC2014] changed logical chain in branch.c to lookup tables TamerTas
2014-03-10 21:05     ` Stefan Beller
2014-03-10 21:25     ` Eric Sunshine
2014-03-10 21:47       ` Tamer TAS
2014-03-10 22:39         ` Eric Sunshine
2014-03-11 11:33           ` Tamer TAS
2014-03-11 20:32             ` Eric Sunshine
2014-03-18 12:31 ` [PATCH][GSOC2014] add: Rewrite run_add_interactive to use struct argv_array Movchan Pavel
2014-03-18 19:47   ` Junio C Hamano
2016-06-09 17:46 ` [PATCH] Use "working tree" instead of "working directory" for git status Lars Vogel
2016-06-09 17:55   ` Eric Sunshine
2016-06-09 18:21     ` Lars Vogel
2017-10-11 18:03 ` [PATCH 1/1] git-stash.txt: correct "git stash" behavior with no arguments Takahito Ogawa
2017-10-12  0:53   ` Junio C Hamano
     [not found]     ` <CAC2Jkr+ZDUxd9JcKvVwZqCHVW+Bpp2CbdyehwgKV_Ru-Uqxo8A@mail.gmail.com>
2017-10-12  3:52       ` 小川恭史
2017-10-12  3:54         ` 小川恭史
2017-10-12  9:56           ` Junio C Hamano
     [not found] <n>
2017-10-11 18:06 ` Takahito Ogawa
2017-10-11 18:37 ` Takahito Ogawa
2017-10-11 19:09   ` Thomas Gummerer
2017-10-11 19:12     ` Thomas Gummerer
2017-10-11 20:01 ` Takahito Ogawa

git@vger.kernel.org mailing list mirror (one of many)

Archives are clonable:
	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.org/gmane.comp.version-control.git

 note: .onion URLs require Tor: https://www.torproject.org/
       or Tor2web: https://www.tor2web.org/

AGPL code for this site: git clone https://public-inbox.org/ public-inbox