* [PATCH (GITK) 1/6] gitk: Kill back-end processes on window close.
From: Alexander Gavrilov @ 2008-07-27 6:18 UTC (permalink / raw)
To: git; +Cc: Paul Mackerras
In-Reply-To: <200807271017.23272.angavrilov@gmail.com>
Date: Sat, 12 Jul 2008 16:09:28 +0400
When collecting commits for a rarely changed, or recently
created file or directory, rev-list may work for a noticeable
period of time without producing any output. Such processes
don't receive SIGPIPE for a while after gitk is closed, thus
becoming runaway CPU hogs.
Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---
gitk | 35 +++++++++++++++++++++++++----------
1 files changed, 25 insertions(+), 10 deletions(-)
diff --git a/gitk b/gitk
index fddcb45..29d79d6 100755
--- a/gitk
+++ b/gitk
@@ -375,19 +375,33 @@ proc start_rev_list {view} {
return 1
}
+proc stop_instance {inst} {
+ global commfd leftover
+
+ set fd $commfd($inst)
+ catch {
+ set pid [pid $fd]
+ exec kill $pid
+ }
+ catch {close $fd}
+ nukefile $fd
+ unset commfd($inst)
+ unset leftover($inst)
+}
+
+proc stop_backends {} {
+ global commfd
+
+ foreach inst [array names commfd] {
+ stop_instance $inst
+ }
+}
+
proc stop_rev_list {view} {
- global commfd viewinstances leftover
+ global viewinstances
foreach inst $viewinstances($view) {
- set fd $commfd($inst)
- catch {
- set pid [pid $fd]
- exec kill $pid
- }
- catch {close $fd}
- nukefile $fd
- unset commfd($inst)
- unset leftover($inst)
+ stop_instance $inst
}
set viewinstances($view) {}
}
@@ -2103,6 +2117,7 @@ proc makewindow {} {
bind . <$M1B-minus> {incrfont -1}
bind . <$M1B-KP_Subtract> {incrfont -1}
wm protocol . WM_DELETE_WINDOW doquit
+ bind . <Destroy> {stop_backends}
bind . <Button-1> "click %W"
bind $fstring <Key-Return> {dofind 1 1}
bind $sha1entry <Key-Return> gotocommit
--
1.5.6.3.18.gfe82
^ permalink raw reply related
* [PATCH (GITK) 0/6] Runaway process and commit selection fixes
From: Alexander Gavrilov @ 2008-07-27 6:17 UTC (permalink / raw)
To: git; +Cc: Paul Mackerras
This series includes three patches that I sent 8 days ago,
because I haven't received any reply so far.
These patches address the following problems:
1) Runaway processes (resend)
As in the 'git gui blame' case, gitk back-end processes can sometimes
run for a while without producing any output, e.g. diff-files on a slow
filesystem.
These patches make gitk explicitly kill its back-end processes.
2) Gitk stopping showing any diffs under random conditions.
3) Broken commit selection on view reload: gitk tried to preserve
the selected commit, but usually failed because of code rot.
I added selection preservation on Reload and Edit View.
Update still should reset the selection to HEAD if anything changed.
Also, if the previously selected commit was not found in the new view,
gitk should fall back to selecting HEAD.
Alexander Gavrilov (6):
gitk: Kill back-end processes on window close.
gitk: Register diff-files & diff-index in commfd, to ensure kill.
gitk: On Windows use a Cygwin-specific flag for kill.
gitk: Fixed broken exception handling in diff.
gitk: Fixed automatic row selection during load.
gitk: Fallback to selecting the head commit upon load.
gitk | 148 +++++++++++++++++++++++++++++++++++++++++++-----------------------
1 files changed, 97 insertions(+), 51 deletions(-)
^ permalink raw reply
* [PATCH] make sure parsed wildcard refspec ends with slash
From: Junio C Hamano @ 2008-07-27 6:15 UTC (permalink / raw)
To: Jeff King; +Cc: Daniel Barkalow, git
In-Reply-To: <7vvdysb2na.fsf@gitster.siamese.dyndns.org>
A wildcard refspec is internally parsed into a refspec structure with src
and dst strings. Many parts of the code assumed that these do not include
the trailing "/*" when matching the wildcard pattern with an actual ref we
see at the remote. What this meant was that we needed to make sure not
just that the prefix matched, and also that a slash followed the part that
matched.
But a codepath that scans the result from ls-remote and finds matching
refs forgot to check the "matching part must be followed by a slash" rule.
This resulted in "refs/heads/b1" from the remote side to mistakenly match
the source side of "refs/heads/b/*:refs/remotes/b/*" refspec.
Worse, the refspec crafted internally by "git-clone", and a hardcoded
preparsed refspec that is used to implement "git-fetch --tags", violated
this "parsed widcard refspec does not end with slash" rule; simply adding
the "matching part must be followed by a slash" rule then would have
broken codepaths that use these refspecs.
This commit changes the rule to require a trailing slash to parsed
wildcard refspecs. IOW, "refs/heads/b/*:refs/remotes/b/*" is parsed as
src = "refs/heads/b/" and dst = "refs/remotes/b/". This allows us to
simplify the matching logic because we only need to do a prefixcmp() to
notice "refs/heads/b/one" matches and "refs/heads/b1" does not.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
Junio C Hamano <gitster@pobox.com> writes:
> I have a nagging suspicion that it might be a simpler and cleaner change
> to change parse_refspec_internal() to keep the trailing slash, instead of
> dropping it. Then the check you added is not needed (the trailing slash
> guarantees that the pattern matches at the hierarchy boundary), neither
> any of the change in this patch.
This is the other variant, and it turns out that I was right. Among the
64-18 = 46 new lines, 30 are from the new test file. Two existing
"matching part is followed by '/'" tests are removed.
remote.c | 52 +++++++++++++++++++++++++++++++----------------
t/t5513-fetch-track.sh | 30 +++++++++++++++++++++++++++
2 files changed, 64 insertions(+), 18 deletions(-)
diff --git a/remote.c b/remote.c
index 0d6020b..f61a3ab 100644
--- a/remote.c
+++ b/remote.c
@@ -427,6 +427,28 @@ static void read_config(void)
alias_all_urls();
}
+/*
+ * We need to make sure the tracking branches are well formed, but a
+ * wildcard refspec in "struct refspec" must have a trailing slash. We
+ * temporarily drop the trailing '/' while calling check_ref_format(),
+ * and put it back. The caller knows that a CHECK_REF_FORMAT_ONELEVEL
+ * error return is Ok for a wildcard refspec.
+ */
+static int verify_refname(char *name, int is_glob)
+{
+ int result, len = -1;
+
+ if (is_glob) {
+ len = strlen(name);
+ assert(name[len - 1] == '/');
+ name[len - 1] = '\0';
+ }
+ result = check_ref_format(name);
+ if (is_glob)
+ name[len - 1] = '/';
+ return result;
+}
+
static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
{
int i;
@@ -434,11 +456,11 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
for (i = 0; i < nr_refspec; i++) {
- size_t llen, rlen;
+ size_t llen;
int is_glob;
const char *lhs, *rhs;
- llen = rlen = is_glob = 0;
+ llen = is_glob = 0;
lhs = refspec[i];
if (*lhs == '+') {
@@ -458,12 +480,9 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
}
if (rhs) {
- rhs++;
- rlen = strlen(rhs);
+ size_t rlen = strlen(++rhs);
is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*"));
- if (is_glob)
- rlen -= 2;
- rs[i].dst = xstrndup(rhs, rlen);
+ rs[i].dst = xstrndup(rhs, rlen - is_glob);
}
llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
@@ -471,7 +490,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
if ((rhs && !is_glob) || (!rhs && fetch))
goto invalid;
is_glob = 1;
- llen -= 2;
+ llen--;
} else if (rhs && is_glob) {
goto invalid;
}
@@ -488,7 +507,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
if (!*rs[i].src)
; /* empty is ok */
else {
- st = check_ref_format(rs[i].src);
+ st = verify_refname(rs[i].src, is_glob);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
goto invalid;
}
@@ -503,7 +522,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
} else if (!*rs[i].dst) {
; /* ok */
} else {
- st = check_ref_format(rs[i].dst);
+ st = verify_refname(rs[i].dst, is_glob);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
goto invalid;
}
@@ -518,7 +537,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
if (!*rs[i].src)
; /* empty is ok */
else if (is_glob) {
- st = check_ref_format(rs[i].src);
+ st = verify_refname(rs[i].src, is_glob);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
goto invalid;
}
@@ -532,13 +551,13 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
* - otherwise it must be a valid looking ref.
*/
if (!rs[i].dst) {
- st = check_ref_format(rs[i].src);
+ st = verify_refname(rs[i].src, is_glob);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
goto invalid;
} else if (!*rs[i].dst) {
goto invalid;
} else {
- st = check_ref_format(rs[i].dst);
+ st = verify_refname(rs[i].dst, is_glob);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
goto invalid;
}
@@ -687,8 +706,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
if (!fetch->dst)
continue;
if (fetch->pattern) {
- if (!prefixcmp(needle, key) &&
- needle[strlen(key)] == '/') {
+ if (!prefixcmp(needle, key)) {
*result = xmalloc(strlen(value) +
strlen(needle) -
strlen(key) + 1);
@@ -966,9 +984,7 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
continue;
}
- if (rs[i].pattern &&
- !prefixcmp(src->name, rs[i].src) &&
- src->name[strlen(rs[i].src)] == '/')
+ if (rs[i].pattern && !prefixcmp(src->name, rs[i].src))
return rs + i;
}
if (matching_refs != -1)
diff --git a/t/t5513-fetch-track.sh b/t/t5513-fetch-track.sh
new file mode 100755
index 0000000..9e74862
--- /dev/null
+++ b/t/t5513-fetch-track.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+test_description='fetch follows remote tracking branches correctly'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ >file &&
+ git add . &&
+ test_tick &&
+ git commit -m Initial &&
+ git branch b-0 &&
+ git branch b1 &&
+ git branch b/one &&
+ test_create_repo other &&
+ (
+ cd other &&
+ git config remote.origin.url .. &&
+ git config remote.origin.fetch "+refs/heads/b/*:refs/remotes/b/*"
+ )
+'
+
+test_expect_success fetch '
+ (
+ cd other && git fetch origin &&
+ test "$(git for-each-ref --format="%(refname)")" = refs/remotes/b/one
+ )
+'
+
+test_done
^ permalink raw reply related
* Re: [PATCH v2] t6030 (bisect): work around Mac OS X "ls"
From: Christian Couder @ 2008-07-27 5:10 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: git
In-Reply-To: <Pine.GSO.4.62.0807262343510.426@harper.uchicago.edu>
Le dimanche 27 juillet 2008, Jonathan Nieder a écrit :
> t6030-bisect-porcelain.sh relies on "ls" exiting with nonzero
> status when asked to list nonexistent files. Unfortunately,
> /bin/ls on Mac OS X 10.3 exits with exit code 0. So look at
> its output instead.
>
> Signed-off-by: Jonathan Nieder <jrnieder@uchicago.edu>
> Acked-by: Christian Couder <chriscool@tuxfamily.org>
> ---
>
> On Sun, 27 Jul 2008, Christian Couder wrote:
> > It seems that there is a problem with the message itself though. When I
> > "git am" it, I get:
> >
> > fatal: cannot convert from x-unknown to utf-8
>
> Hmm, not sure what happened. Maybe resending it will work...
Yes, this one works fine.
Thanks,
Christian.
>
> t/t6030-bisect-porcelain.sh | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
> index 0626544..244fda6 100755
> --- a/t/t6030-bisect-porcelain.sh
> +++ b/t/t6030-bisect-porcelain.sh
> @@ -76,7 +76,7 @@ test_expect_success 'bisect fails if given any junk
> instead of revs' ' test_must_fail git bisect start foo $HASH1 -- &&
> test_must_fail git bisect start $HASH4 $HASH1 bar -- &&
> test -z "$(git for-each-ref "refs/bisect/*")" &&
> - test_must_fail ls .git/BISECT_* &&
> + test -z "$(ls .git/BISECT_* 2>/dev/null)" &&
> git bisect start &&
> test_must_fail git bisect good foo $HASH1 &&
> test_must_fail git bisect good $HASH1 bar &&
^ permalink raw reply
* [PATCH v2] t6030 (bisect): work around Mac OS X "ls"
From: Jonathan Nieder @ 2008-07-27 4:53 UTC (permalink / raw)
To: Christian Couder; +Cc: git
In-Reply-To: <200807270604.16581.chriscool@tuxfamily.org>
t6030-bisect-porcelain.sh relies on "ls" exiting with nonzero
status when asked to list nonexistent files. Unfortunately,
/bin/ls on Mac OS X 10.3 exits with exit code 0. So look at
its output instead.
Signed-off-by: Jonathan Nieder <jrnieder@uchicago.edu>
Acked-by: Christian Couder <chriscool@tuxfamily.org>
---
On Sun, 27 Jul 2008, Christian Couder wrote:
> It seems that there is a problem with the message itself though. When I "git
> am" it, I get:
>
> fatal: cannot convert from x-unknown to utf-8
Hmm, not sure what happened. Maybe resending it will work...
t/t6030-bisect-porcelain.sh | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 0626544..244fda6 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -76,7 +76,7 @@ test_expect_success 'bisect fails if given any junk instead of revs' '
test_must_fail git bisect start foo $HASH1 -- &&
test_must_fail git bisect start $HASH4 $HASH1 bar -- &&
test -z "$(git for-each-ref "refs/bisect/*")" &&
- test_must_fail ls .git/BISECT_* &&
+ test -z "$(ls .git/BISECT_* 2>/dev/null)" &&
git bisect start &&
test_must_fail git bisect good foo $HASH1 &&
test_must_fail git bisect good $HASH1 bar &&
--
1.5.5.1.328.gbfcc6
^ permalink raw reply related
* Re: [RFC/PATCH v2] merge-base: teach "git merge-base" to accept more than 2 arguments
From: Junio C Hamano @ 2008-07-27 4:47 UTC (permalink / raw)
To: Christian Couder; +Cc: git, Johannes Schindelin, Miklos Vajna
In-Reply-To: <20080727053324.b54fe48e.chriscool@tuxfamily.org>
Christian Couder <chriscool@tuxfamily.org> writes:
> OPTIONS
> -------
> --all::
> - Output all common ancestors for the two commits instead of
> - just one.
> + Output all merge bases for the commits instead of just one. No
> + merge bases in the output should be an ancestor of another
> + merge base in the output. Each common ancestor of the first
> + commit and any of the other commits passed as arguments,
> + should be an ancestor of one of the merge bases in the output.
The point of merge_bases_many() is that it allows you to compute a merge
base between a commit and another commit that does not yet exist which is
a merge across all others.
o---o---o---o---C
/ :
/ o---o---o---B..(M)
/ / :
---o---*---o---o---o---A..(X)
Suppose you have commits A, B and C, and you would want to come up with an
Octopus merge X across these three commits. Because our low-level merge
machinery works always on two trees with one common ancestor tree, we
would first create a tree that is a merge between B and C (which is marked
as (M) in the picture), and then merge the tree of (M) and A using common
ancestor between (M) and A.
If we did not have merge_bases_many(), we would actually create (M) as a
real commit, and compute merge base between A and (M), which is marked as
"*" in the picture. The use of merge_bases_many() allows us to run the
same merge base computation without actually creating commit (M). Instead
of computing merge-base between A and (M), you can ask for the merge base
between A ("the first commit") and B, C ("the other commits") to obtain
the same answer "*".
Base between A and B is that "*", and you are correct to say that it is an
ancestor of the "*" that is output from the command; base between A and C
is the parent of "*", and again you are correct to say it is ancestor of
the "*" that is output from the command.
But if we output any other commit between "*" and A from the command, it
still satisifies your condition. "The merge base between A and each of B,
C,... should be an ancestor of what is output". In order to satisify your
condition, in the extreme case, we could even output A. Both the merge
base between A and B, and the merge base between A and C, would be an
ancestor of A.
So your description may not be incorrect, but I think it completely misses
the point of what is being computed.
> Author
> ------
> diff --git a/builtin-merge-base.c b/builtin-merge-base.c
> index 1cb2925..f2c9756 100644
> --- a/builtin-merge-base.c
> +++ b/builtin-merge-base.c
> @@ -2,9 +2,11 @@
> #include "cache.h"
> #include "commit.h"
>
> -static int show_merge_base(struct commit *rev1, struct commit *rev2, int show_all)
> +static int show_merge_base(struct commit *rev1, int prev2_nr,
> + struct commit **prev2, int show_all)
> {
> - struct commit_list *result = get_merge_bases(rev1, rev2, 0);
> + struct commit_list *result = get_merge_bases_many(rev1, prev2_nr,
> + prev2, 0);
This is just style, but if you must break lines somewhere, I'd prefer to
have prev2_nr and prev2 on the same line, like this:
struct commit_list *result = get_merge_bases_many(rev1,
prev2_nr, prev2, 0);
because they logically belong to each other. Further, I think this
84-column single-line statement is perfectly fine as well in this case:
struct commit_list *result = get_merge_bases_many(rev1, prev2_nr, prev2, 0);
I would probably do this myself in this case, though:
struct commit_list *result;
result = get_merge_bases_many(rev1, prev2_nr, prev2, 0);
^ permalink raw reply
* [JGIT PATCH 2/2] Teach fetch command line a --verbose/-v switch for unchanged refs
From: Shawn O. Pearce @ 2008-07-27 4:33 UTC (permalink / raw)
To: Robin Rosenberg, Marek Zawirski; +Cc: git
In-Reply-To: <1217133221-15513-1-git-send-email-spearce@spearce.org>
We normally don't want to know about unchanged refs, as these
are not very interesting. We now skip showing them by default
and only produce an output line for unchanged refs if -v is
given to us on the command line.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/pgm/Fetch.java | 18 +++++++++++++++---
1 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
index 194f669..84b5258 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
@@ -40,6 +40,7 @@ package org.spearce.jgit.pgm;
import java.util.List;
import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
import org.spearce.jgit.lib.RefUpdate;
import org.spearce.jgit.lib.TextProgressMonitor;
import org.spearce.jgit.transport.FetchResult;
@@ -48,6 +49,9 @@ import org.spearce.jgit.transport.TrackingRefUpdate;
import org.spearce.jgit.transport.Transport;
class Fetch extends TextBuiltin {
+ @Option(name = "--verbose", aliases = { "-v" }, usage = "be more verbose")
+ private boolean verbose;
+
@Argument(index = 0, metaVar = "uri-ish")
private String remote = "origin";
@@ -66,15 +70,23 @@ class Fetch extends TextBuiltin {
tn.close();
}
- out.print("From ");
- out.print(tn.getURI());
- out.println();
+ boolean shownURI = false;
for (final TrackingRefUpdate u : r.getTrackingRefUpdates()) {
+ if (!verbose && u.getResult() == RefUpdate.Result.NO_CHANGE)
+ continue;
+
final char type = shortTypeOf(u.getResult());
final String longType = longTypeOf(u);
final String src = abbreviateRef(u.getRemoteName(), false);
final String dst = abbreviateRef(u.getLocalName(), true);
+ if (!shownURI) {
+ out.print("From ");
+ out.print(tn.getURI());
+ out.println();
+ shownURI = true;
+ }
+
out.format(" %c %-17s %-10s -> %s", type, longType, src, dst);
out.println();
}
--
1.6.0.rc0.182.gb96c7
^ permalink raw reply related
* [JGIT PATCH 1/2] Fix missing packed-refs entries during ref lookup/enumeration
From: Shawn O. Pearce @ 2008-07-27 4:33 UTC (permalink / raw)
To: Robin Rosenberg, Marek Zawirski; +Cc: git
Some codepaths in RefDatabase allowed the caller to lookup a ref
without making sure the packed-refs file was loaded into memory.
This caused refs which were only packed to appear to not exist,
which meant fetch would still try to fetch something we already
have had for quite some time.
This resolves the issue I was seeing where `jgit fetch` was always
downloading the stable branch of egit.git, even though it has not
changed in many weeks.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/lib/RefDatabase.java | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
index 82b995e..98c365e 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
@@ -115,6 +115,7 @@ class RefDatabase {
}
ObjectId idOf(final String name) throws IOException {
+ refreshPackedRefs();
final Ref r = readRefBasic(name, 0);
return r != null ? r.getObjectId() : null;
}
@@ -132,6 +133,7 @@ class RefDatabase {
* to the base ref, as the symbolic ref could not be read.
*/
RefUpdate newUpdate(final String name) throws IOException {
+ refreshPackedRefs();
Ref r = readRefBasic(name, 0);
if (r == null)
r = new Ref(Ref.Storage.NEW, name, null);
--
1.6.0.rc0.182.gb96c7
^ permalink raw reply related
* Re: [PATCH] fsck: Don't require tmp_obj_ file names are 14 bytes in length
From: Junio C Hamano @ 2008-07-27 4:15 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: git, Brandon Casey
In-Reply-To: <20080727023300.GB17425@spearce.org>
"Shawn O. Pearce" <spearce@spearce.org> writes:
> Brandon Casey <casey@nrlssc.navy.mil> wrote:
> > Since 5723fe7e, temporary objects are now created in their final destination
> > directories, rather than in .git/objects/. Teach fsck to recognize and
> > ignore the temporary objects it encounters, and teach prune to remove them.
>
> jgit can't exactly follow the 14 character naming rule.
> This should be a safe way around it.
More importantly, we might want to change the temporary filename to ensure
that it is 38 bytes in length in the future (cf. $gmane/85106).
^ permalink raw reply
* [JGIT PATCH 1/1] Compile all Java sources in jgit as UTF-8
From: Shawn O. Pearce @ 2008-07-27 4:11 UTC (permalink / raw)
To: Robin Rosenberg, Marek Zawirski; +Cc: git
We use a UTF-8 encoding in our source files whenever possible.
If the compiler assumes ASCII we sometimes get warnings parsing
copyright information for authors whose names aren't representable
in US-ASCII.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
make_jgit.sh | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/make_jgit.sh b/make_jgit.sh
index 89df80c..13d0e32 100755
--- a/make_jgit.sh
+++ b/make_jgit.sh
@@ -58,6 +58,7 @@ do
xargs javac \
-source 1.5 \
-target 1.5 \
+ -encoding UTF-8 \
-g \
-d ../bin2) || die "Building $p failed."
CLASSPATH="$CLASSPATH:$R/$p/bin2"
--
1.6.0.rc0.182.gb96c7
^ permalink raw reply related
* Re: [PATCH v2] t6030 (bisect): work around Mac OS X "ls"
From: Christian Couder @ 2008-07-27 4:04 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: Mike Hommey, git
In-Reply-To: <200807270519.41441.chriscool@tuxfamily.org>
Le dimanche 27 juillet 2008, Christian Couder a écrit :
> Le jeudi 24 juillet 2008, Jonathan Nieder a écrit :
> > t6030-bisect-porcelain.sh relies on "ls" exiting with nonzero
> > status when asked to list nonexistent files. Unfortunately,
> > /bin/ls on Mac OS X 10.3 exits with exit code 0. So look at
> > its output instead.
> >
> > Signed-off-by: Jonathan Nieder <jrnieder@uchicago.edu>
>
> Acked-by: Christian Couder <chriscool@tuxfamily.org>
It seems that there is a problem with the message itself though. When I "git
am" it, I get:
fatal: cannot convert from x-unknown to utf-8
It seems that it is mime encoded or something and my git
(1.6.0.rc0.80.gf54f0) doesn't like it.
Regards,
Christian.
^ permalink raw reply
* [RFC/PATCH v2] merge-base: teach "git merge-base" to accept more than 2 arguments
From: Christian Couder @ 2008-07-27 3:33 UTC (permalink / raw)
To: git, Junio C Hamano, Johannes Schindelin; +Cc: Miklos Vajna
Before this patch "git merge-base" accepted only 2 arguments, so
only merge bases between 2 references could be computed.
The purpose of this patch is to make "git merge-base" accept more
than 2 arguments, so that the merge bases between the first given
reference and all the other references can be computed.
This is easily implemented because the "get_merge_bases_many"
function in "commit.c" already implements the needed computation.
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
Documentation/git-merge-base.txt | 27 +++++++++++++++-------
builtin-merge-base.c | 45 ++++++++++++++++++++++++++-----------
commit.h | 2 +
3 files changed, 51 insertions(+), 23 deletions(-)
Hi,
No tests yet, but the following changes since the first version:
- added documentation
- don't use static variables anymore
Thanks for your comments,
Christian.
diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.txt
index 1a7ecbf..463c230 100644
--- a/Documentation/git-merge-base.txt
+++ b/Documentation/git-merge-base.txt
@@ -8,26 +8,35 @@ git-merge-base - Find as good common ancestors as possible for a merge
SYNOPSIS
--------
-'git merge-base' [--all] <commit> <commit>
+'git merge-base' [--all] <commit> <commit>...
DESCRIPTION
-----------
-'git-merge-base' finds as good a common ancestor as possible between
-the two commits. That is, given two commits A and B, `git merge-base A
-B` will output a commit which is reachable from both A and B through
-the parent relationship.
+'git-merge-base' finds as good common ancestors as possible between
+the first commit and the other commits. The default behavior is to
+output only one as good as possible common ancestor, called a merge
+base.
+
+For example, given two commits A and B, `git merge-base A B` will
+output a commit which is reachable from both A and B through the
+parent relationship.
+
+Given three commits A, B and C, `git merge-base A B C` will output a
+commit which is reachable through the parent relationship from both A
+and B, or from both A and C.
Given a selection of equally good common ancestors it should not be
relied on to decide in any particular way.
-The 'git-merge-base' algorithm is still in flux - use the source...
-
OPTIONS
-------
--all::
- Output all common ancestors for the two commits instead of
- just one.
+ Output all merge bases for the commits instead of just one. No
+ merge bases in the output should be an ancestor of another
+ merge base in the output. Each common ancestor of the first
+ commit and any of the other commits passed as arguments,
+ should be an ancestor of one of the merge bases in the output.
Author
------
diff --git a/builtin-merge-base.c b/builtin-merge-base.c
index 1cb2925..f2c9756 100644
--- a/builtin-merge-base.c
+++ b/builtin-merge-base.c
@@ -2,9 +2,11 @@
#include "cache.h"
#include "commit.h"
-static int show_merge_base(struct commit *rev1, struct commit *rev2, int show_all)
+static int show_merge_base(struct commit *rev1, int prev2_nr,
+ struct commit **prev2, int show_all)
{
- struct commit_list *result = get_merge_bases(rev1, rev2, 0);
+ struct commit_list *result = get_merge_bases_many(rev1, prev2_nr,
+ prev2, 0);
if (!result)
return 1;
@@ -20,12 +22,20 @@ static int show_merge_base(struct commit *rev1, struct commit *rev2, int show_al
}
static const char merge_base_usage[] =
-"git merge-base [--all] <commit-id> <commit-id>";
+"git merge-base [--all] <commit-id> <commit-id>...";
+
+static struct commit *get_commit_reference(const char *arg)
+{
+ unsigned char revkey[20];
+ if (get_sha1(arg, revkey))
+ die("Not a valid object name %s", arg);
+ return lookup_commit_reference(revkey);
+}
int cmd_merge_base(int argc, const char **argv, const char *prefix)
{
- struct commit *rev1, *rev2;
- unsigned char rev1key[20], rev2key[20];
+ struct commit *rev1, **prev2 = NULL;
+ size_t prev2_nr = 0, prev2_alloc = 0;
int show_all = 0;
git_config(git_default_config, NULL);
@@ -38,15 +48,22 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
usage(merge_base_usage);
argc--; argv++;
}
- if (argc != 3)
+ if (argc < 3)
usage(merge_base_usage);
- if (get_sha1(argv[1], rev1key))
- die("Not a valid object name %s", argv[1]);
- if (get_sha1(argv[2], rev2key))
- die("Not a valid object name %s", argv[2]);
- rev1 = lookup_commit_reference(rev1key);
- rev2 = lookup_commit_reference(rev2key);
- if (!rev1 || !rev2)
+
+ rev1 = get_commit_reference(argv[1]);
+ if (!rev1)
return 1;
- return show_merge_base(rev1, rev2, show_all);
+ argc--; argv++;
+
+ do {
+ struct commit *rev2 = get_commit_reference(argv[1]);
+ if (!rev2)
+ return 1;
+ ALLOC_GROW(prev2, prev2_nr + 1, prev2_alloc);
+ prev2[prev2_nr++] = rev2;
+ argc--; argv++;
+ } while (argc > 1);
+
+ return show_merge_base(rev1, prev2_nr, prev2, show_all);
}
diff --git a/commit.h b/commit.h
index 77de962..4829a5c 100644
--- a/commit.h
+++ b/commit.h
@@ -121,6 +121,8 @@ int read_graft_file(const char *graft_file);
struct commit_graft *lookup_commit_graft(const unsigned char *sha1);
extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
+extern struct commit_list *get_merge_bases_many(struct commit *one,
+ int n, struct commit **twos, int cleanup);
extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
extern int register_shallow(const unsigned char *sha1);
--
1.6.0.rc0.43.g00eb.dirty
^ permalink raw reply related
* Re: problem using jgit
From: Shawn O. Pearce @ 2008-07-27 3:21 UTC (permalink / raw)
To: Marek Zawirski; +Cc: Stephen Bannasch, git, Robin Rosenberg
In-Reply-To: <4889E88E.8000701@gmail.com>
Marek Zawirski <marek.zawirski@gmail.com> wrote:
> Shawn O. Pearce wrote:
>> Marek Zawirski <marek.zawirski@gmail.com> wrote:
>>>
>>> It's caused by 14a630c3: Cached modification times for symbolic refs too
>>> Changes introduced by this patch made Repository#getAllRefs()
>>> including Ref objects with null ObjectId in case of unresolvable
>>> (invalid?) HEAD symbolic ref, and null Ref for HEAD when it doesn't
>>> exist. Previous behavior was just not including such refs in result.
>>
>> My intention here was that if a ref cannot be resolved, it should
>> not be reported. [...]
>
> Beside of my temporary fix for that that filters null Ref and Ref with
> null objectId, I think that 2 more issues may need to be resolved:
Well, I think your temporary fix is correct. I don't see another way
to implement around it.
> 1) readRefBasic() method is used for reading arbitrary refs, potentially
> not only those from well-known prefixes as readRefs() does. Is calling
> setModified() appropriate for those other refs?
Yes. If we read something and it is different from what we have cached
we need to signal that the cached data is invalid (which is setModified).
Doing so allows listeners to (eventually) find out that there are changes
made on disk which their subscribers don't know about, but may need to be
informed of. This way we can identify changes made by command line tools
to a repository that egit has open in the workbench.
> 2) Am I wrong that setModified() is not called in all cases? Consider
> empty ref file and just...
> if (line == null || line.length() == 0)
> return new Ref(Ref.Storage.LOOSE, name, null);
>
In this case (and the other like it) we don't call setModified
because there hasn't been a change on disk. The file wasn't
previously in our cache and the file is empty now. Either way
the ref has no data so there is no need to notify listeners.
Now there may be other cases that are missing, but this one
is fine as is.
So I'm thinking of applying this:
--8<--
From: Marek Zawirski <marek.zawirski@gmail.com>
Subject: [PATCH] Fix Repository.getAllRefs to skip HEAD if it points to an unborn branch
If HEAD is a symbolic reference pointing to an unborn branch (branch
not yet created) we get a Ref object back for it supplying the name
of the branch, but its ObjectId is null as the branch file itself is
not present in the repository. In such cases we should not include
the HEAD reference in the returned output.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/lib/RefDatabase.java | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
index 82b995e..b9c8c8c 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
@@ -209,7 +209,9 @@ class RefDatabase {
readPackedRefs(avail);
readLooseRefs(avail, REFS_SLASH, refsDir);
try {
- avail.put(Constants.HEAD, readRefBasic(Constants.HEAD, 0));
+ final Ref r = readRefBasic(Constants.HEAD, 0);
+ if (r != null && r.getObjectId() != null)
+ avail.put(Constants.HEAD, r);
} catch (IOException e) {
// ignore here
}
--
1.6.0.rc0.182.gb96c7
--
Shawn.
^ permalink raw reply related
* Re: [PATCH v2] t6030 (bisect): work around Mac OS X "ls"
From: Christian Couder @ 2008-07-27 3:19 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: Mike Hommey, git
In-Reply-To: <Pine.GSO.4.62.0807240233310.27074@harper.uchicago.edu>
Le jeudi 24 juillet 2008, Jonathan Nieder a écrit :
> t6030-bisect-porcelain.sh relies on "ls" exiting with nonzero
> status when asked to list nonexistent files. Unfortunately,
> /bin/ls on Mac OS X 10.3 exits with exit code 0. So look at
> its output instead.
>
> Signed-off-by: Jonathan Nieder <jrnieder@uchicago.edu>
Acked-by: Christian Couder <chriscool@tuxfamily.org>
Thanks,
Christian.
> ---
>
> Mike Hommey wrote:
> > On Thu, Jul 24, 2008 at 07:57:26AM +0200, Christian Couder wrote:
> >> Le jeudi 24 juillet 2008, Jonathan Nieder a écrit :
> >>> - test_must_fail ls .git/BISECT_* &&
> >>> + echo .git/BISECT_* | test_must_fail grep BISECT_[^*] &&
> >>
> >> Perhaps the following is simpler:
> >>
> >> + test -z "$(ls .git/BISECT_*)" &&
> >
> > That is still a useless use of ls ;)
>
> It is much better than what I wrote, at least.
>
> Good night (well, good morning I guess), and thanks.
>
> t/t6030-bisect-porcelain.sh | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
> index 0626544..244fda6 100755
> --- a/t/t6030-bisect-porcelain.sh
> +++ b/t/t6030-bisect-porcelain.sh
> @@ -76,7 +76,7 @@ test_expect_success 'bisect fails if given any junk
> instead of revs' ' test_must_fail git bisect start foo $HASH1 -- &&
> test_must_fail git bisect start $HASH4 $HASH1 bar -- &&
> test -z "$(git for-each-ref "refs/bisect/*")" &&
> - test_must_fail ls .git/BISECT_* &&
> + test -z "$(ls .git/BISECT_* 2>/dev/null)" &&
> git bisect start &&
> test_must_fail git bisect good foo $HASH1 &&
> test_must_fail git bisect good $HASH1 bar &&
^ permalink raw reply
* [PATCH] fsck: Don't require tmp_obj_ file names are 14 bytes in length
From: Shawn O. Pearce @ 2008-07-27 2:33 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Brandon Casey
In-Reply-To: <6ruv3Y98_kSSVnJFTkV0PNdiNcQ3g-a3M4BhGoT7S1PorElp5tJAkw@cipher.nrlssc.navy.mil>
Not all temporary file creation routines will ensure 14 bytes are
used to generate the temporary file name. In C Git this may be
true, but alternate implementations such as jgit are not always
able to generate a temporary file name with a specific prefix and
also ensure the file name length is 14 bytes long.
Since temporary files in a directory we are fsck'ing should be
uncommon (as they are short lived only long enough for an active
writer to finish writing the file and rename it) we shouldn't see
these show up very often. Always using a prefixcmp() call and
ignoring the length opens up room for other implementations to use
different name generation schemes.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
Brandon Casey <casey@nrlssc.navy.mil> wrote:
> Since 5723fe7e, temporary objects are now created in their final destination
> directories, rather than in .git/objects/. Teach fsck to recognize and
> ignore the temporary objects it encounters, and teach prune to remove them.
jgit can't exactly follow the 14 character naming rule.
This should be a safe way around it.
builtin-fsck.c | 6 ++----
1 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/builtin-fsck.c b/builtin-fsck.c
index 7a4a4f1..6eb7da8 100644
--- a/builtin-fsck.c
+++ b/builtin-fsck.c
@@ -377,10 +377,6 @@ static void fsck_dir(int i, char *path)
if (de->d_name[0] != '.')
break;
continue;
- case 14:
- if (prefixcmp(de->d_name, "tmp_obj_"))
- break;
- continue;
case 38:
sprintf(name, "%02x", i);
memcpy(name+2, de->d_name, len+1);
@@ -389,6 +385,8 @@ static void fsck_dir(int i, char *path)
add_sha1_list(sha1, DIRENT_SORT_HINT(de));
continue;
}
+ if (prefixcmp(de->d_name, "tmp_obj_"))
+ continue;
fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
}
closedir(dir);
--
1.6.0.rc0.182.gb96c7
--
Shawn.
^ permalink raw reply related
* [JGIT PATCH 1/2] Fix RepositoryConfig.setStringList to not corrupt internal state
From: Shawn O. Pearce @ 2008-07-27 2:11 UTC (permalink / raw)
To: Robin Rosenberg, Marek Zawirski; +Cc: git
Calling setStringList was incorrectly storing the String objects
directly in byName. The byName table should have either an Entry or
a List<Entry> stored within its value position. Storing the String
(or List<String>) directly confused our get code as it did not find
the object type it expected. This caused the get code to fallback
to the base configuration (e.g. ~/.gitconfig) or just return null
(claiming the value was never set).
A test case for this appears in the next commit.
Noticed-by: Marek Zawirski <marek.zawirski@gmail.com>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/lib/RepositoryConfig.java | 23 ++++++++++++++++---
1 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
index 1431f1f..d1cd5fc 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
@@ -381,10 +381,25 @@ public class RepositoryConfig {
key += "." + name.toLowerCase();
if (values.size() == 0)
byName.remove(key);
- else if (values.size() == 1)
- byName.put(key, values.get(0));
- else
- byName.put(key, new ArrayList<String>(values));
+ else if (values.size() == 1) {
+ final Entry e = new Entry();
+ e.base = section;
+ e.extendedBase = subsection;
+ e.name = name;
+ e.value = values.get(0);
+ byName.put(key, e);
+ } else {
+ final ArrayList<Entry> eList = new ArrayList<Entry>(values.size());
+ for (final String v : values) {
+ final Entry e = new Entry();
+ e.base = section;
+ e.extendedBase = subsection;
+ e.name = name;
+ e.value = v;
+ eList.add(e);
+ }
+ byName.put(key, eList);
+ }
int entryIndex = 0;
int valueIndex = 0;
--
1.6.0.rc0.182.gb96c7
^ permalink raw reply related
* [JGIT PATCH 2/2] Extended test cases for RepositoryConfigTest
From: Shawn O. Pearce @ 2008-07-27 2:11 UTC (permalink / raw)
To: Robin Rosenberg, Marek Zawirski; +Cc: git, Marek Zawirski
In-Reply-To: <1217124716-12063-1-git-send-email-spearce@spearce.org>
From: Marek Zawirski <marek.zawirski@gmail.com>
Add cases for getting values after setting them. It's something
different from reading config file from scratch or writing it out after
modifications. It's case for getting values after modifications in
object model.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../org/spearce/jgit/lib/RepositoryConfigTest.java | 20 +++++++++++++++++++-
1 files changed, 19 insertions(+), 1 deletions(-)
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
index 8c55fe8..da7e704 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
@@ -2,6 +2,7 @@
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
*
* All rights reserved.
*
@@ -41,6 +42,8 @@ package org.spearce.jgit.lib;
import java.io.File;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.LinkedList;
/**
* Test reading of git config
@@ -84,11 +87,26 @@ public class RepositoryConfigTest extends RepositoryTestCase {
checkFile(cfgFile, "[sec \"ext\"]\n\tname = value\n\tname2 = value2\n");
}
- public void test004_PutSimple() throws IOException {
+ public void test004_PutGetSimple() throws IOException {
File cfgFile = writeTrashFile("config_004", "");
RepositoryConfig repositoryConfig = new RepositoryConfig(null, cfgFile);
repositoryConfig.setString("my", null, "somename", "false");
repositoryConfig.save();
checkFile(cfgFile, "[my]\n\tsomename = false\n");
+ assertEquals("false", repositoryConfig
+ .getString("my", null, "somename"));
+ }
+
+ public void test005_PutGetStringList() throws IOException {
+ File cfgFile = writeTrashFile("config_005", "");
+ RepositoryConfig repositoryConfig = new RepositoryConfig(null, cfgFile);
+ final LinkedList<String> values = new LinkedList<String>();
+ values.add("value1");
+ values.add("value2");
+ repositoryConfig.setStringList("my", null, "somename", values);
+ repositoryConfig.save();
+ assertTrue(Arrays.equals(values.toArray(), repositoryConfig
+ .getStringList("my", null, "somename")));
+ checkFile(cfgFile, "[my]\n\tsomename = value1\n\tsomename = value2\n");
}
}
--
1.6.0.rc0.182.gb96c7
^ permalink raw reply related
* [PATCH] Documentation/git-rev-parse.txt: update for new git-describe output format
From: Cesar Eduardo Barros @ 2008-07-27 0:46 UTC (permalink / raw)
To: git, gitster; +Cc: Cesar Eduardo Barros
Signed-off-by: Cesar Eduardo Barros <cesarb@cesarb.net>
---
Documentation/git-rev-parse.txt | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 5c93669..2921da3 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -155,8 +155,9 @@ blobs contained in a commit.
name the same commit object if there are no other object in
your repository whose object name starts with dae86e.
-* An output from 'git-describe'; i.e. a closest tag, followed by a
- dash, a `g`, and an abbreviated object name.
+* An output from 'git-describe'; i.e. a closest tag, optionally
+ followed by a dash and a number of commits, followed by a dash, a
+ `g`, and an abbreviated object name.
* A symbolic ref name. E.g. 'master' typically means the commit
object referenced by $GIT_DIR/refs/heads/master. If you
--
1.5.6.4
^ permalink raw reply related
* [PATCH] Optional grouping of projects by category.
From: Sebastien Cevey @ 2008-07-27 0:36 UTC (permalink / raw)
To: git
This adds the GITWEB_GROUP_CATEGORIES option which, if enabled, will
result in grouping projects by category on the project list page. The
category is specified for each project by the $GIT_DIR/category file
or the 'category' variable in its configuration file.
The feature is inspired from Sham Chukoury's patch for the XMMS2
gitweb, but has been rewritten for the current gitweb development
HEAD.
Thanks to Florian Ragwitz for Perl tips.
Signed-off-by: Sebastien Cevey <seb@cine7.net>
---
We used to run a modified gitweb for XMMS2 Git repositories which,
among other things, grouped projects by categories. The feature was
lost when we caught up with upstream gitweb, but I've rehacked this
feature back on top of the current HEAD.
I assume this might be a wanted feature, or at least it was in Jakub's
old wishlist he posted on 2006-06-21 02:51:18.
Feedback on the idea and implementation are welcome.
Makefile | 2 +
gitweb/README | 11 ++++
gitweb/gitweb.css | 5 ++
gitweb/gitweb.perl | 129 ++++++++++++++++++++++++++++++++++++++--------------
4 files changed, 112 insertions(+), 35 deletions(-)
diff --git a/Makefile b/Makefile
index 798a2f2..2309260 100644
--- a/Makefile
+++ b/Makefile
@@ -208,6 +208,7 @@ GITWEB_EXPORT_OK =
GITWEB_STRICT_EXPORT =
GITWEB_BASE_URL =
GITWEB_LIST =
+GITWEB_GROUP_CATEGORIES =
GITWEB_HOMETEXT = indextext.html
GITWEB_CSS = gitweb.css
GITWEB_LOGO = git-logo.png
@@ -1145,6 +1146,7 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl
-e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \
-e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \
-e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
+ -e 's|++GITWEB_GROUP_CATEGORIES++|$(GITWEB_GROUP_CATEGORIES)|g' \
-e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
-e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
-e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
diff --git a/gitweb/README b/gitweb/README
index 6908036..2b77c20 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -38,6 +38,11 @@ You can specify the following configuration variables when building GIT:
using gitweb" in INSTALL file for gitweb to find out how to generate
such file from scan of a directory. [No default, which means use root
directory for projects]
+ * GITWEB_GROUP_CATEGORIES
+ Groups projects by category on the main projects list page if set
+ to true. The category of a project is determined by the
+ $GIT_DIR/category file or the 'category' variable in its
+ configuration file. [No default / Not set]
* GITWEB_EXPORT_OK
Show repository only if this file exists (in repository). Only
effective if this variable evaluates to true. [No default / Not set]
@@ -188,6 +193,12 @@ not include variables usually directly set during build):
full description is available as 'title' attribute (usually shown on
mouseover). By default set to 25, which might be too small if you
use long project descriptions.
+ * $projects_list_group_categories
+ Enables the grouping of projects by category on the project list page.
+ * $project_list_default_category
+ Default category for projects for which none is specified. If set
+ to the empty string, such projects will remain uncategorized and
+ listed at the top, above categorized projects.
* @git_base_url_list
List of git base URLs used for URL to where fetch project from, shown
in project summary page. Full URL is "$git_base_url/$project".
diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index aa0eeca..7f1e2cc 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -264,6 +264,11 @@ td.current_head {
text-decoration: underline;
}
+td.category {
+ padding-top: 1em;
+ font-weight: bold;
+}
+
table.diff_tree span.file_status.new {
color: #008000;
}
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 90cd99b..fe8ae72 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -78,6 +78,13 @@ our $projects_list = "++GITWEB_LIST++";
# the width (in characters) of the projects list "Description" column
our $projects_list_description_width = 25;
+# group projects by category on the projects list
+our $projects_list_group_categories = "++GITWEB_GROUP_CATEGORIES++";
+
+# default category if none specified
+# (leave the empty string for no category)
+our $project_list_default_category = "";
+
# default order of projects list
# valid values are none, project, descr, owner, and age
our $default_projects_order = "project";
@@ -1710,18 +1717,28 @@ sub git_get_path_by_hash {
## ......................................................................
## git utility functions, directly accessing git repository
-sub git_get_project_description {
- my $path = shift;
+sub git_get_project_config_from_file {
+ my ($name, $path) = @_;
$git_dir = "$projectroot/$path";
- open my $fd, "$git_dir/description"
- or return git_get_project_config('description');
- my $descr = <$fd>;
+ open my $fd, "<", "$git_dir/$name"
+ or return git_get_project_config($name);
+ my $conf = <$fd>;
close $fd;
- if (defined $descr) {
- chomp $descr;
+ if (defined $conf) {
+ chomp $conf;
}
- return $descr;
+ return $conf;
+}
+
+sub git_get_project_description {
+ my $path = shift;
+ return git_get_project_config_from_file('description', $path);
+}
+
+sub git_get_project_category {
+ my $path = shift;
+ return git_get_project_config_from_file('category', $path);
}
sub git_get_project_url_list {
@@ -3535,8 +3552,9 @@ sub git_patchset_body {
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-# fills project list info (age, description, owner, forks) for each
-# project in the list, removing invalid projects from returned list
+# fills project list info (age, description, owner, category, forks)
+# for each project in the list, removing invalid projects from
+# returned list
# NOTE: modifies $projlist, but does not remove entries from it
sub fill_project_list_info {
my ($projlist, $check_forks) = @_;
@@ -3558,6 +3576,11 @@ sub fill_project_list_info {
if (!defined $pr->{'owner'}) {
$pr->{'owner'} = git_get_project_owner("$pr->{'path'}") || "";
}
+ if ($projects_list_group_categories && !defined $pr->{'cat'}) {
+ my $cat = git_get_project_category($pr->{'path'}) ||
+ $project_list_default_category;
+ $pr->{'cat'} = to_utf8($cat);
+ }
if ($check_forks) {
my $pname = $pr->{'path'};
if (($pname =~ s/\.git$//) &&
@@ -3574,6 +3597,17 @@ sub fill_project_list_info {
return @projects;
}
+sub build_sorted_category_list {
+ my ($projlist) = @_;
+ my %categories;
+
+ for my $pr (@{ $projlist }) {
+ push @{$categories{ $pr->{'cat'} }}, $pr;
+ }
+
+ return %categories;
+}
+
# print 'sort by' <th> element, either sorting by $key if $name eq $order
# (changing $list), or generating 'sort by $name' replay link otherwise
sub print_sort_th {
@@ -3604,36 +3638,15 @@ sub print_sort_th_num {
print_sort_th(0, @_);
}
-sub git_project_list_body {
- my ($projlist, $order, $from, $to, $extra, $no_header) = @_;
-
- my ($check_forks) = gitweb_check_feature('forks');
- my @projects = fill_project_list_info($projlist, $check_forks);
+sub print_project_rows {
+ my ($projects, $from, $to, $check_forks) = @_;
- $order ||= $default_projects_order;
$from = 0 unless defined $from;
- $to = $#projects if (!defined $to || $#projects < $to);
+ $to = $#$projects if (!defined $to || $#$projects < $to);
- print "<table class=\"project_list\">\n";
- unless ($no_header) {
- print "<tr>\n";
- if ($check_forks) {
- print "<th></th>\n";
- }
- print_sort_th_str('project', $order, 'path',
- 'Project', \@projects);
- print_sort_th_str('descr', $order, 'descr_long',
- 'Description', \@projects);
- print_sort_th_str('owner', $order, 'owner',
- 'Owner', \@projects);
- print_sort_th_num('age', $order, 'age',
- 'Last Change', \@projects);
- print "<th></th>\n" . # for links
- "</tr>\n";
- }
my $alternate = 1;
for (my $i = $from; $i <= $to; $i++) {
- my $pr = $projects[$i];
+ my $pr = $projects->[$i];
if ($alternate) {
print "<tr class=\"dark\">\n";
} else {
@@ -3665,6 +3678,52 @@ sub git_project_list_body {
"</td>\n" .
"</tr>\n";
}
+}
+
+sub git_project_list_body {
+ my ($projlist, $order, $from, $to, $extra, $no_header) = @_;
+
+ my ($check_forks) = gitweb_check_feature('forks');
+ my @all_projects = fill_project_list_info($projlist, $check_forks);
+
+ $order ||= $default_projects_order;
+
+ print "<table class=\"project_list\">\n";
+ unless ($no_header) {
+ print "<tr>\n";
+ if ($check_forks) {
+ print "<th></th>\n";
+ }
+ print_sort_th_str('project', $order, 'path',
+ 'Project', \@all_projects);
+ print_sort_th_str('descr', $order, 'descr_long',
+ 'Description', \@all_projects);
+ print_sort_th_str('owner', $order, 'owner',
+ 'Owner', \@all_projects);
+ print_sort_th_num('age', $order, 'age',
+ 'Last Change', \@all_projects);
+ print "<th></th>\n" . # for links
+ "</tr>\n";
+ }
+
+ if ($projects_list_group_categories) {
+ my %categories = build_sorted_category_list(\@all_projects);
+ foreach my $cat (sort keys %categories) {
+ unless ($cat eq "") {
+ print "<tr>\n";
+ if ($check_forks) {
+ print "<td></td>\n";
+ }
+ print "<td class=\"category\" colspan=\"5\">" . $cat . "</td>\n";
+ print "</tr>\n";
+ }
+
+ print_project_rows($categories{$cat}, $from, $to, $check_forks);
+ }
+ } else {
+ print_project_rows(\@all_projects, $from, $to, $check_forks);
+ }
+
if (defined $extra) {
print "<tr>\n";
if ($check_forks) {
--
1.5.3.7
^ permalink raw reply related
* Re: fetch refspec foo/* matches foo*
From: Junio C Hamano @ 2008-07-27 0:18 UTC (permalink / raw)
To: Jeff King; +Cc: Daniel Barkalow, git
In-Reply-To: <20080726082405.GA10104@sigill.intra.peff.net>
Jeff King <peff@peff.net> writes:
> On Fri, Jul 25, 2008 at 02:02:15PM -0700, Junio C Hamano wrote:
>
>> BTW, has anybody taken a look at this one?
>>
>> Subject: BUG: fetch incorrect interpretation of globing patterns in refspecs
>> Date: Thu, 24 Jul 2008 09:07:21 +0200
>> Message-ID: <71295b5a0807240007k246973abj1897895d0d67bb6c@mail.gmail.com>
>>
>> If not, I think I probably need to take a look at this, reproducing and
>> possibly fixing, before applying non-fix patches.
>
> I have been meaning to look at it for days, so I finally took a peek. I
> was able to reproduce the problem easily. I think it is (almost) as
> simple as the patch below. In the refspec parsing, we already require
> globs to come after '/', so this is the analagous check during match.
>
> Unfortunately, this breaks t1020 (something about failing to clone HEAD
Your patch expects that the parsed refspec->{src,dst} omit the terminating
slash, which is in line with what parse_refspec_internal() in remote.c
does. The problem is that builtin-clone.c uses a refspec that is
incompatible from that assumption. The static "tag_refspec" variable
defined in remote.c has the same problem. These two have trailing slash
e.g. "refs/heads/", "refs/tags/", that should be dropped for your updated
check to work.
The attached patch, that includes your one-liner change, makes all tests
pass.
I have a nagging suspicion that it might be a simpler and cleaner change
to change parse_refspec_internal() to keep the trailing slash, instead of
dropping it. Then the check you added is not needed (the trailing slash
guarantees that the pattern matches at the hierarchy boundary), neither
any of the change in this patch.
---
builtin-clone.c | 9 +++++----
remote.c | 7 ++++---
t/t5513-fetch-track.sh | 30 ++++++++++++++++++++++++++++++
3 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/builtin-clone.c b/builtin-clone.c
index e086a40..022ffb9 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -440,12 +440,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
if (option_bare) {
- strcpy(branch_top, "refs/heads/");
+ strcpy(branch_top, "refs/heads");
git_config_set("core.bare", "true");
} else {
snprintf(branch_top, sizeof(branch_top),
- "refs/remotes/%s/", option_origin);
+ "refs/remotes/%s", option_origin);
/* Configure the remote */
snprintf(key, sizeof(key), "remote.%s.url", option_origin);
@@ -453,13 +453,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
snprintf(key, sizeof(key), "remote.%s.fetch", option_origin);
snprintf(value, sizeof(value),
- "+refs/heads/*:%s*", branch_top);
+ "+refs/heads/*:%s/*", branch_top);
git_config_set_multivar(key, value, "^$", 0);
}
refspec.force = 0;
refspec.pattern = 1;
- refspec.src = "refs/heads/";
+ refspec.src = "refs/heads";
refspec.dst = branch_top;
if (path && !is_bundle)
@@ -514,6 +514,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_init(&head_ref, 0);
strbuf_addstr(&head_ref, branch_top);
+ strbuf_addch(&head_ref, '/');
strbuf_addstr(&head_ref, "HEAD");
/* Remote branch link */
diff --git a/remote.c b/remote.c
index 0d6020b..6b313fb 100644
--- a/remote.c
+++ b/remote.c
@@ -9,8 +9,8 @@ static struct refspec s_tag_refspec = {
0,
1,
0,
- "refs/tags/",
- "refs/tags/"
+ "refs/tags",
+ "refs/tags"
};
const struct refspec *tag_refspec = &s_tag_refspec;
@@ -1108,7 +1108,8 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
for (ref = remote_refs; ref; ref = ref->next) {
if (strchr(ref->name, '^'))
continue; /* a dereference item */
- if (!prefixcmp(ref->name, refspec->src)) {
+ if (!prefixcmp(ref->name, refspec->src) &&
+ ref->name[remote_prefix_len] == '/') {
const char *match;
struct ref *cpy = copy_ref(ref);
match = ref->name + remote_prefix_len;
diff --git a/t/t5513-fetch-track.sh b/t/t5513-fetch-track.sh
new file mode 100755
index 0000000..9e74862
--- /dev/null
+++ b/t/t5513-fetch-track.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+test_description='fetch follows remote tracking branches correctly'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ >file &&
+ git add . &&
+ test_tick &&
+ git commit -m Initial &&
+ git branch b-0 &&
+ git branch b1 &&
+ git branch b/one &&
+ test_create_repo other &&
+ (
+ cd other &&
+ git config remote.origin.url .. &&
+ git config remote.origin.fetch "+refs/heads/b/*:refs/remotes/b/*"
+ )
+'
+
+test_expect_success fetch '
+ (
+ cd other && git fetch origin &&
+ test "$(git for-each-ref --format="%(refname)")" = refs/remotes/b/one
+ )
+'
+
+test_done
^ permalink raw reply related
* Re: [PATCH] gitweb: More about how gitweb gets 'owner' of repository
From: Petr Baudis @ 2008-07-26 23:27 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <20080726232316.23589.62384.stgit@localhost.localdomain>
On Sun, Jul 27, 2008 at 01:23:46AM +0200, Jakub Narebski wrote:
> Signed-off-by: Jakub Narebski <jnareb@gmail.com>
> ---
> Just an improvement in gitweb documentation...
Acked-by: Petr Baudis <pasky@suse.cz>
^ permalink raw reply
* Summer of Code 2008 Midterm Summary
From: Shawn O. Pearce @ 2008-07-26 23:27 UTC (permalink / raw)
To: git
Part of the Google Summer of Code program is to ask the students
to evaluate their mentors, and their own involvement with their
community. That evaluation period closed on July 14th, but I
haven't had a chance to go through the results until now.
At the mid-term all 6 of our students "passed" their evaluations.
This means we asked Google to pay out their $2000 USD stipend, and
allow the student to continue the program for the rest of the summer.
This decision was made by each individual mentor. Payment of the
remaining $2000 USD stipend will be determined during the final
evaluations, which are after August 11th.
What follows is a condensed summary of the student responses from
the mid-term survey.
Q: At what point did you first make contact with your
mentoring organization?
This was about split 50/50 between "after the organization was
accepted" and "during the student application and acceptance
phase of the program". As you may well know, Summer of Code
takes a short 'break' between announcing what organizations will
participate as mentors, and when students can begin applying.
The fact that about 50% of our accepted students were talking to
our potential mentors before they could even submit applications
suggests that it worked in their favor, and improved their odds
of being selected.
Since this was a significant part of our application selection
process, I am not surprised by this figure.
Q: How often do you and your mentor interact?
2 students answered "Every day" and 4 answered "once every few
days". By and large our mentors are active with their students.
Q: How do you communicate with your mentor?
Overwhelmingly our students use IRC and private emails to
communicate with their mentors.
Most of them also keep a private Git repository with a list of
notes they want to share with their mentor, and their mentors
monitor this notes file by git-fetch'ing it every so often.
It seems we eat our own dog food quite a bit around here. :-)
Q: How much time have you spent per week interacting with your
mentor, on average?
All of our students (except 1) said 0-5 hours per week, and the
lone dissenter said 6-10 hours per week. Nearly all of the
mentors on the other hand chose 6-10 hours per week in their
own surveys.
It may be safe to say that in the average case we are spending
about 10 hours per week as mentors just communicating with our
students and helping them to meet their goals.
Q: How would you describe your interaction with your overall
project community?
5 out of 6 of our students said "Somewhat active (e.g. I read
and sometimes responds to mailing lists, some interaction in
community communication channels)". I think most of them really
should have chosen instead "Very active (e.g. I send code reviews
to development mailing lists, am active and ask/answer questions
in our IRC channel or project forums)".
Most of our summer of code students _are_ sending code reviews
to this mailing list, and are taking advantage of the fantastic
contributors we have to help them out. They also tend to answer
questions on IRC and the mailing list when they are pretty sure
they know the answer and can take the time to help someone else.
Certainly our students aren't as active as our intrepid maintainer
is, but most of them aren't lurking in the shadows either.
Q: If you cannot reach your mentor, how do you go about getting
help when you need it?
3 of our students selected "I hope I can figure it out myself
before my mentor resurfaces.". This is a less-than-optimal result
in my opinion. Despite the prior question indicating that our
students may actually be actively involved in the community
they don't feel involved enough to obtain assistance without
their mentor.
3 students also chose "I ask questions on our project's developer
or other main mailing list.".
This was a multiple choice question, so there is some overlap,
but I do know that at least one student chose _only_ "I hope
I can figure it out myself before my mentor resurfaces".
In terms of community building this question's answers seem to
suggest we need to try harder to make our students included,
and get help beyond just their mentor/co-mentor.
Q: How responsive was your mentor to any questions or other requests
for communication from you?
All of our students chose "Mentor responded quickly with the
information I requested" (which is the best rating available),
though one of them qualified it with "For some values of
'quickly'". ;-)
Q: Do you feel that you are on track to complete your project?
I'm not sure if this is good or bad. 3 students (50%!) are
ahead of schedule, 1 is on schedule, and 2 are behind.
On the one hand I applaud our 3 students who happen to be ahead
of schedule. They have clearly worked hard and produced some
useful code, much of which will be in the next release of their
respective projects.
On the other hand I wonder if as mentors we didn't demand
enough of our students? Looking at the students who are ahead
of schedule, I know that at least 2 of them had what we thought
as mentors to be difficult, time consuming tasks in front them.
So we did intentially try to define the project such that it
would be more likely to succeed.
Q: What areas were the most difficult for you in preparing
for/working on Summer of Code?
Most of our students (5/6) had trouble balancing their time
between their Git project and school (exams, etc.). This is a
common theme in Summer of Code and Git isn't alone in seeing it.
As I understand it a number of our students are in European
based university programs, which causes exams to fall in the
early part of the Summer of Code timeline.
Half of our students found getting up to speed with our code
base and/or documentation was difficult. In other words, they
did not feel that Git was "new contributor friendly".
A couple of students have had time-zone issues with their mentors,
but looking at the progress of most projects that doesn't seem
to be a major issue.
--
Shawn.
^ permalink raw reply
* [PATCH] gitweb: More about how gitweb gets 'owner' of repository
From: Jakub Narebski @ 2008-07-26 23:23 UTC (permalink / raw)
To: git
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Just an improvement in gitweb documentation...
gitweb/README | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/gitweb/README b/gitweb/README
index 6908036..825162a 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -277,7 +277,8 @@ You can use the following files in repository:
* gitweb.owner
You can use the gitweb.owner repository configuration variable to set
repository's owner. It is displayed in the project list and summary
- page. If it's not set, filesystem directory's owner is used.
+ page. If it's not set, filesystem directory's owner is used
+ (via GECOS field / real name field from getpwiud(3)).
* various gitweb.* config variables (in config)
Read description of %feature hash for detailed list, and some
descriptions.
^ permalink raw reply related
* Re: git-scm.com
From: Junio C Hamano @ 2008-07-26 23:11 UTC (permalink / raw)
To: Wincent Colaiuta
Cc: Scott Chacon, david, Petr Baudis, Patrick Aljord, git list
In-Reply-To: <F3D70DCD-E9A9-42C3-8870-ABB7EECF83CC@wincent.com>
Wincent Colaiuta <win@wincent.com> writes:
> I'd like to see the "official" Git homepage as distanced as possible
> from GitHub. They've taken Git (free as in speech, free as in beer)
> and built a closed-source commercial product on top of it -- curiously
> for something which you can do for free yourself anyway ...
I do not share that sentiment. It is perfectly fine for somebody to offer
managed git repositories as a commercial _service_ to people who want to
just _use_ git. It is what they could do themselves, but from the end
user's point of view, it's just "outsourcing" and is nothing unusual.
If GitHub folks improved the core part of the system while building their
service, we would want to get the changes back, and we will, _if_ they
distribute their software (i.e. they are not allowed to just distribute
binaries, if it links with git).
At the emotional level, if some people make the world a better place by
building new software around what I wrote, I would like to have the same
kind of access to its source as I gave them access to my sources, whether
they distribute the end product as packaged software or they offer it as a
service to be used by others without ever distributing anything. But that
is merely my _wish_; it is different from the terms git is distributed
under.
I think you are going a bit too far to hate them for not opening up their
sources they use to implement "managed git repositories service", which is
a _user_ of the core git, but most likely is not a derivative of git
itself. IOW, it's not your code.
^ permalink raw reply
* Re: [EGIT PATCH] Support linked resources
From: Shawn O. Pearce @ 2008-07-26 21:59 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: Richie Vos, git
In-Reply-To: <200807261707.18299.robin.rosenberg.lists@dewire.com>
Robin Rosenberg <robin.rosenberg.lists@dewire.com> wrote:
> torsdagen den 24 juli 2008 05.34.06 skrev Richie Vos:
> > I have a project that outputs to a linked directory (for example the
> > project is in /projects/foo and the project outputs to /projects/bar).
...
> I'd be inclined to prefer ignoring any non-plain resource, always. Linked
> resources are either absolute or relative to a variable. Other than that
> there is an analogy to symbolic links. Git manages the link, not its
> content (unless handled elsewhere). The link in this case is in the
> .project file and thus managed there.
>
> EGit could still managed the resource, but not via the link, but rather at
> the place it is located, iff that happens to be in a project managed by Egit.
My last day-job used a project layout in the filesystem of:
GIT_REPO/
.git/
.gitignore
_eclipse_projects/
com.sekret.foo/.project
com.sekret.bar/.project
foo/
com/sekret/foo/Foo.java
bar/
com/sekret/bar/Bar.java
The two .project files contained links called "src" to "foo" and
"bar" respectively. The _eclipse_projects folder is ignored by
.gitignore, and the .project files were actually generated on the
fly by our non-Eclipse based buildsystem.
Consequently I wanted egit to be able to manage the stuff inside of
a linked folder, so long as it mapped onto the same repository that
the project mapped onto. Without that the "src" folder contents
wouldn't be available to egit, and egit would be more-or-less
useless on this sort of layout.
--
Shawn.
^ 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