* Re: hosting git on a nfs
From: Linus Torvalds @ 2008-11-13 23:48 UTC (permalink / raw)
To: James Pickens; +Cc: Bruce Fields, Junio C Hamano, Git Mailing List
In-Reply-To: <885649360811131523h2e10dc44x8603c9793dae03b8@mail.gmail.com>
On Thu, 13 Nov 2008, James Pickens wrote:
>
> I'm trying to test this and so far I'm not seeing any effect.
Ok, try my second version. The first version would get _some_ parallelism,
but very little due to all the threads often trying to just look up in the
same directory. The second version should hopefully have less of that
effect.
Also, under Linux, try it with caches cleared in between runs, so that you
can avoid any issues of the Linux client caching the directory lookup data
(which linux _will_ do - I think the default timeout is 30 seconds or
something like that):
echo 3 > /proc/sys/vm/drop_caches ; time git diff
which should hopefully get you more reliable timings.
Linus
^ permalink raw reply
* Re: hosting git on a nfs
From: Linus Torvalds @ 2008-11-13 23:42 UTC (permalink / raw)
To: James Pickens, Bruce Fields, Junio C Hamano; +Cc: Git Mailing List
In-Reply-To: <alpine.LFD.2.00.0811131252040.3468@nehalem.linux-foundation.org>
On Thu, 13 Nov 2008, Linus Torvalds wrote:
>
> And if there are per-directory locking etc that screws this up, we can
> look at using different heuristics for the lstat() patterns. Right now I
> divvy it up so that thread 0 gets entries 0, 10, 20, 30.. and thread 1
> does entries 1, 11, 21, 31.., but we could easily split it up differently,
> and do 0,1,2,3.. and 1000,1001,1002,1003.. instead. That migth avoid some
> per-directory locks. Dunno.
Yeah, I just checked. We really should to the lookups in clusters, because
yes, we do have directory locks that limit parallel lookups in the same
directory, so to get good parallelism you want to look up in different
places.
Admittedly that's really a Linux kernel deficiency, and I'd love to fix it
(in the long run), but we optimize file lookup for the common (cached)
case, and the uncommon case of parallel misses in the same directory has
been written for simplicity and robustness.
So don't even bother trying the previous patch, even if it might work. At
least not on Linux. Try this one instead, which does the parallel things
in batches, so that we hopefully hit different directories.
Parallelism is hard.
The good news is that I seem to actualluy see a bit of a win from this
even on a disk, now that the kernel doesn't serialize things. So it may
be worth it. So I have some hope that it actually helps on NFS too.
The numbers for five runs (with clearing of the caches in between, of
course) are:
Before:
0.01user 0.23system 0:10.87elapsed 2%CPU
0.04user 0.19system 0:10.86elapsed 2%CPU
0.03user 0.26system 0:10.82elapsed 2%CPU
0.02user 0.27system 0:12.67elapsed 2%CPU
0.01user 0.22system 0:10.86elapsed 2%CPU
After:
0.03user 0.26system 0:07.88elapsed 3%CPU
0.02user 0.25system 0:07.63elapsed 3%CPU
0.01user 0.26system 0:08.62elapsed 3%CPU
0.01user 0.26system 0:07.27elapsed 3%CPU
0.05user 0.28system 0:08.61elapsed 3%CPU
so it really does seem like it has possibly given a 30% improvement in
cold-cache performance even on a disk.
NOTE NOTE NOTE! This is still a total hack. If this was done properly, we
would do the "preload_uptodate()" thing when we load the cache for all the
different programs where it can matter, not just the one special case
place. So see this as a proof-of-concept, nothing more.
Linus
---
diff-lib.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 74 insertions(+), 0 deletions(-)
diff --git a/diff-lib.c b/diff-lib.c
index ae96c64..83c180d 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2005 Junio C Hamano
*/
+#include <pthread.h>
#include "cache.h"
#include "quote.h"
#include "commit.h"
@@ -54,6 +55,77 @@ static int check_removed(const struct cache_entry *ce, struct stat *st)
return 0;
}
+/* Hacky hack-hack start */
+#define MAX_PARALLEL (10)
+static int parallel_lstats = 1;
+
+struct thread_data {
+ pthread_t pthread;
+ struct index_state *index;
+ const char **pathspec;
+ int offset, nr;
+};
+
+static void *preload_thread(void *_data)
+{
+ int nr;
+ struct thread_data *p = _data;
+ struct index_state *index = p->index;
+ struct cache_entry **cep = index->cache + p->offset;
+
+ nr = p->nr;
+ if (nr + p->offset > index->cache_nr)
+ nr = index->cache_nr - p->offset;
+
+ do {
+ struct cache_entry *ce = *cep++;
+ struct stat st;
+
+ if (ce_stage(ce))
+ continue;
+ if (ce_uptodate(ce))
+ continue;
+ if (!ce_path_match(ce, p->pathspec))
+ continue;
+ if (lstat(ce->name, &st))
+ continue;
+ if (ie_match_stat(index, ce, &st, 0))
+ continue;
+ ce_mark_uptodate(ce);
+ } while (--nr > 0);
+ return NULL;
+}
+
+static void preload_uptodate(const char **pathspec, struct index_state *index)
+{
+ int i, work, offset;
+ int threads = index->cache_nr / 100;
+ struct thread_data data[MAX_PARALLEL];
+
+ if (threads < 2)
+ return;
+ if (threads > MAX_PARALLEL)
+ threads = MAX_PARALLEL;
+ offset = 0;
+ work = (index->cache_nr + threads - 1) / threads;
+ for (i = 0; i < threads; i++) {
+ struct thread_data *p = data+i;
+ p->index = index;
+ p->pathspec = pathspec;
+ p->offset = offset;
+ p->nr = work;
+ offset += work;
+ if (pthread_create(&p->pthread, NULL, preload_thread, p))
+ die("unable to create threaded lstat");
+ }
+ for (i = 0; i < threads; i++) {
+ struct thread_data *p = data+i;
+ if (pthread_join(p->pthread, NULL))
+ die("unable to join threaded lstat");
+ }
+}
+/* Hacky hack-hack mostly ends */
+
int run_diff_files(struct rev_info *revs, unsigned int option)
{
int entries, i;
@@ -68,6 +140,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
if (diff_unmerged_stage < 0)
diff_unmerged_stage = 2;
entries = active_nr;
+ if (parallel_lstats)
+ preload_uptodate(revs->prune_data, &the_index);
symcache[0] = '\0';
for (i = 0; i < entries; i++) {
struct stat st;
^ permalink raw reply related
* [RFC PATCH] repack: make repack -a equivalent to repack -A and drop previous -a behavior
From: Brandon Casey @ 2008-11-13 23:20 UTC (permalink / raw)
To: git; +Cc: Brandon Casey
Once upon a time, repack had only a single option which began with the first
letter of the alphabet. Then, a second was created which would repack
unreachable objects into the newly created pack so that git-gc --auto could
be invented. But, the -a option was still necessary so that it could be
called every now and then to discard the unreachable objects that were being
repacked over and over and over into newly generated packs. Later, -A was
changed so that instead of repacking the unreachable objects, it ejected
them from the pack so that they resided in the object store in loose form,
to be garbage collected by prune-packed according to normal expiry rules.
And so, -a lost its raison d'etre.
Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil>
---
This is on top of bc/maint-keep-pack
-brandon
Documentation/git-repack.txt | 25 ++++++++++++-------------
git-repack.sh | 8 ++++----
2 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index aaa8852..d04d5c2 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -32,21 +32,20 @@ OPTIONS
pack everything referenced into a single pack.
Especially useful when packing a repository that is used
for private development and there is no need to worry
- about people fetching via dumb protocols from it. Use
- with '-d'. This will clean up the objects that `git prune`
- leaves behind, but `git fsck --full` shows as
- dangling.
+ about people fetching via dumb protocols from it. If used
+ with '-d' , then any unreachable objects in a previous pack will
+ become loose, unpacked objects, instead of being left in the
+ old pack. Unreachable objects are never intentionally added to
+ a pack, even when repacking. This option prevents unreachable
+ objects from being immediately deleted by way of being left in
+ the old pack and then removed. Instead, the loose unreachable
+ objects will be pruned according to normal expiry rules
+ with the next 'git-gc' invocation. See linkgit:git-gc[1].
-A::
- Same as `-a`, unless '-d' is used. Then any unreachable
- objects in a previous pack become loose, unpacked objects,
- instead of being left in the old pack. Unreachable objects
- are never intentionally added to a pack, even when repacking.
- This option prevents unreachable objects from being immediately
- deleted by way of being left in the old pack and then
- removed. Instead, the loose unreachable objects
- will be pruned according to normal expiry rules
- with the next 'git-gc' invocation. See linkgit:git-gc[1].
+ Same as `-a`. Historical note: the -a and -A options used to differ
+ in that -a did not leave unreachable objects unpacked. Instead,
+ they were removed along with the redundant pack (when -d was used).
-d::
After packing, if the newly created packs make some
diff --git a/git-repack.sh b/git-repack.sh
index 458a497..f1e21b9 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -7,8 +7,9 @@ OPTIONS_KEEPDASHDASH=
OPTIONS_SPEC="\
git repack [options]
--
-a pack everything in a single pack
-A same as -a, and turn unreachable objects loose
+a pack everything in a single pack, and turn unreachable objects
+ loose
+A same as -a
d remove redundant packs, and run git-prune-packed
f pass --no-reuse-object to git-pack-objects
n do not run git-update-server-info
@@ -29,8 +30,7 @@ while test $# != 0
do
case "$1" in
-n) no_update_info=t ;;
- -a) all_into_one=t ;;
- -A) all_into_one=t
+ -a|-A) all_into_one=t
unpack_unreachable=--unpack-unreachable ;;
-d) remove_redundant=t ;;
-q) quiet=-q ;;
--
1.6.0.3.552.g12334
^ permalink raw reply related
* Re: [BUG] fatal error during merge
From: Anders Melchiorsen @ 2008-11-13 23:34 UTC (permalink / raw)
To: Alex Riesen
Cc: SZEDER Gábor, Samuel Tardieu, git, Johannes Schindelin,
Junio C Hamano
In-Reply-To: <20081113230932.GA8552@blimp.localdomain>
Alex Riesen wrote:
> Well, the case is a bit unfair: all files have the same SHA-1!
Here is an updated test, where all files have different SHA-1. It still
fails.
Your patch got rid of the errors and it commits the merged tree. But the
working tree is not updated correctly, so the moved file disappears.
Cheers,
Anders.
mkdir am-merge-fail
cd am-merge-fail
git init
mkdir before
yes | head -n100 >before/100
touch after
git add before/100 after
git commit -minitial
git branch parallel
git rm before/100 after
mkdir after
yes | head -n99 >after/99
git add after/99
git commit -mmove
git checkout parallel
echo "Just to cause a non-ff" >other
git add other
git commit -mparallel
git merge master
^ permalink raw reply
* Re: hosting git on a nfs
From: Julian Phillips @ 2008-11-13 23:23 UTC (permalink / raw)
To: Linus Torvalds
Cc: James Pickens, Bruce Fields, Junio C Hamano, Git Mailing List
In-Reply-To: <alpine.LFD.2.00.0811131252040.3468@nehalem.linux-foundation.org>
On Thu, 13 Nov 2008, Linus Torvalds wrote:
> Before:
>
> [torvalds@nehalem linux]$ /usr/bin/time git diff > /dev/null
> 0.03user 0.04system 0:00.07elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k
>
> After:
>
> 0.02user 0.07system 0:00.04elapsed 243%CPU (0avgtext+0avgdata 0maxresident)k
> 0inputs+0outputs (0major+2241minor)pagefaults 0swaps
>
> ie it actually did cut elapsed time from 7 hundredths of a second to just
> 4. And the CPU usage went from 100% to 243%. Ooooh. Magic.
>
> But it's still hacky as hell. Who has NFS? Can you do the same thing over
> NFS and test it? I'm not going to set up NFS to test this, and as I
> suspected, on a local disk, the cold-cache case makes no difference
> what-so-ever, because whatever seek optimizations can be done are still
> totally irrelevant.
The timings seem to vary quite a bit (not really a surprise with a network
involved ;), but the patch definately makes things faster:
master:
jp3@kaos: linux-2.6(master)>/usr/bin/time ~/bin/git diff > /dev/null
0.01user 0.19system 0:02.50elapsed 8%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+1766minor)pagefaults 0swaps
master + patch:
jp3@kaos: linux-2.6(master)>/usr/bin/time ~/bin/git diff > /dev/null
0.02user 0.88system 0:00.96elapsed 93%CPU (0avgtext+0avgdata
0maxresident)k
0inputs+0outputs (0major+1783minor)pagefaults 0swaps
seems to be approximately twice as fast?
--
Julian
---
<nelchael> "XML is like violence, if it doesn't solve the problem, just
use more."
* nelchael hides
^ permalink raw reply
* Re: hosting git on a nfs
From: James Pickens @ 2008-11-13 23:23 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Bruce Fields, Junio C Hamano, Git Mailing List
In-Reply-To: <alpine.LFD.2.00.0811131252040.3468@nehalem.linux-foundation.org>
On Thu, Nov 13, 2008, Linus Torvalds <torvalds@linux-foundation.org> wrote:
> But it's still hacky as hell. Who has NFS? Can you do the same thing over
> NFS and test it? I'm not going to set up NFS to test this, and as I
> suspected, on a local disk, the cold-cache case makes no difference
> what-so-ever, because whatever seek optimizations can be done are still
> totally irrelevant.
I'm trying to test this and so far I'm not seeing any effect. The
timings are all over the map, but the average time is about the same as
before. If I run 'git status' over and over without pausing in between,
it runs very fast, so I guess the client is caching some things for a
short time. Here are the timings I got by running git 1.6.0.4 and
1.6.0.4 plus this patch, alternating between them and sleeping for 60
seconds after each run:
Git 1.6.0.4:
4.83
4.47
4.54
9.04
5.28
4.33
6.40
13.71
4.51
5.90
Git 1.6.0.4 plus patch:
7.82
10.94
4.61
5.06
5.59
5.22
4.65
5.58
6.70
9.15
I'll play around with the code and see if I figure anything out.
In case it matters, I'm using a 4 core machine with a fairly old kernel:
$ uname -r
2.6.5-7.287.3.PTF.363939.1-smp
BTW thanks a lot for working on it. I was expecting a response along
the lines of "it's possible but would require extensive code changes so
it's not likely to happen", and instead a patch was posted only a few
hours later. Maybe I should ask for all those other upgrades I've had
in mind... ;-)
James
^ permalink raw reply
* [RFC PATCH] repack: make repack -a equivalent to repack -A and drop previous -a behavior
From: Brandon Casey @ 2008-11-13 23:22 UTC (permalink / raw)
To: git
Once upon a time, repack had only a single option which began with the first
letter of the alphabet. Then, a second was created which would repack
unreachable objects into the newly created pack so that git-gc --auto could
be invented. But, the -a option was still necessary so that it could be
called every now and then to discard the unreachable objects that were being
repacked over and over and over into newly generated packs. Later, -A was
changed so that instead of repacking the unreachable objects, it ejected
them from the pack so that they resided in the object store in loose form,
to be garbage collected by prune-packed according to normal expiry rules.
And so, -a lost its raison d'etre.
Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil>
---
This is on top of bc/maint-keep-pack
-brandon
Documentation/git-repack.txt | 25 ++++++++++++-------------
git-repack.sh | 8 ++++----
2 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index aaa8852..d04d5c2 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -32,21 +32,20 @@ OPTIONS
pack everything referenced into a single pack.
Especially useful when packing a repository that is used
for private development and there is no need to worry
- about people fetching via dumb protocols from it. Use
- with '-d'. This will clean up the objects that `git prune`
- leaves behind, but `git fsck --full` shows as
- dangling.
+ about people fetching via dumb protocols from it. If used
+ with '-d' , then any unreachable objects in a previous pack will
+ become loose, unpacked objects, instead of being left in the
+ old pack. Unreachable objects are never intentionally added to
+ a pack, even when repacking. This option prevents unreachable
+ objects from being immediately deleted by way of being left in
+ the old pack and then removed. Instead, the loose unreachable
+ objects will be pruned according to normal expiry rules
+ with the next 'git-gc' invocation. See linkgit:git-gc[1].
-A::
- Same as `-a`, unless '-d' is used. Then any unreachable
- objects in a previous pack become loose, unpacked objects,
- instead of being left in the old pack. Unreachable objects
- are never intentionally added to a pack, even when repacking.
- This option prevents unreachable objects from being immediately
- deleted by way of being left in the old pack and then
- removed. Instead, the loose unreachable objects
- will be pruned according to normal expiry rules
- with the next 'git-gc' invocation. See linkgit:git-gc[1].
+ Same as `-a`. Historical note: the -a and -A options used to differ
+ in that -a did not leave unreachable objects unpacked. Instead,
+ they were removed along with the redundant pack (when -d was used).
-d::
After packing, if the newly created packs make some
diff --git a/git-repack.sh b/git-repack.sh
index 458a497..f1e21b9 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -7,8 +7,9 @@ OPTIONS_KEEPDASHDASH=
OPTIONS_SPEC="\
git repack [options]
--
-a pack everything in a single pack
-A same as -a, and turn unreachable objects loose
+a pack everything in a single pack, and turn unreachable objects
+ loose
+A same as -a
d remove redundant packs, and run git-prune-packed
f pass --no-reuse-object to git-pack-objects
n do not run git-update-server-info
@@ -29,8 +30,7 @@ while test $# != 0
do
case "$1" in
-n) no_update_info=t ;;
- -a) all_into_one=t ;;
- -A) all_into_one=t
+ -a|-A) all_into_one=t
unpack_unreachable=--unpack-unreachable ;;
-d) remove_redundant=t ;;
-q) quiet=-q ;;
--
1.6.0.3.552.g12334
^ permalink raw reply related
* Re: [BUG] git ls-files -m --with-tree does double output
From: Anders Melchiorsen @ 2008-11-13 23:11 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vod0jfe51.fsf@gitster.siamese.dyndns.org>
Junio C Hamano wrote:
> What's the use case of using -m together with --with-tree to begin with?
The script runs
git ls-files -d -m -o -t --with-tree=HEAD
to get a parseable "git status"-like output. If I leave out
--with-tree=HEAD, I do not get information about staged changes.
I could use "git diff --name-status HEAD", but then there was a problem
about untracked files, I think.
Thanks,
Anders.
^ permalink raw reply
* Re: [BUG] fatal error during merge
From: Alex Riesen @ 2008-11-13 23:09 UTC (permalink / raw)
To: SZEDER Gábor
Cc: Anders Melchiorsen, Samuel Tardieu, Linus Torvalds, git,
Johannes Schindelin, Junio C Hamano
In-Reply-To: <20081113180931.GE29274@neumann>
SZEDER Gábor, Thu, Nov 13, 2008 19:09:31 +0100:
> On Thu, Nov 13, 2008 at 06:06:52PM +0100, Anders Melchiorsen wrote:
> > SZEDER Gábor wrote:
> > > It doesn't matter. The test script errors out at the merge, and not
> > > at the checkout. Furthermore, it doesn't matter, whether HEAD~,
> > > HEAD~, or HEAD^ is checked out, the results are the same.
> >
> > Just to be sure, I tried reverting the commit that you bisected -- and my
> > test case still fails.
>
> Well, oddly enough, your second test case behaves somewhat differently
> than the first one, at least as far as bisect is concerned. Bisect
> nails down the second test case to 0d5e6c97 (Ignore merged status of
> the file-level merge, 2007-04-26; put Alex on Cc). Reverting this
> commit on master makes both of your test cases pass.
Well, the case is a bit unfair: all files have the same SHA-1!
Whatever, the code pointed by the commit you bisected does look like a
problem: it does not update the index after refusing to rewrite the
worktree file (because its SHA-1 matches the SHA-1 of the data it
would be rewritten with. So updating the file would be a no-op, just
wasted effort). Instead of reverting the commit, I suggest the
attached patch. It is a long time ago since I looked at the code
(and it is a mess, which I'm feeling a bit ashamed of), so another
lot of reviewing eyeglasses is definitely in order.
From c395f4234ca5492206923e1821a316a777c651cd Mon Sep 17 00:00:00 2001
From: Alex Riesen <raa.lkml@gmail.com>
Date: Thu, 13 Nov 2008 23:55:04 +0100
Subject: [PATCH] Update index after refusing to rewrite unchanged files
Specifically, which were not changed during recursive merge.
Otherwise the path can stay marked as unresolved in the index,
causing the merge to fail.
Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
diff --git a/merge-recursive.c b/merge-recursive.c
index 7472d3e..28f9e12 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -944,14 +944,15 @@ static int process_renames(struct merge_options *o,
if (mfi.clean &&
sha_eq(mfi.sha, ren1->pair->two->sha1) &&
- mfi.mode == ren1->pair->two->mode)
+ mfi.mode == ren1->pair->two->mode) {
/*
* This messaged is part of
* t6022 test. If you change
* it update the test too.
*/
output(o, 3, "Skipped %s (merged same as existing)", ren1_dst);
- else {
+ add_cacheinfo(mfi.mode, mfi.sha, ren1_dst, 0, 0, ADD_CACHE_OK_TO_ADD);
+ } else {
if (mfi.merge || !mfi.clean)
output(o, 1, "Renaming %s => %s", ren1_src, ren1_dst);
if (mfi.merge)
^ permalink raw reply related
* [PATCH v2 09/11] gitweb: git_is_head_detached() function
From: Giuseppe Bilotta @ 2008-11-13 22:49 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski, Petr Baudis, Junio C Hamano, Giuseppe Bilotta
In-Reply-To: <1226616555-24503-9-git-send-email-giuseppe.bilotta@gmail.com>
The function checks if the HEAD for the current project is detached by
checking if 'git branch' returns "* (no branch)"
Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
---
gitweb/gitweb.perl | 13 +++++++++----
1 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index a168f6f..ceb0271 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1844,6 +1844,13 @@ sub git_get_head_hash {
return $retval;
}
+# check if current HEAD is detached
+sub git_is_head_detached {
+ my @x = (git_cmd(), 'branch');
+ my @ret = split("\n", qx(@x));
+ return 0 + grep { /^\* \(no branch\)$/ } @ret;
+}
+
# get type of given object
sub git_get_type {
my $hash = shift;
@@ -2673,11 +2680,9 @@ sub git_get_heads_list {
my @headslist;
if (grep { $_ eq 'heads' } @class) {
- my @x = (git_cmd(), 'branch');
- my @ret = split("\n", qx(@x));
- if (grep { /^\* \(no branch\)$/ } @ret) { ;
+ if (git_is_head_detached()) {
my %ref_item;
- @x = (git_cmd(), 'log', '-1', '--pretty=format:%H%n%ct%n%s');
+ my @x = (git_cmd(), 'log', '-1', '--pretty=format:%H%n%ct%n%s');
my ($hash, $epoch, $title) = split("\n", qx(@x), 3);
$ref_item{'class'} = 'head';
--
1.5.6.5
^ permalink raw reply related
* [PATCH v2 08/11] gitweb: display HEAD in heads list when detached
From: Giuseppe Bilotta @ 2008-11-13 22:49 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski, Petr Baudis, Junio C Hamano, Giuseppe Bilotta
In-Reply-To: <1226616555-24503-8-git-send-email-giuseppe.bilotta@gmail.com>
Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
---
gitweb/gitweb.perl | 21 +++++++++++++++++++++
1 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 09728cb..a168f6f 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -2672,6 +2672,27 @@ sub git_get_heads_list {
my @refs = map { "refs/$_" } @class;
my @headslist;
+ if (grep { $_ eq 'heads' } @class) {
+ my @x = (git_cmd(), 'branch');
+ my @ret = split("\n", qx(@x));
+ if (grep { /^\* \(no branch\)$/ } @ret) { ;
+ my %ref_item;
+ @x = (git_cmd(), 'log', '-1', '--pretty=format:%H%n%ct%n%s');
+ my ($hash, $epoch, $title) = split("\n", qx(@x), 3);
+
+ $ref_item{'class'} = 'head';
+ $ref_item{'name'} = 'HEAD';
+ $ref_item{'id'} = $hash;
+ $ref_item{'title'} = $title || '(no commit message)';
+ if ($ref_item{'epoch'} = $epoch) {
+ $ref_item{'age'} = age_string(time - $ref_item{'epoch'});
+ } else {
+ $ref_item{'age'} = "unknown";
+ }
+ push @headslist, \%ref_item;
+ }
+ }
+
open my $fd, '-|', git_cmd(), 'for-each-ref',
($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate',
'--format=%(objectname) %(refname) %(subject)%00%(committer)',
--
1.5.6.5
^ permalink raw reply related
* [PATCH v2 07/11] gitweb: add 'remotes' action
From: Giuseppe Bilotta @ 2008-11-13 22:49 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski, Petr Baudis, Junio C Hamano, Giuseppe Bilotta
In-Reply-To: <1226616555-24503-7-git-send-email-giuseppe.bilotta@gmail.com>
This action is similar to the 'heads' action, but it displays
remote heads, grouped by remote repository.
Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
---
gitweb/gitweb.perl | 16 +++++++++++++++-
1 files changed, 15 insertions(+), 1 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 03e0b21..09728cb 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -507,6 +507,7 @@ our %actions = (
"commit" => \&git_commit,
"forks" => \&git_forks,
"heads" => \&git_heads,
+ "remotes" => \&git_remotes,
"history" => \&git_history,
"log" => \&git_log,
"rss" => \&git_rss,
@@ -4755,13 +4756,26 @@ sub git_heads {
git_print_page_nav('','', $head,undef,$head);
git_print_header_div('summary', $project);
- my @headslist = git_get_heads_list();
+ my @headslist = git_get_heads_list(undef, 'heads');
if (@headslist) {
git_heads_body(\@headslist, $head);
}
git_footer_html();
}
+sub git_remotes {
+ my $head = git_get_head_hash($project);
+ git_header_html();
+ git_print_page_nav('','', $head,undef,$head);
+ git_print_header_div('summary', $project . ' remotes');
+
+ my @headslist = git_get_heads_list(undef, 'remotes');
+ if (@headslist) {
+ git_split_heads_body(\@headslist, $head);
+ }
+ git_footer_html();
+}
+
sub git_blob_plain {
my $type = shift;
my $expires;
--
1.5.6.5
^ permalink raw reply related
* [PATCH v2 06/11] gitweb: use CSS to style split head lists.
From: Giuseppe Bilotta @ 2008-11-13 22:49 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski, Petr Baudis, Junio C Hamano, Giuseppe Bilotta
In-Reply-To: <1226616555-24503-6-git-send-email-giuseppe.bilotta@gmail.com>
Introduce a new div class 'subsection' in the CSS and use it to style
split head lists.
Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
---
gitweb/gitweb.css | 10 ++++++++++
gitweb/gitweb.perl | 4 +++-
2 files changed, 13 insertions(+), 1 deletions(-)
diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index a01eac8..751749f 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -8,6 +8,16 @@ body {
color: #000000;
}
+div.subsection {
+ border: solid #d9d8d1;
+ border-width: 1px;
+ margin: 10px;
+}
+
+.subsection .title {
+ font-size: smaller;
+}
+
a {
color: #0000cc;
}
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 836b6ba..03e0b21 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4296,9 +4296,11 @@ sub git_split_heads_body {
} @$headlist;
foreach $leader (sort(keys %headlists)) {
- print "<b>$leader</b><br/>\n" unless $leader eq "\000";
+ print "<div class=\"subsection\">\n";
+ git_print_header_div(undef, $leader) unless $leader eq "\000";
$list = $headlists{$leader};
git_heads_body($list, $head, $from, $to, $extra);
+ print "</div>\n";
}
}
--
1.5.6.5
^ permalink raw reply related
* [PATCH v2 05/11] gitweb: git_split_heads_body function.
From: Giuseppe Bilotta @ 2008-11-13 22:49 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski, Petr Baudis, Junio C Hamano, Giuseppe Bilotta
In-Reply-To: <1226616555-24503-5-git-send-email-giuseppe.bilotta@gmail.com>
The purpose of this function is to split a headlist into groups
determined by the leading part of the refname, and call git_heads_body()
on each group.
Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
---
gitweb/gitweb.perl | 33 ++++++++++++++++++++++++++++++++-
1 files changed, 32 insertions(+), 1 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index a736f2a..836b6ba 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4271,6 +4271,37 @@ sub git_tags_body {
print "</table>\n";
}
+sub git_split_heads_body {
+ my ($headlist, $head, $from, $to, $extra) = @_;
+ my %headlists;
+ my $leader; my $list; my @list;
+
+ # Split @$headlist into a hash of lists
+ map {
+ my %ref = %$_;
+ $ref{'hname'} = $ref{'name'};
+ if ($ref{'name'} =~ /\//) {
+ $ref{'name'} =~ s!^([^/]+)/!!;
+ $leader = $1;
+ } else {
+ $leader = "\000";
+ }
+ if (defined $headlists{$leader}) {
+ @list = @{$headlists{$leader}}
+ } else {
+ @list = ()
+ }
+ push @list, \%ref;
+ $headlists{$leader} = [@list];
+ } @$headlist;
+
+ foreach $leader (sort(keys %headlists)) {
+ print "<b>$leader</b><br/>\n" unless $leader eq "\000";
+ $list = $headlists{$leader};
+ git_heads_body($list, $head, $from, $to, $extra);
+ }
+}
+
sub git_heads_body {
# uses global variable $project
my ($headlist, $head, $from, $to, $extra) = @_;
@@ -4541,7 +4572,7 @@ sub git_summary {
if (@remotelist) {
git_print_header_div('remotes');
- git_heads_body(\@remotelist, $head, 0, 15,
+ git_split_heads_body(\@remotelist, $head, 0, 15,
$#remotelist <= 15 ? undef :
$cgi->a({-href => href(action=>"heads")}, "..."));
}
--
1.5.6.5
^ permalink raw reply related
* [PATCH v2 03/11] gitweb: separate heads and remotes list in summary view
From: Giuseppe Bilotta @ 2008-11-13 22:49 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski, Petr Baudis, Junio C Hamano, Giuseppe Bilotta
In-Reply-To: <1226616555-24503-3-git-send-email-giuseppe.bilotta@gmail.com>
Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
---
gitweb/gitweb.perl | 11 ++++++++++-
1 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index d7c97a3..ab29aec 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4449,6 +4449,7 @@ sub git_summary {
my %co = parse_commit("HEAD");
my %cd = %co ? parse_date($co{'committer_epoch'}, $co{'committer_tz'}) : ();
my $head = $co{'id'};
+ my ($remote_heads) = gitweb_check_feature('remote_heads');
my $owner = git_get_project_owner($project);
@@ -4456,7 +4457,8 @@ sub git_summary {
# These get_*_list functions return one more to allow us to see if
# there are more ...
my @taglist = git_get_tags_list(16);
- my @headlist = git_get_heads_list(16);
+ my @headlist = git_get_heads_list(16, 'heads');
+ my @remotelist = $remote_heads ? git_get_heads_list(16, 'remotes') : ();
my @forklist;
my ($check_forks) = gitweb_check_feature('forks');
@@ -4535,6 +4537,13 @@ sub git_summary {
$cgi->a({-href => href(action=>"heads")}, "..."));
}
+ if (@remotelist) {
+ git_print_header_div('remotes');
+ git_heads_body(\@remotelist, $head, 0, 15,
+ $#remotelist <= 15 ? undef :
+ $cgi->a({-href => href(action=>"heads")}, "..."));
+ }
+
if (@forklist) {
git_print_header_div('forks');
git_project_list_body(\@forklist, 'age', 0, 15,
--
1.5.6.5
^ permalink raw reply related
* [PATCH v2 04/11] gitweb: optional custom name for refs in git_heads_body
From: Giuseppe Bilotta @ 2008-11-13 22:49 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski, Petr Baudis, Junio C Hamano, Giuseppe Bilotta
In-Reply-To: <1226616555-24503-4-git-send-email-giuseppe.bilotta@gmail.com>
We make a clear separation between the hash reference and the displayed
name for refs displayed by git_heads_body. This can be used e.g. to
group them and display only the distinct part of the name.
Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
---
gitweb/gitweb.perl | 12 +++++++-----
1 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index ab29aec..a736f2a 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4288,16 +4288,18 @@ sub git_heads_body {
} else {
print "<tr class=\"light\">\n";
}
+ my $hname = $ref{'hname'} || $ref{'fullname'} || $ref{'name'};
+ my $name = $ref{'name'};
$alternate ^= 1;
print "<td><i>$ref{'age'}</i></td>\n" .
($curr ? "<td class=\"current_head\">" : "<td>") .
- $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'fullname'}),
- -class => "list name"},esc_html($ref{'name'})) .
+ $cgi->a({-href => href(action=>"shortlog", hash=>$hname),
+ -class => "list name"},esc_html($name)) .
"</td>\n" .
"<td class=\"link\">" .
- $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'fullname'})}, "shortlog") . " | " .
- $cgi->a({-href => href(action=>"log", hash=>$ref{'fullname'})}, "log") . " | " .
- $cgi->a({-href => href(action=>"tree", hash=>$ref{'fullname'}, hash_base=>$ref{'name'})}, "tree") .
+ $cgi->a({-href => href(action=>"shortlog", hash=>$hname)}, "shortlog") . " | " .
+ $cgi->a({-href => href(action=>"log", hash=>$hname)}, "log") . " | " .
+ $cgi->a({-href => href(action=>"tree", hash=>$hname, hash_base=>$hname)}, "tree") .
"</td>\n" .
"</tr>";
}
--
1.5.6.5
^ permalink raw reply related
* [PATCH v2 02/11] gitweb: git_get_heads_list accepts an optional list of refs.
From: Giuseppe Bilotta @ 2008-11-13 22:49 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski, Petr Baudis, Junio C Hamano, Giuseppe Bilotta
In-Reply-To: <1226616555-24503-2-git-send-email-giuseppe.bilotta@gmail.com>
git_get_heads_list(limit, dir1, dir2, ...) can now be used to retrieve
refs/dir1, refs/dir2 etc. Defaults to ('heads') or ('heads', 'remotes')
depending on the remote_heads option.
Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
---
gitweb/gitweb.perl | 11 +++++++----
1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index b6c4233..d7c97a3 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -2663,15 +2663,18 @@ sub parse_from_to_diffinfo {
## parse to array of hashes functions
sub git_get_heads_list {
- my $limit = shift;
+ my ($limit, @class) = @_;
+ unless (defined @class) {
+ my ($remote_heads) = gitweb_check_feature('remote_heads');
+ @class = ('heads', $remote_heads ? 'remotes' : undef);
+ }
+ my @refs = map { "refs/$_" } @class;
my @headslist;
- my ($remote_heads) = gitweb_check_feature('remote_heads');
-
open my $fd, '-|', git_cmd(), 'for-each-ref',
($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate',
'--format=%(objectname) %(refname) %(subject)%00%(committer)',
- 'refs/heads', ( $remote_heads ? 'refs/remotes' : '')
+ @refs
or return;
while (my $line = <$fd>) {
my %ref_item;
--
1.5.6.5
^ permalink raw reply related
* [PATCH v2 01/11] gitweb: introduce remote_heads feature
From: Giuseppe Bilotta @ 2008-11-13 22:49 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski, Petr Baudis, Junio C Hamano, Giuseppe Bilotta
In-Reply-To: <1226616555-24503-1-git-send-email-giuseppe.bilotta@gmail.com>
With this feature enabled, remotes are retrieved (and displayed)
when getting (and displaying) the heads list.
Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
---
gitweb/gitweb.perl | 31 +++++++++++++++++++++++++++++--
1 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 933e137..b6c4233 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -327,6 +327,18 @@ our %feature = (
'ctags' => {
'override' => 0,
'default' => [0]},
+
+ # Make gitweb show remotes too in the heads list
+
+ # To enable system wide have in $GITWEB_CONFIG
+ # $feature{'remote_heads'}{'default'} = [1];
+ # To have project specific config enable override in $GITWEB_CONFIG
+ # $feature{'remote_heads'}{'override'} = 1;
+ # and in project config gitweb.remote_heads = 0|1;
+ 'remote_heads' => {
+ 'sub' => \&feature_remote_heads,
+ 'override' => 0,
+ 'default' => [0]},
);
sub gitweb_check_feature {
@@ -392,6 +404,18 @@ sub feature_pickaxe {
return ($_[0]);
}
+sub feature_remote_heads {
+ my ($val) = git_get_project_config('remote_heads', '--bool');
+
+ if ($val eq 'true') {
+ return (1);
+ } elsif ($val eq 'false') {
+ return (0);
+ }
+
+ return ($_[0]);
+}
+
# checking HEAD file with -e is fragile if the repository was
# initialized long time ago (i.e. symlink HEAD) and was pack-ref'ed
# and then pruned.
@@ -2642,10 +2666,12 @@ sub git_get_heads_list {
my $limit = shift;
my @headslist;
+ my ($remote_heads) = gitweb_check_feature('remote_heads');
+
open my $fd, '-|', git_cmd(), 'for-each-ref',
($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate',
'--format=%(objectname) %(refname) %(subject)%00%(committer)',
- 'refs/heads'
+ 'refs/heads', ( $remote_heads ? 'refs/remotes' : '')
or return;
while (my $line = <$fd>) {
my %ref_item;
@@ -2656,8 +2682,9 @@ sub git_get_heads_list {
my ($committer, $epoch, $tz) =
($committerinfo =~ /^(.*) ([0-9]+) (.*)$/);
$ref_item{'fullname'} = $name;
- $name =~ s!^refs/heads/!!;
+ $name =~ s!^refs/(head|remote)s/!!;
+ $ref_item{'class'} = $1;
$ref_item{'name'} = $name;
$ref_item{'id'} = $hash;
$ref_item{'title'} = $title || '(no commit message)';
--
1.5.6.5
^ permalink raw reply related
* [PATCH v2 00/11] gitweb: display remote heads
From: Giuseppe Bilotta @ 2008-11-13 22:49 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski, Petr Baudis, Junio C Hamano, Giuseppe Bilotta
This is a patchset I presented about a year ago or so, but after a lively
discussion it dropped into silence. I'm now presenting it again, with minor
cleanups and adjustements.
Giuseppe Bilotta (11):
gitweb: introduce remote_heads feature
gitweb: git_get_heads_list accepts an optional list of refs.
gitweb: separate heads and remotes list in summary view
gitweb: optional custom name for refs in git_heads_body
gitweb: git_split_heads_body function.
gitweb: use CSS to style split head lists.
gitweb: add 'remotes' action
gitweb: display HEAD in heads list when detached
gitweb: git_is_head_detached() function
gitweb: add HEAD to list of shortlog refs if detached
gitweb: CSS style and refs mark for detached HEAD
gitweb/gitweb.css | 15 ++++++
gitweb/gitweb.perl | 138 ++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 143 insertions(+), 10 deletions(-)
^ permalink raw reply
* Re: [BUG] git ls-files -m --with-tree does double output
From: Junio C Hamano @ 2008-11-13 22:39 UTC (permalink / raw)
To: Anders Melchiorsen; +Cc: gitster, git
In-Reply-To: <7vod0jfe51.fsf@gitster.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> writes:
> What's the use case of using -m together with --with-tree to begin with?
> I think the only sensible other option that makes sense with --with-tree
> is --error-unmatch.
The reason I ask this question is that the cleanest fix to the issue might
turn out to be to forbid that combination of the options, if it turns out
that it does not make any sense.
^ permalink raw reply
* Re: [BUG] git ls-files -m --with-tree does double output
From: Junio C Hamano @ 2008-11-13 22:35 UTC (permalink / raw)
To: Anders Melchiorsen; +Cc: gitster, git
In-Reply-To: <37512.N1gUGH5fRhE=.1226613228.squirrel@webmail.hotelhot.dk>
"Anders Melchiorsen" <mail@cup.kalibalik.dk> writes:
> and@dylle:~/repo$ git ls-files -m --with-tree=HEAD
> a
> a
>
>
> Jeff King added:
> ...
> It isn't clear to me which code is _supposed_ to be pulling out such
> duplicates here. That is, is read_tree broken, or is
> overlay_tree_on_cache just calling it wrong?
I had to look up what -m meant in ls-files, as I never considered that
option as part of the plumbing.
What's the use case of using -m together with --with-tree to begin with?
I think the only sensible other option that makes sense with --with-tree
is --error-unmatch.
^ permalink raw reply
* Re: [BUG] fatal error during merge
From: Anders Melchiorsen @ 2008-11-13 22:25 UTC (permalink / raw)
To: SZEDER Gábor; +Cc: Alex Riesen, git
In-Reply-To: <20081113180931.GE29274@neumann>
SZEDER Gábor wrote:
> Well, oddly enough, your second test case behaves somewhat differently
> than the first one, at least as far as bisect is concerned. Bisect
> nails down the second test case to 0d5e6c97 (Ignore merged status of
> the file-level merge, 2007-04-26; put Alex on Cc). Reverting this
> commit on master makes both of your test cases pass.
Hmm. With that one reverted, git prints out this error instead:
error: failed to create path 'after/one': perhaps a D/F conflict?
and still has the moved file disapper in the working tree. The merge is
successful, though, and the moved file is in the committed tree.
Anders.
^ permalink raw reply
* Re: [EGIT PATCH 1/7] Test the origName part of the key vs the ref itself
From: Robin Rosenberg @ 2008-11-13 22:13 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: git
In-Reply-To: <20081111180520.GN2932@spearce.org>
tisdag 11 november 2008 19:05:20 skrev Shawn O. Pearce:
> Robin Rosenberg <robin.rosenberg@dewire.com> wrote:
> > @@ -127,4 +129,12 @@ public void testDeleteEmptyDirs() throws IOException {
> > private void assertExists(final boolean expected, final String name) {
> > assertEquals(expected, new File(db.getDirectory(), name).exists());
> > }
> > +
> > + public void testRefKeySameAsOrigName() {
> > + Map<String, Ref> allRefs = db.getAllRefs();
> > + for (Entry<String, Ref> e : allRefs.entrySet()) {
> > + assertEquals(e.getKey(), e.getValue().getOrigName());
> > +
> > + }
> > + }
>
> Hmm, doesn't this have to go after "Keep original ref name ..."
> so getOrigName() is actually defined?
Oops, Seems we should try to build each new commit before accepting
a push. Shouldn't be too hard.
-- robin
^ permalink raw reply
* Re: post-update hook
From: Junio C Hamano @ 2008-11-13 22:06 UTC (permalink / raw)
To: Jeremy Ramer; +Cc: Junio C Hamano, git
In-Reply-To: <b9fd99020811131048p741cd9aqdcdf4cf410830915@mail.gmail.com>
"Jeremy Ramer" <jdramer@gmail.com> writes:
> I had to make one change to this example to get it to work. I'll put
> it here for completeness
>
> #!/bin/sh
> case "$*" in
> "refs/remotes/origin/master")
> cd ..
> GIT_DIR=".git"
> git merge refs/remotes/origin/master
> ;;
> esac
Yeah, thanks for correction. My bad not resetting GIT_DIR.
By the way, I _did_ write these seemingly extra spaces around $* and the
refname on purpose.
^ permalink raw reply
* Re: [PATCH (GITK)] gitk: Make line origin search update the busy status.
From: Paul Mackerras @ 2008-11-13 22:00 UTC (permalink / raw)
To: Alexander Gavrilov; +Cc: git
In-Reply-To: <200811132343.13910.angavrilov@gmail.com>
Alexander Gavrilov writes:
> Currently the 'show origin of this line' feature does
> not update the status field of the gitk window, so it
> is not evident that any processing is going on. It may
> seem at first that clicking the item had no effect.
>
> This commit adds calls to set and clear the busy
> status with an appropriate title, similar to other
> search commands.
I have been meaning to do this myself. I want to find something
better than "Blaming" to put in the status field, though, since
"blaming" is jargon in this context. Actually, "Searching" would
probably do.
Paul.
^ 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