Git development
 help / color / mirror / Atom feed
* Re: git-grep Bus Error
From: Brian Gernhardt @ 2009-03-09  1:48 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Sam Hocevar, Git List
In-Reply-To: <7vtz63ijoz.fsf@gitster.siamese.dyndns.org>


On Mar 8, 2009, at 9:11 PM, Junio C Hamano wrote:

> Brian, would this patch help?
>
> grep.c |    4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/grep.c b/grep.c
> index cace1c8..dcdbd5e 100644
> --- a/grep.c
> +++ b/grep.c
> @@ -490,9 +490,9 @@ static void show_line(struct grep_opt *opt, char  
> *bol, char *eol,
> 		*eol = '\0';
> 		while (next_match(opt, bol, eol, ctx, &match, eflags)) {
> 			printf("%.*s%s%.*s%s",
> -			       match.rm_so, bol,
> +			       (int) match.rm_so, bol,
> 			       opt->color_match,
> -			       match.rm_eo - match.rm_so, bol + match.rm_so,
> +			       (int)(match.rm_eo - match.rm_so), bol + match.rm_so,
> 			       GIT_COLOR_RESET);
> 			bol += match.rm_eo;
> 			rest -= match.rm_eo;

Apparently so.  Despite the fact that match.rm_so is 0 at times,  
"%.*s" works properly so the other half of the patch isn't needed.  Odd.

~~ B

^ permalink raw reply

* Re: [PATCH] grep: make show_line more portable
From: Jay Soffian @ 2009-03-09  2:22 UTC (permalink / raw)
  To: Brian Gernhardt; +Cc: Git List, Junio C Hamano
In-Reply-To: <1236561326-1231-1-git-send-email-benji@silverinsanity.com>

On Sun, Mar 8, 2009 at 9:15 PM, Brian Gernhardt
<benji@silverinsanity.com> wrote:
> On OS X the printf specifier "%.0s" outputs the entire string instead
> of 0 characters as POSIX states.

Does not reproduce for me:

$ cat foo.c && gcc -m64 foo.c -o foo32 && gcc foo.c -o foo64 && file
foo32 foo64 && ./foo32 && ./foo64
#include "stdio.h"
#include "stdlib.h"
main() {
	printf("1 '%.0s'\n", "foobar");
	printf("2 '%.*s'\n", 0, "foobar");
	exit(0);
}
foo32: Mach-O 64-bit executable x86_64
foo64: Mach-O executable i386
1 ''
2 ''
1 ''
2 ''

OS X 10.5.6 (Darwin 9.6.0). i686-apple-darwin9-gcc-4.0.1. Same linkage for both:

/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current
version 111.1.3)

j.

^ permalink raw reply

* Re: [PATCH] grep: make show_line more portable
From: Jay Soffian @ 2009-03-09  2:23 UTC (permalink / raw)
  To: Brian Gernhardt; +Cc: Git List, Junio C Hamano
In-Reply-To: <76718490903081922p105ebf79vb0bf06989413887c@mail.gmail.com>

On Sun, Mar 8, 2009 at 10:22 PM, Jay Soffian <jaysoffian@gmail.com> wrote:
> foo32: Mach-O 64-bit executable x86_64
> foo64: Mach-O executable i386

Okay, so I may be brain-damaged in my naming, but that doesn't
invalidate the results. :-)

j.

^ permalink raw reply

* Re: [PATCH] grep: make show_line more portable
From: Brian Gernhardt @ 2009-03-09  2:44 UTC (permalink / raw)
  To: Jay Soffian; +Cc: Git List, Junio C Hamano
In-Reply-To: <76718490903081922p105ebf79vb0bf06989413887c@mail.gmail.com>


On Mar 8, 2009, at 10:22 PM, Jay Soffian wrote:

> On Sun, Mar 8, 2009 at 9:15 PM, Brian Gernhardt
> <benji@silverinsanity.com> wrote:
>> On OS X the printf specifier "%.0s" outputs the entire string instead
>> of 0 characters as POSIX states.
>
> Does not reproduce for me:

Nor for me, as I noted on the other thread...  And looking again, I  
was reading the man page for printf(1), not printf(3).  Ouch.   
*grumble, grumble*  I'm crawling back under my rock now.

~~ B

^ permalink raw reply

* [PoC PATCH JGIT 0/2] Proof of concept code for Git Freenet transport
From: Daniel Cheng (aka SDiZ) @ 2009-03-09  3:36 UTC (permalink / raw)
  To: devl-RdDMkVZAZeuJnvDnx1genB2eb7JE58TQ, git-u79uwXL29TY76Z2rM5mHXA

Hi JGit / Freenet community,

Here is some proof-of-concept code for Git-over-Freenet.
I am sending this to see the feedback from communities.

The code need some more cleanups, so it it is not ready for apply (yet).

This is a real-life example

Push:
   $ git remote add fcp fcp://SSK@[my public key]^[my private key]/test.git
   $ ./jgit push fcp refs/remotes/origin/stable:refs/heads/master
 
 /ALTERNATIVLY/

   Insert a bare repository under USK@<.....>/test.git/-1/

Pull:
 $ ./jgit clone fcp://SSK@[my public key]^[my private key]/test.git


To workaround the metadata update problem, this client translate the
path seperator to "-", that means:

On push:
   objects/aa/bbbbbbbb   --> USK@..../test.git-objects-aa-bbbbbbb/-1/
   refs/heads/xxx        --> USK@..../test.git-objects-ref-heads-xxx/-1/

On pull:
   To support uploading from jSite, 
    when we load the info/refs we first check USK@..../test.git-info-refs/-1/
    if it is unavailiable, we would use USK@..../test.git/-1/info/refs

   The "traditional" type (USK@..../test.git/-1/objects) repository is
   always added as an alternative objects database. No other info/alternatives 
   are supported

FIXME:
 - How to store the private key of repository?
   Currently, we use URI of form fcp://SSK@<public key>^<private key>/some-id
   This is quite ugly. Could we use a per remote Config ? How can I get remote
   name from transport?

 - Make pushing async, could we?

^ permalink raw reply

* [PoC PATCH JGIT 1/2] Freenet Freenet Client Protocol (FCP) 2.0 Client
From: Daniel Cheng (aka SDiZ) @ 2009-03-09  3:36 UTC (permalink / raw)
  To: devl-RdDMkVZAZeuJnvDnx1genB2eb7JE58TQ, git-u79uwXL29TY76Z2rM5mHXA
  Cc: Daniel Cheng (aka SDiZ)
In-Reply-To: <1236569765-8882-1-git-send-email-j16sdiz+freenet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>


Signed-off-by: Daniel Cheng (aka SDiZ) <j16sdiz+freenet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 .../jgit/transport/fcpv2/FCPConnection.java        |  427 ++++++++++++++++++++
 1 files changed, 427 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/fcpv2/FCPConnection.java

diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/fcpv2/FCPConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/fcpv2/FCPConnection.java
new file mode 100644
index 0000000..ce2ca90
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/fcpv2/FCPConnection.java
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2008, CHENG Yuk-Pong, Daniel <j16sdiz+freenet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ *
+ * 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.transport.fcpv2;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spearce.jgit.lib.ProgressMonitor;
+
+/**
+ * Freenet Client Protocol 2.0 Connection
+ * 
+ * A simplified interface to Freenet 0.7 node using FCPv2. This is not a
+ * full-blown interface to Freenet node, but rather some "quick and dirty" hack
+ * just enough to upload/download simple file from the network.
+ * <p>
+ * See <a href="http://wiki.freenetproject.org/FreenetFCPSpec2Point0">Freenet
+ * Client Protocol 2.0 Specification</a> for detail on this protocol.
+ */
+public class FCPConnection {
+	/** Default FCP port */
+	public static final int DEFAULT_FCP_PORT = 9481;
+
+	protected InetAddress addr;
+
+	protected int port;
+
+	protected Socket socket;
+
+	protected InputStream is;
+
+	protected OutputStream os;
+
+	/**
+	 * Create a new FCP Connection to default host and port (
+	 * <code>localhost:9481</code>)
+	 * 
+	 * @throws UnknownHostException
+	 *             if no IP address for the <code>localhost</code> could be
+	 *             found.
+	 */
+	public FCPConnection() throws UnknownHostException {
+		this(InetAddress.getAllByName("127.0.0.1")[0], DEFAULT_FCP_PORT);
+	}
+
+	/**
+	 * Create a new FCP Connection to the specified IP address and port
+	 * 
+	 * @param address
+	 *            the node IP address
+	 * @param port
+	 *            the port number
+	 */
+	public FCPConnection(InetAddress address, int port) {
+		this.addr = address;
+		this.port = port;
+	}
+
+	/**
+	 * Connect to the node
+	 * 
+	 * @throws IOException
+	 *             if any I/O error occurred
+	 */
+	public void connect() throws IOException {
+		socket = new Socket(addr, port);
+
+		is = new BufferedInputStream(socket.getInputStream());
+		os = new BufferedOutputStream(socket.getOutputStream());
+	}
+
+	/**
+	 * Hello Message
+	 * 
+	 * Send handshake <code>ClientHello</code> message to node. Block until
+	 * <code>NodeHello</code> is received.
+	 * 
+	 * @param clientName
+	 *            Client name, must be unique in the freenet node
+	 * 
+	 * @throws IOException
+	 *             if any I/O error occurred
+	 */
+	public void hello(String clientName) throws IOException {
+		FCPMessage msg = new FCPMessage();
+		msg.messageType = "ClientHello";
+		msg.put("ExpectedVersion", "2.0");
+		msg.put("Name", clientName);
+
+		msg.writeTo(os);
+
+		while (true) {
+			FCPMessage reply = FCPMessage.parse(is);
+			if ("NodeHello".equals(reply.messageType))
+				return;
+			if ("ProtocolError".equals(reply.messageType))
+				throw new IOException("Protocol error");
+		}
+	}
+
+	/**
+	 * Simple FCP Put
+	 * 
+	 * This method block until the data are fetchable or <code>PutFailed</code>
+	 * received.
+	 * 
+	 * @param freenetURI
+	 *            the freenet URI
+	 * @param data
+	 *            the data to be put
+	 * @param monitor
+	 *            progress monitor to post write completion to during the
+	 *            stream's close method.
+	 * @param monitorTask
+	 *            task name to display during the close method.
+	 * @return <code>true</code> iff <code>PutFetchable</code>,
+	 *         <code>PutSuccessful</code> or <code>PutFetchable</code> with
+	 *         insert collision (data already inserted)
+	 * @throws IOException
+	 *             if any I/O error occurred
+	 */
+	public boolean simplePut(String freenetURI, byte[] data,
+			ProgressMonitor monitor, String monitorTask) throws IOException {
+		System.err.println(freenetURI);
+
+		FCPMessage msg = new FCPMessage();
+		msg.messageType = "ClientPut";
+		msg.put("URI", freenetURI);
+		msg.put("Identifier", freenetURI);
+		msg.put("Verbosity", "1");
+		msg.put("Global", "false");
+		msg.put("UploadFrom", "direct");
+		msg.put("DataLength", "" + data.length);
+		msg.extraData = data;
+
+		msg.writeTo(os);
+
+		int totalBlocks = -1;
+		int completedBlocks = 0;
+
+		try {
+			while (true) {
+				FCPMessage reply = FCPMessage.parse(is);
+
+				if ("ProtocolError".equals(reply.messageType))
+					throw new IOException("Protocol error");
+				if (!freenetURI.equals(reply.get("Identifier"))) // identifier don't match, ignore it
+					continue;
+				if ("IdentifierCollision".equals(reply.messageType))
+					throw new IOException("IdentifierCollision");
+
+				if ("PutFailed".equals(reply.messageType)) {
+					if ("9".equals(reply.get("Code"))) // collision, data already inserted
+						return true;
+					return false;
+				}
+
+				if ("SimpleProgress".equals(reply.messageType)) {
+					if (totalBlocks == -1) {
+						totalBlocks = Integer.parseInt(reply.get("Total"));
+						monitor.beginTask(monitorTask, totalBlocks);
+					}
+					int tmp = Integer.parseInt(reply.get("Succeeded"));
+					if (tmp < totalBlocks)
+						monitor.update(tmp - completedBlocks);
+					completedBlocks = tmp;
+				}
+
+				if ("PutSuccessful".equals(reply.messageType))
+					return true;
+				if ("PutFetchable".equals(reply.messageType))
+					return true;
+			}
+		} finally {
+			if (totalBlocks == -1)
+				monitor.beginTask(monitorTask, 1);
+			monitor.endTask();
+		}
+	}
+
+	/**
+	 * Simple FCP Get
+	 * 
+	 * @param freenetURI
+	 *            the freenet URI
+	 * @return the data
+	 * @throws IOException
+	 *             if any I/O error occurred
+	 * @throws FileNotFoundException
+	 *             if data not found
+	 */
+	public byte[] simpleGet(String freenetURI) throws IOException,
+			FileNotFoundException {
+		FCPMessage msg = new FCPMessage();
+		msg.messageType = "ClientGet";
+		msg.put("URI", freenetURI);
+		msg.put("Identifier", freenetURI);
+		msg.put("Verbosity", "1");
+		msg.put("MaxSize", "2147483647");
+		msg.put("Global", "false");
+		msg.put("ClientToken", freenetURI);
+		msg.put("ReturnType", "direct");
+
+		msg.writeTo(os);
+
+		while (true) {
+			FCPMessage reply = FCPMessage.parse(is);
+			if ("ProtocolError".equals(reply.messageType))
+				throw new IOException("Protocol error");
+			if (!freenetURI.equals(reply.get("Identifier"))) // identifier don't match, ignore it
+				continue;
+			if ("IdentifierCollision".equals(reply.messageType))
+				throw new IOException("IdentifierCollision");
+
+			if ("GetFailed".equals(reply.messageType)) {
+				String redirectURI = reply.get("RedirectURI");
+				if (redirectURI != null)
+					return simpleGet(redirectURI);
+
+				System.err.println(" -> nf");
+				throw new FileNotFoundException();
+			}
+
+			if ("AllData".equals(reply.messageType))
+				return reply.extraData;
+		}
+	}
+
+	/**
+	 * Generate SSK Key Pair
+	 * 
+	 * @return the generated SSK key pair. <code>key[0]</code> is the public
+	 *         key, <code>key[1]</code> is the private key.
+	 * @throws IOException
+	 *             if any I/O error occurred
+	 */
+	public String[] generateSSK() throws IOException {
+		FCPMessage msg = new FCPMessage();
+		msg.messageType = "GenerateSSK";
+		msg.put("Identifier", "GenerateSSK");
+
+		msg.writeTo(os);
+
+		while (true) {
+			FCPMessage reply = FCPMessage.parse(is);
+			if ("ProtocolError".equals(reply.messageType))
+				throw new IOException("Protocol error");
+
+			if ("SSKKeypair".equals(reply.messageType)) {
+				String[] keys = new String[2];
+				keys[0] = reply.get("RequestURI");
+				keys[1] = reply.get("InsertURI");
+				return keys;
+			}
+		}
+	}
+
+	/**
+	 * Close the connection
+	 * 
+	 * @throws IOException
+	 *             if any I/O error occurred
+	 */
+	public void close() throws IOException {
+		os.close();
+		is.close();
+		socket.close();
+	}
+
+	private static class FCPMessage {
+		private String messageType;
+
+		private Map<String, String> parameter = new HashMap<String, String>();
+
+		byte[] extraData;
+
+		FCPMessage() {
+			// default constructor
+		}
+
+		private static FCPMessage parse(InputStream in) throws IOException {
+			FCPMessage ret = new FCPMessage();
+			String line = readLine(in);
+			ret.messageType = line;
+
+			while (true) {
+				line = readLine(in);
+
+				if (line == null)
+					throw new IOException("Malformed FCP message");
+				if ("EndMessage".equals(line))
+					break;
+				if ("Data".equals(line)) {
+					String strLen = ret.parameter.get("DataLength");
+					if (strLen == null)
+						throw new IOException("DataLength not found");
+					int len;
+					try {
+						len = Integer.parseInt(strLen);
+					} catch (NumberFormatException e) {
+						throw new IOException("DataLength malformed");
+					}
+					ret.extraData = readData(in, len);
+					break;
+				}
+
+				String[] v = line.split("=", 2);
+				if (v.length != 2)
+					throw new IOException("No '=' found in: " + line);
+				ret.parameter.put(v[0], v[1]);
+			}
+
+			return ret;
+		}
+
+		void put(String key, String value) {
+			parameter.put(key, value);
+		}
+
+		String get(String key) {
+			return parameter.get(key);
+		}
+
+		void writeTo(OutputStream os) throws IOException {
+			os.write(messageType.getBytes("UTF-8"));
+			os.write('\n');
+
+			for (Map.Entry<String, String> e : parameter.entrySet()) {
+				String l = e.getKey() + '=' + e.getValue();
+				os.write(l.getBytes("UTF-8"));
+				os.write('\n');
+			}
+
+			os.write("EndMessage".getBytes("UTF-8"));
+			os.write('\n');
+
+			if (extraData != null)
+				os.write(extraData);
+			os.flush();
+		}
+	}
+
+	private static String readLine(InputStream in) throws IOException {
+		byte[] buf = new byte[256];
+		int offset = 0;
+
+		while (true) {
+			int b = in.read();
+			if (b == -1)
+				return null;
+			if (b == '\n') {
+				if (offset == 0)
+					continue; // skip empty line
+				break;
+			}
+
+			if (offset == buf.length) {
+				if (offset >= 4096)
+					throw new IOException("line too long");
+
+				byte[] buf2 = new byte[buf.length * 2];
+				System.arraycopy(buf, 0, buf2, 0, buf.length);
+				buf = buf2;
+			}
+
+			buf[offset++] = (byte) b;
+		}
+
+		return new String(buf, 0, offset, "UTF-8");
+	}
+
+	private static byte[] readData(InputStream in, int len) throws IOException {
+		byte[] buf = new byte[len];
+		int read = 0;
+		while (read < len) {
+			int r = in.read(buf, read, len - read);
+			if (r == -1)
+				throw new IOException("Not enough data");
+			read += r;
+		}
+		return buf;
+	}
+}
-- 
1.6.2.rc2

^ permalink raw reply related

* [PoC PATCH JGIT 2/2] PoC Freenet transport
From: Daniel Cheng (aka SDiZ) @ 2009-03-09  3:36 UTC (permalink / raw)
  To: devl-RdDMkVZAZeuJnvDnx1genB2eb7JE58TQ, git-u79uwXL29TY76Z2rM5mHXA
  Cc: Daniel Cheng (aka SDiZ)
In-Reply-To: <1236569765-8882-2-git-send-email-j16sdiz+freenet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>


Signed-off-by: Daniel Cheng (aka SDiZ) <j16sdiz+freenet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 .../src/org/spearce/jgit/transport/Transport.java  |    3 +
 .../org/spearce/jgit/transport/TransportFcp2.java  |  436 ++++++++++++++++++++
 2 files changed, 439 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/TransportFcp2.java

diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java
index a0a2575..3fc1735 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java
@@ -206,6 +206,9 @@ else if (TransportGitAnon.canHandle(remote))
 		else if (TransportAmazonS3.canHandle(remote))
 			return new TransportAmazonS3(local, remote);
 
+		else if (TransportFcp2.canHandle(remote))
+			return new TransportFcp2(local, remote);
+		
 		else if (TransportBundleFile.canHandle(remote))
 			return new TransportBundleFile(local, remote);
 
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportFcp2.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportFcp2.java
new file mode 100644
index 0000000..ed12995
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportFcp2.java
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2009, CHENG Yuk-Pong, Daniel <j16sdiz+freenet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce-o8xcbExO1WpAfugRpC6u6w@public.gmane.org>
+ *
+ * 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.transport;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.spearce.jgit.errors.NotSupportedException;
+import org.spearce.jgit.errors.PackProtocolException;
+import org.spearce.jgit.errors.TransportException;
+import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.lib.NullProgressMonitor;
+import org.spearce.jgit.lib.ObjectId;
+import org.spearce.jgit.lib.ProgressMonitor;
+import org.spearce.jgit.lib.Ref;
+import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.lib.Ref.Storage;
+import org.spearce.jgit.transport.fcpv2.FCPConnection;
+
+/**
+ * Transport over Freenet Client Protocol 2.0
+ * <p>
+ * The Freenet transport is similar to HTTP Transport, but more restrictive. To
+ * workaround the freenet restrictions, path separator ('/') are replaced with
+ * dash ('-').
+ *<p>
+ * URI are in forms of <code>fcp://USK@PUBLIC_KEY/identifier</code> (read-only)
+ * or <code>fcp://USK@PUBLIC_KEY^PRIVATE_KEY/identifier</code>. The identifier
+ * must not contain any slash. The Freenet URI should begin with
+ * <code>SSK@</code>, all updatable component are converted to <code>USK@</code>
+ * internally.
+ * 
+ * @see WalkFetchConnection
+ */
+class TransportFcp2 extends WalkTransport {
+	static boolean canHandle(final URIish uri) {
+		if (!uri.isRemote())
+			return false;
+		final String s = uri.getScheme();
+		return "fcp".equals(s);
+	}
+
+	private final String publicKey;
+
+	private final String privateKey;
+
+	private final String identifier;
+
+	private FCPConnection fcp;
+
+	TransportFcp2(final Repository local, final URIish uri)
+			throws NotSupportedException {
+		super(local, uri);
+
+		String uriString = uri.toString();
+		if (!uriString.startsWith("fcp://SSK@"))
+			throw new NotSupportedException("URL not SSK@ " + uri);
+
+		String[] uriSegment = uriString.split("\\/");
+		if (uriSegment.length != 4)
+			throw new NotSupportedException("Invalid URL " + uri);
+
+		String[] keys = uriSegment[2].split("\\^");
+		if (keys.length > 2)
+			throw new NotSupportedException("Invalid URL " + uri);
+		publicKey = keys[0].substring(4); // Remove 'SSK@' prefix
+		privateKey = (keys.length == 2) ? keys[1] : null;
+		System.out.println(privateKey);
+		identifier = uriSegment[3];
+	}
+
+	@Override
+	public FetchConnection openFetch() throws TransportException {
+		try {
+			fcp = new FCPConnection();
+			fcp.connect();
+			fcp.hello("JGit-" + toString());
+
+			final Fcp2ObjectDB c = new Fcp2ObjectDB("/objects", false);
+			final WalkFetchConnection r = new WalkFetchConnection(this, c);
+			r.available(c.readAdvertisedRefs());
+			return r;
+		} catch (IOException e) {
+			throw new TransportException("IO Error" + e, e);
+		}
+	}
+
+	@Override
+	public PushConnection openPush() throws TransportException {
+		try {
+			fcp = new FCPConnection();
+			fcp.connect();
+			fcp.hello("JGit-" + toString());
+
+			final Fcp2ObjectDB c = new Fcp2ObjectDB("/objects", false);
+			final WalkPushConnection r = new WalkPushConnection(this, c);
+			r.available(c.readAdvertisedRefs());
+			return r;
+		} catch (IOException e) {
+			throw new TransportException("IO Error" + e, e);
+		}
+	}
+
+	@Override
+	public void close() {
+		try {
+			if (fcp != null)
+				fcp.close();
+		} catch (IOException e) {
+			// Fall through.
+		}
+		fcp = null;
+	}
+
+	class Fcp2ObjectDB extends WalkRemoteObjectDatabase {
+		private final String path;
+		private boolean useArchive;
+
+		@Override
+		void deleteFile(String path) throws IOException {
+			// TODO Auto-generated method stub
+			super.deleteFile(path);
+		}
+
+		@Override
+		OutputStream writeFile(String path, ProgressMonitor monitor,
+				String monitorTask) throws IOException {
+			System.err.println(" write -> " + path);
+			return new FcpOutputStream(path, monitor, monitorTask);
+		}
+
+		class FcpOutputStream extends OutputStream {
+			ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+			private String path;
+
+			private ProgressMonitor monitor;
+
+			private String monitorTask;
+
+			public FcpOutputStream(String path, ProgressMonitor monitor,
+					String monitorTask) {
+				if (monitor == null)
+					monitor = NullProgressMonitor.INSTANCE;
+				if (monitorTask == null)
+					monitorTask = "Uploading " + path;
+
+				this.path = path;
+				this.monitor = monitor;
+				this.monitorTask = monitorTask;
+			}
+
+			@Override
+			public void write(int b) throws IOException {
+				os.write(b);
+			}
+
+			@Override
+			public void close() throws IOException {
+				byte[] b = os.toByteArray();
+				os = null;
+
+				fcp.simplePut(getFreenetURI(path, true), b, monitor,
+						monitorTask);
+			}
+		}
+
+		Fcp2ObjectDB(String path, boolean useArchive) {
+			if (path.endsWith("/"))
+				path = path.substring(0, path.length() - 1);
+			if (!path.startsWith("/"))
+				path = "/" + path;
+			this.path = path;
+			this.useArchive = useArchive;
+		}
+
+		private String resolveKey(String subpath) {
+			if (subpath.endsWith("/"))
+				subpath = subpath.substring(0, subpath.length() - 1);
+			String k = path;
+			while (subpath.startsWith(ROOT_DIR)) {
+				k = k.substring(0, k.lastIndexOf('/'));
+				subpath = subpath.substring(3);
+			}
+			return k + "/" + subpath;
+		}
+
+		@Override
+		URIish getURI() {
+			try {
+				// just a pseudo-URIish for logging, not really supported
+				return new URIish("fcp://SSK@" + publicKey + "/" + identifier
+						+ path);
+			} catch (URISyntaxException e) {
+				return null;
+			}
+		}
+
+		@Override
+		Collection<WalkRemoteObjectDatabase> getAlternates() throws IOException {
+			if (!useArchive)	// try to use archive
+				return java.util.Arrays.asList( 
+				 new WalkRemoteObjectDatabase[] { new  Fcp2ObjectDB(path, true) } );
+			return null;
+		}
+
+		@Override
+		WalkRemoteObjectDatabase openAlternate(final String location)
+				throws IOException {
+			return null;
+		}
+
+		@Override
+		Collection<String> getPackNames() throws IOException {
+			final Collection<String> packs = new ArrayList<String>();
+			try {
+				final BufferedReader br = openReader(INFO_PACKS);
+				try {
+					for (;;) {
+						final String s = br.readLine();
+						if (s == null || s.length() == 0)
+							break;
+						if (!s.startsWith("P pack-") || !s.endsWith(".pack"))
+							throw invalidAdvertisement(s);
+						packs.add(s.substring(2));
+					}
+					return packs;
+				} finally {
+					br.close();
+				}
+			} catch (FileNotFoundException err) {
+				return packs;
+			}
+		}
+
+		@Override
+		FileStream open(final String path) throws IOException {
+			System.err.println(" read -> " + path);
+			byte[] b = fcp.simpleGet(getFreenetURI(path, false));
+			if (b == null)
+				throw new FileNotFoundException();
+
+			ByteArrayInputStream is = new ByteArrayInputStream(b);
+			return new FileStream(is);
+		}
+
+		private String getFreenetURI(final String path, boolean push) {
+			String key = push ? privateKey : publicKey;
+			String fPath = resolveKey(path);
+			String ret;
+
+			if (useArchive)
+				ret = "USK@" + key + "/" + identifier + "/1/" + fPath;
+			else
+				ret = "USK@" + key + "/" + identifier + fPath.replaceAll("\\/", "-") + "/1/";
+
+			System.err.println(ret);
+			return ret;
+		}
+
+		Map<String, Ref> readAdvertisedRefs() throws TransportException {
+			final TreeMap<String, Ref> avail = new TreeMap<String, Ref>();
+			try {
+				readPackedRefs(avail);
+			} catch (TransportException t) {}
+			try {
+				readInfoRefs(avail);
+			} catch (TransportException t) {}
+			try {
+				readRef(avail, Constants.HEAD);
+			} catch (TransportException t) {}
+
+			if (avail.isEmpty() && !useArchive) {
+				return  new Fcp2ObjectDB(path, true).readAdvertisedRefs();
+			}
+
+			return avail;
+		}
+
+		private Map<String, Ref> readInfoRefs(TreeMap<String, Ref> avail)
+				throws TransportException {
+			try {
+				final BufferedReader br = openReader(INFO_REFS);
+				for (;;) {
+					String line = br.readLine();
+					if (line == null)
+						break;
+
+					final int tab = line.indexOf('\t');
+					if (tab < 0)
+						throw invalidAdvertisement(line);
+
+					String name;
+					final ObjectId id;
+
+					name = line.substring(tab + 1);
+					id = ObjectId.fromString(line.substring(0, tab));
+					if (name.endsWith("^{}")) {
+						name = name.substring(0, name.length() - 3);
+						final Ref prior = avail.get(name);
+						if (prior == null)
+							throw outOfOrderAdvertisement(name);
+
+						if (prior.getPeeledObjectId() != null)
+							throw duplicateAdvertisement(name + "^{}");
+
+						avail.put(name, new Ref(Ref.Storage.NETWORK, name,
+								prior.getObjectId(), id, true));
+					} else {
+						final Ref prior = avail.put(name, new Ref(
+								Ref.Storage.NETWORK, name, id));
+						if (prior != null)
+							throw duplicateAdvertisement(name);
+					}
+				}
+				return avail;
+			} catch (IOException err) {
+				throw new TransportException(INFO_REFS
+						+ ": cannot read available refs", err);
+			}
+		}
+
+		private PackProtocolException outOfOrderAdvertisement(final String n) {
+			return new PackProtocolException("advertisement of " + n
+					+ "^{} came before " + n);
+		}
+
+		private PackProtocolException duplicateAdvertisement(final String n) {
+			return new PackProtocolException("duplicate advertisements of " + n);
+		}
+
+		private Ref readRef(final TreeMap<String, Ref> avail, final String rn)
+				throws TransportException {
+			final String s;
+			String ref = ROOT_DIR + rn;
+			try {
+				final BufferedReader br = openReader(ref);
+				try {
+					s = br.readLine();
+				} finally {
+					br.close();
+				}
+			} catch (FileNotFoundException noRef) {
+				return null;
+			} catch (IOException err) {
+				throw new TransportException(getURI(), "read " + ref, err);
+			}
+
+			if (s == null)
+				throw new TransportException(getURI(), "Empty ref: " + rn);
+
+			if (s.startsWith("ref: ")) {
+				final String target = s.substring("ref: ".length());
+				Ref r = avail.get(target);
+				if (r == null)
+					r = readRef(avail, target);
+				if (r == null)
+					return null;
+				r = new Ref(r.getStorage(), rn, r.getObjectId(), r
+						.getPeeledObjectId(), r.isPeeled());
+				avail.put(r.getName(), r);
+				return r;
+			}
+
+			if (ObjectId.isId(s)) {
+				// FIXME this does not really works
+				final Ref r = new Ref(loose(avail.get(rn)), rn, ObjectId
+						.fromString(s));
+				avail.put(r.getName(), r);
+				return r;
+			}
+
+			throw new TransportException(getURI(), "Bad ref: " + rn + ": " + s);
+		}
+
+		private Storage loose(final Ref r) {
+			if (r != null && r.getStorage() == Storage.PACKED)
+				return Storage.LOOSE_PACKED;
+			return Storage.LOOSE;
+		}
+
+		private PackProtocolException invalidAdvertisement(final String n) {
+			return new PackProtocolException("invalid advertisement of " + n);
+		}
+
+		@Override
+		void close() {
+			// We do not maintain persistent connections.
+		}
+	}
+}
-- 
1.6.2.rc2

^ permalink raw reply related

* Re: [PATCH] grep: make show_line more portable
From: Junio C Hamano @ 2009-03-09  3:52 UTC (permalink / raw)
  To: Brian Gernhardt; +Cc: Jay Soffian, Git List
In-Reply-To: <5ACAF49A-84B5-4F55-A8B8-0FC711708810@silverinsanity.com>

Brian Gernhardt <benji@silverinsanity.com> writes:

> On Mar 8, 2009, at 10:22 PM, Jay Soffian wrote:
>
>> On Sun, Mar 8, 2009 at 9:15 PM, Brian Gernhardt
>> <benji@silverinsanity.com> wrote:
>>> On OS X the printf specifier "%.0s" outputs the entire string instead
>>> of 0 characters as POSIX states.
>>
>> Does not reproduce for me:
>
> Nor for me, as I noted on the other thread...  And looking again, I
> was reading the man page for printf(1), not printf(3).  Ouch.
> *grumble, grumble*  I'm crawling back under my rock now.

Heh, people make mistakes and others are here to help spot them.
Collectively we all win.

Thanks for a breakage report, initial fix and a confirmation.

^ permalink raw reply

* Re: import files w/ history
From: Csaba Henk @ 2009-03-09  5:15 UTC (permalink / raw)
  To: git
In-Reply-To: <20090308001021.GA26167@coredump.intra.peff.net>

On 2009-03-08, Jeff King <peff@peff.net> wrote:
> What you really want to do is say:
>
>   - for every commit, narrow the tree to _just_ the one file
>
>   - if there were no changes in the narrowed tree, just throw out the
>     commit
>
> You can use an --index-filter to do the former, and a --commit-filter to
> do the latter (or just use --prune-empty, which is a shorthand).
>
> Another poster had a similar problem, and you can see the right
> filter-branch recipe there:
>
>   http://article.gmane.org/gmane.comp.version-control.git/111991

Thanks, this did the job.

>
> I think you need an extra '--' to separate the paths from the revisions
> in the rev-list arguments:
>
>   git filter-branch -- master -- sys/dev/disk/vn/vn.c
>
> but even that doesn't quite do what you want. It limits the commits that
> are shown, similar to your first attempt above, but it doesn't cut down
> the tree itself (OTOH, limiting by path rather than using --prune-empty
> is likely to run faster, since you won't even look at commits that are
> uninteresting. However, it may change the shape of your history with
> respect to branching and merging).

Finally I choose to add the path to the rev-list args -- 80 vs
15000 commits does make a difference. (I can still check if there was
any histroy [I just coined this from "history" and "destroy" :)] and
go back to the full-scan way if yes.)

But I still had a hard time with it... Finally I realized that if I do
filtering this way, I have to start filtering from the topmost commit
which affects the given file.

If I just start from origin/HEAD (assuming that it's on a commit which
does not affect the file), then it won't be found as a key of the mapping
created by git-filter-branch (as it's ignored because rev-listing was
narrowed down to the file), and therefore filter-branch finally punts
with "WARNING: Ref '<sha1>' is unchanged". I don't know if it's an
intended behaviour, or something which could/should be improved, or at
least documented... seems to be some sort of POLS violation to me (at
least I was surprised :) ).

Regards,
Csaba

^ permalink raw reply

* Re: [PoC PATCH JGIT 0/2] Proof of concept code for Git Freenet transport
From: Daniel Cheng @ 2009-03-09  5:58 UTC (permalink / raw)
  To: devl-RdDMkVZAZeuJnvDnx1genB2eb7JE58TQ, git-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1236569765-8882-1-git-send-email-j16sdiz+freenet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

On Mon, Mar 9, 2009 at 11:36 AM, Daniel Cheng (aka SDiZ)
<j16sdiz+freenet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> Hi JGit / Freenet community,
>
> Here is some proof-of-concept code for Git-over-Freenet.
> I am sending this to see the feedback from communities.

Sorry, all. The code I have posted wasn't work.
(the pack file is missing on push, only idx files are pushed)

The new, fixed code is now available at http://github.com/j16sdiz/egit-freenet/
Please use this repository if you want to actually try it.

>
> The code need some more cleanups, so it it is not ready for apply (yet).
>
> This is a real-life example
>
> Push:
>   $ git remote add fcp fcp://SSK@[my public key]^[my private key]/test.git
>   $ ./jgit push fcp refs/remotes/origin/stable:refs/heads/master
>
>  /ALTERNATIVLY/
>
>   Insert a bare repository under USK@<.....>/test.git/-1/
>
> Pull:
>  $ ./jgit clone fcp://SSK@[my public key]^[my private key]/test.git
>
>
> To workaround the metadata update problem, this client translate the
> path seperator to "-", that means:
>
> On push:
>   objects/aa/bbbbbbbb   --> USK@..../test.git-objects-aa-bbbbbbb/-1/
>   refs/heads/xxx        --> USK@..../test.git-objects-ref-heads-xxx/-1/
>
> On pull:
>   To support uploading from jSite,
>    when we load the info/refs we first check USK@..../test.git-info-refs/-1/
>    if it is unavailiable, we would use USK@..../test.git/-1/info/refs
>
>   The "traditional" type (USK@..../test.git/-1/objects) repository is
>   always added as an alternative objects database. No other info/alternatives
>   are supported
>
> FIXME:
>  - How to store the private key of repository?
>   Currently, we use URI of form fcp://SSK@<public key>^<private key>/some-id
>   This is quite ugly. Could we use a per remote Config ? How can I get remote
>   name from transport?
>
>  - Make pushing async, could we?
>
>
>

^ permalink raw reply

* [PATCH] contrib/difftool: use a separate config namespace for difftool commands
From: David Aguilar @ 2009-03-09  9:12 UTC (permalink / raw)
  To: git; +Cc: David Aguilar

Some users have different mergetool and difftool settings, so teach
difftool to read config vars from the difftool.* namespace.  This allows
having distinct configurations for the diff and merge scenarios.

We don't want to force existing users to set new values for no reason
so difftool falls back to existing mergetool config variables when the
difftool equivalents are not defined.

Signed-off-by: David Aguilar <davvid@gmail.com>
---

This patch was motivated by an upset user telling me that
"difftool is wasting screen real-estate by launching a 3-way diff".
After looking into it I realized that they needed to be able to
support a diff.tool that is separate from git-mergetool's merge.tool.

This patch brought up a few questions:

	Custom difftool commands use $LOCAL and $REMOTE just like
mergetool but in a diff there really is no $LOCAL or $REMOTE.
At best there's $PRE and $POST, but even that breaks down when
viewing reverse diffs. So really there's just $A and $B.
I felt that keeping difftool and mergetool consistent was the
best choice since users are already familiar with $LOCAL and $REMOTE.

	A lot of the difftool code traces its lineage to the
mergetool command and thus the code uses variables such as
$merge_tool when talking about diff tools.  Renaming all of the
variables seemed pointless and would also have made reviewing
this patch much more difficult so I chose to leave the variables
named as-is.  If someone is really bothered by the variable naming
then I can send a second patch that renames things, but doing so
basically results in a complete rewrite of difftool-helper and
the documentation with no real added benefit.

	Why does difftool fallback to mergetool when choosing
defaults?  Answer: backwards compatibility, respect existing users,
and be friendly to lazy users that don't feel like configuring a
separate config variable just for difftool when they've already
configured a merge.tool that works in both situations as-is
(e.g. any of the built-in tools such as xxdiff, vimdiff, etc.)

 contrib/difftool/git-difftool        |    6 +++---
 contrib/difftool/git-difftool-helper |   19 ++++++++++++++-----
 contrib/difftool/git-difftool.txt    |   30 +++++++++++++++---------------
 3 files changed, 32 insertions(+), 23 deletions(-)

diff --git a/contrib/difftool/git-difftool b/contrib/difftool/git-difftool
index 0cda3d2..0deda3a 100755
--- a/contrib/difftool/git-difftool
+++ b/contrib/difftool/git-difftool
@@ -4,7 +4,7 @@
 # This is a wrapper around the GIT_EXTERNAL_DIFF-compatible
 # git-difftool-helper script.  This script exports
 # GIT_EXTERNAL_DIFF and GIT_PAGER for use by git, and
-# GIT_DIFFTOOL_NO_PROMPT and GIT_MERGE_TOOL for use by git-difftool-helper.
+# GIT_DIFFTOOL_NO_PROMPT and GIT_DIFF_TOOL for use by git-difftool-helper.
 # Any arguments that are unknown to this script are forwarded to 'git diff'.
 
 use strict;
@@ -49,12 +49,12 @@ sub generate_command
 		}
 		if ($arg eq '-t' or $arg eq '--tool') {
 			usage() if $#ARGV <= $idx;
-			$ENV{GIT_MERGE_TOOL} = $ARGV[$idx + 1];
+			$ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
 			$skip_next = 1;
 			next;
 		}
 		if ($arg =~ /^--tool=/) {
-			$ENV{GIT_MERGE_TOOL} = substr($arg, 7);
+			$ENV{GIT_DIFF_TOOL} = substr($arg, 7);
 			next;
 		}
 		if ($arg eq '--no-prompt') {
diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper
index db3af6a..9c0a134 100755
--- a/contrib/difftool/git-difftool-helper
+++ b/contrib/difftool/git-difftool-helper
@@ -128,8 +128,10 @@ launch_merge_tool () {
 	cleanup_temp_files
 }
 
-# Verifies that mergetool.<tool>.cmd exists
+# Verifies that (difftool|mergetool).<tool>.cmd exists
 valid_custom_tool() {
+	merge_tool_cmd="$(git config difftool.$1.cmd)"
+	test -z "$merge_tool_cmd" &&
 	merge_tool_cmd="$(git config mergetool.$1.cmd)"
 	test -n "$merge_tool_cmd"
 }
@@ -150,8 +152,11 @@ valid_tool() {
 }
 
 # Sets up the merge_tool_path variable.
-# This handles the mergetool.<tool>.path configuration.
+# This handles the difftool.<tool>.path configuration.
+# This also falls back to mergetool defaults.
 init_merge_tool_path() {
+	merge_tool_path=$(git config difftool."$1".path)
+	test -z "$merge_tool_path" &&
 	merge_tool_path=$(git config mergetool."$1".path)
 	if test -z "$merge_tool_path"; then
 		case "$1" in
@@ -165,15 +170,19 @@ init_merge_tool_path() {
 	fi
 }
 
-# Allow the GIT_MERGE_TOOL variable to provide a default value
+# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values
 test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL"
+test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL"
 
-# If not merge tool was specified then use the merge.tool
+# If merge tool was not specified then use the diff.tool
 # configuration variable.  If that's invalid then reset merge_tool.
+# Fallback to merge.tool.
 if test -z "$merge_tool"; then
+	merge_tool=$(git config diff.tool)
+	test -z "$merge_tool" &&
 	merge_tool=$(git config merge.tool)
 	if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
-		echo >&2 "git config option merge.tool set to unknown tool: $merge_tool"
+		echo >&2 "git config option diff.tool set to unknown tool: $merge_tool"
 		echo >&2 "Resetting to default..."
 		unset merge_tool
 	fi
diff --git a/contrib/difftool/git-difftool.txt b/contrib/difftool/git-difftool.txt
index 6e2610c..2b7bc03 100644
--- a/contrib/difftool/git-difftool.txt
+++ b/contrib/difftool/git-difftool.txt
@@ -32,23 +32,23 @@ OPTIONS
 	vimdiff, gvimdiff, ecmerge, and opendiff
 +
 If a merge resolution program is not specified, 'git-difftool'
-will use the configuration variable `merge.tool`.  If the
-configuration variable `merge.tool` is not set, 'git difftool'
+will use the configuration variable `diff.tool`.  If the
+configuration variable `diff.tool` is not set, 'git-difftool'
 will pick a suitable default.
 +
 You can explicitly provide a full path to the tool by setting the
-configuration variable `mergetool.<tool>.path`. For example, you
+configuration variable `difftool.<tool>.path`. For example, you
 can configure the absolute path to kdiff3 by setting
-`mergetool.kdiff3.path`. Otherwise, 'git-difftool' assumes the
+`difftool.kdiff3.path`. Otherwise, 'git-difftool' assumes the
 tool is available in PATH.
 +
 Instead of running one of the known merge tool programs,
 'git-difftool' can be customized to run an alternative program
 by specifying the command line to invoke in a configuration
-variable `mergetool.<tool>.cmd`.
+variable `difftool.<tool>.cmd`.
 +
 When 'git-difftool' is invoked with this tool (either through the
-`-t` or `--tool` option or the `merge.tool` configuration variable)
+`-t` or `--tool` option or the `diff.tool` configuration variable)
 the configured command line will be invoked with the following
 variables available: `$LOCAL` is set to the name of the temporary
 file containing the contents of the diff pre-image and `$REMOTE`
@@ -61,24 +61,24 @@ with custom merge tool commands and has the same value as `$LOCAL`.
 
 CONFIG VARIABLES
 ----------------
-merge.tool::
-	The default merge tool to use.
-+
-See the `--tool=<tool>` option above for more details.
+'git-difftool' falls back to 'git-mergetool' config variables when the
+difftool equivalents have not been defined.
 
-merge.keepBackup::
-	The original, unedited file content can be saved to a file with
-	a `.orig` extension.  Defaults to `true` (i.e. keep the backup files).
+diff.tool::
+	The default merge tool to use.
 
-mergetool.<tool>.path::
+difftool.<tool>.path::
 	Override the path for the given tool.  This is useful in case
 	your tool is not in the PATH.
 
-mergetool.<tool>.cmd::
+difftool.<tool>.cmd::
 	Specify the command to invoke the specified merge tool.
 +
 See the `--tool=<tool>` option above for more details.
 
+merge.keepBackup::
+	The original, unedited file content can be saved to a file with
+	a `.orig` extension.  Defaults to `true` (i.e. keep the backup files).
 
 SEE ALSO
 --------
-- 
1.6.2.77.g8cc3f

^ permalink raw reply related

* Re: [PATCH 0/2] Move push logic to transport.c
From: Johannes Schindelin @ 2009-03-09  9:35 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, git
In-Reply-To: <alpine.LNX.1.00.0903082046280.19665@iabervon.org>

Hi,

On Sun, 8 Mar 2009, Daniel Barkalow wrote:

> It doesn't convert http-push or the rsync transports, largely because I 
> don't have test setups for rsync or webdav to make sure that they're 
> still working.

$ ls t/*http-push*
t/t5540-http-push.sh

$ git grep -n test.*rsync t/
t/t5510-fetch.sh:195:test_expect_success 'fetch via rsync' '
t/t5510-fetch.sh:206:test_expect_success 'push via rsync' '
t/t5510-fetch.sh:217:test_expect_success 'push via rsync' '

It should be just a matter of installing an apache and rsync.

BTW thanks for the patch, I guess it will help Peff to complete "push 
--track" properly ;-)

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH 1/2] Use a common function to get the pretty name of refs
From: Johannes Schindelin @ 2009-03-09  9:38 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, git
In-Reply-To: <alpine.LNX.1.00.0903082104410.19665@iabervon.org>

Hi,

On Sun, 8 Mar 2009, Daniel Barkalow wrote:

> The result should be consistent between fetch and push, so we ought to 
> use the same code in both cases, even though it's short.

You might want to mention that we cannot use skip_prefix() here, as that 
function does not give us any clue if something was skipped at all, and we 
must _not_ skip multiple prefixes.

Ciao,
Dscho

^ permalink raw reply

* Re: [EGIT PATCH] Show diff when double-clicking on file in commit dialog
From: Robin Stocker @ 2009-03-09  9:48 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: Shawn O. Pearce, git
In-Reply-To: <200903082259.35886.robin.rosenberg.lists@dewire.com>

When double-clicking on a file in the commit dialog, a compare dialog is
shown with the changes that are about to be committed. It compares the
HEAD version with the working tree version.

Signed-off-by: Robin Stocker <robin@nibor.org>
---

Robin Rosenberg schrieb:
> söndag 08 mars 2009 21:09:49 skrev Robin Stocker <robin@nibor.org>:
>> An essential feature I miss in EGit at the moment (apart from the
>> synchronize view [1]) is seeing what changes one is about to commit. In
>> the Subclipse SVN plugin one can double-click a file in the commit
>> dialog and the diff is shown.
> Hi, Robin. I miss that too!
> 
>> This patch is a first step for adding this to EGit. It only compares the
>> index version to the working tree version as I couldn't figure out an
>> easy way to get the HEAD version.
> You can look at how GitDocument does it.
> 
>> It's more a proof of concept than a final patch. What do you think?
> 
> I've started on an version with the diff integrated into the same dialog, for
> some reasons it's not done yet, but we might takes this meanwhile unless
> I complete the dialog real quick, as this is really useful, provided we compare
> with HEAD.

That sounds even better! For the meantime, I've updated the patch to
compare with HEAD.

-- Robin

.../egit/ui/internal/dialogs/CommitDialog.java     |   56 ++++++++++++++++++++
 1 files changed, 56 insertions(+), 0 deletions(-)

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/dialogs/CommitDialog.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/dialogs/CommitDialog.java
index 8b7fe45..b69a4ba 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/dialogs/CommitDialog.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/dialogs/CommitDialog.java
@@ -18,6 +18,8 @@
 import java.util.Comparator;
 import java.util.Iterator;
 
+import org.eclipse.compare.CompareUI;
+import org.eclipse.compare.ITypedElement;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.jface.dialogs.Dialog;
@@ -52,9 +54,17 @@
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableColumn;
 import org.eclipse.swt.widgets.Text;
+import org.eclipse.team.core.RepositoryProvider;
+import org.eclipse.team.core.history.IFileHistory;
+import org.eclipse.team.core.history.IFileRevision;
+import org.eclipse.team.internal.ui.history.FileRevisionTypedElement;
 import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.spearce.egit.core.GitProvider;
+import org.spearce.egit.core.internal.storage.GitFileHistoryProvider;
 import org.spearce.egit.core.project.RepositoryMapping;
 import org.spearce.egit.ui.UIText;
+import org.spearce.egit.ui.internal.GitCompareFileRevisionEditorInput;
+import org.spearce.jgit.lib.Commit;
 import org.spearce.jgit.lib.Constants;
 import org.spearce.jgit.lib.GitIndex;
 import org.spearce.jgit.lib.PersonIdent;
@@ -262,6 +272,8 @@ public void modifyText(ModifyEvent e) {
 		resourcesTable.setLayoutData(GridDataFactory.fillDefaults().hint(600,
 				200).span(2,1).grab(true, true).create());
 
+		resourcesTable.addSelectionListener(new CommitItemSelectionListener());
+
 		resourcesTable.setHeaderVisible(true);
 		TableColumn statCol = new TableColumn(resourcesTable, SWT.LEFT);
 		statCol.setText(UIText.CommitDialog_Status);
@@ -505,6 +517,50 @@ public void widgetSelected(SelectionEvent e) {
 
 	}
 
+	class CommitItemSelectionListener extends SelectionAdapter {
+
+		public void widgetDefaultSelected(SelectionEvent e) {
+			IStructuredSelection selection = (IStructuredSelection) filesViewer.getSelection();
+
+			CommitItem commitItem = (CommitItem) selection.getFirstElement();
+			if (commitItem == null) {
+				return;
+			}
+
+			IProject project = commitItem.file.getProject();
+			RepositoryMapping mapping = RepositoryMapping.getMapping(project);
+			if (mapping == null) {
+				return;
+			}
+			Repository repository = mapping.getRepository();
+
+			Commit headCommit;
+			try {
+				headCommit = repository.mapCommit(Constants.HEAD);
+			} catch (IOException e1) {
+				headCommit = null;
+			}
+			if (headCommit == null) {
+				return;
+			}
+
+			GitProvider provider = (GitProvider) RepositoryProvider.getProvider(project);
+			GitFileHistoryProvider fileHistoryProvider = (GitFileHistoryProvider) provider.getFileHistoryProvider();
+
+			IFileHistory fileHistory = fileHistoryProvider.getFileHistoryFor(commitItem.file, 0, null);
+
+			IFileRevision baseFile = fileHistory.getFileRevision(headCommit.getCommitId().name());
+			IFileRevision nextFile = fileHistoryProvider.getWorkspaceFileRevision(commitItem.file);
+
+			ITypedElement base = new FileRevisionTypedElement(baseFile);
+			ITypedElement next = new FileRevisionTypedElement(nextFile);
+
+			GitCompareFileRevisionEditorInput input = new GitCompareFileRevisionEditorInput(base, next, null);
+			CompareUI.openCompareDialog(input);
+		}
+
+	}
+
 	@Override
 	protected void okPressed() {
 		commitMessage = commitText.getText();
-- 
1.6.1.2

^ permalink raw reply related

* Re: [PATCH] grep: make show_line more portable
From: Johannes Schindelin @ 2009-03-09  9:50 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Brian Gernhardt, Jay Soffian, Git List
In-Reply-To: <7vbpsbic85.fsf@gitster.siamese.dyndns.org>

Hi,

On Sun, 8 Mar 2009, Junio C Hamano wrote:

> Brian Gernhardt <benji@silverinsanity.com> writes:
> 
> > On Mar 8, 2009, at 10:22 PM, Jay Soffian wrote:
> >
> >> On Sun, Mar 8, 2009 at 9:15 PM, Brian Gernhardt
> >> <benji@silverinsanity.com> wrote:
> >>> On OS X the printf specifier "%.0s" outputs the entire string instead
> >>> of 0 characters as POSIX states.
> >>
> >> Does not reproduce for me:
> >
> > Nor for me, as I noted on the other thread...  And looking again, I
> > was reading the man page for printf(1), not printf(3).  Ouch.
> > *grumble, grumble*  I'm crawling back under my rock now.
> 
> Heh, people make mistakes and others are here to help spot them.
> Collectively we all win.

One of my favorite quotes these days:

The computer "doth make fools of us all," so that any fool without the 
ability to share a laugh on himself will be unable to tolerate programming 
for long. ''(Gerald M. Weinberg)''

> Thanks for a breakage report, initial fix and a confirmation.

Yes, I think this discussion was valuable, not only because it fixed a 
bug, but also because I learnt that %.*s with a negative length defaults 
to the total string.

Ciao,
Dscho

^ permalink raw reply

* Re: [PoC PATCH JGIT 0/2] Proof of concept code for Git Freenet transport
From: Johannes Schindelin @ 2009-03-09  9:58 UTC (permalink / raw)
  To: Daniel Cheng (aka SDiZ); +Cc: devl, git
In-Reply-To: <1236569765-8882-1-git-send-email-j16sdiz+freenet@gmail.com>

Hi,

On Mon, 9 Mar 2009, Daniel Cheng (aka SDiZ) wrote:

> Hi JGit / Freenet community,
> 
> Here is some proof-of-concept code for Git-over-Freenet.

Thanks!

I was talking to some Freenet guys at the GSoC mentor summit 2007, and 
always wanted to give it a try (albeit using C Git, not JGit), but that 
item just got pushed off my TODO list...

Ciao,
Dscho

^ permalink raw reply

* Re: Git for Windows 1.6.2-preview20090308
From: Rutger Nijlunsing @ 2009-03-09 10:34 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, msysgit
In-Reply-To: <alpine.DEB.1.00.0903080132470.10279@pacific.mpi-cbg.de>


On Sun, Mar 08, 2009 at 02:10:21AM +0100, Johannes Schindelin wrote:
> 
> Hi,
> 
> I just released a new version of Git for Windows (TAFKA WinGit).  It is 
> basically Git 1.6.2 plus a few patches.  Please find the installer here:
> 
> 	http://msysgit.googlecode.com/
> 
[snip]
> Changes since Git-1.6.1-preview20081225
> 
> Bugfixes
> - Comes with updated msys-1.0.dll (should fix some Vista issues).

Thanks! This also fixes the 'git hangs 5s without any reason on some
Windows XP machines'!


-- 
Rutger Nijlunsing ---------------------------------- eludias ed dse.nl
never attribute to a conspiracy which can be explained by incompetence
----------------------------------------------------------------------

^ permalink raw reply

* Re: Git for Windows 1.6.2-preview20090308
From: Johannes Schindelin @ 2009-03-09 10:37 UTC (permalink / raw)
  To: git; +Cc: git, msysgit
In-Reply-To: <20090309103414.GA5247@wingding.demon.nl>


Hi,

On Mon, 9 Mar 2009, Rutger Nijlunsing wrote:

> On Sun, Mar 08, 2009 at 02:10:21AM +0100, Johannes Schindelin wrote:
> > 
> > Hi,
> > 
> > I just released a new version of Git for Windows (TAFKA WinGit).  It is 
> > basically Git 1.6.2 plus a few patches.  Please find the installer here:
> > 
> > 	http://msysgit.googlecode.com/
> > 
> [snip]
> > Changes since Git-1.6.1-preview20081225
> > 
> > Bugfixes
> > - Comes with updated msys-1.0.dll (should fix some Vista issues).
> 
> Thanks! This also fixes the 'git hangs 5s without any reason on some
> Windows XP machines'!

Good to know!

Thanks,
Dscho

^ permalink raw reply

* Re: Help designing work flow
From: Andreas Ericsson @ 2009-03-09 10:55 UTC (permalink / raw)
  To: John Dlugosz; +Cc: git
In-Reply-To: <450196A1AAAE4B42A00A8B27A59278E709F07D30@EXCHANGE.trad.tradestation.com>

John Dlugosz wrote:
> I know we (my group) should use "topic" branches and apply them back to
> the dev branch when done.  There is concern that the commit history gets
> too full of detailed stuff, especially with several developers, that you
> can't tell what "really changed".  So, our dev branch should appear to
> contain only commit nodes representing completed assignments; not every
> day's checkpoint and trying to keep one's own stuff on top to avoid
> merging later.
> 
> I guess that's how it is on these Open Source projects where patches are
> submitted by email and applied by the maintainer.  We don't see the
> details, just the final patch.  But, my situation will be developers
> gathered around an in-house master repo, and everyone should be able to
> push their own changes as assignments are completed.
> 
> What is the best procedure to achieve that?  Or what are some good
> alternatives with trade-offs?
> 

Use topic-branches and let someone merge them into master after having
verified that they work properly.

We usually commit simple bugfixes directly to master and then have
developers rebase their changes onto master when they're ready to
integrate it. They push their development branches though, and further
changes to the topic are done on the topic-branches which can get
merged to master (or stable) many times. Once a topic is merged, we
always "git commit --amend" the merge commit to write a proper
commit-message for it, adding a link to our bug- and feature-tracker
so we get the at-a-glance information quickly and can dig up the
entire discussion history around the bug/feature later. Each topic
should be complete with documentation and test-cases before it's
merged.


> I see that if a topic branch is merged (disabling FF if applicable), the
> main line (leftmost parent) will be a history of completed topics.  But,
> we don't need to keep the detailed side-branches forever, and even if
> gitk and other visualization  tools can be told to just show the main
> line, advanced use such as git log this..that will forever be packed
> with the micro-details.
> 

You can tell "git log" to only show one line of history too, but besides
that, micro-details are good. You definitely want to be able to search
the micro-details when things go awry (and they will), so you see exactly
why some particular algorithm changed later.

> So, unless someone has more input along that line, I'm assuming that we
> want to apply the completed topic as a single-parent commit.  That is
> the natural result if preparing patches and then applying them, but is
> there a simpler, direct way to do that in git?
> 

You do not want to do that. We did it for a while, and it was hell when
we found out that one of them broke down. The really, really *nice* thing
about git is called "git bisect". What makes it so awesomely nice is
that, instead of looking at a 100k diff-file knowing that somewhere in
there a bug was introduced, you get (with good discipline using small
commits), a 1-40 line patch with a clear and concise message of why
those changes were thought necessary at that time. Applying a topic
branch as a single patch would rob you of that functionality, and you
will regret it. Trust me on this.

> The detailed topic branches can be kept around for a while, for the
> original author to extend if it needs to be returned to, and to examine
> if the gestalt change in the single commit is too overwhelming to
> understand, or to help figure out what might have broken.  But after a
> while they can be deleted and then gc will free up the disk space.
> 

But if they do need to be returned to, you cannot merge them again if
you've already applied the topic-patch (ugh), since you'd get conflicts
if any of the sections touched by the patch have been changed since.

We use topic-branches quite a lot. When we're done with them we delete
the branch-pointers but I wouldn't, ever, dream of re-cooking them as
mega-patches when applying them to master.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

Considering the successes of the wars on alcohol, poverty, drugs and
terror, I think we should give some serious thought to declaring war
on peace.

^ permalink raw reply

* [CVSPS PATCH] fix: correct rev order in case commiters clocks were not syncronised
From: Heiko Voigt @ 2009-03-09 11:26 UTC (permalink / raw)
  To: Michael Haggerty, Junio C Hamano, ydirson; +Cc: git
In-Reply-To: <49AC1E88.1010709@hvoigt.net>

This fixes the following kind of cvsps issues:

 Structure of the test cvs repository

 Message   File:Content         Commit Time
 Rev 1     a: 1.1               2009-02-21 19:11:43 +0100
 Rev 2     a: 1.2    b: 1.1     2009-02-21 19:11:14 +0100
 Rev 3               b: 1.2     2009-02-21 19:11:43 +0100

 As you can see the commit of Rev 3 has the same time as
 Rev 1 this was leading to a broken estimation of patchset
 order.

Signed-off-by: Heiko Voigt <hvoigt@hvoigt.net>
---
After precisely formulating my problem with cvsps I was curious if this
issue actually could be fixed. Additionally I don't want my test to be
disabled ;). This patch seems to fix it. Is Yann still maintaining the
patches for cvsps or should I forward this patch to someone else ?

Calculating with time_t like I did is probably not valid on all systems
if you know of a nicer, more portable solution please let me know.

 cvsps.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/cvsps.c b/cvsps.c
index 81c6e21..d5c30d4 100644
--- a/cvsps.c
+++ b/cvsps.c
@@ -259,6 +259,32 @@ int main(int argc, char *argv[])
     exit(0);
 }
 
+void detect_and_repair_time_skew(const char *last_date, char *date, int n,
+                                 const char *filename)
+{
+
+    time_t smaller;
+    time_t bigger;
+    struct tm *ts;
+
+    /* if last_date does not exist do nothing */
+    if (last_date[0] == '\0')
+        return;
+
+    /* important: because rlog is showing revisions backwards last_date should
+     * always be bigger than date */
+    convert_date(&bigger, last_date);
+    convert_date(&smaller, date);
+
+    if (difftime(bigger, smaller) <= 0) {
+        debug(DEBUG_APPMSG1, "broken revision date: %s -> %s file: %s, repairing.\n",
+              date, last_date, filename);
+        smaller = bigger - 1;
+        ts = gmtime(&smaller);
+        strftime(date, n, "%Y-%m-%d %H:%M:%S", ts);
+    }
+}
+
 static void load_from_cvs()
 {
     FILE * cvsfp;
@@ -267,6 +293,7 @@ static void load_from_cvs()
     CvsFile * file = NULL;
     PatchSetMember * psm = NULL;
     char datebuff[20];
+    char last_datebuff[20];
     char authbuff[AUTH_STR_MAX];
     int logbufflen = LOG_STR_MAX + 1;
     char * logbuff = malloc(logbufflen);
@@ -334,6 +361,8 @@ static void load_from_cvs()
 	exit(1);
     }
 
+    /* initialize the last_datebuff with value indicating invalid date */
+    last_datebuff[0]='\0';
     for (;;)
     {
 	char * tst;
@@ -474,8 +503,14 @@ static void load_from_cvs()
 	    {
 		if (psm)
 		{
+		    detect_and_repair_time_skew(last_datebuff, datebuff, 20, psm->file->filename);
 		    PatchSet * ps = get_patch_set(datebuff, logbuff, authbuff, psm->post_rev->branch, psm);
 		    patch_set_add_member(ps, psm);
+
+		    /* remember last revision */
+		    strncpy(last_datebuff, datebuff, 20);
+		    /* just to be sure */
+		    last_datebuff[19] = '\0';
 		}
 
 		logbuff[0] = 0;
@@ -487,8 +522,13 @@ static void load_from_cvs()
 	    {
 		if (psm)
 		{
+		    detect_and_repair_time_skew(last_datebuff, datebuff, 20, psm->file->filename);
 		    PatchSet * ps = get_patch_set(datebuff, logbuff, authbuff, psm->post_rev->branch, psm);
 		    patch_set_add_member(ps, psm);
+
+		    /* just finished the last revision of this file, set last_datebuff to invalid */
+		    last_datebuff[0]='\0';
+
 		    assign_pre_revision(psm, NULL);
 		}
 

^ permalink raw reply related

* Re: [freenet-dev] [PoC PATCH JGIT 0/2] Proof of concept code for Git  Freenet transport
From: Daniel Cheng @ 2009-03-09 11:35 UTC (permalink / raw)
  To: Discussion of development issues; +Cc: git
In-Reply-To: <1541866875@web.de>

On Mon, Mar 9, 2009 at 6:46 PM,  <bo-le@web.de> wrote:
>> -----Ursprüngliche Nachricht-----
>> Von: "Daniel Cheng (aka SDiZ)" <j16sdiz+freenet@gmail.com>
>> Gesendet: 09.03.09 04:36:25
>> An:  git@vger.kernel.org
>> Betreff: [freenet-dev] [PoC PATCH JGIT 0/2] Proof of concept code for Git Freenet transport
>
>> Hi JGit / Freenet community,
>>
>> Here is some proof-of-concept code for Git-over-Freenet.
>> I am sending this to see the feedback from communities.
>>
>> The code need some more cleanups, so it it is not ready for apply (yet).
>>
>> This is a real-life example
>>
>> Push:
>>    $ git remote add fcp fcp://SSK@[my public key]^[my private key]/test.git
>>    $ ./jgit push fcp refs/remotes/origin/stable:refs/heads/master
>>
>>  /ALTERNATIVLY/
>>
>>    Insert a bare repository under USK@<.....>/test.git/-1/
>>
>> Pull:
>>  $ ./jgit clone fcp://SSK@[my public key]^[my private key]/test.git
>
> a pull from fproxy should be possible. so the average user can grab and build sources with an unpatched/regular git version
> $ git clone http://127.0.0.1:8888/key/app.git  //grab & build a app
> $ git clone http://127.0.0.1:8888/key/jFreeGit.git  //ha, bootstrap! grab & build the modified git for creating repos in freenet
>
>>
>>
>> To workaround the metadata update problem, this client translate the
>> path seperator to "-", that means:
>
> you need to mangele path names properly, it may fail on names with '-' inside.

It doesn't matter -- we don't have to convert it back.

>> On push:
>>    objects/aa/bbbbbbbb   --> USK@..../test.git-objects-aa-bbbbbbb/-1/
>>    refs/heads/xxx        --> USK@..../test.git-objects-ref-heads-xxx/-1/
>>
> why not 'USK@..../test.git/1/objects/aa/bbbbbbb' ?

In freenet,
all files under   USK@..../test.git/1/* are packed in a zip file and
must be updated at once.
If we do this, we have to upload all pack files again on every push --
this is very bad.

see http://wiki.github.com/j16sdiz/egit-freenet for more detail reply.

>> On pull:
>>    To support uploading from jSite,
>>     when we load the info/refs we first check USK@..../test.git-info-refs/-1/
>>     if it is unavailiable, we would use USK@..../test.git/-1/info/refs
>>
>>    The "traditional" type (USK@..../test.git/-1/objects) repository is
>>    always added as an alternative objects database. No other info/alternatives
>>    are supported
>>
>> FIXME:
>>  - How to store the private key of repository?
> hg have a per repository config. was quite easy here ;)
>
>>    Currently, we use URI of form fcp://SSK@<public key>^<private key>/some-id
>>    This is quite ugly. Could we use a per remote Config ? How can I get remote
>>    name from transport?
>>
>>  - Make pushing async, could we?
> inserting to an USK should be blocking until the toplevel chunk is in. this is a helpful tactic to hold the edition chain clean.

^ permalink raw reply

* Re: Help designing work flow
From: John Tapsell @ 2009-03-09 11:44 UTC (permalink / raw)
  To: Andreas Ericsson; +Cc: John Dlugosz, git
In-Reply-To: <49B4F5A9.5060304@op5.se>

2009/3/9 Andreas Ericsson <ae@op5.se>:
> John Dlugosz wrote:
>>
>> I know we (my group) should use "topic" branches and apply them back to
>> the dev branch when done.  There is concern that the commit history gets
>> too full of detailed stuff, especially with several developers, that you
>> can't tell what "really changed".  So, our dev branch should appear to
>> contain only commit nodes representing completed assignments; not every
>> day's checkpoint and trying to keep one's own stuff on top to avoid
>> merging later.
>>
>> I guess that's how it is on these Open Source projects where patches are
>> submitted by email and applied by the maintainer.  We don't see the
>> details, just the final patch.  But, my situation will be developers
>> gathered around an in-house master repo, and everyone should be able to
>> push their own changes as assignments are completed.
>>
>> What is the best procedure to achieve that?  Or what are some good
>> alternatives with trade-offs?
>>
>
> Use topic-branches and let someone merge them into master after having
> verified that they work properly.
>
> We usually commit simple bugfixes directly to master and then have
> developers rebase their changes onto master when they're ready to

The trouble with rebasing is that it then you end up with lots of
patches that haven't been tested.  You can end up with lots of
uncompiling commits.

Although merging is no better either.  Then you end up with one single
commit that tries to merge two trees, making it almost impossible to
track down bugs that resulted from the merge.

> integrate it. They push their development branches though, and further
> changes to the topic are done on the topic-branches which can get
> merged to master (or stable) many times. Once a topic is merged, we
> always "git commit --amend" the merge commit to write a proper
> commit-message for it, adding a link to our bug- and feature-tracker
> so we get the at-a-glance information quickly and can dig up the
> entire discussion history around the bug/feature later. Each topic
> should be complete with documentation and test-cases before it's
> merged.
>
>
>> I see that if a topic branch is merged (disabling FF if applicable), the
>> main line (leftmost parent) will be a history of completed topics.  But,
>> we don't need to keep the detailed side-branches forever, and even if
>> gitk and other visualization  tools can be told to just show the main
>> line, advanced use such as git log this..that will forever be packed
>> with the micro-details.
>>
>
> You can tell "git log" to only show one line of history too, but besides
> that, micro-details are good. You definitely want to be able to search
> the micro-details when things go awry (and they will), so you see exactly
> why some particular algorithm changed later.
>
>> So, unless someone has more input along that line, I'm assuming that we
>> want to apply the completed topic as a single-parent commit.  That is
>> the natural result if preparing patches and then applying them, but is
>> there a simpler, direct way to do that in git?
>>
>
> You do not want to do that. We did it for a while, and it was hell when
> we found out that one of them broke down. The really, really *nice* thing
> about git is called "git bisect". What makes it so awesomely nice is
> that, instead of looking at a 100k diff-file knowing that somewhere in
> there a bug was introduced, you get (with good discipline using small
> commits), a 1-40 line patch with a clear and concise message of why
> those changes were thought necessary at that time. Applying a topic
> branch as a single patch would rob you of that functionality, and you
> will regret it. Trust me on this.
>
>> The detailed topic branches can be kept around for a while, for the
>> original author to extend if it needs to be returned to, and to examine
>> if the gestalt change in the single commit is too overwhelming to
>> understand, or to help figure out what might have broken.  But after a
>> while they can be deleted and then gc will free up the disk space.
>>
>
> But if they do need to be returned to, you cannot merge them again if
> you've already applied the topic-patch (ugh), since you'd get conflicts
> if any of the sections touched by the patch have been changed since.
>
> We use topic-branches quite a lot. When we're done with them we delete
> the branch-pointers but I wouldn't, ever, dream of re-cooking them as
> mega-patches when applying them to master.
>
> --
> Andreas Ericsson                   andreas.ericsson@op5.se
> OP5 AB                             www.op5.se
> Tel: +46 8-230225                  Fax: +46 8-230231
>
> Considering the successes of the wars on alcohol, poverty, drugs and
> terror, I think we should give some serious thought to declaring war
> on peace.
> --
> 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

* Re: [PATCH] http: add_fill_function checks if function has been added
From: Tay Ray Chuan @ 2009-03-09 12:01 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vd4crls8q.fsf@gitster.siamese.dyndns.org>

Hi,

On Mon, Mar 9, 2009 at 3:38 AM, Junio C Hamano <gitster@pobox.com> wrote:
> That is not what I was worried about.  There are two callsites to
> add_fill_function().

I'm sorry I didn't catch this from your earlier message; on a
re-reading I caught it.

> But it is not immediately obvious in http-walker.c callchain if multiple
> calls to add_fill_function(), if they were ever made, give the same
> "walker" as the callback data.  Your patch only looks at the function but
> not the callback data for its filtering.  Doesn't it mean that if a caller
> made two calls to add_fill_function() with walker#1 and then walker#2 as
> the callback data, you would discard the request for walker#2 and call the
> callback function fill_active_slot() with walker#1 inside run_active_slot
> repeatedly, without ever calling it for walker#2?

You're right, in addition to checking whether the callback is the
same, I should also have checked the callback data, before discarding
the invocation of add_fill_function as a duplicate.

> If it is the former, then your change is introducing a bug. If it is the
> latter, your change won't break anything immediately, but still introduces
> a potential bug waiting to happen, as the API looks as if you can call
> add_fill_function() to ask for callback functions to be called with
> different callback data and the caller can rely on both of them to be
> called at appropriate times, but in reality that guarantee does not hold.

That indeed is true, but afaik, none of the two instances of the API
usage does that -- calling callback functions with different callback
data to change behaviour. The fill functions are basically used to
"clear" the request queue.

Look at the fill function in http-walker.c. Yes, it's true that
callback data is passed on by the fill function, unlike the one in
http-push.c, which is passed NULL. But it doesn't really seem to use
the callback data. It loops through the request queue to find requests
that have yet to start (ie. their state is WAITING), and starts them
if they haven't start yet. The request object (struct file_request)
already contains a pointer to the callback data (walker), so it
doesn't really need it.

Nevertheless, I'll make add_fill_function additionally check the callback data.

-- 
Cheers,
Ray Chuan

^ permalink raw reply

* Re: Help designing work flow
From: Andreas Ericsson @ 2009-03-09 12:27 UTC (permalink / raw)
  To: John Tapsell; +Cc: John Dlugosz, git
In-Reply-To: <43d8ce650903090444n352f310fs9cd4b8b0184be010@mail.gmail.com>

John Tapsell wrote:
> 2009/3/9 Andreas Ericsson <ae@op5.se>:
>> John Dlugosz wrote:
>>> I know we (my group) should use "topic" branches and apply them back to
>>> the dev branch when done.  There is concern that the commit history gets
>>> too full of detailed stuff, especially with several developers, that you
>>> can't tell what "really changed".  So, our dev branch should appear to
>>> contain only commit nodes representing completed assignments; not every
>>> day's checkpoint and trying to keep one's own stuff on top to avoid
>>> merging later.
>>>
>>> I guess that's how it is on these Open Source projects where patches are
>>> submitted by email and applied by the maintainer.  We don't see the
>>> details, just the final patch.  But, my situation will be developers
>>> gathered around an in-house master repo, and everyone should be able to
>>> push their own changes as assignments are completed.
>>>
>>> What is the best procedure to achieve that?  Or what are some good
>>> alternatives with trade-offs?
>>>
>> Use topic-branches and let someone merge them into master after having
>> verified that they work properly.
>>
>> We usually commit simple bugfixes directly to master and then have
>> developers rebase their changes onto master when they're ready to
> 
> The trouble with rebasing is that it then you end up with lots of
> patches that haven't been tested.  You can end up with lots of
> uncompiling commits.
> 

Not really, no. Unit-tests can still run just fine, and integration
testing still needs to be done after each feature is completed.

> Although merging is no better either.  Then you end up with one single
> commit that tries to merge two trees, making it almost impossible to
> track down bugs that resulted from the merge.
> 

Not really. If bugs are in "unrelated" areas (if the topic changed some
API without changing its' other callers, fe), you can backstep between
each commit on the merged branch, remerge that commit (instead of the
tip) and then run the tests again. But really, such bugs should have
been detected prior to merging the branch, and in any case "git bisect"
will find the commit that introduced the bug for you either way.


For next time, please cut away those parts of the email you didn't
reply to. I had to scroll down to the bottom to make sure you hadn't
written more.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

Considering the successes of the wars on alcohol, poverty, drugs and
terror, I think we should give some serious thought to declaring war
on peace.

^ permalink raw reply

* [PATCH 2/2] grep Added --blame so that grep can show result tagged with blame entries
From: pi song @ 2009-03-09 13:20 UTC (permalink / raw)
  To: git, gitster

This part:-
1) Implementation & man for grep --blame option

Signed-off-by: Pi Song <pi.songs@gmail.com>
---
 Documentation/git-grep.txt |    5 ++
 builtin-grep.c             |   10 ++++-
 grep.c                     |   98 
++++++++++++++++++++++++++++++++++++-------
 grep.h                     |    1 +
 4 files changed, 96 insertions(+), 18 deletions(-)

diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 553da6c..23dae7f 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -18,6 +18,7 @@ SYNOPSIS
        [-z | --null]
        [-c | --count] [--all-match]
        [-A <post-context>] [-B <pre-context>] [-C <context>]
+       [-b | --blame ]
        [-f <file>] [-e] <pattern>
        [--and|--or|--not|(|)|-e <pattern>...] [<tree>...]
        [--] [<path>...]
@@ -105,6 +106,10 @@ OPTIONS
     Instead of showing every matched line, show the number of
     lines that match.
 
+-b::
+--blame::
+    Show blame of every matched line and context
+
 -[ABC] <context>::
     Show `context` trailing (`A` -- after), or leading (`B`
     -- before), or both (`C` -- context) lines, and place a
diff --git a/builtin-grep.c b/builtin-grep.c
index 3f12ba3..c6cffa0 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -630,6 +630,11 @@ int cmd_grep(int argc, const char **argv, const 
char *prefix)
             opt.word_regexp = 1;
             continue;
         }
+                if (!strcmp("-b", arg) ||
+            !strcmp("--blame", arg)) {
+            opt.include_blame = 1;
+            continue;
+        }
         if (!prefixcmp(arg, "-A") ||
             !prefixcmp(arg, "-B") ||
             !prefixcmp(arg, "-C") ||
diff --git a/grep.c b/grep.c
index 062b2b6..0514384 100644
--- a/grep.c
+++ b/grep.c
@@ -1,3 +1,4 @@
+#include "blame.h"
 #include "cache.h"
 #include "grep.h"
 #include "xdiff-interface.h"
@@ -252,14 +253,17 @@ static int word_char(char ch)
 }
 
 static void show_line(struct grep_opt *opt, const char *bol, const char 
*eol,
-              const char *name, unsigned lno, char sign)
+              const char *name, unsigned lno, char sign,
+                      char sign2, char* suspect)
 {
     if (opt->null_following_name)
         sign = '\0';
     if (opt->pathname)
         printf("%s%c", name, sign);
+        if ((opt->include_blame) && (suspect!=NULL))
+        printf("%s%c", suspect);
     if (opt->linenum)
-        printf("%d%c", lno, sign);
+        printf("%d%c", lno, sign2);
     printf("%.*s\n", (int)(eol-bol), bol);
 }
 
@@ -442,6 +446,14 @@ static int match_line(struct grep_opt *opt, char 
*bol, char *eol,
     return 0;
 }
 
+static int setup_revision_by_revId(char *revId, struct rev_info *revs)
+{
+    const char *args[] = {"grep", revId};
+    init_revisions(revs, NULL);
+    setup_revisions(2, args, revs, NULL);
+    return 1 ;
+};
+
 static int grep_buffer_1(struct grep_opt *opt, const char *name,
              char *buf, unsigned long size, int collect_hits)
 {
@@ -457,6 +469,7 @@ static int grep_buffer_1(struct grep_opt *opt, const 
char *name,
     int binary_match_only = 0;
     const char *hunk_mark = "";
     unsigned count = 0;
+        int blame_calculated = 0 ;
     enum grep_context ctx = GREP_CONTEXT_HEAD;
 
     if (buffer_is_binary(buf, size)) {
@@ -477,6 +490,8 @@ static int grep_buffer_1(struct grep_opt *opt, const 
char *name,
     if (opt->pre_context || opt->post_context)
         hunk_mark = "--\n";
 
+        /* List of blame tags */
+        struct blame_tag *blame_tags  = NULL;
     while (left) {
         char *eol, ch;
         int hit;
@@ -505,6 +520,35 @@ static int grep_buffer_1(struct grep_opt *opt, 
const char *name,
                 return 0;
             goto next_line;
         }
+
+                /* Calculate blame if necessary */
+                if (hit && opt->include_blame && !blame_calculated)
+                {
+                    struct blame_stat blame_stat ;
+                    struct rev_info revs;
+                    char filename[128] ;
+                    char revId[41] ;
+                    char *splitterPtr ;
+                   
+                    if ((splitterPtr=strstr(name, ":")) != NULL)
+                    {
+                        strcpy(filename, splitterPtr + 1) ;
+                        strncpy(revId, name, splitterPtr - name) ;
+                        revId[40] = '\0' ;
+                        setup_revision_by_revId(revId, &revs) ;
+                    }
+                    else
+                    {
+                        const char *args[] = {};
+                        strcpy(filename, name) ;
+                        init_revisions(&revs, NULL);
+                        setup_revisions(0, args, &revs, NULL);
+                    }
+
+                    blame_tags = retrieve_blame_tags(&revs, 
&blame_stat, filename) ;
+                    blame_calculated = 1 ;
+                }
+
         if (hit) {
             count++;
             if (opt->status_only)
@@ -533,30 +577,47 @@ static int grep_buffer_1(struct grep_opt *opt, 
const char *name,
                     from = last_shown + 1;
                 if (last_shown && from != last_shown + 1)
                     fputs(hunk_mark, stdout);
-                while (from < lno) {
+
+                                /* This prints the precontext*/
+                while (from < lno)
+                                {
                     pcl = &prev[lno-from-1];
                     show_line(opt, pcl->bol, pcl->eol,
-                          name, from, '-');
+                          name, from, ':', '-',
+                                                  blame_tags==NULL?
+                                                  NULL: 
blame_tags[from-1].author);
                     from++;
                 }
                 last_shown = lno-1;
             }
             if (last_shown && lno != last_shown + 1)
                 fputs(hunk_mark, stdout);
-            if (!opt->count)
-                show_line(opt, bol, eol, name, lno, ':');
+
+            if (!opt->count) {
+                                /* The matching line */
+                                show_line(opt, bol, eol, name, lno,
+                                          ':', ':',
+                                        blame_tags==NULL?
+                                        NULL:blame_tags[lno-1].author);
+                        }
+               
             last_shown = last_hit = lno;
         }
-        else if (last_hit &&
-             lno <= last_hit + opt->post_context) {
-            /* If the last hit is within the post context,
-             * we need to show this line.
-             */
-            if (last_shown && lno != last_shown + 1)
-                fputs(hunk_mark, stdout);
-            show_line(opt, bol, eol, name, lno, '-');
-            last_shown = lno;
-        }
+                else if (last_hit && lno <= last_hit + opt->post_context)
+                {
+                            /* If the last hit is within the post context,
+                             * we need to show this line.
+                             */
+                            if (last_shown && lno != last_shown + 1)
+                                    fputs(hunk_mark, stdout);
+
+                            show_line(opt, bol, eol, name, lno, ':', '-',
+                                     blame_tags==NULL?
+                                     NULL:blame_tags[lno-1].author);
+                           
+                            last_shown = lno;
+                }
+
         if (opt->pre_context) {
             memmove(prev+1, prev,
                 (opt->pre_context-1) * sizeof(*prev));
@@ -572,6 +633,11 @@ static int grep_buffer_1(struct grep_opt *opt, 
const char *name,
         lno++;
     }
 
+        if (blame_calculated)
+        {
+                free(blame_tags) ;
+        }
+
     free(prev);
     if (collect_hits)
         return 0;
diff --git a/grep.h b/grep.h
index 5102ce3..2e12e03 100644
--- a/grep.h
+++ b/grep.h
@@ -79,6 +79,7 @@ struct grep_opt {
     int regflags;
     unsigned pre_context;
     unsigned post_context;
+        unsigned include_blame;
 };
 
 extern void append_grep_pattern(struct grep_opt *opt, const char *pat, 
const char *origin, int no, enum grep_pat_token t);
-- 
1.5.4.3

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox