* Re: How do gmail users try out patches from this list?
From: Nguyen Thai Ngoc Duy @ 2009-08-12 13:43 UTC (permalink / raw)
To: Michael J Gruber; +Cc: Wesley J. Landaker, Nicolas Sebrecht, skillzero, git
In-Reply-To: <4A827BF3.8080208@drmicha.warpmail.net>
On 8/12/09, Michael J Gruber <git@drmicha.warpmail.net> wrote:
> I guess for them (webmail users) it would be better if we attached
> patches, but we don't do that here. In any case, our list is mirrored on
> gmane, and you can use the interface there. For example, you get the
> first message in this thread using the gmane id or the message id like this:
>
> http://article.gmane.org/gmane.comp.version-control.git/125591
> http://mid.gmane.org/2729632a0908111343v73fa475fqb6353dcf2f718101@mail.gmail.com
>
> If you add /raw to those URLs you get the original message so that you
> can happily wget/curl/browse and save away.
even better http://download.gmane.org/gmane.comp.version-control.git/N/M
[1] (where N and M is the gmane message ID range) gives you mbox
format of a series of consecutive messages.
[1] http://gmane.org/export.php
--
Duy
^ permalink raw reply
* Re: [EGIT PATCH] Provide a more JavaBeans-style 'getName' accessor for the id Signed-off-by: Alex Blewitt <alex.blewitt@gmail.com>
From: Shawn O. Pearce @ 2009-08-12 14:20 UTC (permalink / raw)
To: Alex Blewitt; +Cc: robin.rosenberg@dewire.com, git@vger.kernel.org
In-Reply-To: <8ACC6C83-75FD-477C-9083-96CA426FC069@gmail.com>
Alex Blewitt <alex.blewitt@gmail.com> wrote:
> On 10 Aug 2009, at 21:59, "Shawn O." <spearce@spearce.org> wrote:
>>
>>>> ./org/spearce/jgit/revwalk/RevTag.java:206: getName() in
>>>> org.spearce.jgit.revwalk.RevTag cannot override getName() in
>>>> org.spearce.jgit.lib.AnyObjectId; overridden method is final
>>
>> I can't apply this patch because getName() on RevTag is already
>> defined with a different meaning. :-(
>
> That sounds dangerous. We now have a .name() and a .getName() with
> different semantics. Can we not change the RevTag method name to
> something else so that we dont have an inconsistency?
Good point. We didn't think that RevTag.getName method through
very well. Rename it to getTagName() ?
--
Shawn.
^ permalink raw reply
* Re: [JGIT PATCH 1/1] Fix for Repository.stripWorkDir when using partial paths
From: Shawn O. Pearce @ 2009-08-12 14:29 UTC (permalink / raw)
To: Adam W. Hawks; +Cc: git
In-Reply-To: <4A821167.6030107@writeme.com>
"Adam W. Hawks" <awhawks@writeme.com> wrote:
> When you call stripWorkDir with a relative path
> you can get a string out of bounds error.
>
> This change fixes that problem by using the absolute paths
> of the file instead of its relative name.
Except it made the existing test suite fail, badly. I'm counting
7 errors and 28 test failures as a result of applying this patch.
> 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 468cf4c..a68817b 100644
> --- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
> +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
> @@ -1036,7 +1036,7 @@ public static boolean isValidRefName(final String refName) {
> * @return normalized repository relative path
> */
> public static String stripWorkDir(File wd, File f) {
> - String relName = f.getPath().substring(wd.getPath().length() + 1);
> + String relName = f.getAbsolutePath().substring(wd.getPath().length() + 1);
> relName = relName.replace(File.separatorChar, '/');
> return relName;
> }
--
Shawn.
^ permalink raw reply
* [PATCH JGIT 1/5] TODO: Update and retitle to "JGit Wishlist"
From: Jonas Fonseca @ 2009-08-12 14:33 UTC (permalink / raw)
To: Robin Rosenberg, Shawn O. Pearce; +Cc: git
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
TODO | 14 ++++----------
1 files changed, 4 insertions(+), 10 deletions(-)
diff --git a/TODO b/TODO
index 5f35b25..c4ce95e 100644
--- a/TODO
+++ b/TODO
@@ -1,15 +1,9 @@
-= Eclipse Plugin Wishlist =
+= JGit Wishlist =
-Now that we have some basic features in the Eclipse plugin, we need
-to focus on making it usable by average users doing daily tasks.
+Below are some of the areas that needs work. Also take a look at JGit
+related issues in the EGit project:
-== Create Branch ==
-
-Create a new branch from any revision specification.
-
-== Delete Branch ==
-
-Delete a branch.
+ - http://code.google.com/p/egit/issues/list?q=label:Component-JGit
== Switch Branch ==
--
1.6.4.rc3.195.g2b05f
^ permalink raw reply related
* [PATCH JGIT 2/5] FileMode: Store bit masks in int constants
From: Jonas Fonseca @ 2009-08-12 14:33 UTC (permalink / raw)
To: Robin Rosenberg, Shawn O. Pearce; +Cc: git
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
.../src/org/spearce/jgit/lib/FileMode.java | 38 ++++++++++++--------
.../spearce/jgit/treewalk/WorkingTreeIterator.java | 8 ++--
2 files changed, 27 insertions(+), 19 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/FileMode.java
b/org.spearce.jgit/src/org/spearce/jgit/lib/FileMode.java
index cf42f37..a1f82f8 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/FileMode.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/FileMode.java
@@ -50,21 +50,29 @@
* </p>
*/
public abstract class FileMode {
+
+ public static final int TYPE_MASK = 0170000;
+ public static final int TREE_MASK = 0040000;
+ public static final int SYMLINK_MASK = 0120000;
+ public static final int FILE_MASK = 0100000;
+ public static final int GITLINK_MASK = 0160000;
+ public static final int MISSING_MASK = 0000000;
+
/** Mode indicating an entry is a {@link Tree}. */
@SuppressWarnings("synthetic-access")
- public static final FileMode TREE = new FileMode(0040000,
+ public static final FileMode TREE = new FileMode(TREE_MASK,
Constants.OBJ_TREE) {
public boolean equals(final int modeBits) {
- return (modeBits & 0170000) == 0040000;
+ return (modeBits & TYPE_MASK) == TREE_MASK;
}
};
/** Mode indicating an entry is a {@link SymlinkTreeEntry}. */
@SuppressWarnings("synthetic-access")
- public static final FileMode SYMLINK = new FileMode(0120000,
+ public static final FileMode SYMLINK = new FileMode(SYMLINK_MASK,
Constants.OBJ_BLOB) {
public boolean equals(final int modeBits) {
- return (modeBits & 0170000) == 0120000;
+ return (modeBits & TYPE_MASK) == SYMLINK_MASK;
}
};
@@ -73,7 +81,7 @@ public boolean equals(final int modeBits) {
public static final FileMode REGULAR_FILE = new FileMode(0100644,
Constants.OBJ_BLOB) {
public boolean equals(final int modeBits) {
- return (modeBits & 0170000) == 0100000 && (modeBits & 0111) == 0;
+ return (modeBits & TYPE_MASK) == FILE_MASK && (modeBits & 0111) == 0;
}
};
@@ -82,22 +90,22 @@ public boolean equals(final int modeBits) {
public static final FileMode EXECUTABLE_FILE = new FileMode(0100755,
Constants.OBJ_BLOB) {
public boolean equals(final int modeBits) {
- return (modeBits & 0170000) == 0100000 && (modeBits & 0111) != 0;
+ return (modeBits & TYPE_MASK) == FILE_MASK && (modeBits & 0111) != 0;
}
};
/** Mode indicating an entry is a submodule commit in another repository. */
@SuppressWarnings("synthetic-access")
- public static final FileMode GITLINK = new FileMode(0160000,
+ public static final FileMode GITLINK = new FileMode(GITLINK_MASK,
Constants.OBJ_COMMIT) {
public boolean equals(final int modeBits) {
- return (modeBits & 0170000) == 0160000;
+ return (modeBits & TYPE_MASK) == GITLINK_MASK;
}
};
/** Mode indicating an entry is missing during parallel walks. */
@SuppressWarnings("synthetic-access")
- public static final FileMode MISSING = new FileMode(0000000,
+ public static final FileMode MISSING = new FileMode(MISSING_MASK,
Constants.OBJ_BAD) {
public boolean equals(final int modeBits) {
return modeBits == 0;
@@ -112,20 +120,20 @@ public boolean equals(final int modeBits) {
* @return the FileMode instance that represents the given bits.
*/
public static final FileMode fromBits(final int bits) {
- switch (bits & 0170000) {
- case 0000000:
+ switch (bits & TYPE_MASK) {
+ case MISSING_MASK:
if (bits == 0)
return MISSING;
break;
- case 0040000:
+ case TREE_MASK:
return TREE;
- case 0100000:
+ case FILE_MASK:
if ((bits & 0111) != 0)
return EXECUTABLE_FILE;
return REGULAR_FILE;
- case 0120000:
+ case SYMLINK_MASK:
return SYMLINK;
- case 0160000:
+ case GITLINK_MASK:
return GITLINK;
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/WorkingTreeIterator.java
b/org.spearce.jgit/src/org/spearce/jgit/treewalk/WorkingTreeIterator.java
index d4291ea..6003736 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/WorkingTreeIterator.java
@@ -134,16 +134,16 @@ protected WorkingTreeIterator(final
WorkingTreeIterator p) {
public byte[] idBuffer() {
if (contentIdFromPtr == ptr)
return contentId;
- switch (mode & 0170000) {
- case 0100000: /* normal files */
+ switch (mode & FileMode.TYPE_MASK) {
+ case FileMode.FILE_MASK:
contentIdFromPtr = ptr;
return contentId = idBufferBlob(entries[ptr]);
- case 0120000: /* symbolic links */
+ case FileMode.SYMLINK_MASK:
// Java does not support symbolic links, so we should not
// have reached this particular part of the walk code.
//
return zeroid;
- case 0160000: /* gitlink */
+ case FileMode.GITLINK_MASK:
// TODO: Support obtaining current HEAD SHA-1 from nested repository
//
return zeroid;
--
1.6.4.rc3.195.g2b05f
^ permalink raw reply related
* Re: [PATCH] Limit git-gui to display a maximum number of files
From: Shawn O. Pearce @ 2009-08-12 14:43 UTC (permalink / raw)
To: Dan Zwell; +Cc: Git Mailing List, raa.lkml
In-Reply-To: <4A81BD58.8070300@zwell.net>
Dan Zwell <dzwell@zwell.net> wrote:
> When there is a large number of new or modified files,
> "display_all_files" takes a long time, and git-gui appears to
> hang. This change limits the number of files that are displayed.
> This limit can be set as gui.maxfilesdisplayed, and is
> 5000 by default.
>
> A warning is shown when the list of files is truncated.
Thanks, applied.
--
Shawn.
^ permalink raw reply
* Re: git gc expanding packed data?
From: Hin-Tak Leung @ 2009-08-12 14:45 UTC (permalink / raw)
To: Nicolas Pitre; +Cc: git
In-Reply-To: <alpine.LFD.2.00.0908111718490.10633@xanadu.home>
On Tue, Aug 11, 2009 at 10:33 PM, Nicolas Pitre<nico@cam.org> wrote:
<snipped>
> From git v1.6.3 the --aggressive switch makes for 'git repack' to be
> called with --window=250 --depth=250, meaning the equivalent of:
>
> git repack -a -d -f --window=250 --depth=250
>
> Do you still get a huge pack with the above?
>
>> I guess --aggressive doesn't always save space...
>
> If so that is (and was) a bug.
I tried 'git repack -a -d -f --window=250 --depth=250' with 1.6.2.5
(fc11.x86_64) and it took half a day, swallowed up all the memory -
3GB virtual & 1.3GB resident - and finally the kernel oom killer
killed it at a last message of (601460/957910). Left no temp files.
Would git 1.6.3 use less memory? :-(
Hin-Tak
^ permalink raw reply
* [PATCH JGIT 3/5] Introduce InvalidObjectIdException to reduce code duplicated
From: Jonas Fonseca @ 2009-08-12 15:06 UTC (permalink / raw)
To: Robin Rosenberg, Shawn O. Pearce; +Cc: git
Collects error handling code related to parsing of object id's in one
place.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
.../jgit/errors/InvalidObjectIdException.java | 69 ++++++++++++++++++++
.../org/spearce/jgit/lib/AbbreviatedObjectId.java | 10 +--
.../src/org/spearce/jgit/lib/MutableObjectId.java | 12 +---
.../src/org/spearce/jgit/lib/ObjectId.java | 10 +--
4 files changed, 75 insertions(+), 26 deletions(-)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/errors/InvalidObjectIdException.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/errors/InvalidObjectIdException.java b/org.spearce.jgit/src/org/spearce/jgit/errors/InvalidObjectIdException.java
new file mode 100644
index 0000000..5d50884
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/errors/InvalidObjectIdException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2009, Jonas Fonseca <fonseca@diku.dk>
+ *
+ * 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.errors;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Thrown when an invalid object id is passed in as an argument.
+ */
+public class InvalidObjectIdException extends IllegalArgumentException {
+
+ /**
+ * Create exception with bytes of the invalid object id.
+ *
+ * @param bytes containing the invalid id.
+ * @param offset in the byte array where the error occured.
+ * @param length of the sequence of invalid bytes.
+ */
+ public InvalidObjectIdException(byte[] bytes, int offset, int length) {
+ super("Invalid id" + asAscii(bytes, offset, length));
+ }
+
+ private static String asAscii(byte[] bytes, int offset, int length) {
+ try {
+ return ": " + new String(bytes, offset, length, "US-ASCII");
+ } catch (UnsupportedEncodingException e2) {
+ return "";
+ } catch (StringIndexOutOfBoundsException e2) {
+ return "";
+ }
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
index 1706e88..6ad2ea1 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
@@ -37,8 +37,7 @@
package org.spearce.jgit.lib;
-import java.io.UnsupportedEncodingException;
-
+import org.spearce.jgit.errors.InvalidObjectIdException;
import org.spearce.jgit.util.NB;
import org.spearce.jgit.util.RawParseUtils;
@@ -97,12 +96,7 @@ private static final AbbreviatedObjectId fromHexString(final byte[] bs,
final int e = hexUInt32(bs, ptr + 32, end);
return new AbbreviatedObjectId(end - ptr, a, b, c, d, e);
} catch (ArrayIndexOutOfBoundsException e1) {
- try {
- final String str = new String(bs, ptr, end - ptr, "US-ASCII");
- throw new IllegalArgumentException("Invalid id: " + str);
- } catch (UnsupportedEncodingException e2) {
- throw new IllegalArgumentException("Invalid id");
- }
+ throw new InvalidObjectIdException(bs, ptr, end - ptr);
}
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/MutableObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/MutableObjectId.java
index 805f328..9e25908 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/MutableObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/MutableObjectId.java
@@ -37,8 +37,7 @@
package org.spearce.jgit.lib;
-import java.io.UnsupportedEncodingException;
-
+import org.spearce.jgit.errors.InvalidObjectIdException;
import org.spearce.jgit.util.NB;
import org.spearce.jgit.util.RawParseUtils;
@@ -166,14 +165,7 @@ private void fromHexString(final byte[] bs, int p) {
w4 = RawParseUtils.parseHexInt32(bs, p + 24);
w5 = RawParseUtils.parseHexInt32(bs, p + 32);
} catch (ArrayIndexOutOfBoundsException e1) {
- try {
- final String str = new String(bs, p, STR_LEN, "US-ASCII");
- throw new IllegalArgumentException("Invalid id: " + str);
- } catch (UnsupportedEncodingException e2) {
- throw new IllegalArgumentException("Invalid id");
- } catch (StringIndexOutOfBoundsException e2) {
- throw new IllegalArgumentException("Invalid id");
- }
+ throw new InvalidObjectIdException(bs, p, STR_LEN);
}
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectId.java
index cdd523f..310d6e0 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectId.java
@@ -38,8 +38,7 @@
package org.spearce.jgit.lib;
-import java.io.UnsupportedEncodingException;
-
+import org.spearce.jgit.errors.InvalidObjectIdException;
import org.spearce.jgit.util.NB;
import org.spearce.jgit.util.RawParseUtils;
@@ -230,12 +229,7 @@ private static final ObjectId fromHexString(final byte[] bs, int p) {
final int e = RawParseUtils.parseHexInt32(bs, p + 32);
return new ObjectId(a, b, c, d, e);
} catch (ArrayIndexOutOfBoundsException e1) {
- try {
- final String str = new String(bs, p, STR_LEN, "US-ASCII");
- throw new IllegalArgumentException("Invalid id: " + str);
- } catch (UnsupportedEncodingException e2) {
- throw new IllegalArgumentException("Invalid id");
- }
+ throw new InvalidObjectIdException(bs, p, STR_LEN);
}
}
--
1.6.4.rc3.195.g2b05f
^ permalink raw reply related
* [PATCH JGIT 4/5] Repository: Make listener collections members final
From: Jonas Fonseca @ 2009-08-12 15:06 UTC (permalink / raw)
To: Robin Rosenberg, Shawn O. Pearce; +Cc: git
Silences warnings related with using synchronized() on these members.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
.../src/org/spearce/jgit/lib/Repository.java | 4 ++--
1 files changed, 2 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 468cf4c..d6be9bf 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -100,8 +100,8 @@
private GitIndex index;
- private List<RepositoryListener> listeners = new Vector<RepositoryListener>(); // thread safe
- static private List<RepositoryListener> allListeners = new Vector<RepositoryListener>(); // thread safe
+ private final List<RepositoryListener> listeners = new Vector<RepositoryListener>(); // thread safe
+ static private final List<RepositoryListener> allListeners = new Vector<RepositoryListener>(); // thread safe
/**
* Construct a representation of a Git repository.
--
1.6.4.rc3.195.g2b05f
^ permalink raw reply related
* [PATCH JGIT 5/5] Treat gitlink tree entries similar to symlink tree entries
From: Jonas Fonseca @ 2009-08-12 15:07 UTC (permalink / raw)
To: Robin Rosenberg, Shawn O. Pearce; +Cc: git
Adds minimal support for gitlinks, based on the existing code for
handling symlinks. The goal is to avoid exceptions when reading trees
with gitlinks.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
.../jgit/errors/GitlinksNotSupportedException.java | 58 +++++++++++++
.../src/org/spearce/jgit/lib/ForceModified.java | 4 +
.../src/org/spearce/jgit/lib/GitlinkTreeEntry.java | 85 ++++++++++++++++++++
.../src/org/spearce/jgit/lib/TreeVisitor.java | 8 ++
.../src/org/spearce/jgit/lib/WriteTree.java | 7 ++
5 files changed, 162 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/errors/GitlinksNotSupportedException.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/GitlinkTreeEntry.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/errors/GitlinksNotSupportedException.java b/org.spearce.jgit/src/org/spearce/jgit/errors/GitlinksNotSupportedException.java
new file mode 100644
index 0000000..8f8883f
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/errors/GitlinksNotSupportedException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2007, Shawn O. Pearce <spearce@spearce.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.errors;
+
+import java.io.IOException;
+
+/**
+ * An exception thrown when a gitlink entry is found and cannot be
+ * handled.
+ */
+public class GitlinksNotSupportedException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a GitlinksNotSupportedException for the specified link
+ *
+ * @param s name of link in tree or workdir
+ */
+ public GitlinksNotSupportedException(final String s) {
+ super(s);
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ForceModified.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ForceModified.java
index 6d38068..9c94e13 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/ForceModified.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ForceModified.java
@@ -61,4 +61,8 @@ public void visitSymlink(final SymlinkTreeEntry s) throws IOException {
// Eclipse
// and Pure Java does not know what to do about symbolic links.
}
+
+ public void visitGitlink(GitlinkTreeEntry s) throws IOException {
+ // TODO: handle gitlinks.
+ }
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/GitlinkTreeEntry.java b/org.spearce.jgit/src/org/spearce/jgit/lib/GitlinkTreeEntry.java
new file mode 100644
index 0000000..babbc26
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/GitlinkTreeEntry.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2007, Shawn O. Pearce <spearce@spearce.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.lib;
+
+import java.io.IOException;
+
+/**
+ * A tree entry representing a symbolic link.
+ *
+ * Note. Java cannot really handle these as file system objects.
+ */
+public class GitlinkTreeEntry extends TreeEntry {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a {@link SymlinkTreeEntry} with the specified name and SHA-1 in
+ * the specified parent
+ *
+ * @param parent
+ * @param id
+ * @param nameUTF8
+ */
+ public GitlinkTreeEntry(final Tree parent, final ObjectId id,
+ final byte[] nameUTF8) {
+ super(parent, id, nameUTF8);
+ }
+
+ public FileMode getMode() {
+ return FileMode.GITLINK;
+ }
+
+ public void accept(final TreeVisitor tv, final int flags)
+ throws IOException {
+ if ((MODIFIED_ONLY & flags) == MODIFIED_ONLY && !isModified()) {
+ return;
+ }
+
+ tv.visitGitlink(this);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer r = new StringBuffer();
+ r.append(ObjectId.toString(getId()));
+ r.append(" G ");
+ r.append(getFullName());
+ return r.toString();
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/TreeVisitor.java b/org.spearce.jgit/src/org/spearce/jgit/lib/TreeVisitor.java
index 78a6c22..8293c24 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/TreeVisitor.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/TreeVisitor.java
@@ -77,4 +77,12 @@
* @throws IOException
*/
public void visitSymlink(final SymlinkTreeEntry s) throws IOException;
+
+ /**
+ * Visit to a gitlink.
+ *
+ * @param s Gitlink entry
+ * @throws IOException
+ */
+ public void visitGitlink(final GitlinkTreeEntry s) throws IOException;
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/WriteTree.java b/org.spearce.jgit/src/org/spearce/jgit/lib/WriteTree.java
index 9841678..d6725a9 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/WriteTree.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/WriteTree.java
@@ -41,6 +41,7 @@
import java.io.File;
import java.io.IOException;
+import org.spearce.jgit.errors.GitlinksNotSupportedException;
import org.spearce.jgit.errors.SymlinksNotSupportedException;
/**
@@ -78,4 +79,10 @@ public void endVisitTree(final Tree t) throws IOException {
super.endVisitTree(t);
t.setId(ow.writeTree(t));
}
+
+ public void visitGitlink(GitlinkTreeEntry s) throws IOException {
+ if (s.isModified()) {
+ throw new GitlinksNotSupportedException(s.getFullName());
+ }
+ }
}
--
1.6.4.rc3.195.g2b05f
^ permalink raw reply related
* [PATCH JGIT 2/5] FileMode: Store bit masks in int constants
From: Jonas Fonseca @ 2009-08-12 15:09 UTC (permalink / raw)
To: Robin Rosenberg, Shawn O. Pearce; +Cc: git
In-Reply-To: <2c6b72b30908120733h4ecb3fccm3a1e80c111c1185c@mail.gmail.com>
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
.../src/org/spearce/jgit/lib/FileMode.java | 38 ++++++++++++--------
.../spearce/jgit/treewalk/WorkingTreeIterator.java | 8 ++--
2 files changed, 27 insertions(+), 19 deletions(-)
Resend without mailer errors ...
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/FileMode.java b/org.spearce.jgit/src/org/spearce/jgit/lib/FileMode.java
index cf42f37..a1f82f8 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/FileMode.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/FileMode.java
@@ -50,21 +50,29 @@
* </p>
*/
public abstract class FileMode {
+
+ public static final int TYPE_MASK = 0170000;
+ public static final int TREE_MASK = 0040000;
+ public static final int SYMLINK_MASK = 0120000;
+ public static final int FILE_MASK = 0100000;
+ public static final int GITLINK_MASK = 0160000;
+ public static final int MISSING_MASK = 0000000;
+
/** Mode indicating an entry is a {@link Tree}. */
@SuppressWarnings("synthetic-access")
- public static final FileMode TREE = new FileMode(0040000,
+ public static final FileMode TREE = new FileMode(TREE_MASK,
Constants.OBJ_TREE) {
public boolean equals(final int modeBits) {
- return (modeBits & 0170000) == 0040000;
+ return (modeBits & TYPE_MASK) == TREE_MASK;
}
};
/** Mode indicating an entry is a {@link SymlinkTreeEntry}. */
@SuppressWarnings("synthetic-access")
- public static final FileMode SYMLINK = new FileMode(0120000,
+ public static final FileMode SYMLINK = new FileMode(SYMLINK_MASK,
Constants.OBJ_BLOB) {
public boolean equals(final int modeBits) {
- return (modeBits & 0170000) == 0120000;
+ return (modeBits & TYPE_MASK) == SYMLINK_MASK;
}
};
@@ -73,7 +81,7 @@ public boolean equals(final int modeBits) {
public static final FileMode REGULAR_FILE = new FileMode(0100644,
Constants.OBJ_BLOB) {
public boolean equals(final int modeBits) {
- return (modeBits & 0170000) == 0100000 && (modeBits & 0111) == 0;
+ return (modeBits & TYPE_MASK) == FILE_MASK && (modeBits & 0111) == 0;
}
};
@@ -82,22 +90,22 @@ public boolean equals(final int modeBits) {
public static final FileMode EXECUTABLE_FILE = new FileMode(0100755,
Constants.OBJ_BLOB) {
public boolean equals(final int modeBits) {
- return (modeBits & 0170000) == 0100000 && (modeBits & 0111) != 0;
+ return (modeBits & TYPE_MASK) == FILE_MASK && (modeBits & 0111) != 0;
}
};
/** Mode indicating an entry is a submodule commit in another repository. */
@SuppressWarnings("synthetic-access")
- public static final FileMode GITLINK = new FileMode(0160000,
+ public static final FileMode GITLINK = new FileMode(GITLINK_MASK,
Constants.OBJ_COMMIT) {
public boolean equals(final int modeBits) {
- return (modeBits & 0170000) == 0160000;
+ return (modeBits & TYPE_MASK) == GITLINK_MASK;
}
};
/** Mode indicating an entry is missing during parallel walks. */
@SuppressWarnings("synthetic-access")
- public static final FileMode MISSING = new FileMode(0000000,
+ public static final FileMode MISSING = new FileMode(MISSING_MASK,
Constants.OBJ_BAD) {
public boolean equals(final int modeBits) {
return modeBits == 0;
@@ -112,20 +120,20 @@ public boolean equals(final int modeBits) {
* @return the FileMode instance that represents the given bits.
*/
public static final FileMode fromBits(final int bits) {
- switch (bits & 0170000) {
- case 0000000:
+ switch (bits & TYPE_MASK) {
+ case MISSING_MASK:
if (bits == 0)
return MISSING;
break;
- case 0040000:
+ case TREE_MASK:
return TREE;
- case 0100000:
+ case FILE_MASK:
if ((bits & 0111) != 0)
return EXECUTABLE_FILE;
return REGULAR_FILE;
- case 0120000:
+ case SYMLINK_MASK:
return SYMLINK;
- case 0160000:
+ case GITLINK_MASK:
return GITLINK;
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/treewalk/WorkingTreeIterator.java b/org.spearce.jgit/src/org/spearce/jgit/treewalk/WorkingTreeIterator.java
index d4291ea..6003736 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/treewalk/WorkingTreeIterator.java
@@ -134,16 +134,16 @@ protected WorkingTreeIterator(final WorkingTreeIterator p) {
public byte[] idBuffer() {
if (contentIdFromPtr == ptr)
return contentId;
- switch (mode & 0170000) {
- case 0100000: /* normal files */
+ switch (mode & FileMode.TYPE_MASK) {
+ case FileMode.FILE_MASK:
contentIdFromPtr = ptr;
return contentId = idBufferBlob(entries[ptr]);
- case 0120000: /* symbolic links */
+ case FileMode.SYMLINK_MASK:
// Java does not support symbolic links, so we should not
// have reached this particular part of the walk code.
//
return zeroid;
- case 0160000: /* gitlink */
+ case FileMode.GITLINK_MASK:
// TODO: Support obtaining current HEAD SHA-1 from nested repository
//
return zeroid;
--
1.6.4.rc3.195.g2b05f
^ permalink raw reply related
* Re: [PATCH JGIT 2/5] FileMode: Store bit masks in int constants
From: Shawn O. Pearce @ 2009-08-12 15:22 UTC (permalink / raw)
To: Jonas Fonseca; +Cc: Robin Rosenberg, git
In-Reply-To: <1250089776-22895-1-git-send-email-fonseca@diku.dk>
Jonas Fonseca <fonseca@diku.dk> wrote:
> + public static final int TYPE_MASK = 0170000;
> + public static final int TREE_MASK = 0040000;
> + public static final int SYMLINK_MASK = 0120000;
> + public static final int FILE_MASK = 0100000;
> + public static final int GITLINK_MASK = 0160000;
> + public static final int MISSING_MASK = 0000000;
These last 5 entries aren't masks, they are type codes. I'd rather
they be called FOO_TYPE than FOO_MASK. In particular what is really
troubling is MISSING_MASK, being all 0 it always destroys the input
and then matches everything. :-)
I'm going to amend this name change in here, s/_MASK/_TYPE/ on the
last 5 fields.
--
Shawn.
^ permalink raw reply
* [PATCH] git-gui: Update russian translation
From: Alex Riesen @ 2009-08-12 15:24 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Dan Zwell, Git Mailing List
In-Reply-To: <20090812144345.GC1033@spearce.org>
Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---
Shawn O. Pearce, Wed, Aug 12, 2009 16:43:45 +0200:
> Dan Zwell <dzwell@zwell.net> wrote:
> > When there is a large number of new or modified files,
> > "display_all_files" takes a long time, and git-gui appears to
> > hang. This change limits the number of files that are displayed.
> > This limit can be set as gui.maxfilesdisplayed, and is
> > 5000 by default.
> >
> > A warning is shown when the list of files is truncated.
>
> Thanks, applied.
>
And the updated translation.
But now, when I really think about the change, it looks useless.
What has the _number_ of files has to do with the files you actually
have to handle? As the sorting of the file list cannot be changed (and
it wouldn't be a big help anyway), you have no chance to get to your
file if it happens to be past the limit!
Wouldn't a pathname/glob filter in the command-line (or file/path
selection dialog) to limit the scope be more appropriate and useful?
And have the file list reading to happen in background, as gitk does?
po/ru.po | 28 ++++++++++++++++------------
1 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/po/ru.po b/po/ru.po
index 0ffc4a4..364c074 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -90,12 +90,18 @@ msgstr "Вызов программы поддержки репозитория
#: git-gui.sh:1384
msgid "Commit declined by prepare-commit-msg hook."
-msgstr "Сохранение прервано программой поддержки репозитория prepare-commit-msg"
+msgstr ""
+"Сохранение прервано программой поддержки репозитория prepare-commit-msg"
#: git-gui.sh:1542 lib/browser.tcl:246
msgid "Ready."
msgstr "Готово."
+#: git-gui.sh:1726
+#, tcl-format
+msgid "Displaying only %s of %s files."
+msgstr "Показано %s из %s файлов."
+
#: git-gui.sh:1819
msgid "Unmodified"
msgstr "Не изменено"
@@ -1297,8 +1303,8 @@ msgid ""
msgstr ""
"Невозможно исправить состояние во время операции слияния.\n"
"\n"
-"Текущее слияние не завершено. Невозможно исправить предыдущее "
-"сохраненное состояние, не прерывая эту операцию.\n"
+"Текущее слияние не завершено. Невозможно исправить предыдущее сохраненное "
+"состояние, не прерывая эту операцию.\n"
#: lib/commit.tcl:48
msgid "Error loading commit data for amend:"
@@ -1723,8 +1729,7 @@ msgid ""
msgstr ""
"Невозможно выполнить слияние во время исправления.\n"
"\n"
-"Завершите исправление данного состояния перед выполнением операции "
-"слияния.\n"
+"Завершите исправление данного состояния перед выполнением операции слияния.\n"
#: lib/merge.tcl:27
msgid ""
@@ -1888,8 +1893,8 @@ msgstr ""
#, tcl-format
msgid "File %s seems to have unresolved conflicts, still stage?"
msgstr ""
-"Файл %s кажется содержит необработаные конфликты. "
-"Продолжить подготовку к сохранению?"
+"Файл %s кажется содержит необработаные конфликты. Продолжить подготовку к "
+"сохранению?"
#: lib/mergetool.tcl:60
#, tcl-format
@@ -2213,8 +2218,8 @@ msgid ""
"One or more of the merge tests failed because you have not fetched the "
"necessary commits. Try fetching from %s first."
msgstr ""
-"Некоторые тесты на слияние не прошли, потому что Вы не "
-"получили необходимые состояния. Попытайтесь получить их из %s."
+"Некоторые тесты на слияние не прошли, потому что Вы не получили необходимые "
+"состояния. Попытайтесь получить их из %s."
#: lib/remote_branch_delete.tcl:207
msgid "Please select one or more branches to delete."
@@ -2381,8 +2386,8 @@ msgstr "Выполнение: %s"
#: lib/tools.tcl:149
#, tcl-format
-msgid "Tool completed succesfully: %s"
-msgstr "Программа %s успешно завершилась."
+msgid "Tool completed successfully: %s"
+msgstr "Программа %s завершилась успешно."
#: lib/tools.tcl:151
#, tcl-format
@@ -2538,4 +2543,3 @@ msgstr "Использовать thin pack (для медленных сетев
#: lib/transport.tcl:179
msgid "Include tags"
msgstr "Передать метки"
-
--
1.6.4.140.gc6dfd
^ permalink raw reply related
* Re: [PATCH JGIT 5/5] Treat gitlink tree entries similar to symlink tree entries
From: Shawn O. Pearce @ 2009-08-12 15:32 UTC (permalink / raw)
To: Jonas Fonseca; +Cc: Robin Rosenberg, git
In-Reply-To: <1250089629-22547-1-git-send-email-fonseca@diku.dk>
Jonas Fonseca <fonseca@diku.dk> wrote:
> Adds minimal support for gitlinks, based on the existing code for
> handling symlinks. The goal is to avoid exceptions when reading trees
> with gitlinks.
Applied, but who calls GitlinkTreeEntry ?
> .../jgit/errors/GitlinksNotSupportedException.java | 58 +++++++++++++
> .../src/org/spearce/jgit/lib/ForceModified.java | 4 +
> .../src/org/spearce/jgit/lib/GitlinkTreeEntry.java | 85 ++++++++++++++++++++
> .../src/org/spearce/jgit/lib/TreeVisitor.java | 8 ++
> .../src/org/spearce/jgit/lib/WriteTree.java | 7 ++
> 5 files changed, 162 insertions(+), 0 deletions(-)
> create mode 100644 org.spearce.jgit/src/org/spearce/jgit/errors/GitlinksNotSupportedException.java
> create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/GitlinkTreeEntry.java
--
Shawn.
^ permalink raw reply
* Re: git gc expanding packed data?
From: Nicolas Pitre @ 2009-08-12 15:35 UTC (permalink / raw)
To: Hin-Tak Leung; +Cc: git
In-Reply-To: <3ace41890908120745y305b2a59hd453b7e146e4a774@mail.gmail.com>
On Wed, 12 Aug 2009, Hin-Tak Leung wrote:
> On Tue, Aug 11, 2009 at 10:33 PM, Nicolas Pitre<nico@cam.org> wrote:
> <snipped>
>
> > From git v1.6.3 the --aggressive switch makes for 'git repack' to be
> > called with --window=250 --depth=250, meaning the equivalent of:
> >
> > git repack -a -d -f --window=250 --depth=250
> >
> > Do you still get a huge pack with the above?
> >
> >> I guess --aggressive doesn't always save space...
> >
> > If so that is (and was) a bug.
>
> I tried 'git repack -a -d -f --window=250 --depth=250' with 1.6.2.5
> (fc11.x86_64) and it took half a day, swallowed up all the memory -
> 3GB virtual & 1.3GB resident - and finally the kernel oom killer
> killed it at a last message of (601460/957910). Left no temp files.
> Would git 1.6.3 use less memory? :-(
Probably not. However you should try:
git config pack.deltaCacheSize 1
That limits the delta cache size to one byte (effectively disabling it)
instead of the default of 0 which means unlimited. With that I'm able
to repack that repository using the above git repack command on an
x86-64 system with 4GB of RAM and using 4 threads (this is a quad core).
Resident memory usage grows to nearly 3.3GB though.
If your machine is SMP and you don't have sufficient RAM then you can
reduce the number of threads to only one:
git config pack.threads 1
Additionally, you can further limit memory usage with the
--window-memory argument to 'git repack'. For example, using
--window-memory=128M should keep a reasonable upper bound on the delta
search memory usage although this can result in less optimal delta match
if the repo contains lots of large files (and I think this is the case
for the gcc repo).
Nicolas
^ permalink raw reply
* Re: [PATCH] git-gui: Update russian translation
From: Shawn O. Pearce @ 2009-08-12 15:40 UTC (permalink / raw)
To: Alex Riesen; +Cc: Dan Zwell, Git Mailing List
In-Reply-To: <20090812152409.GA5407@blimp.localdomain>
Alex Riesen <raa.lkml@gmail.com> wrote:
> Shawn O. Pearce, Wed, Aug 12, 2009 16:43:45 +0200:
> > Dan Zwell <dzwell@zwell.net> wrote:
> > > When there is a large number of new or modified files,
> > > "display_all_files" takes a long time, and git-gui appears to
> > > hang. This change limits the number of files that are displayed.
> > > This limit can be set as gui.maxfilesdisplayed, and is
> > > 5000 by default.
> > >
> > > A warning is shown when the list of files is truncated.
> >
> > Thanks, applied.
>
> But now, when I really think about the change, it looks useless.
> What has the _number_ of files has to do with the files you actually
> have to handle? As the sorting of the file list cannot be changed (and
> it wouldn't be a big help anyway), you have no chance to get to your
> file if it happens to be past the limit!
>
> Wouldn't a pathname/glob filter in the command-line (or file/path
> selection dialog) to limit the scope be more appropriate and useful?
> And have the file list reading to happen in background, as gitk does?
Good point. I suspect the problem wasn't so much with Tcl doing the
list processing as it was with Tk actually creating the underlying
icons and stuff for each file name. But with the list clipped,
you are right, you are basically SOL. You can't do much beyond
dropping back to the CLI and using the CLI tools.
IMHO, if we aren't going to handle 20k file names, we should at least
punt and tell the user we aren't going to handle 20k file names,
rather than just play Outlook wannabe and lockup the entire UI until
the user gets bored and kill -9's us. So this patch is better than
nothing, it at least lets the user know we have given up on them.
--
Shawn.
^ permalink raw reply
* Re: [RFC PATCH v3 8/8] --sparse for porcelains
From: Raja R Harinath @ 2009-08-12 15:40 UTC (permalink / raw)
To: git
In-Reply-To: <fcaeb9bf0908120253p192125a4mbb6a0838fc90f10e@mail.gmail.com>
Hi,
Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
> 2009/8/12 Johannes Sixt <j.sixt@viscovery.net>:
>> BTW, the name .git/info/sparse is perhaps a bit too technical in the sense
>> that only git developers know that this feature runs under the name
>> "sparse checkout". Perhaps it should be named
>>
>> .git/info/indexonly
>> .git/info/nocheckout
>>
>> or so.
>
> I did not like the name "sparse" either. Another option is
> .git/info/assume-unchanged.
Or .git/info/doppelgangers, or even .git/info/doppelgängers :-)
- Hari
^ permalink raw reply
* Re: [RFC/PATCH 5/6] Let transport_helper_init() decide if a remote helper program can be used
From: Daniel Barkalow @ 2009-08-12 16:21 UTC (permalink / raw)
To: Jeff King; +Cc: Johan Herland, git, gitster, benji, Johannes.Schindelin
In-Reply-To: <20090812074658.GE15152@coredump.intra.peff.net>
On Wed, 12 Aug 2009, Jeff King wrote:
> On Tue, Aug 11, 2009 at 07:28:19PM -0400, Daniel Barkalow wrote:
>
> > of 'Could not find (...) "git remote-master.kernel.org" (...)'? That
> > would be certain to upset some people. I think we can assume that people's
> > scheme parts of their URLs that are actually URLs don't contain '.', and
> > that people with:
> >
> > url = master:something
> >
> > will append their domains if the warning gets annoying.
>
> Keep in mind that these URLs should be usable from the command-line,
> too. So it is not just appending the domain in the config, but appending
> it every time you want to do a one-off pull.
For that sort of thing, I think that url.*.insteadOf in your global config
is the way to go. It applies before anything else, and can supply parts of
the path as well as the hostname.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* [JGIT PATCH] Use SoftReference in WindowCache to keep Repository around
From: Shawn O. Pearce @ 2009-08-12 17:03 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
This is meant to be a memory sensitive cache that holds the
Repository object around if there is JVM memory available to
store it, and any packs it might have loaded.
Unfortunately I wrote the cache with a WeakReference, which
is cleared as soon as there are no more strong references to
the Repository. This isn't very suitable for use in a server
application or a GUI which is depending upon this cache to hold
frequently accessed Repositories for near-term reuse.
Switching these to SoftReference, which is what we also use in the
WindowCache, permits the JVM to retain these Repository objects until
the JVM is low on memory and the Repository is not strongly held.
This new behavior is more consistent with the name and intent of
the class.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/lib/RepositoryCache.java | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryCache.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryCache.java
index 386f798..3aaffee 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryCache.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryCache.java
@@ -40,7 +40,7 @@
import java.io.File;
import java.io.IOException;
import java.lang.ref.Reference;
-import java.lang.ref.WeakReference;
+import java.lang.ref.SoftReference;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -156,7 +156,7 @@ private Repository openRepository(final Key location,
db = ref != null ? ref.get() : null;
if (db == null) {
db = location.open(mustExist);
- ref = new WeakReference<Repository>(db);
+ ref = new SoftReference<Repository>(db);
cacheMap.put(location, ref);
}
}
@@ -167,7 +167,7 @@ private Repository openRepository(final Key location,
private void registerRepository(final Key location, final Repository db) {
db.incrementOpen();
- WeakReference<Repository> newRef = new WeakReference<Repository>(db);
+ SoftReference<Repository> newRef = new SoftReference<Repository>(db);
Reference<Repository> oldRef = cacheMap.put(location, newRef);
Repository oldDb = oldRef != null ? oldRef.get() : null;
if (oldDb != null)
--
1.6.4.225.gb589e
^ permalink raw reply related
* [PATCHv4/RFC 2/3] gitweb: Incremental blame (WIP)
From: Jakub Narebski @ 2009-08-12 17:08 UTC (permalink / raw)
To: git
Cc: Petr Baudis, Fredrik Kuivinen, Giuseppe Bilotta, Luben Tuikov,
Martin Koegler, Jakub Narebski
In-Reply-To: <1249578712-3862-3-git-send-email-jnareb@gmail.com>
This is tweaked up version of Petr Baudis <pasky@suse.cz> patch, which
in turn was tweaked up version of Fredrik Kuivinen <frekui@gmail.com>'s
proof of concept patch. It adds 'blame_incremental' view, which
incrementally displays line data in blame view using JavaScript (AJAX).
This patch does not (contrary to the one by Petr Baudis) enable this
view in gitweb: there are no links leading to 'blame_incremental'
action. You would have to generate URL 'by hand' (e.g. changing 'blame'
or 'blob' in gitweb URL to 'blame_incremental'). Having links in gitweb
lead to this new action (e.g. by rewriting them like in previous patch,
if JavaScript is enabled in browser) is left for later.
Like earlier patch by Per Baudis it avoids code duplication, but it goes
one step further and use git_blame_common for ordinary blame view, for
incremental blame, and (which is change from previous patch) for
incremental blame data.
How the 'blame_incremental' view works:
* gitweb generates initial info by putting file contents (from
git-cat-file) together with line numbers in blame table
* then gitweb makes web browser JavaScript engine call startBlame()
function from blame.js
* startBlame() opens connection to 'blame_data' view, which in turn
calls "git blame --incremental" for a file, and streams output of
git-blame to JavaScript (blame.js)
* blame.js updates line info in blame view, coloring it, and updating
progress info; note that it has to use 3 colors to ensure that
different neighboring groups have different styles
* when 'blame_data' ends, and blame.js finishes updating line info,
it fixes colors to match (as far as possible) ordinary 'blame' view,
and updates generating time info.
It deals with streamed 'blame_data' server error by notifying about them
in the progress info area (just in case).
Differences between 'blame_incremental' and original 'blame' view:
* 'blame_incremental' always used (partial) query form for links
generated by JavaScript. The difference is visible if we use path_info
link (pass some or all arguments in path_info), e.g. in 'blame' view
called using:
http://git.example.com/w/git.git/blame/HEAD:/README
we have 'linenr' links using the same form:
http://git.example.com/w/git.git/blame/e83c5163316f89bfbde7d9ab23ca2e25604af290:/README#l4
while in 'blame_incremental' view called with:
http://git.example.com/w/git.git/blame_incremental/HEAD:/README
we have "partial query" form
http://git.example.com/w/git.git?;a=blame_incremental;hb=e83c5163316f89bfbde7d9ab23ca2e25604af290;f=README#l4
Changing this would require implementing something akin to href()
subroutine from gitweb.perl in JavaScript
* 'blame_incremental' always uses "rowspan" attribute, even if
rowspan="1". This is not visible to user. (The code actually
could work without it).
This patch adds GITWEB_BLAMEJS compile configuration option, and
modifies git-instaweb.sh to take blame.js into account, but it does not
update gitweb/README file (as it is only proof of concept patch). The
code for git-instaweb.sh was taken from Pasky's patch.
Signed-off-by: Fredrik Kuivinen <frekui@gmail.com>
Signed-off-by: Petr Baudis <pasky@suse.cz>
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Refrences:
1. Original patch by Frederik Kuivinen
http://article.gmane.org/gmane.comp.version-control.git/41361
2. Tweaked up version by Petr Baudis
http://article.gmane.org/gmane.comp.version-control.git/47614
http://article.gmane.org/gmane.comp.version-control.git/56657
3. New link rewriting and some optimization in Matrin Koegler
series introducing some JavaScript support in Git
http://thread.gmane.org/gmane.comp.version-control.git/47902/focus=47905
4. My earlier patches
http://thread.gmane.org/gmane.comp.version-control.git/102657/focus=102712
http://article.gmane.org/gmane.comp.version-control.git/123202
http://thread.gmane.org/gmane.comp.version-control.git/123957/focus=123968
Changes compared to last version (v3):
* Try yet another method (window.createrequest()) in
createRequestObject() function.
* Rename variable holding XMLHttpRequest object from 'http' to 'xhr'
* Separate data about group of lines which are changed by the smae
commit (which blame the same commit): srcline, resline, numlines,
and put it in curGroup variable instead of using Commit object
(curCommit) for that. handleLine() function acquires 'group' as
second parameter.
* delete no longer needed Commit properties (to be removed)
* Simplify logic and code of selecting unprocessed part of
XMLHttpRequest responseText for processing. nextLine global
variable is now named nextReadPos, code now check first if there
are any complete unprocessed lines before doing split('\n'),
and there is now no need to remove incomplete line from 'lines'.
This code which was inside handleResponse() can now be found in
processData subroutine.
* Separate parts of handleResponse() as a cleanup and in preparation
for having (simpler) event handlers for 'progress', 'load' and
'error' W3C Progress Events, and having 'readystatechange' handler
to be just dispatcher for those event handlers. Introduce functions:
processBlameLines, processData, handleError and responseLoaded
* Use DOM 2 HTML "elem.style.cssText = value;" instead of
DOM 2 Core "elem.setAttribute('style', value);"
* Add a few 'work in progress' comments.
* Remove comment about 'multipart/x-mixed-replace': it is
non-standard, and it requires server to know when chunks ands to
send replacements, something that cannot easily be done: incremental
git-blame sends data in chunks, but gitweb doesn't know when they
end.
TODO list:
* Use W3C Progress Events instead of 'readystatechange' event
http://www.w3.org/TR/progress-events/
http://www.w3.org/TR/XMLHttpRequest2/
http://www.nczonline.net/blog/2009/07/09/firefox-35firebug-xmlhttprequest-and-readystatechange-bug/
if XMLHttpResponse supports it, 'readystatechange' event + poll
timer otherwise.
* handleResponse is used both as onreadystatechange and pollTimer;
if onreadystatechange works for partial responses we can turn off
the timer.
* Clean up handling concurrency, i.e. dealing with situation when
handleResponse event handler is called before previous call finished
working. Currently it is done using inProgress flag, and busy-read
while loop.
* Get rid of global variables, if possible.
* Instead of running startBlame, put it in window.onload handler
* Rename blame.js to gitweb.js to have all JavaScript in a single
file. Note that this would require changes to next commit in
series (enabling 'blame_incremental' view if browser has javaScript
turned on).
TODO for future commits:
* Remove (fade out) progress bar and progress info after blame
incremental finished run (left for a separate commit).
* Profile blame.js using YUI Profiler or other JavaScript profile tool
http://developer.yahoo.com/yui/profiler/
to check whether performance improvements described in articles
on NCZOnline blog by Nicholas C. Zakas are required, and would help
http://www.nczonline.net/blog/
* Check whether it is worth to do some server processing of
incremental blame output, and send e.g. JSON and not text/plain
of raw 'git blame --incremental' output.
* Check how supported is 'multipart/x-mixed-replace' mimetype for data
pushed from server (and how to correctly implement it); perhaps that
would be a solution to concurrency problem?
* Check whether it would make sense to use some lightweight JavaScript
library (framework) like jQuery, Prototype, ExtJS, MooTools, etc.
* Minify JavaScript during building gitweb/gitweb.cgi, if minification
tool is found.
Makefile | 6 +-
git-instaweb.sh | 7 +
gitweb/blame.js | 819 ++++++++++++++++++++++++++++++++++++++++++++++++++++
gitweb/gitweb.css | 16 +
gitweb/gitweb.perl | 271 ++++++++++++------
5 files changed, 1032 insertions(+), 87 deletions(-)
create mode 100644 gitweb/blame.js
diff --git a/Makefile b/Makefile
index daf4296..cb93aa3 100644
--- a/Makefile
+++ b/Makefile
@@ -265,6 +265,7 @@ GITWEB_HOMETEXT = indextext.html
GITWEB_CSS = gitweb.css
GITWEB_LOGO = git-logo.png
GITWEB_FAVICON = git-favicon.png
+GITWEB_BLAMEJS = blame.js
GITWEB_SITE_HEADER =
GITWEB_SITE_FOOTER =
@@ -1407,13 +1408,14 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl
-e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
-e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
-e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
+ -e 's|++GITWEB_BLAMEJS++|$(GITWEB_BLAMEJS)|g' \
-e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
-e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
$< >$@+ && \
chmod +x $@+ && \
mv $@+ $@
-git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
+git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/blame.js
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
@@ -1422,6 +1424,8 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
-e '/@@GITWEB_CGI@@/d' \
-e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \
-e '/@@GITWEB_CSS@@/d' \
+ -e '/@@GITWEB_BLAMEJS@@/r gitweb/blame.js' \
+ -e '/@@GITWEB_BLAMEJS@@/d' \
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
$@.sh > $@+ && \
chmod +x $@+ && \
diff --git a/git-instaweb.sh b/git-instaweb.sh
index 5f5cac7..0288450 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -331,8 +331,15 @@ gitweb_css () {
EOFGITWEB
}
+gitweb_blamejs () {
+ cat > "$1" <<\EOFGITWEB
+@@GITWEB_BLAMEJS@@
+EOFGITWEB
+}
+
gitweb_cgi "$GIT_DIR/gitweb/gitweb.cgi"
gitweb_css "$GIT_DIR/gitweb/gitweb.css"
+gitweb_blamejs "$GIT_DIR/gitweb/blame.js"
case "$httpd" in
*lighttpd*)
diff --git a/gitweb/blame.js b/gitweb/blame.js
new file mode 100644
index 0000000..9230cb7
--- /dev/null
+++ b/gitweb/blame.js
@@ -0,0 +1,819 @@
+// Copyright (C) 2007, Fredrik Kuivinen <frekui@gmail.com>
+// 2007, Petr Baudis <pasky@suse.cz>
+// 2008-2009, Jakub Narebski <jnareb@gmail.com>
+
+/**
+ * @fileOverview JavaScript part of 'blame_incremental' action in gitweb.
+ * @license GPLv2 or later
+ */
+
+/*
+ * This code uses DOM methods instead of (nonstandard) innerHTML
+ * to modify page.
+ *
+ * innerHTML is non-standard IE extension, though supported by most
+ * browsers; however Firefox up to version 1.5 didn't implement it in
+ * a strict mode (application/xml+xhtml mimetype). Also my simple
+ * benchmarks show that using elem.firstChild.data = 'content' is
+ * slightly faster than elem.innerHTML = 'content', if more fragile
+ * (text element fragment must exists), and less feature-rich (we
+ * cannot add HTML).
+ */
+
+/* ============================================================ */
+/* generic utility functions */
+
+var DEBUG = 0;
+function debug(str) {
+ if (DEBUG) {
+ alert(str);
+ }
+}
+
+/**
+ * pad number N with nonbreakable spaces on the left, to WIDTH characters
+ * example: spacePad(12, 3) == ' 12' (' ' is nonbreakable space)
+ *
+ * @param {Number} n: number to pad
+ * @param {Number} width: visible width of output
+ * @returns {String} N prefixed with (WIDTH - N.length) x ' '
+ */
+function spacePad(n, width) {
+ var prefix = '';
+
+ width -= n.toString().length;
+ while (width > 1) {
+ prefix += ' ';
+ width--;
+ }
+ return prefix + n;
+}
+
+/**
+ * Pad INPUT on the left to SIZE width, using given padding character CH,
+ * for example padLeft('a', 3, '_') is '__a'.
+ *
+ * @param {String} input: input value converted to string.
+ * @param {Number} size: desired length of output.
+ * @param {String} ch: single character to prefix to string.
+ *
+ * @returns {String} Modified string, at least SIZE length.
+ */
+function padLeft(input, size, ch) {
+ var s = input + "";
+ while (s.length < size) {
+ s = ch + s;
+ }
+ return s;
+}
+
+/**
+ * Create XMLHttpRequest object in cross-browser way
+ * @returns XMLHttpRequest object, or null
+ */
+function createRequestObject() {
+ try {
+ return new XMLHttpRequest();
+ } catch (e) {}
+ try {
+ return window.createRequest();
+ } catch (e) {}
+ try {
+ return new ActiveXObject("Msxml2.XMLHTTP");
+ } catch (e) {}
+ try {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ } catch (e) {}
+
+ //debug("XMLHttpRequest not supported");
+ return null;
+}
+
+/* ============================================================ */
+/* utility/helper functions (and variables) */
+
+var xhr; // XMLHttpRequest object
+var projectUrl; // partial query + separator ('?' or ';')
+
+// 'commits' is an associative map. It maps SHA1s to Commit objects.
+var commits = {};
+
+/**
+ * constructor for Commit objects, used in 'blame'
+ * @class Represents a blamed commit
+ * @param {String} sha1: SHA-1 identifier of a commit
+ */
+function Commit(sha1) {
+ if (this instanceof Commit) {
+ this.sha1 = sha1;
+ this.nprevious = 0; /* number of 'previous', effective parents */
+ } else {
+ return new Commit(sha1);
+ }
+}
+
+/* ............................................................ */
+/* progress info, timing, error reporting */
+
+var blamedLines = 0;
+var totalLines = '???';
+var div_progress_bar;
+var div_progress_info;
+
+/**
+ * Detects how many lines does a blamed file have,
+ * This information is used in progress info
+ *
+ * @returns {Number|String} Number of lines in file, or string '...'
+ */
+function countLines() {
+ var table =
+ document.getElementById('blame_table') ||
+ document.getElementsByTagName('table')[0];
+
+ if (table) {
+ return table.getElementsByTagName('tr').length - 1; // for header
+ } else {
+ return '...';
+ }
+}
+
+/**
+ * update progress info and length (width) of progress bar
+ */
+function updateProgressInfo() {
+ if (!div_progress_info) {
+ div_progress_info = document.getElementById('progress_info');
+ }
+ if (!div_progress_bar) {
+ div_progress_bar = document.getElementById('progress_bar');
+ }
+ if (!div_progress_info && !div_progress_bar) {
+ return;
+ }
+
+ var percentage = Math.floor(100.0*blamedLines/totalLines);
+
+ if (div_progress_info) {
+ div_progress_info.firstChild.data = blamedLines + ' / ' + totalLines +
+ ' (' + spacePad(percentage, 3) + '%)';
+ }
+
+ if (div_progress_bar) {
+ //div_progress_bar.setAttribute('style', 'width: '+percentage+'%;');
+ div_progress_bar.style.width = percentage + '%';
+ }
+}
+
+
+var t_interval_server = '';
+var cmds_server = '';
+var t0 = new Date();
+
+/**
+ * write how much it took to generate data, and to run script
+ */
+function writeTimeInterval() {
+ var info_time = document.getElementById('generate_time');
+ if (!info_time || !t_interval_server) {
+ return;
+ }
+ var t1 = new Date();
+ info_time.firstChild.data += ' + (' +
+ t_interval_server + 's server blame_data / ' +
+ (t1.getTime() - t0.getTime())/1000 + 's client JavaScript)';
+
+ var info_cmds = document.getElementById('generate_cmd');
+ if (!info_time || !cmds_server) {
+ return;
+ }
+ info_cmds.firstChild.data += ' + ' + cmds_server;
+}
+
+/**
+ * show an error message alert to user within page (in prohress info area)
+ * @param {String} str: plain text error message (no HTML)
+ */
+function errorInfo(str) {
+ if (!div_progress_info) {
+ div_progress_info = document.getElementById('progress_info');
+ }
+ if (div_progress_info) {
+ div_progress_info.className = 'error';
+ div_progress_info.firstChild.data = str;
+ }
+}
+
+/* ............................................................ */
+/* coloring rows during blame_data (git blame --incremental) run */
+
+/**
+ * used to extract N from 'colorN', where N is a number,
+ * @constant
+ */
+var colorRe = /\bcolor([0-9]*)\b/;
+
+/**
+ * return N if <tr class="colorN">, otherwise return null
+ * (some browsers require CSS class names to begin with letter)
+ *
+ * @param {HTMLElement} tr: table row element to check
+ * @param {String} tr.className: 'class' attribute of tr element
+ * @returns {Number|null} N if tr.className == 'colorN', otherwise null
+ */
+function getColorNo(tr) {
+ if (!tr) {
+ return null;
+ }
+ var className = tr.className;
+ if (className) {
+ var match = colorRe.exec(className);
+ if (match) {
+ return parseInt(match[1], 10);
+ }
+ }
+ return null;
+}
+
+var colorsFreq = [0, 0, 0];
+/**
+ * return one of given possible colors (curently least used one)
+ * example: chooseColorNoFrom(2, 3) returns 2 or 3
+ *
+ * @param {Number[]} arguments: one or more numbers
+ * assumes that 1 <= arguments[i] <= colorsFreq.length
+ * @returns {Number} Least used color number from arguments
+ */
+function chooseColorNoFrom() {
+ // choose the color which is least used
+ var colorNo = arguments[0];
+ for (var i = 1; i < arguments.length; i++) {
+ if (colorsFreq[arguments[i]-1] < colorsFreq[colorNo-1]) {
+ colorNo = arguments[i];
+ }
+ }
+ colorsFreq[colorNo-1]++;
+ return colorNo;
+}
+
+/**
+ * given two neigbour <tr> elements, find color which would be different
+ * from color of both of neighbours; used to 3-color blame table
+ *
+ * @param {HTMLElement} tr_prev
+ * @param {HTMLElement} tr_next
+ * @returns {Number} color number N such that
+ * colorN != tr_prev.className && colorN != tr_next.className
+ */
+function findColorNo(tr_prev, tr_next) {
+ var color_prev = getColorNo(tr_prev);
+ var color_next = getColorNo(tr_next);
+
+
+ // neither of neighbours has color set
+ // THEN we can use any of 3 possible colors
+ if (!color_prev && !color_next) {
+ return chooseColorNoFrom(1,2,3);
+ }
+
+ // either both neighbours have the same color,
+ // or only one of neighbours have color set
+ // THEN we can use any color except given
+ var color;
+ if (color_prev === color_next) {
+ color = color_prev; // = color_next;
+ } else if (!color_prev) {
+ color = color_next;
+ } else if (!color_next) {
+ color = color_prev;
+ }
+ if (color) {
+ return chooseColorNoFrom((color % 3) + 1, ((color+1) % 3) + 1);
+ }
+
+ // neighbours have different colors
+ // THEN there is only one color left
+ return (3 - ((color_prev + color_next) % 3));
+}
+
+/* ............................................................ */
+/* coloring rows like 'blame' after 'blame_data' finishes */
+
+/**
+ * returns true if given row element (tr) is first in commit group
+ * to be used only after 'blame_data' finishes (after processing)
+ *
+ * @param {HTMLElement} tr: table row
+ * @returns {Boolean} true if TR is first in commit group
+ */
+function isStartOfGroup(tr) {
+ return tr.firstChild.className === 'sha1';
+}
+
+/**
+ * change colors to use zebra coloring (2 colors) instead of 3 colors
+ * concatenate neighbour commit groups belonging to the same commit
+ */
+function fixColorsAndGroups() {
+ var colorClasses = ['light', 'dark'];
+ var linenum = 1;
+ var tr, prev_group;
+ var colorClass = 0;
+ var table =
+ document.getElementById('blame_table') ||
+ document.getElementsByTagName('table')[0];
+
+ while ((tr = document.getElementById('l'+linenum))) {
+ // index origin is 0, which is table header; start from 1
+ //while ((tr = table.rows[linenum])) { // <- it is slower
+ if (isStartOfGroup(tr, linenum, document)) {
+ if (prev_group &&
+ prev_group.firstChild.firstChild.href ===
+ tr.firstChild.firstChild.href) {
+ // we have to concatenate groups
+ var prev_rows = prev_group.firstChild.rowSpan || 1;
+ var curr_rows = tr.firstChild.rowSpan || 1;
+ prev_group.firstChild.rowSpan = prev_rows + curr_rows;
+ //tr.removeChild(tr.firstChild);
+ tr.deleteCell(0); // DOM2 HTML way
+ } else {
+ colorClass = (colorClass + 1) % 2;
+ prev_group = tr;
+ }
+ }
+ var tr_class = tr.className;
+ tr.className = tr_class.replace(colorRe, colorClasses[colorClass]);
+ linenum++;
+ }
+}
+
+/* ............................................................ */
+/* time and data */
+
+/**
+ * used to extract hours and minutes from timezone info, e.g '-0900'
+ * @constant
+ */
+var tzRe = /^([+-][0-9][0-9])([0-9][0-9])$/;
+
+/**
+ * return date in local time formatted in iso-8601 like format
+ * 'yyyy-mm-dd HH:MM:SS +/-ZZZZ' e.g. '2005-08-07 21:49:46 +0200'
+ *
+ * @param {Number} epoch: seconds since '00:00:00 1970-01-01 UTC'
+ * @param {String} timezoneInfo: numeric timezone '(+|-)HHMM'
+ * @returns {String} date in local time in iso-8601 like format
+ */
+function formatDateISOLocal(epoch, timezoneInfo) {
+ var match = tzRe.exec(timezoneInfo);
+ // date corrected by timezone
+ var localDate = new Date(1000 * (epoch +
+ (parseInt(match[1],10)*3600 + parseInt(match[2],10)*60)));
+ var localDateStr = // e.g. '2005-08-07'
+ localDate.getUTCFullYear() + '-' +
+ padLeft(localDate.getUTCMonth()+1, 2, '0') + '-' +
+ padLeft(localDate.getUTCDate(), 2, '0');
+ var localTimeStr = // e.g. '21:49:46'
+ padLeft(localDate.getUTCHours(), 2, '0') + ':' +
+ padLeft(localDate.getUTCMinutes(), 2, '0') + ':' +
+ padLeft(localDate.getUTCSeconds(), 2, '0');
+
+ return localDateStr + ' ' + localTimeStr + ' ' + timezoneInfo;
+}
+
+/* ............................................................ */
+/* unquoting/unescaping filenames */
+
+/**
+ * Used to detect escape sequences (octal e.g. \008 and symbolic e.g. \n)
+ * @constant
+ */
+var escCodeRe = /\\([^0-7]|[0-7]{1,3})/g;
+
+/**
+ * unquote maybe git-quoted filename
+ * e.g. 'aa' -> 'aa', '"a\ta"' -> 'a a'
+ *
+ * @param {String} str: git-quoted string
+ * @returns {String} Unquoted and unescaped string
+ */
+function unquote(str) {
+ function unq(seq) {
+ var es = { // character escape codes, aka escape sequences
+ t: "\t", // tab (HT, TAB)
+ n: "\n", // newline (NL)
+ r: "\r", // return (CR)
+ f: "\f", // form feed (FF)
+ b: "\b", // backspace (BS)
+ a: "\x07", // alarm (bell) (BEL)
+ e: "\x1B", // escape (ESC)
+ v: "\v" // vertical tab (VT)
+ };
+
+ if (seq.search(/^[0-7]{1,3}$/) !== -1) {
+ // octal char sequence
+ return String.fromCharCode(parseInt(seq, 8));
+ } else if (seq in es) {
+ // C escape sequence, aka character escape code
+ return es[seq];
+ }
+ // quoted ordinary character
+ return seq;
+ }
+
+ var match = str.match(/^\"(.*)\"$/);
+ if (match) {
+ str = match[1];
+ // perhaps str = eval('"'+str+'"'); would be enough?
+ str = str.replace(escCodeRe,
+ function (substr, p1, offset, s) { return unq(p1); });
+ }
+ return str;
+}
+
+/* ============================================================ */
+/* main part: parsing response */
+
+/**
+ * Function called for each blame entry, as soon as it finishes.
+ * It updates page via DOM manipulation, adding sha1 info, etc.
+ *
+ * @param {Commit} commit: blamed commit
+ * @param {Object} group: object representing group of lines,
+ * which blame the same commit (blame entry)
+ */
+function handleLine(commit, group) {
+ /*
+ This is the structure of the HTML fragment we are working
+ with:
+
+ <tr id="l123" class="">
+ <td class="sha1" title=""><a href=""> </a></td>
+ <td class="linenr"><a class="linenr" href="">123</a></td>
+ <td class="pre"># times (my ext3 doesn't).</td>
+ </tr>
+ */
+
+ var resline = group.resline;
+
+ // format date and time string only once per commit
+ if (!commit.info) {
+ /* e.g. 'Kay Sievers, 2005-08-07 21:49:46 +0200' */
+ commit.info = commit.author + ', ' +
+ formatDateISOLocal(commit.authorTime, commit.authorTimezone);
+ // delete properties no longer needed, to reduce memory footprint
+ //delete commit.author;
+ delete commit.authorTime;
+ delete commit.authorTimezone;
+ }
+
+ // color depends on group of lines, not only on blamed commit
+ var colorNo = findColorNo(
+ document.getElementById('l'+(resline-1)),
+ document.getElementById('l'+(resline+group.numlines))
+ );
+
+ // loop over lines in commit group
+ for (var i = 0; i < group.numlines; i++, resline++) {
+ var tr = document.getElementById('l'+resline);
+ if (!tr) {
+ //debug('tr is null! resline: ' + resline);
+ break;
+ }
+ /*
+ <tr id="l123" class="">
+ <td class="sha1" title=""><a href=""> </a></td>
+ <td class="linenr"><a class="linenr" href="">123</a></td>
+ <td class="pre"># times (my ext3 doesn't).</td>
+ </tr>
+ */
+ var td_sha1 = tr.firstChild;
+ var a_sha1 = td_sha1.firstChild;
+ var a_linenr = td_sha1.nextSibling.firstChild;
+
+ /* <tr id="l123" class=""> */
+ var tr_class = '';
+ if (colorNo !== null) {
+ tr_class = 'color'+colorNo;
+ }
+ if (commit.boundary) {
+ tr_class += ' boundary';
+ }
+ if (commit.nprevious === 0) {
+ tr_class += ' no-previous';
+ } else if (commit.nprevious > 1) {
+ tr_class += ' multiple-previous';
+ }
+ tr.className = tr_class;
+
+ /* <td class="sha1" title="?" rowspan="?"><a href="?">?</a></td> */
+ if (i === 0) {
+ td_sha1.title = commit.info;
+ td_sha1.rowSpan = group.numlines;
+
+ a_sha1.href = projectUrl + 'a=commit;h=' + commit.sha1;
+ a_sha1.firstChild.data = commit.sha1.substr(0, 8);
+ if (group.numlines >= 2) {
+ var fragment = document.createDocumentFragment();
+ var br = document.createElement("br");
+ var text = document.createTextNode(
+ commit.author.match(/\b([A-Z])\B/g).join(''));
+ if (br && text) {
+ var elem = fragment || td_sha1;
+ elem.appendChild(br);
+ elem.appendChild(text);
+ if (fragment) {
+ td_sha1.appendChild(fragment);
+ }
+ }
+ }
+ } else {
+ //tr.removeChild(td_sha1); // DOM2 Core way
+ tr.deleteCell(0); // DOM2 HTML way
+ }
+
+ /* <td class="linenr"><a class="linenr" href="?">123</a></td> */
+ var linenr_commit =
+ ('previous' in commit ? commit.previous : commit.sha1);
+ var linenr_filename =
+ ('file_parent' in commit ? commit.file_parent : commit.filename);
+ a_linenr.href = projectUrl + 'a=blame_incremental' +
+ ';hb=' + linenr_commit +
+ ';f=' + encodeURIComponent(linenr_filename) +
+ '#l' + (group.srcline + i);
+
+ blamedLines++;
+
+ //updateProgressInfo();
+ }
+}
+
+// ----------------------------------------------------------------------
+
+var prevDataLength = -1; // used to detect if we have new data
+var nextReadPos = 0; // where unread part of response starts
+var inProgress = false; // are we processing response
+
+/**#@+
+ * @constant
+ */
+var sha1Re = /^([0-9a-f]{40}) ([0-9]+) ([0-9]+) ([0-9]+)/;
+var infoRe = /^([a-z-]+) ?(.*)/;
+var endRe = /^END ?([^ ]*) ?(.*)/;
+/**@-*/
+
+var curCommit = new Commit();
+var curGroup = {};
+
+var pollTimer = null;
+
+/*
+ * W3C Progress Events (http://www.w3.org/TR/progress-events)
+ * events: loadstart, progress, error, abort, load
+ * interface: lengthComputable, loaded, total (0 if unknown)
+ */
+
+/*
+ * handleResponse ->
+ * handleError (or onXHReqError, onError, ...)
+ * handleAbort (?)
+ * handleProgress
+ * parseResponse / parseProgress
+ * parseBlame | parseJSON
+ * handleLine
+ * updateProgressInfo
+ * handleLoad
+ */
+
+/**
+ * Parse output from 'git blame --incremental [...]', received via
+ * XMLHttpRequest from server (blamedataUrl), and call handleLine
+ * (which updates page) as soon as blame entry is completed.
+ *
+ * @param {String[]} lines: new complete lines from blamedata server
+ */
+function processBlameLines(lines) {
+ var match;
+
+ for (var i = 0, len = lines.length; i < len; i++) {
+
+ if ((match = sha1Re.exec(lines[i]))) {
+ var sha1 = match[1];
+ var srcline = parseInt(match[2], 10);
+ var resline = parseInt(match[3], 10);
+ var numlines = parseInt(match[4], 10);
+
+ var c = commits[sha1];
+ if (!c) {
+ c = new Commit(sha1);
+ commits[sha1] = c;
+ }
+ curCommit = c;
+
+ curGroup.srcline = srcline;
+ curGroup.resline = resline;
+ curGroup.numlines = numlines;
+
+ } else if ((match = infoRe.exec(lines[i]))) {
+ var info = match[1];
+ var data = match[2];
+ switch (info) {
+ case 'filename':
+ curCommit.filename = unquote(data);
+ // 'filename' information terminates the entry
+ handleLine(curCommit, curGroup);
+ updateProgressInfo();
+ break;
+ case 'author':
+ curCommit.author = data;
+ break;
+ case 'author-time':
+ curCommit.authorTime = parseInt(data, 10);
+ break;
+ case 'author-tz':
+ curCommit.authorTimezone = data;
+ break;
+ case 'previous':
+ curCommit.nprevious++;
+ // store only first 'previous' header
+ if (!'previous' in curCommit) {
+ var parts = data.split(' ', 2);
+ curCommit.previous = parts[0];
+ curCommit.file_parent = unquote(parts[1]);
+ }
+ break;
+ case 'boundary':
+ //debug('Boundary commit: '+curCommit.sha1);
+ curCommit.boundary = true;
+ break;
+ } // end switch
+
+ } else if ((match = endRe.exec(lines[i]))) {
+ t_interval_server = match[1];
+ cmds_server = match[2];
+ //debug('END: '+lines[i]);
+
+ } else if (lines[i] !== '') {
+ //debug('malformed line: ' + lines[i]);
+
+ } // end if (match)
+
+ } // end for (lines)
+}
+
+/**
+ * Process new data and return pointer to end of processed part
+ *
+ * @param {String} unprocessed: new data (from nextReadPos)
+ * @param {Number} nextReadPos: end of last processed data
+ * @return {Number} end of processed data (new value for nextReadPos)
+ */
+function processData(unprocessed, nextReadPos) {
+ var lastLineEnd = unprocessed.lastIndexOf('\n');
+ if (lastLineEnd !== -1) {
+ var lines = unprocessed.substring(0, lastLineEnd).split('\n');
+ nextReadPos += lastLineEnd + 1 /* 1 == '\n'.length */;
+
+ processBlameLines(lines);
+ } // end if
+
+ return nextReadPos;
+}
+
+/**
+ * Handle XMLHttpRequest errors
+ */
+function handleError() {
+ errorInfo('Server error: ' +
+ xhr.status + ' - ' + (xhr.statusText || 'Error contacting server'));
+
+ clearInterval(pollTimer);
+ commits = {}; // free memory
+
+ inProgress = false;
+}
+
+/**
+ * Called after XMLHttpRequest finishes (loads)
+ */
+function responseLoaded() {
+ clearInterval(pollTimer);
+
+ fixColorsAndGroups();
+ writeTimeInterval();
+ commits = {}; // free memory
+
+ inProgress = false;
+}
+
+/**
+ * handler for XMLHttpRequest onreadystatechange event
+ * @see startBlame
+ */
+function handleResponse() {
+ //debug('handleResp ready: ' + xhr.readyState +
+ // ' respText null?: ' + (xhr.responseText === null) +
+ // ' progress: ' + inProgress);
+
+ /*
+ * xhr.readyState
+ *
+ * Value Constant (W3C) Description
+ * -------------------------------------------------------------------
+ * 0 UNSENT open() has not been called yet.
+ * 1 OPENED send() has not been called yet.
+ * 2 HEADERS_RECEIVED send() has been called, and headers
+ * and status are available.
+ * 3 LOADING Downloading; responseText holds partial data.
+ * 4 DONE The operation is complete.
+ */
+
+ if (xhr.readyState !== 4 && xhr.readyState !== 3) {
+ return;
+ }
+
+ // the server returned error
+ if (xhr.readyState === 3 && xhr.status !== 200) {
+ return;
+ }
+ if (xhr.readyState === 4 && xhr.status !== 200) {
+ handleError();
+ return;
+ }
+
+ // In konqueror xhr.responseText is sometimes null here...
+ if (xhr.responseText === null) {
+ return;
+ }
+
+ // in case we were called before finished processing
+ if (inProgress) {
+ return;
+ } else {
+ inProgress = true;
+ }
+
+ // extract new whole (complete) lines, and process them
+ while (prevDataLength !== xhr.responseText.length) {
+ if (xhr.readyState === 4 &&
+ prevDataLength === xhr.responseText.length) {
+ break;
+ }
+
+ prevDataLength = xhr.responseText.length;
+ var unprocessed = xhr.responseText.substring(nextReadPos);
+ nextReadPos = processData(unprocessed, nextReadPos);
+ } // end while
+
+ // did we finish work?
+ if (xhr.readyState === 4 &&
+ prevDataLength === xhr.responseText.length) {
+ responseLoaded();
+ }
+
+ inProgress = false;
+}
+
+// ============================================================
+// ------------------------------------------------------------
+
+/**
+ * Incrementally update line data in blame_incremental view in gitweb.
+ *
+ * @param {String} blamedataUrl: URL to server script generating blame data.
+ * @param {String} bUrl: partial URL to project, used to generate links.
+ *
+ * Called from 'blame_incremental' view after loading table with
+ * file contents, a base for blame view.
+*/
+function startBlame(blamedataUrl, bUrl) {
+ //debug('startBlame('+blamedataUrl+', '+bUrl+')');
+
+ xhr = createRequestObject();
+ if (!xhr) {
+ errorInfo('ERROR: XMLHttpRequest not supported');
+ return;
+ }
+
+ t0 = new Date();
+ projectUrl = bUrl + (bUrl.indexOf('?') === -1 ? '?' : ';');
+ if ((div_progress_bar = document.getElementById('progress_bar'))) {
+ //div_progress_bar.setAttribute('style', 'width: 100%;');
+ div_progress_bar.style.cssText = 'width: 100%;';
+ }
+ totalLines = countLines();
+ updateProgressInfo();
+
+ xhr.open('get', blamedataUrl);
+ xhr.setRequestHeader('Accept', 'text/plain');
+ xhr.onreadystatechange = handleResponse;
+ //xhr.onreadystatechange = function () { handleResponse(xhr); };
+ xhr.send(null);
+
+ // not all browsers call onreadystatechange event on each server flush
+ if (!DEBUG) {
+ pollTimer = setInterval(handleResponse, 1000);
+ }
+}
+
+// end of blame.js
diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index 8f68fe3..c9a7501 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -250,6 +250,11 @@ tr.no-previous td.linenr {
font-weight: bold;
}
+/* for 'blame_incremental', during processing */
+tr.color1 { background-color: #f6fff6; }
+tr.color2 { background-color: #f6f6ff; }
+tr.color3 { background-color: #fff6f6; }
+
td {
padding: 2px 5px;
font-size: 100%;
@@ -341,6 +346,17 @@ td.mode {
font-family: monospace;
}
+/* progress of blame_interactive */
+div#progress_bar {
+ height: 2px;
+ margin-bottom: -2px;
+ background-color: #d8d9d0;
+}
+div#progress_info {
+ float: right;
+ text-align: right;
+}
+
/* styling of diffs (patchsets): commitdiff and blobdiff views */
div.diff.header,
div.diff.extended_header {
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 6f47659..cf1b8bb 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -96,6 +96,8 @@ our $stylesheet = undef;
our $logo = "++GITWEB_LOGO++";
# URI of GIT favicon, assumed to be image/png type
our $favicon = "++GITWEB_FAVICON++";
+# URI of blame.js
+our $blamejs = "++GITWEB_BLAMEJS++";
# URI and label (title) of GIT logo link
#our $logo_url = "http://www.kernel.org/pub/software/scm/git/docs/";
@@ -564,6 +566,8 @@ our %cgi_param_mapping = @cgi_param_mapping;
# we will also need to know the possible actions, for validation
our %actions = (
"blame" => \&git_blame,
+ "blame_incremental" => \&git_blame_incremental,
+ "blame_data" => \&git_blame_data,
"blobdiff" => \&git_blobdiff,
"blobdiff_plain" => \&git_blobdiff_plain,
"blob" => \&git_blob,
@@ -4789,7 +4793,9 @@ sub git_tag {
git_footer_html();
}
-sub git_blame {
+sub git_blame_common {
+ my $format = shift || 'porcelain';
+
# permissions
gitweb_check_feature('blame')
or die_error(403, "Blame view not allowed");
@@ -4811,10 +4817,43 @@ sub git_blame {
}
}
- # run git-blame --porcelain
- open my $fd, "-|", git_cmd(), "blame", '-p',
- $hash_base, '--', $file_name
- or die_error(500, "Open git-blame failed");
+ my $fd;
+ if ($format eq 'incremental') {
+ # get file contents (as base)
+ open $fd, "-|", git_cmd(), 'cat-file', 'blob', $hash
+ or die_error(500, "Open git-cat-file failed");
+ } elsif ($format eq 'data') {
+ # run git-blame --incremental
+ open $fd, "-|", git_cmd(), "blame", "--incremental",
+ $hash_base, "--", $file_name
+ or die_error(500, "Open git-blame --incremental failed");
+ } else {
+ # run git-blame --porcelain
+ open $fd, "-|", git_cmd(), "blame", '-p',
+ $hash_base, '--', $file_name
+ or die_error(500, "Open git-blame --porcelain failed");
+ }
+
+ # incremental blame data returns early
+ if ($format eq 'data') {
+ print $cgi->header(
+ -type=>"text/plain", -charset => "utf-8",
+ -status=> "200 OK");
+ local $| = 1; # output autoflush
+ print while <$fd>;
+ close $fd
+ or print "ERROR $!\n";
+
+ print 'END';
+ if (defined $t0 && gitweb_check_feature('timed')) {
+ print ' '.
+ Time::HiRes::tv_interval($t0, [Time::HiRes::gettimeofday()]).
+ ' '.$number_of_git_cmds;
+ }
+ print "\n";
+
+ return;
+ }
# page header
git_header_html();
@@ -4825,109 +4864,169 @@ sub git_blame {
$cgi->a({-href => href(action=>"history", -replay=>1)},
"history") .
" | " .
- $cgi->a({-href => href(action=>"blame", file_name=>$file_name)},
+ $cgi->a({-href => href(action=>$action, file_name=>$file_name)},
"HEAD");
git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
git_print_page_path($file_name, $ftype, $hash_base);
# page body
+ if ($format eq 'incremental') {
+ print "<noscript>\n<div class=\"error\"><center><b>\n".
+ "This page requires JavaScript to run.\n Use ".
+ $cgi->a({-href => href(action=>'blame',-replay=>1)}, 'this page').
+ " instead.\n".
+ "</b></center></div>\n</noscript>\n";
+
+ print qq!<div id="progress_bar" style="width: 100%; background-color: yellow"></div>\n!;
+ }
+
+ print qq!<div class="page_body">\n!;
+ print qq!<div id="progress_info">... / ...</div>\n!
+ if ($format eq 'incremental');
+ print qq!<table id="blame_table" class="blame" width="100%">\n!.
+ #qq!<col width="5.5em" /><col width="2.5em" /><col width="*" />\n!.
+ qq!<thead>\n!.
+ qq!<tr><th>Commit</th><th>Line</th><th>Data</th></tr>\n!.
+ qq!</thead>\n!.
+ qq!<tbody>\n!;
+
my @rev_color = qw(light dark);
my $num_colors = scalar(@rev_color);
my $current_color = 0;
- my %metainfo = ();
- print <<HTML;
-<div class="page_body">
-<table class="blame">
-<tr><th>Commit</th><th>Line</th><th>Data</th></tr>
-HTML
- LINE:
- while (my $line = <$fd>) {
- chomp $line;
- # the header: <SHA-1> <src lineno> <dst lineno> [<lines in group>]
- # no <lines in group> for subsequent lines in group of lines
- my ($full_rev, $orig_lineno, $lineno, $group_size) =
- ($line =~ /^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/);
- if (!exists $metainfo{$full_rev}) {
- $metainfo{$full_rev} = { 'nprevious' => 0 };
- }
- my $meta = $metainfo{$full_rev};
- my $data;
- while ($data = <$fd>) {
- chomp $data;
- last if ($data =~ s/^\t//); # contents of line
- if ($data =~ /^(\S+)(?: (.*))?$/) {
- $meta->{$1} = $2 unless exists $meta->{$1};
+ if ($format eq 'incremental') {
+ my $color_class = $rev_color[$current_color];
+
+ #contents of a file
+ my $linenr = 0;
+ LINE:
+ while (my $line = <$fd>) {
+ chomp $line;
+ $linenr++;
+
+ print qq!<tr id="l$linenr" class="$color_class">!.
+ qq!<td class="sha1"><a href=""> </a></td>!.
+ qq!<td class="linenr">!.
+ qq!<a class="linenr" href="">$linenr</a></td>!;
+ print qq!<td class="pre">! . esc_html($line) . "</td>\n";
+ print qq!</tr>\n!;
+ }
+
+ } else { # porcelain, i.e. ordinary blame
+ my %metainfo = (); # saves information about commits
+
+ # blame data
+ LINE:
+ while (my $line = <$fd>) {
+ chomp $line;
+ # the header: <SHA-1> <src lineno> <dst lineno> [<lines in group>]
+ # no <lines in group> for subsequent lines in group of lines
+ my ($full_rev, $orig_lineno, $lineno, $group_size) =
+ ($line =~ /^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/);
+ if (!exists $metainfo{$full_rev}) {
+ $metainfo{$full_rev} = { 'nprevious' => 0 };
}
- if ($data =~ /^previous /) {
- $meta->{'nprevious'}++;
+ my $meta = $metainfo{$full_rev};
+ my $data;
+ while ($data = <$fd>) {
+ chomp $data;
+ last if ($data =~ s/^\t//); # contents of line
+ if ($data =~ /^(\S+)(?: (.*))?$/) {
+ $meta->{$1} = $2 unless exists $meta->{$1};
+ }
+ if ($data =~ /^previous /) {
+ $meta->{'nprevious'}++;
+ }
}
- }
- my $short_rev = substr($full_rev, 0, 8);
- my $author = $meta->{'author'};
- my %date =
- parse_date($meta->{'author-time'}, $meta->{'author-tz'});
- my $date = $date{'iso-tz'};
- if ($group_size) {
- $current_color = ($current_color + 1) % $num_colors;
- }
- my $tr_class = $rev_color[$current_color];
- $tr_class .= ' boundary' if (exists $meta->{'boundary'});
- $tr_class .= ' no-previous' if ($meta->{'nprevious'} == 0);
- $tr_class .= ' multiple-previous' if ($meta->{'nprevious'} > 1);
- print "<tr id=\"l$lineno\" class=\"$tr_class\">\n";
- if ($group_size) {
- print "<td class=\"sha1\"";
- print " title=\"". esc_html($author) . ", $date\"";
- print " rowspan=\"$group_size\"" if ($group_size > 1);
- print ">";
- print $cgi->a({-href => href(action=>"commit",
- hash=>$full_rev,
- file_name=>$file_name)},
- esc_html($short_rev));
- if ($group_size >= 2) {
- my @author_initials = ($author =~ /\b([[:upper:]])\B/g);
- if (@author_initials) {
- print "<br />" .
- esc_html(join('', @author_initials));
- # or join('.', ...)
+ my $short_rev = substr($full_rev, 0, 8);
+ my $author = $meta->{'author'};
+ my %date =
+ parse_date($meta->{'author-time'}, $meta->{'author-tz'});
+ my $date = $date{'iso-tz'};
+ if ($group_size) {
+ $current_color = ($current_color + 1) % $num_colors;
+ }
+ my $tr_class = $rev_color[$current_color];
+ $tr_class .= ' boundary' if (exists $meta->{'boundary'});
+ $tr_class .= ' no-previous' if ($meta->{'nprevious'} == 0);
+ $tr_class .= ' multiple-previous' if ($meta->{'nprevious'} > 1);
+ print "<tr id=\"l$lineno\" class=\"$tr_class\">\n";
+ if ($group_size) {
+ print "<td class=\"sha1\"";
+ print " title=\"". esc_html($author) . ", $date\"";
+ print " rowspan=\"$group_size\"" if ($group_size > 1);
+ print ">";
+ print $cgi->a({-href => href(action=>"commit",
+ hash=>$full_rev,
+ file_name=>$file_name)},
+ esc_html($short_rev));
+ if ($group_size >= 2) {
+ my @author_initials = ($author =~ /\b([[:upper:]])\B/g);
+ if (@author_initials) {
+ print "<br />" .
+ esc_html(join('', @author_initials));
+ # or join('.', ...)
+ }
}
+ print "</td>\n";
}
- print "</td>\n";
- }
- # 'previous' <sha1 of parent commit> <filename at commit>
- if (exists $meta->{'previous'} &&
- $meta->{'previous'} =~ /^([a-fA-F0-9]{40}) (.*)$/) {
- $meta->{'parent'} = $1;
- $meta->{'file_parent'} = unquote($2);
- }
- my $linenr_commit =
- exists($meta->{'parent'}) ?
- $meta->{'parent'} : $full_rev;
- my $linenr_filename =
- exists($meta->{'file_parent'}) ?
- $meta->{'file_parent'} : unquote($meta->{'filename'});
- my $blamed = href(action => 'blame',
- file_name => $linenr_filename,
- hash_base => $linenr_commit);
- print "<td class=\"linenr\">";
- print $cgi->a({ -href => "$blamed#l$orig_lineno",
- -class => "linenr" },
- esc_html($lineno));
- print "</td>";
- print "<td class=\"pre\">" . esc_html($data) . "</td>\n";
- print "</tr>\n";
+ # 'previous' <sha1 of parent commit> <filename at commit>
+ if (exists $meta->{'previous'} &&
+ $meta->{'previous'} =~ /^([a-fA-F0-9]{40}) (.*)$/) {
+ $meta->{'parent'} = $1;
+ $meta->{'file_parent'} = unquote($2);
+ }
+ my $linenr_commit =
+ exists($meta->{'parent'}) ?
+ $meta->{'parent'} : $full_rev;
+ my $linenr_filename =
+ exists($meta->{'file_parent'}) ?
+ $meta->{'file_parent'} : unquote($meta->{'filename'});
+ my $blamed = href(action => 'blame',
+ file_name => $linenr_filename,
+ hash_base => $linenr_commit);
+ print "<td class=\"linenr\">";
+ print $cgi->a({ -href => "$blamed#l$orig_lineno",
+ -class => "linenr" },
+ esc_html($lineno));
+ print "</td>";
+ print "<td class=\"pre\">" . esc_html($data) . "</td>\n";
+ print "</tr>\n";
+ } # end while
+
}
- print "</table>\n";
- print "</div>";
+
+ # footer
+ print "</tbody>\n".
+ "</table>\n"; # class="blame"
+ print "</div>\n"; # class="blame_body"
close $fd
or print "Reading blob failed\n";
- # page footer
+ if ($format eq 'incremental') {
+ print qq!<script type="text/javascript" src="$blamejs"></script>\n!.
+ qq!<script type="text/javascript">\n!.
+ qq!startBlame("!. href(action=>"blame_data", -replay=>1) .qq!",\n!.
+ qq! "!. href() .qq!");\n!.
+ qq!</script>\n!;
+ }
+
git_footer_html();
}
+sub git_blame {
+ git_blame_common();
+}
+
+sub git_blame_incremental {
+ git_blame_common('incremental');
+}
+
+sub git_blame_data {
+ git_blame_common('data');
+}
+
sub git_tags {
my $head = git_get_head_hash($project);
git_header_html();
--
1.6.3.3
^ permalink raw reply related
* [PATCH JGIT] Recognize gitlink tree entries when mapping a tree
From: Jonas Fonseca @ 2009-08-12 17:30 UTC (permalink / raw)
To: Robin Rosenberg, Shawn O. Pearce; +Cc: git
In-Reply-To: <20090812153210.GF1033@spearce.org>
Also adds minimal testing of symlink and gitlink tree entries and amends
gitlink related javadoc.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
On Wed, Aug 12, 2009 at 11:32, Shawn O. Pearce<spearce@spearce.org> wrote:
> Jonas Fonseca <fonseca@diku.dk> wrote:
>> Adds minimal support for gitlinks, based on the existing code for
>> handling symlinks. The goal is to avoid exceptions when reading trees
>> with gitlinks.
>
> Applied, but who calls GitlinkTreeEntry ?
True, here is a follow up, which should fix this. With this the Netbeans
module no longer dumps stack traces when dealing with a repository containing
submodules.
.../spearce/jgit/test/resources/create-second-pack | 13 ++++++++++++-
...ck-cbdeda40019ae0e6e789088ea0f51f164f489d14.idx | Bin 0 -> 1240 bytes
...k-cbdeda40019ae0e6e789088ea0f51f164f489d14.pack | Bin 0 -> 651 bytes
.../org/spearce/jgit/test/resources/packed-refs | 2 ++
.../org/spearce/jgit/lib/RepositoryTestCase.java | 1 +
.../tst/org/spearce/jgit/lib/T0002_Tree.java | 7 +++++++
.../org/spearce/jgit/transport/TransportTest.java | 2 +-
.../src/org/spearce/jgit/lib/GitlinkTreeEntry.java | 2 +-
.../src/org/spearce/jgit/lib/Tree.java | 14 ++++++++------
.../src/org/spearce/jgit/lib/TreeEntry.java | 2 +-
10 files changed, 33 insertions(+), 10 deletions(-)
create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.idx
create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.pack
diff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/create-second-pack b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/create-second-pack
index 5501a67..7241fa6 100755
--- a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/create-second-pack
+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/create-second-pack
@@ -148,8 +148,19 @@ mkdir f
echo "an F" >f/f
git add f/f
git commit -m "An F"
+
git repack -d
-git pack-refs --all
+git checkout -b symlink master
+ln -s c/c1.txt symlink.txt
+git add symlink.txt
+git_commit -m "A symlink"
+
+git checkout -b gitlink master
+git submodule add "$(pwd)/.git" submodule
+git_commit -m "A gitlink"
+
+git repack -d
+git pack-refs --all
gitk --all master
diff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.idx b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.idx
new file mode 100644
index 0000000000000000000000000000000000000000..a5aed7def26f945bc329429195702b6c5f82444e
GIT binary patch
literal 1240
zcmexg;-AdGz`z8=LlH0n9X(VqD2$OYGmwuBvjD}hVOF5{D5h^1umQt-L||Q(cO|zM
zGgKV9bGy*?cK4G#9KK}{MLm<dW_8ajIK!!&vwq6jB^fi7V;(SYoVVZcamrV9CnoMI
zycM56ZcfsiRrP4XwN}ZzDP8)fYkSy##?)q<mRHtH`Fu9B>yPaEr_Ga#n2)v}U9D~~
zW#ai1xsB3Wwl8mU{M4|e>CBhT@0-kPc{h9$XyamDB^6LtD7$dd;$mP{Ndso>L%{G~
z3Zy}KoCheTvs+fx_VNdg(i1Ef@{3<GG~MPrAv_`8pq2B=iun8P36r;N{?oH6s!a+2
Df+%BI
literal 0
HcmV?d00001
diff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.pack b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.pack
new file mode 100644
index 0000000000000000000000000000000000000000..24f69429a0fa4f206a7e6481e17fd0e11725c219
GIT binary patch
literal 651
zcmV;60(AXQK|@Ob00062000J@4S1ZL%UcS<Fc5{|_pBltu;kKaG9Y62pbMBxrdsTc
zl7h=O-GXn2|L~PvL<i>(2}m589AalN2)2>jzzK3>0|RypS#7k-Qgn;nxs)tqPt0iB
zFkobaY@p)$#gqomM$u8;>#lqK)Q@vqsX3Z6-Q`R3Hc7+leACuiht+jnUkn(dYMsYY
z<PWNP{Tj<OE+6#+d)Pm+;RS#hc$~Y#c!yE9q$o92A=xxB$;jN;z|zFhFgeZ4#4t6<
z&@d^<B*{F{+ycl=GqNy9GO;k4s2k5@XgRUZQq<7WSV7mo+`xc~%Tb}YGB+nPFPjSh
z!RHoirVMzTGc+(TGci%nOV2FH%}*)KNiAlGDC(KqHLH7O!5L2Fob^-IF3FgwY+?We
z3W*F{w&g`0-Pr>9+cboaT)U<|v3Fu4L@tRzfaSvVHEO@V83ZgcIk}_DjXhlQGDI$!
z!Sm>kK!>~rmK|a{#QF0j9`n5@-)RW3IybSnB(+Gdq@skOY2$^Kw3h+#ZE4#pO8jS;
z6fWm!G&BPnQCyk?aUX-Hk@m(~t1}bbe)deiP!VXPvHSA@0OH(DH@paVoIT1x4uBvG
zMA5aJg1DESz>^pkh!r(xO<V3SsBt%We+J3ZL32)M+kdvBX)dp;?d@--$(#znN(aJ1
zr(p0P9AJ-|0&#S5q33|Ef>RU)745iwN`^1L|0gpF<w63kn7IMT$}+U>0)Z=doIA$2
zka41VwVIIu5GWK^=H_JPW$TqxlrZSByeqlAn4#j(o!f=Bx4WP0;qWa30EL1Q>o|Cv
lOV&>|)GMhd0RRgq0=2sxB|X#d2zAH=&~J0;0D{{I$P-a{H+%p9
literal 0
HcmV?d00001
diff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/packed-refs b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/packed-refs
index a6a14f2..82fb0d7 100644
--- a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/packed-refs
+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/test/resources/packed-refs
@@ -7,8 +7,10 @@ d0114ab8ac326bab30e3a657a0397578c5a1af88 refs/heads/e
47d3697c3747e8184e0dc479ccbd01e359023577 refs/heads/f
175d5b80bd9768884d8fced02e9bd33488174396 refs/heads/g
175d5b80bd9768884d8fced02e9bd33488174396 refs/heads/prefix/a
+68cb1f232964f3cd698afc1dafe583937203c587 refs/heads/gitlink
49322bb17d3acc9146f98c97d078513228bbf3c0 refs/heads/master
d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864 refs/heads/pa
+5ce00008cf3fb8f194f52742020bd40d78f3f1b3 refs/heads/symlink
6db9c2ebf75590eef973081736730a9ea169a0c4 refs/tags/A
17768080a2318cd89bba4c8b87834401e2095703 refs/tags/B
^d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864
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 6de9afe..b1adde9 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
@@ -249,6 +249,7 @@ public void run() {
"pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371",
"pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745",
"pack-546ff360fe3488adb20860ce3436a2d6373d2796",
+ "pack-cbdeda40019ae0e6e789088ea0f51f164f489d14",
"pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa",
"pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12"
};
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/T0002_Tree.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/T0002_Tree.java
index 97f299c..febcbc6 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/T0002_Tree.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/T0002_Tree.java
@@ -271,4 +271,11 @@ public void test008_SubtreeInternalSorting() throws IOException {
assertSame(e4, ents[3]);
assertSame(e2, ents[4]);
}
+
+ public void test009_SymlinkAndGitlink() throws IOException {
+ final Tree symlinkTree = db.mapTree("symlink");
+ assertTrue("Symlink entry exists", symlinkTree.existsBlob("symlink.txt"));
+ final Tree gitlinkTree = db.mapTree("gitlink");
+ assertTrue("Gitlink entry exists", gitlinkTree.existsBlob("submodule"));
+ }
}
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java
index fcf3f5c..c6bd13d 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java
@@ -123,7 +123,7 @@ public void testFindRemoteRefUpdatesWildcardNoTracking() throws IOException {
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
"+refs/heads/*:refs/heads/test/*")));
- assertEquals(10, result.size());
+ assertEquals(12, result.size());
boolean foundA = false;
boolean foundB = false;
for (final RemoteRefUpdate rru : result) {
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/GitlinkTreeEntry.java b/org.spearce.jgit/src/org/spearce/jgit/lib/GitlinkTreeEntry.java
index db6a8e2..5cabbd6 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/GitlinkTreeEntry.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/GitlinkTreeEntry.java
@@ -42,7 +42,7 @@
import java.io.IOException;
/**
- * A tree entry representing a symbolic link.
+ * A tree entry representing a gitlink entry used for submodules.
*
* Note. Java cannot really handle these as file system objects.
*/
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Tree.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Tree.java
index ff9e666..291fce8 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Tree.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Tree.java
@@ -428,7 +428,7 @@ private boolean exists(final String s, byte slast) throws IOException {
}
/**
- * @param path
+ * @param path to the tree.
* @return true if a tree with the specified path can be found under this
* tree.
* @throws IOException
@@ -438,9 +438,9 @@ public boolean existsTree(String path) throws IOException {
}
/**
- * @param path
- * @return true if a blob or symlink with the specified name can be found
- * under this tree.
+ * @param path of the non-tree entry.
+ * @return true if a blob, symlink, or gitlink with the specified name
+ * can be found under this tree.
* @throws IOException
*/
public boolean existsBlob(String path) throws IOException {
@@ -576,10 +576,12 @@ else if (c < '0' || c > '7')
ent = new FileTreeEntry(this, id, name, false);
else if (FileMode.EXECUTABLE_FILE.equals(mode))
ent = new FileTreeEntry(this, id, name, true);
- else if (FileMode.TREE.equals(mode)) {
+ else if (FileMode.TREE.equals(mode))
ent = new Tree(this, id, name);
- } else if (FileMode.SYMLINK.equals(mode))
+ else if (FileMode.SYMLINK.equals(mode))
ent = new SymlinkTreeEntry(this, id, name);
+ else if (FileMode.GITLINK.equals(mode))
+ ent = new GitlinkTreeEntry(this, id, name);
else
throw new CorruptObjectException(getId(), "Invalid mode: "
+ Integer.toOctalString(mode));
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/TreeEntry.java b/org.spearce.jgit/src/org/spearce/jgit/lib/TreeEntry.java
index c95863c..4921c7a 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/TreeEntry.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/TreeEntry.java
@@ -232,7 +232,7 @@ public int compareTo(final Object o) {
* @return '/' for Tree entries and NUL for non-treeish objects.
*/
final public static int lastChar(TreeEntry treeEntry) {
- if (treeEntry instanceof FileTreeEntry)
+ if (!(treeEntry instanceof Tree))
return '\0';
else
return '/';
--
1.6.4.rc3.195.g2b05f
^ permalink raw reply related
* Re: [RFCv3 2/4] Add Python support library for CVS remote helper
From: Sverre Rabbelier @ 2009-08-12 17:43 UTC (permalink / raw)
To: Johan Herland; +Cc: David Aguilar, git, barkalow, gitster, Johannes.Schindelin
In-Reply-To: <200908121108.28714.johan@herland.net>
Heya,
On Wed, Aug 12, 2009 at 02:08, Johan Herland<johan@herland.net> wrote:
> I can't find a good rationale for this rule in PEP8 (other than Guido's
> personal style), and I personally find the above much more readable
> (otherwise I wouldn't go through the trouble of lining them all up...). Can
> I claim exception (1) (readability)?
Working with python a lot myself, if you want to claim readability _to
python hackers_, then you should follow PEP8. If you want to follow
your own personal style which is easily readable to you, then by all
means; just know that people that read python a lot will have a hard
time reading your code ;).
--
Cheers,
Sverre Rabbelier
^ permalink raw reply
* Re: git index: how does it work?
From: Sverre Rabbelier @ 2009-08-12 17:47 UTC (permalink / raw)
To: Shaun Cutts; +Cc: Junio C Hamano, git
In-Reply-To: <436D5ED1-2F0E-4227-AC4A-3A5FD16B2DCF@cuttshome.net>
Heya,
On Wed, Aug 12, 2009 at 04:52, Shaun Cutts<shaun@cuttshome.net> wrote:
> Are renames being tracked by the index, and is there a more basic interface
> than "status" to query about them?
Nope, git never explicitly tracks renames. Try this:
$ mv foo bar
$ git rm --cached foo
$ git add bar
$ git status
It'll tell you that you renamed foo to bar, even if you never executed 'git mv'.
This is because git does rename _detection_, that is, it'll notice
that you have another file with (almost) the same contents, so it
assumes you did a rename.
--
Cheers,
Sverre Rabbelier
^ permalink raw reply
* Re: [PATCH] git-gui: Update russian translation
From: Dan Zwell @ 2009-08-12 15:51 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Alex Riesen, Git Mailing List
In-Reply-To: <20090812154016.GG1033@spearce.org>
> Alex Riesen <raa.lkml@gmail.com> wrote:
>> But now, when I really think about the change, it looks useless.
>> What has the _number_ of files has to do with the files you actually
>> have to handle? As the sorting of the file list cannot be changed (and
>> it wouldn't be a big help anyway), you have no chance to get to your
>> file if it happens to be past the limit!
> Good point. I suspect the problem wasn't so much with Tcl doing the
> list processing as it was with Tk actually creating the underlying
> icons and stuff for each file name. But with the list clipped,
> you are right, you are basically SOL. You can't do much beyond
> dropping back to the CLI and using the CLI tools.
>
> IMHO, if we aren't going to handle 20k file names, we should at least
> punt and tell the user we aren't going to handle 20k file names,
> rather than just play Outlook wannabe and lockup the entire UI until
> the user gets bored and kill -9's us. So this patch is better than
> nothing, it at least lets the user know we have given up on them.
>
A warning would be good, but this gives users more information. In my
case, I only wanted to see a few files, but the rest were from a
directory that should have been in .gitignore. If I had seen the
filenames, I would have known which directory was the culprit. This way,
you don't need to drop to the command line to fix the problem.
-Dan
^ permalink raw reply
* Tie a CVS-aware app into GIT?
From: david.hagood @ 2009-08-12 18:01 UTC (permalink / raw)
To: git
I have an application (closed source, unfortunately) that can use CVS to
manage its files (specifically, Enterprise Architect by Sparx).
I'd rather use GIT to manage the files, but EA doesn't "speak" git - just
CVS and Subversion (and Microsoft's SCC protocol, but...)
Are there any programs which
1) accept the same command line parameters as CVS or Subversion
and
2) access a GIT repository.
git-svn is almost exactly NOT what I need, as it accepts "git" type
command line parameters and access a SVN repo, rather than accepting SVN
command line parameters and accessing a GIT repo.
Now, obviously, such a tool wouldn't have access to all the things that
GIT can do, and that is NOT what I am expecting - what I want is just to
enable EA to do the things it needs to do, namely adding/removing/moving
files from a repo. Branching, commits, and so on can be done manually.
I've thought about git-cvsserver as a solution, but I don't know if it can
be run on a local machine to access a local repository.
I'd appreciate any help on this.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox