Git development
 help / color / mirror / Atom feed
* Re: [spf:guess] Re: [PATCH 2/5] git-svn: Make merge metadata accessible to make_log_entry
From: Alex Vandiver @ 2009-12-19 22:24 UTC (permalink / raw)
  To: Sam Vilain; +Cc: Eric Wong, git
In-Reply-To: <1260053972.22680.5.camel@denix>

At Sat Dec 05 17:59:32 -0500 2009, Sam Vilain wrote:
> Hi, I've just seen the series, looks like a good idea.  Just a couple of
> questions then I'll review the code;

Have you had time to take a look at these?
 - Alex
-- 
Networking -- only one letter away from not working

^ permalink raw reply

* Re: Efficiency and correctness patches for git-svn mergeinfo support
From: Andrew Myrick @ 2009-12-19 22:15 UTC (permalink / raw)
  To: Sam Vilain; +Cc: git, Eric Wong
In-Reply-To: <1261240435-8948-1-git-send-email-sam@vilain.net>

> It would be nice if the people who have experienced slow git-svn
> performance in these situations could test that this fixes the
> performance issues, and that the resulting repositories seem to have
> correct contents.

I tried cloning from a fairly recent revision that I knew was after
our switchover to svn 1.5, and I received a number of these errors:

   Couldn't find revmap for [branch]
   Exiting subroutine via next at /Users/adm/libexec/git-core/git-svn line 2983.
   Exiting subroutine via next at /Users/adm/libexec/git-core/git-svn line 2983.
   Exiting subroutine via next at /Users/adm/libexec/git-core/git-svn line 2983.

I'm not sure if this is expected, since I didn't clone from the whole
repo, but it did cause a lot of spew.  I'm starting a fresh clone now,
but it takes a few days to get through the whole repository.  I'm
fairly new to git, so I would welcome any tips on how I can test this
more quickly.

-Andrew

^ permalink raw reply

* Re: [PATCH] rebase -i: abort cleanly if the editor fails to launch
From: Johannes Schindelin @ 2009-12-19 20:57 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Björn Gustavsson, git
In-Reply-To: <7v8wcy7kyc.fsf@alter.siamese.dyndns.org>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1282 bytes --]

Hi,

On Sat, 19 Dec 2009, Junio C Hamano wrote:

> Björn Gustavsson <bgustavsson@gmail.com> writes:
> 
> > If the user's configured editor is emacsclient, the editor
> > will fail to launch if emacs is not running and the git
> > command that tried to lanuch the editor will abort. For most
> > commands, all you have to do is to start emacs and repeat
> > the command.
> >
> > The "git rebase -i" command, however, aborts without cleaning
> > the "$GIT_DIR/rebase-merge" directory if it fails to launch the
> > editor, so you'll need to do "git rebase --abort" before
> > repeating the rebase command.
> >
> > Change "git rebase -i" to terminate using "die_abort" (instead of
> > with "die") if the initial launch of the editor fails.
> >
> > Signed-off-by: Björn Gustavsson <bgustavsson@gmail.com>
> 
> Two questions:
> 
>  - Is emacsclient the _only_ editor that can exit with non-zero status to
>    signal an error condition "the user invoked me to edit an existing
>    file, but I ended up not letting the user edit it"?

The non-existent editor also aborts with a non-zero status.

> An editor that can exit with non-zero status on demand could use this
> codepath to abort the rebase,

Removing all lines of the edit script will abort an interactive rebase.

Ciao,
Dscho

^ permalink raw reply

* Re: Query remote repository files, blobs
From: Johannes Schindelin @ 2009-12-19 20:50 UTC (permalink / raw)
  To: A Large Angry SCM; +Cc: Shawn O. Pearce, Bill Lear, Shakthi Kannan, git
In-Reply-To: <4B2D3AB1.5000504@gmail.com>

Hi,

On Sat, 19 Dec 2009, A Large Angry SCM wrote:

> Shawn O. Pearce wrote:
> > Bill Lear <rael@zopyra.com> wrote:
> > > On Saturday, December 19, 2009 at 12:02:02 (+0100) Johannes Schindelin
> > > writes:
> > > > On Sat, 19 Dec 2009, Shakthi Kannan wrote:
> > > > ...
> > > > > I am able to query for list of remote heads, and tags. I would like to
> > > > > know if it is possible to query for information on remote files, or
> > > > > blobs?
> > > > This has been discussed a number of times, but we cannot allow that for
> > > > security reasons.  A blob might contain confidential information, in
> > > > which case the branch has to be rewritten and force-pushed.  However,
> > > > that does not make the blob go away, but makes it only unreachable.
> > > > Until the next garbage collection kicks in, that is (which you typically
> > > > cannot control).
> > > Hmm, I thought this had been addressed by git in a different way (removing
> > > confidential information).  A company will not be satisfied that its
> > > proprietary information is "unreachable" in your software repository.
> > > They want absolute assurance that the information is completely
> > > removed.
> > >
> > > Have I remembered wrongly --- is this still not possible with git?
> > 
> > Its still possible, but you have to wipe out the reflog record(s)
> > that had the object in it, and you have to repack to evict it from
> > the pack files, and you have to run `git prune --expire=0` to force
> > it to wipe out the object immediately.
> > 
> > We already support dumping back random commits via upload-archive, if
> > its enabled in the daemon, and I think a lot of people do turn it on.
> > There is no validation that the requested tree-ish is reachable.
> > 
> > I think gitweb winds up doing the same thing, it doesn't actually
> > try to validate the object is reachable, it just serves whatever
> > it was asked for, if its present in the repository.
> > 
> > 
> > I'm getting some mild suggestions over here at $DAY_JOB to implement
> > shallow clones by lazily downloading large blobs on demand.
> > We've resisted doing this in git because of the reachability test
> > Dscho mentioned above... but many people skip that anyway due
> > to gitweb and upload-archive being enabled.  Which is making me
> > start to question who is broken... upload-pack for not being more
> > willing to serve arbitrary content, or gitweb/upload-archive for
> > not validating their requests are reachable.
> 
> The security argument hasn't been true for a while if any of the following are
> enabled on the server:
> 	Gitweb
> 	http transport
> 	rsync transport
> 	ftp transport
> 	alternates (the alternates are the ones at risk)

Right.  But we must not break the security for careful administrators 
(read: who did _not_ enable any of the above) just out of a whim, right?  
Certainly not if the only reason to do it was "somebody thought it would 
be neat, but most probably is not going to use it herself after having 
played with it for a few days".

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH] rebase -i: abort cleanly if the editor fails to launch
From: Junio C Hamano @ 2009-12-19 20:44 UTC (permalink / raw)
  To: Björn Gustavsson; +Cc: git
In-Reply-To: <4B2CC133.9010704@gmail.com>

Björn Gustavsson <bgustavsson@gmail.com> writes:

> If the user's configured editor is emacsclient, the editor
> will fail to launch if emacs is not running and the git
> command that tried to lanuch the editor will abort. For most
> commands, all you have to do is to start emacs and repeat
> the command.
>
> The "git rebase -i" command, however, aborts without cleaning
> the "$GIT_DIR/rebase-merge" directory if it fails to launch the
> editor, so you'll need to do "git rebase --abort" before
> repeating the rebase command.
>
> Change "git rebase -i" to terminate using "die_abort" (instead of
> with "die") if the initial launch of the editor fails.
>
> Signed-off-by: Björn Gustavsson <bgustavsson@gmail.com>

Two questions:

 - Is emacsclient the _only_ editor that can exit with non-zero status to
   signal an error condition "the user invoked me to edit an existing
   file, but I ended up not letting the user edit it"?

 - Are there editors that let you exit with non-zero status on demand?

The above is not a complaint to your log message, but is a genuine request
for information.

An editor that can exit with non-zero status on demand could use this
codepath to abort the rebase, when a user realizes that the edit s/he has
done so far was completely bogus [*1*].  In such a case, the existing
error message "Could not execute editor" may sound funny.

Regardless of that small issue, I think the patch to clean-up makes sense.

Thanks.


[Footnote]

*1* We interpret a completely empty $TODO as a signal from the user to
abort the sequencer (the literal interpretation of such a $TODO would be
to not pick any commits, which could be a source of potential confusion),
so it is not an issue in practice if your editor does not allow you to
exit with non-zero status to signal an exception.  You can remove all
lines and exit the editor normally instead.

^ permalink raw reply

* Re: Query remote repository files, blobs
From: A Large Angry SCM @ 2009-12-19 20:42 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Johannes Schindelin, Bill Lear, Shakthi Kannan, git
In-Reply-To: <20091219192415.GC10687@spearce.org>

Shawn O. Pearce wrote:
> Bill Lear <rael@zopyra.com> wrote:
>> On Saturday, December 19, 2009 at 12:02:02 (+0100) Johannes Schindelin writes:
>>> On Sat, 19 Dec 2009, Shakthi Kannan wrote:
>>> ...
>>>> I am able to query for list of remote heads, and tags. I would like to
>>>> know if it is possible to query for information on remote files, or
>>>> blobs?
>>> This has been discussed a number of times, but we cannot allow that for 
>>> security reasons.  A blob might contain confidential information, in which 
>>> case the branch has to be rewritten and force-pushed.  However, that does 
>>> not make the blob go away, but makes it only unreachable.  Until the next 
>>> garbage collection kicks in, that is (which you typically cannot control).
>> Hmm, I thought this had been addressed by git in a different way (removing
>> confidential information).  A company will not be satisfied that its
>> proprietary information is "unreachable" in your software repository.
>> They want absolute assurance that the information is completely
>> removed.
>>
>> Have I remembered wrongly --- is this still not possible with git?
> 
> Its still possible, but you have to wipe out the reflog record(s)
> that had the object in it, and you have to repack to evict it from
> the pack files, and you have to run `git prune --expire=0` to force
> it to wipe out the object immediately.
> 
> We already support dumping back random commits via upload-archive, if
> its enabled in the daemon, and I think a lot of people do turn it on.
> There is no validation that the requested tree-ish is reachable.
> 
> I think gitweb winds up doing the same thing, it doesn't actually
> try to validate the object is reachable, it just serves whatever
> it was asked for, if its present in the repository.
> 
> 
> I'm getting some mild suggestions over here at $DAY_JOB to implement
> shallow clones by lazily downloading large blobs on demand.
> We've resisted doing this in git because of the reachability test
> Dscho mentioned above... but many people skip that anyway due
> to gitweb and upload-archive being enabled.  Which is making me
> start to question who is broken... upload-pack for not being more
> willing to serve arbitrary content, or gitweb/upload-archive for
> not validating their requests are reachable.

The security argument hasn't been true for a while if any of the 
following are enabled on the server:
	Gitweb
	http transport
	rsync transport
	ftp transport
	alternates (the alternates are the ones at risk)

^ permalink raw reply

* Re: Query remote repository files, blobs
From: Shawn O. Pearce @ 2009-12-19 19:24 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Bill Lear, Shakthi Kannan, git
In-Reply-To: <19244.54684.250532.801766@lisa.zopyra.com>

Bill Lear <rael@zopyra.com> wrote:
> On Saturday, December 19, 2009 at 12:02:02 (+0100) Johannes Schindelin writes:
> >On Sat, 19 Dec 2009, Shakthi Kannan wrote:
> >...
> >> I am able to query for list of remote heads, and tags. I would like to
> >> know if it is possible to query for information on remote files, or
> >> blobs?
> >
> >This has been discussed a number of times, but we cannot allow that for 
> >security reasons.  A blob might contain confidential information, in which 
> >case the branch has to be rewritten and force-pushed.  However, that does 
> >not make the blob go away, but makes it only unreachable.  Until the next 
> >garbage collection kicks in, that is (which you typically cannot control).
> 
> Hmm, I thought this had been addressed by git in a different way (removing
> confidential information).  A company will not be satisfied that its
> proprietary information is "unreachable" in your software repository.
> They want absolute assurance that the information is completely
> removed.
> 
> Have I remembered wrongly --- is this still not possible with git?

Its still possible, but you have to wipe out the reflog record(s)
that had the object in it, and you have to repack to evict it from
the pack files, and you have to run `git prune --expire=0` to force
it to wipe out the object immediately.

We already support dumping back random commits via upload-archive, if
its enabled in the daemon, and I think a lot of people do turn it on.
There is no validation that the requested tree-ish is reachable.

I think gitweb winds up doing the same thing, it doesn't actually
try to validate the object is reachable, it just serves whatever
it was asked for, if its present in the repository.


I'm getting some mild suggestions over here at $DAY_JOB to implement
shallow clones by lazily downloading large blobs on demand.
We've resisted doing this in git because of the reachability test
Dscho mentioned above... but many people skip that anyway due
to gitweb and upload-archive being enabled.  Which is making me
start to question who is broken... upload-pack for not being more
willing to serve arbitrary content, or gitweb/upload-archive for
not validating their requests are reachable.

-- 
Shawn.

^ permalink raw reply

* Re: [PATCH] Introduce the GIT_HOME environment variable
From: Junio C Hamano @ 2009-12-19 19:21 UTC (permalink / raw)
  To: Miklos Vajna; +Cc: Moe, git
In-Reply-To: <20091219153046.GG25474@genesis.frugalware.org>

Miklos Vajna <vmiklos@frugalware.org> writes:

> diff --git a/builtin-config.c b/builtin-config.c
> index a2d656e..da9ebd4 100644
> --- a/builtin-config.c
> +++ b/builtin-config.c
> @@ -146,7 +146,9 @@ static int get_value(const char *key_, const char *regex_)
>  
>  	local = config_exclusive_filename;
>  	if (!local) {
> -		const char *home = getenv("HOME");
> +		const char *home = getenv("GIT_HOME");
> +		if (!home)
> +			home = getenv("HOME");

If you introduce a helper like this:

	const char *git_custom_home(void)
        {
        	const char *val = getenv("GIT_HOME");
                if (!val)
                	val = getenv("HOME");
		return val;
	}

then a mechanical s/getenv("GIT_HOME")/gitcustom_home()/; will make the
resulting code a lot simpler and a new callsite somebody may add in the
future would not have to duplicate three lines.

But I sense that Moe is retracting his claim that the unmodified git
doesn't do what he needs to do, after Dscho suggested to use more specific
environment variables to the task at hand?

^ permalink raw reply

* Re: [PATCH] Introduce the GIT_HOME environment variable
From: Junio C Hamano @ 2009-12-19 19:13 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Miklos Vajna, Moe, git
In-Reply-To: <vpqeimq51pq.fsf@bauges.imag.fr>

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

> http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
>
> It solves the same problem ("set on environment variable, and change
> my whole Git config"), but
>
> * It's a standard. It's really nice to be able to ...
> * It avoids hidden files. With $GIT_CONFIG, a user doing

I think the above are actually three bullet points (i.e. you lack line
break and bullet before "It's really nice").  And the third bullet is more
or less a small subset of the second one, since you need "ls -a" without
making them non-dot,  And I personally don't care very much about that
second "It's really nice to be able to" point.

As to the particular "standard" cited, I don't know how relevant it is to
us at this moment, or in this topic.  Judging from the fact that it
doesn't even define the scope of the standard (e.g. what classes of
applications are expected to follow it, for what benefit do they follow
it, how are they expected to handle differences between their historical
practice and the new world order it introduces, etc. etc....), I suspect
it is a very early draft that will be heavily copyedited before final,
once professional standard writers start looking at it.

^ permalink raw reply

* Re: [PATCH] Introduce the GIT_HOME environment variable
From: Matthieu Moy @ 2009-12-19 17:10 UTC (permalink / raw)
  To: Miklos Vajna; +Cc: Junio C Hamano, Moe, git
In-Reply-To: <20091219153046.GG25474@genesis.frugalware.org>

Miklos Vajna <vmiklos@frugalware.org> writes:

> Honor $GIT_HOME that is favoured over $HOME,

I'd personally prefer obeying $XDG_CONFIG_HOME, and read
$XDG_CONFIG_HOME/git/config (defaulting to $HOME/.config/git/config)
or something like this :

http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html

It solves the same problem ("set on environment variable, and change
my whole Git config"), but

* It's a standard. It's really nice to be able to

cd ~/.config
ls

to see a user's configuration for many applications at a time, and

cd ~/.config
git init

to version-control it.

* It avoids hidden files. With $GIT_CONFIG, a user doing

cd $GIT_HOME
ls

sees nothing. I understand why $HOME/something config files are
hidden, but a config file stored in a separate directory shouldn't be
hidden (just like $GIT_DIR/config is not hidden).

> -		const char *home = getenv("HOME");
> +		const char *home = getenv("GIT_HOME");
> +		if (!home)
> +			home = getenv("HOME");

If you go this way, why not define

const char *getenv_home()
{
	const char *home = getenv("GIT_HOME");
	if (!home)
		home = getenv("HOME");
	return home;
}

?

(probably in git-compat-util.h)

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

^ permalink raw reply

* [PATCH] Introduce the GIT_HOME environment variable
From: Miklos Vajna @ 2009-12-19 16:44 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Moe, git, Michael J Gruber
In-Reply-To: <4B2CFCD1.3010208@drmicha.warpmail.net>

Honor $GIT_HOME that is favoured over $HOME, just like $GIT_EDITOR
overrides $EDITOR.  That allows us to extend the notion more naturally
in the future.  For example, when we read from $HOME/.gitconfig, if the
GIT_HOME environment is set, we instead read from $GIT_HOME/.gitconfig.

Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---

On Sat, Dec 19, 2009 at 05:18:25PM +0100, Michael J Gruber <git@drmicha.warpmail.net> wrote:
> Yes, but it makes less sense this way... Junio wrote "when we start
> reading" because we don't do that yet. But we read ~/.gitconfig, of
> course, so "when we start reading" sounds funny here.
>
> (...)
>
> "different from"

Fixed both, thanks.

 Documentation/config.txt |   14 ++++++++++----
 builtin-config.c         |    8 ++++++--
 config.c                 |    4 +++-
 path.c                   |    4 +++-
 t/t1300-repo-config.sh   |    7 +++++++
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index a1e36d7..09cbc71 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -8,6 +8,10 @@ is used to store the configuration for that repository, and
 fallback values for the `.git/config` file. The file `/etc/gitconfig`
 can be used to store a system-wide default configuration.
 
+In case you want to store your per-user configuration in a directory
+different from `$HOME`, you can use the `$GIT_HOME` environment variable
+which has preference.
+
 The configuration variables are used by both the git plumbing
 and the porcelains. The variables are divided into sections, wherein
 the fully qualified variable name of the variable itself is the last
@@ -406,8 +410,9 @@ core.excludesfile::
 	In addition to '.gitignore' (per-directory) and
 	'.git/info/exclude', git looks into this file for patterns
 	of files which are not meant to be tracked.  "{tilde}/" is expanded
-	to the value of `$HOME` and "{tilde}user/" to the specified user's
-	home directory.  See linkgit:gitignore[5].
+	to the value of `$GIT_HOME` (or `$HOME` if `$GIT_HOME` is not
+	set) and "{tilde}user/" to the specified user's home directory.  See
+	linkgit:gitignore[5].
 
 core.editor::
 	Commands such as `commit` and `tag` that lets you edit
@@ -707,8 +712,9 @@ color.ui::
 
 commit.template::
 	Specify a file to use as the template for new commit messages.
-	"{tilde}/" is expanded to the value of `$HOME` and "{tilde}user/" to the
-	specified user's home directory.
+	"{tilde}/" is expanded to the value of `$GIT_HOME` (or `$HOME`
+	if `$GIT_HOME` is not set) and "{tilde}user/" to the specified user's
+	home directory.
 
 diff.autorefreshindex::
 	When using 'git-diff' to compare with work tree
diff --git a/builtin-config.c b/builtin-config.c
index a2d656e..da9ebd4 100644
--- a/builtin-config.c
+++ b/builtin-config.c
@@ -146,7 +146,9 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = getenv("GIT_HOME");
+		if (!home)
+			home = getenv("HOME");
 		local = repo_config = git_pathdup("config");
 		if (git_config_global() && home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -326,7 +328,9 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = getenv("GIT_HOME");
+		if (!home)
+			home = getenv("HOME");
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/config.c b/config.c
index 37385ce..7e2ccdb 100644
--- a/config.c
+++ b/config.c
@@ -711,7 +711,9 @@ int git_config(config_fn_t fn, void *data)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = getenv("GIT_HOME");
+	if (!home)
+		home = getenv("HOME");
 	if (git_config_global() && home) {
 		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 		if (!access(user_config, R_OK)) {
diff --git a/path.c b/path.c
index 2ec950b..b42a1b6 100644
--- a/path.c
+++ b/path.c
@@ -236,7 +236,9 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = getenv("GIT_HOME");
+			if (!home)
+				home = getenv("HOME");
 			strbuf_add(&user_path, home, strlen(home));
 		} else {
 			struct passwd *pw = getpw_str(username, username_len);
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 83b7294..d9818ab 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -18,6 +18,13 @@ EOF
 
 test_expect_success 'initial' 'cmp .git/config expect'
 
+test_expect_success 'GIT_HOME' '
+	GIT_HOME="`pwd`" &&
+	export GIT_HOME &&
+	git config --global core.penguin "little blue" &&
+	cmp "$GIT_HOME"/.gitconfig expect
+'
+
 git config Core.Movie BadPhysics
 
 cat > expect << EOF
-- 
1.6.5.2

^ permalink raw reply related

* Re: Efficiency and correctness patches for git-svn mergeinfo support
From: Sam Vilain @ 2009-12-19 16:42 UTC (permalink / raw)
  To: git; +Cc: Eric Wong, Andrew Myrick
In-Reply-To: <1261240435-8948-1-git-send-email-sam@vilain.net>

On Sun, 2009-12-20 at 05:33 +1300, Sam Vilain wrote:
> This series implements some efficiency enhancements; particularly in
> dealing with repositories which have a single trunk branch which
> receives many merges of feature branches and/or cherry-picks.  It also
> fixes a number of corner cases in the merge conversion code.
> 
> It would be nice if the people who have experienced slow git-svn
> performance in these situations could test that this fixes the
> performance issues, and that the resulting repositories seem to have
> correct contents.
> 
> Eric, I'm using Alex's trick of a single commit which adds failing
> tests - marked as _expect_failure - and then marked them as succeeding
> as the series progresses.

More useful info:

 git-svn.perl               |  220 +++++++++----
 t/t9151-svn-mergeinfo.sh   |   27 ++-
 t/t9151/make-svnmerge-dump |  166 ++++++---
 t/t9151/svn-mergeinfo.dump |  839
++++++++++++++++++++++++++++++++++++++------
 4 files changed, 1018 insertions(+), 234 deletions(-)

And available at git://github.com/samv/git (branch mergeinfo-fixes)

Sam

^ permalink raw reply

* Re: [PATCH 2/5] git-svn: memoize conversion of SVN merge ticket info to git commit ranges
From: Sam Vilain @ 2009-12-19 16:37 UTC (permalink / raw)
  To: git; +Cc: Eric Wong, Andrew Myrick
In-Reply-To: <1261240435-8948-3-git-send-email-sam@vilain.net>

On Sun, 2009-12-20 at 05:33 +1300, Sam Vilain wrote:
> Each time the svn mergeinfo ticket changes, we look it up in the rev_map;
> when there are a lot of merged branches, this will result in many repeated
> lookups of the same information for subsequent commits.  Arrange the slow
> part of the function so that it may be memoized, and memoize it.  The more
> expensive revision walking operation can be memoized separately.

Sorry, that text was an old revision.  Read as:

Each time the svn mergeinfo ticket changes, we look it up in the
rev_map; when there are a lot of merged branches, this will result in
many repeated lookups of the same information for subsequent commits.
Arrange that part of the function so that it may be memoized, and
memoize it.

Sam

^ permalink raw reply

* [PATCH 4/5] git-svn: exclude already merged tips using one rev-list call
From: Sam Vilain @ 2009-12-19 16:33 UTC (permalink / raw)
  To: git; +Cc: Eric Wong, Andrew Myrick, Sam Vilain
In-Reply-To: <1261240435-8948-4-git-send-email-sam@vilain.net>

The old function would have to check all mentioned merge tips, every time
that the mergeinfo ticket changed.  This involved 1-2 rev-list operation
for each listed mergeinfo line.  If there are a lot of feature branches
being merged into a trunk, this makes for a very expensive operation for
detecting the new parents on every merge.

This new version first uses a single 'rev-list' to figure out which commit
ranges are already reachable from the parents.  This is used to eliminate
the already merged branches from the list.

Signed-off-by: Sam Vilain <sam@vilain.net>
---
 git-svn.perl |   52 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index 9cf4a3e..7a790d7 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -3011,6 +3011,41 @@ BEGIN {
 	memoize 'lookup_svn_merge';
 }
 
+sub parents_exclude {
+	my $parents = shift;
+	my @commits = @_;
+	return unless @commits;
+
+	my @excluded;
+	my $excluded;
+	do {
+		my @cmd = ('rev-list', "-1", @commits, "--not", @$parents );
+		$excluded = command_oneline(@cmd);
+		if ( $excluded ) {
+			my @new;
+			my $found;
+			for my $commit ( @commits ) {
+				if ( $commit eq $excluded ) {
+					push @excluded, $commit;
+					$found++;
+					last;
+				}
+				else {
+					push @new, $commit;
+				}
+			}
+			die "saw commit '$excluded' in rev-list output, "
+				."but we didn't ask for that commit (wanted: @commits --not @$parents)"
+					unless $found;
+			@commits = @new;
+		}
+	}
+		while ($excluded and @commits);
+
+	return @excluded;
+}
+
+
 # note: this function should only be called if the various dirprops
 # have actually changed
 sub find_extra_svn_parents {
@@ -3023,23 +3058,32 @@ sub find_extra_svn_parents {
 	# are now marked as merge, we can add the tip as a parent.
 	my @merges = split "\n", $mergeinfo;
 	my @merge_tips;
-	my @merged_commit_ranges;
 	my $url = $self->rewrite_root || $self->{url};
 	my $uuid = $self->ra_uuid;
+	my %ranges;
 	for my $merge ( @merges ) {
 		my ($tip_commit, @ranges) =
 			lookup_svn_merge( $uuid, $url, $merge );
-		push @merged_commit_ranges, @ranges;
 		unless (!$tip_commit or
 				grep { $_ eq $tip_commit } @$parents ) {
 			push @merge_tips, $tip_commit;
+			$ranges{$tip_commit} = \@ranges;
 		} else {
 			push @merge_tips, undef;
 		}
 	}
+
+	my %excluded = map { $_ => 1 }
+		parents_exclude($parents, grep { defined } @merge_tips);
+
+	# check merge tips for new parents
+	my @new_parents;
 	for my $merge_tip ( @merge_tips ) {
 		my $spec = shift @merges;
-		next unless $merge_tip;
+		next unless $merge_tip and $excluded{$merge_tip};
+
+		my $ranges = $ranges{$merge_tip};
+
 		my @cmd = ('rev-list', "-1", $merge_tip,
 			   "--not", @$parents );
 		my ($msg_fh, $ctx) = command_output_pipe(@cmd);
@@ -3049,7 +3093,7 @@ sub find_extra_svn_parents {
 		}
 		command_close_pipe($msg_fh, $ctx);
 		if ( $new ) {
-			push @cmd, @merged_commit_ranges;
+			push @cmd, @$ranges;
 			my ($msg_fh, $ctx) = command_output_pipe(@cmd);
 			my $unmerged;
 			while ( <$msg_fh> ) {
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH 2/5] git-svn: memoize conversion of SVN merge ticket info to git commit ranges
From: Sam Vilain @ 2009-12-19 16:33 UTC (permalink / raw)
  To: git; +Cc: Eric Wong, Andrew Myrick, Sam Vilain
In-Reply-To: <1261240435-8948-2-git-send-email-sam@vilain.net>

Each time the svn mergeinfo ticket changes, we look it up in the rev_map;
when there are a lot of merged branches, this will result in many repeated
lookups of the same information for subsequent commits.  Arrange the slow
part of the function so that it may be memoized, and memoize it.  The more
expensive revision walking operation can be memoized separately.

Signed-off-by: Sam Vilain <sam@vilain.net>
---
 git-svn.perl |   91 ++++++++++++++++++++++++++++++++++-----------------------
 1 files changed, 54 insertions(+), 37 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index a4b052c..3b17a83 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -1634,6 +1634,7 @@ use Carp qw/croak/;
 use File::Path qw/mkpath/;
 use File::Copy qw/copy/;
 use IPC::Open3;
+use Memoize;  # core since 5.8.0, Jul 2002
 
 my ($_gc_nr, $_gc_period);
 
@@ -2967,6 +2968,55 @@ sub find_extra_svk_parents {
 	}
 }
 
+sub lookup_svn_merge {
+	my $uuid = shift;
+	my $url = shift;
+	my $merge = shift;
+
+	my ($source, $revs) = split ":", $merge;
+	my $path = $source;
+	$path =~ s{^/}{};
+	my $gs = Git::SVN->find_by_url($url.$source, $url, $path);
+	if ( !$gs ) {
+		warn "Couldn't find revmap for $url$source\n";
+		next;
+	}
+	my @ranges = split ",", $revs;
+	my ($tip, $tip_commit);
+	my @merged_commit_ranges;
+	# find the tip
+	for my $range ( @ranges ) {
+		my ($bottom, $top) = split "-", $range;
+		$top ||= $bottom;
+		my $bottom_commit =
+			$gs->rev_map_get($bottom, $uuid) ||
+			$gs->rev_map_get($bottom+1, $uuid);
+		my $top_commit;
+		for (; !$top_commit && $top >= $bottom; --$top) {
+			$top_commit =
+				$gs->rev_map_get($top, $uuid);
+		}
+
+		unless ($top_commit and $bottom_commit) {
+			warn "W:unknown path/rev in svn:mergeinfo "
+				."dirprop: $source:$range\n";
+			next;
+		}
+
+		push @merged_commit_ranges,
+			"$bottom_commit..$top_commit";
+
+		if ( !defined $tip or $top > $tip ) {
+			$tip = $top;
+			$tip_commit = $top_commit;
+		}
+	}
+	return ($tip_commit, @merged_commit_ranges);
+}
+BEGIN {
+	memoize 'lookup_svn_merge';
+}
+
 # note: this function should only be called if the various dirprops
 # have actually changed
 sub find_extra_svn_parents {
@@ -2981,44 +3031,11 @@ sub find_extra_svn_parents {
 	my @merge_tips;
 	my @merged_commit_ranges;
 	my $url = $self->rewrite_root || $self->{url};
+	my $uuid = $self->ra_uuid;
 	for my $merge ( @merges ) {
-		my ($source, $revs) = split ":", $merge;
-		my $path = $source;
-		$path =~ s{^/}{};
-		my $gs = Git::SVN->find_by_url($url.$source, $url, $path);
-		if ( !$gs ) {
-			warn "Couldn't find revmap for $url$source\n";
-			next;
-		}
-		my @ranges = split ",", $revs;
-		my ($tip, $tip_commit);
-		# find the tip
-		for my $range ( @ranges ) {
-			my ($bottom, $top) = split "-", $range;
-			$top ||= $bottom;
-			my $bottom_commit =
-				$gs->rev_map_get($bottom, $self->ra_uuid) ||
-				$gs->rev_map_get($bottom+1, $self->ra_uuid);
-			my $top_commit;
-			for (; !$top_commit && $top >= $bottom; --$top) {
-				$top_commit =
-					$gs->rev_map_get($top, $self->ra_uuid);
-			}
-
-			unless ($top_commit and $bottom_commit) {
-				warn "W:unknown path/rev in svn:mergeinfo "
-					."dirprop: $source:$range\n";
-				next;
-			}
-
-			push @merged_commit_ranges,
-				"$bottom_commit..$top_commit";
-
-			if ( !defined $tip or $top > $tip ) {
-				$tip = $top;
-				$tip_commit = $top_commit;
-			}
-		}
+		my ($tip_commit, @ranges) =
+			lookup_svn_merge( $uuid, $url, $merge );
+		push @merged_commit_ranges, @ranges;
 		unless (!$tip_commit or
 				grep { $_ eq $tip_commit } @$parents ) {
 			push @merge_tips, $tip_commit;
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH 5/5] git-svn: detect cherry-picks correctly.
From: Sam Vilain @ 2009-12-19 16:33 UTC (permalink / raw)
  To: git; +Cc: Eric Wong, Andrew Myrick, Sam Vilain
In-Reply-To: <1261240435-8948-5-git-send-email-sam@vilain.net>

The old function was incorrect; in some instances it marks a cherry picked
range as a merged branch (because of an incorrect assumption that
'rev-list COMMIT --not RANGE' would work).  This is replaced with a
function which should detect them correctly, memoized to limit the expense
of dealing with branches with many cherry picks to one 'merge-base' call
per merge, per branch which used cherry picking.

Signed-off-by: Sam Vilain <sam@vilain.net>
---
 git-svn.perl             |   87 +++++++++++++++++++++++++++++++++------------
 t/t9151-svn-mergeinfo.sh |    4 +-
 2 files changed, 66 insertions(+), 25 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index 7a790d7..f06e535 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -3007,8 +3007,35 @@ sub lookup_svn_merge {
 	}
 	return ($tip_commit, @merged_commit_ranges);
 }
+
+sub _rev_list {
+	my ($msg_fh, $ctx) = command_output_pipe(
+		"rev-list", @_,
+	       );
+	my @rv;
+	while ( <$msg_fh> ) {
+		chomp;
+		push @rv, $_;
+	}
+	command_close_pipe($msg_fh, $ctx);
+	@rv;
+}
+
+sub check_cherry_pick {
+	my $base = shift;
+	my $tip = shift;
+	my @ranges = @_;
+	my %commits = map { $_ => 1 }
+		_rev_list("--no-merges", $tip, "--not", $base);
+	for my $range ( @ranges ) {
+		delete @commits{_rev_list($range)};
+	}
+	return (keys %commits);
+}
+
 BEGIN {
 	memoize 'lookup_svn_merge';
+	memoize 'check_cherry_pick';
 }
 
 sub parents_exclude {
@@ -3084,32 +3111,46 @@ sub find_extra_svn_parents {
 
 		my $ranges = $ranges{$merge_tip};
 
-		my @cmd = ('rev-list', "-1", $merge_tip,
-			   "--not", @$parents );
-		my ($msg_fh, $ctx) = command_output_pipe(@cmd);
-		my $new;
-		while ( <$msg_fh> ) {
-			$new=1;last;
-		}
-		command_close_pipe($msg_fh, $ctx);
-		if ( $new ) {
-			push @cmd, @$ranges;
-			my ($msg_fh, $ctx) = command_output_pipe(@cmd);
-			my $unmerged;
-			while ( <$msg_fh> ) {
-				$unmerged=1;last;
-			}
-			command_close_pipe($msg_fh, $ctx);
-			if ( $unmerged ) {
-				warn "W:svn cherry-pick ignored ($spec)\n";
-			} else {
-				warn
-				  "Found merge parent (svn:mergeinfo prop): ",
-				  $merge_tip, "\n";
-				push @$parents, $merge_tip;
+		# check out 'new' tips
+		my $merge_base = command_oneline(
+			"merge-base",
+			@$parents, $merge_tip,
+		       );
+
+		# double check that there are no missing non-merge commits
+		my (@incomplete) = check_cherry_pick(
+			$merge_base, $merge_tip,
+			@$ranges,
+		       );
+
+		if ( @incomplete ) {
+			warn "W:svn cherry-pick ignored ($spec) - missing "
+				.@incomplete." commit(s) (eg $incomplete[0])\n";
+		} else {
+			warn
+				"Found merge parent (svn:mergeinfo prop): ",
+					$merge_tip, "\n";
+			push @new_parents, $merge_tip;
+		}
+	}
+
+	# cater for merges which merge commits from multiple branches
+	if ( @new_parents > 1 ) {
+		for ( my $i = 0; $i <= $#new_parents; $i++ ) {
+			for ( my $j = 0; $j <= $#new_parents; $j++ ) {
+				next if $i == $j;
+				next unless $new_parents[$i];
+				next unless $new_parents[$j];
+				my $revs = command_oneline(
+					"rev-list", "-1", "$i..$j",
+				       );
+				if ( !$revs ) {
+					undef($new_parents[$i]);
+				}
 			}
 		}
 	}
+	push @$parents, grep { defined } @new_parents;
 }
 
 sub make_log_entry {
diff --git a/t/t9151-svn-mergeinfo.sh b/t/t9151-svn-mergeinfo.sh
index f6e00ea..359eeaa 100755
--- a/t/t9151-svn-mergeinfo.sh
+++ b/t/t9151-svn-mergeinfo.sh
@@ -15,13 +15,13 @@ test_expect_success 'load svn dump' "
 	git svn fetch --all
 	"
 
-test_expect_failure 'all svn merges became git merge commits' '
+test_expect_success 'all svn merges became git merge commits' '
 	unmarked=$(git rev-list --parents --all --grep=Merge |
 		grep -v " .* " | cut -f1 -d" ")
 	[ -z "$unmarked" ]
 	'
 
-test_expect_failure 'cherry picks did not become git merge commits' '
+test_expect_success 'cherry picks did not become git merge commits' '
 	bad_cherries=$(git rev-list --parents --all --grep=Cherry |
 		grep " .* " | cut -f1 -d" ")
 	[ -z "$bad_cherries" ]
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH 1/5] git-svn: expand the svn mergeinfo test suite, highlighting some failures
From: Sam Vilain @ 2009-12-19 16:33 UTC (permalink / raw)
  To: git; +Cc: Eric Wong, Andrew Myrick, Sam Vilain
In-Reply-To: <1261240435-8948-1-git-send-email-sam@vilain.net>

As shown, git-svn has some problems; not all svn merges are correctly
detected, and cherry picks may incorrectly be detected as real merges.
These test cases will be marked as _success once the relevant fixes are in.

Signed-off-by: Sam Vilain <sam@vilain.net>
---
 t/t9151-svn-mergeinfo.sh   |   27 ++-
 t/t9151/make-svnmerge-dump |  166 ++++++---
 t/t9151/svn-mergeinfo.dump |  839 ++++++++++++++++++++++++++++++++++++++------
 3 files changed, 860 insertions(+), 172 deletions(-)

diff --git a/t/t9151-svn-mergeinfo.sh b/t/t9151-svn-mergeinfo.sh
index f57daf4..dc3478f 100755
--- a/t/t9151-svn-mergeinfo.sh
+++ b/t/t9151-svn-mergeinfo.sh
@@ -15,12 +15,27 @@ test_expect_success 'load svn dump' "
 	git svn fetch --all
 	"
 
-test_expect_success 'represent svn merges without intervening commits' "
-	[ `git cat-file commit HEAD^1 | grep parent | wc -l` -eq 2 ]
-	"
+test_expect_failure 'all svn merges became git merge commits' '
+	unmarked=$(git rev-list --parents --all --grep=Merge |
+		grep -v " .* " | cut -f1 -d" ")
+	[ -z "$unmarked" ]
+	'
 
-test_expect_success 'represent svn merges with intervening commits' "
-	[ `git cat-file commit HEAD | grep parent | wc -l` -eq 2 ]
-	"
+test_expect_failure 'cherry picks did not become git merge commits' '
+	bad_cherries=$(git rev-list --parents --all --grep=Cherry |
+		grep " .* " | cut -f1 -d" ")
+	[ -z "$bad_cherries" ]
+	'
+
+test_expect_success 'svn non-merge merge commits did not become git merge commits' '
+	bad_non_merges=$(git rev-list --parents --all --grep=non-merge |
+		grep " .* " | cut -f1 -d" ")
+	[ -z "$bad_non_merges" ]
+	'
+
+test_expect_failure 'everything got merged in the end' '
+	unmerged=$(git rev-list --all --not master)
+	[ -z "$unmerged" ]
+	'
 
 test_done
diff --git a/t/t9151/make-svnmerge-dump b/t/t9151/make-svnmerge-dump
index 7e3da75..d917717 100644
--- a/t/t9151/make-svnmerge-dump
+++ b/t/t9151/make-svnmerge-dump
@@ -11,93 +11,151 @@ mkdir foo.svn
 svnadmin create foo.svn
 svn co file://`pwd`/foo.svn foo
 
+commit() {
+    i=$(( $1 + 1 ))
+    shift;
+    svn commit -m "(r$i) $*" >/dev/null || exit 1
+    echo $i
+}
+
+say() {
+    echo "^[[1m * $*^[[0m"
+}
+
+i=0
 cd foo
 mkdir trunk
 mkdir branches
 svn add trunk branches
-svn commit -m "Setup trunk and branches"
-cd trunk
+i=$(commit $i "Setup trunk and branches")
 
-git cat-file blob 6683463e:Makefile > Makefile
-svn add Makefile 
+git cat-file blob 6683463e:Makefile > trunk/Makefile
+svn add trunk/Makefile 
 
-echo "Committing ANCESTOR"
-svn commit -m "ancestor"
-cd ..
+say "Committing ANCESTOR"
+i=$(commit $i "ancestor")
 svn cp trunk branches/left
 
-echo "Committing BRANCH POINT"
-svn commit -m "make left branch"
+say "Committing BRANCH POINT"
+i=$(commit $i "make left branch")
 svn cp trunk branches/right
 
-echo "Committing other BRANCH POINT"
-svn commit -m "make right branch"
-cd branches/left/
+say "Committing other BRANCH POINT"
+i=$(commit $i "make right branch")
 
-#$sm init
-#svn commit -m "init svnmerge"
+say "Committing LEFT UPDATE"
+git cat-file blob 5873b67e:Makefile > branches/left/Makefile
+i=$(commit $i "left update 1")
 
-git cat-file blob 5873b67e:Makefile > Makefile
-echo "Committing BRANCH UPDATE 1"
-svn commit -m "left update 1"
-cd ../..
-
-cd trunk
-git cat-file blob 75118b13:Makefile > Makefile
-echo "Committing TRUNK UPDATE"
-svn commit -m "trunk update"
+git cat-file blob 75118b13:Makefile > branches/right/Makefile
+say "Committing RIGHT UPDATE"
+pre_right_update_1=$i
+i=$(commit $i "right update 1")
 
-cd ../branches/left
-git cat-file blob ff5ebe39:Makefile > Makefile
-echo "Committing BRANCH UPDATE 2"
-svn commit -m "left update 2"
+say "Making more commits on LEFT"
+git cat-file blob ff5ebe39:Makefile > branches/left/Makefile
+i=$(commit $i "left update 2")
+git cat-file blob b5039db6:Makefile > branches/left/Makefile
+i=$(commit $i "left update 3")
 
-git cat-file blob b5039db6:Makefile > Makefile
-echo "Committing BRANCH UPDATE 3"
-svn commit -m "left update 3"
+say "Making a LEFT SUB-BRANCH"
+svn cp branches/left branches/left-sub
+sub_left_make=$i
+i=$(commit $i "make left sub-branch")
 
-# merge to trunk
+say "Making a commit on LEFT SUB-BRANCH"
+echo "crunch" > branches/left-sub/README
+svn add branches/left-sub/README
+i=$(commit $i "left sub-branch update 1")
 
-cd ../..
+say "Merging LEFT to TRUNK"
 svn update
 cd trunk
-
 svn merge ../branches/left --accept postpone
-
-git cat-file blob b51ad431:Makefile > Makefile
-
+git cat-file blob b5039db6:Makefile > Makefile
 svn resolved Makefile
+i=$(commit $i "Merge left to trunk 1")
+cd ..
 
-svn commit -m "Merge trunk 1"
-
-# create commits on both branches
-
-cd ../branches/left
-git cat-file blob ff5ebe39:Makefile > Makefile
-echo "Committing BRANCH UPDATE 4"
-svn commit -m "left update 4"
-
-cd ../right
-git cat-file blob b5039db6:Makefile > Makefile
-echo "Committing other BRANCH UPDATE 1"
-svn commit -m "right update 1"
+say "Making more commits on LEFT and RIGHT"
+echo "touche" > branches/left/zlonk
+svn add branches/left/zlonk
+i=$(commit $i "left update 4")
+echo "thwacke" > branches/right/bang
+svn add branches/right/bang
+i=$(commit $i "right update 2")
 
-# merge to trun again
+say "Squash merge of RIGHT tip 2 commits onto TRUNK"
+svn update
+cd trunk
+svn merge -r$pre_right_update_1:$i ../branches/right
+i=$(commit $i "Cherry-pick right 2 commits to trunk")
+cd ..
 
-cd ../..
+say "Merging RIGHT to TRUNK"
 svn update
 cd trunk
+svn merge ../branches/right --accept postpone
+git cat-file blob b51ad431:Makefile > Makefile
+svn resolved Makefile
+i=$(commit $i "Merge right to trunk 1")
+cd ..
 
-svn merge ../branches/left --accept postpone
+say "Making more commits on RIGHT and TRUNK"
+echo "whamm" > branches/right/urkkk
+svn add branches/right/urkkk
+i=$(commit $i "right update 3")
+echo "pow" > trunk/vronk
+svn add trunk/vronk
+i=$(commit $i "trunk update 1")
 
+say "Merging RIGHT to LEFT SUB-BRANCH"
+svn update
+cd branches/left-sub
+svn merge ../right --accept postpone
 git cat-file blob b51ad431:Makefile > Makefile
-
 svn resolved Makefile
+i=$(commit $i "Merge right to left sub-branch")
+cd ../..
 
-svn commit -m "Merge trunk 2"
+say "Making more commits on LEFT SUB-BRANCH and LEFT"
+echo "zowie" > branches/left-sub/wham_eth
+svn add branches/left-sub/wham_eth
+pre_sub_left_update_2=$i
+i=$(commit $i "left sub-branch update 2")
+sub_left_update_2=$i
+echo "eee_yow" > branches/left/glurpp
+svn add branches/left/glurpp
+i=$(commit $i "left update 5")
+
+say "Cherry pick LEFT SUB-BRANCH commit to LEFT"
+svn update
+cd branches/left
+svn merge -r$pre_sub_left_update_2:$sub_left_update_2 ../left-sub
+i=$(commit $i "Cherry-pick left sub-branch commit to left")
+cd ../..
 
+say "Merging LEFT SUB-BRANCH back to LEFT"
+svn update
+cd branches/left
+# it's only a merge because the previous merge cherry-picked the top commit
+svn merge -r$sub_left_make:$sub_left_update_2 ../left-sub --accept postpone
+i=$(commit $i "Merge left sub-branch to left")
 cd ../..
 
+say "Merging EVERYTHING to TRUNK"
+svn update
+cd trunk
+svn merge ../branches/left --accept postpone
+svn resolved bang
+i=$(commit $i "Merge left to trunk 2")
+# this merge, svn happily updates the mergeinfo, but there is actually
+# nothing to merge.  git-svn will not make a meaningless merge commit.
+svn merge ../branches/right --accept postpone
+i=$(commit $i "non-merge right to trunk 2")
+cd ..
+
+cd ..
 svnadmin dump foo.svn > svn-mergeinfo.dump
 
 rm -rf foo foo.svn
diff --git a/t/t9151/svn-mergeinfo.dump b/t/t9151/svn-mergeinfo.dump
index 11a883f..9543e31 100644
--- a/t/t9151/svn-mergeinfo.dump
+++ b/t/t9151/svn-mergeinfo.dump
@@ -1,6 +1,6 @@
 SVN-fs-dump-format-version: 2
 
-UUID: 1530d5a2-a1dc-4438-8ad5-d95e96db8945
+UUID: 64142547-0943-4db2-836a-d1e1eb2f9924
 
 Revision-number: 0
 Prop-content-length: 56
@@ -9,25 +9,25 @@ Content-length: 56
 K 8
 svn:date
 V 27
-2009-11-12T20:29:38.812226Z
+2009-12-19T16:17:51.232640Z
 PROPS-END
 
 Revision-number: 1
-Prop-content-length: 127
-Content-length: 127
+Prop-content-length: 128
+Content-length: 128
 
 K 7
 svn:log
-V 24
-Setup trunk and branches
+V 29
+(r1) Setup trunk and branches
 K 10
 svn:author
-V 8
-tallsopp
+V 4
+samv
 K 8
 svn:date
 V 27
-2009-11-12T20:29:39.045856Z
+2009-12-19T16:17:51.831965Z
 PROPS-END
 
 Node-path: branches
@@ -49,21 +49,21 @@ PROPS-END
 
 
 Revision-number: 2
-Prop-content-length: 110
-Content-length: 110
+Prop-content-length: 112
+Content-length: 112
 
 K 7
 svn:log
-V 8
-ancestor
+V 13
+(r2) ancestor
 K 10
 svn:author
-V 8
-tallsopp
+V 4
+samv
 K 8
 svn:date
 V 27
-2009-11-12T20:29:40.079587Z
+2009-12-19T16:17:52.300075Z
 PROPS-END
 
 Node-path: trunk/Makefile
@@ -156,21 +156,21 @@ backup: clean
 
 
 Revision-number: 3
-Prop-content-length: 119
-Content-length: 119
+Prop-content-length: 120
+Content-length: 120
 
 K 7
 svn:log
-V 16
-make left branch
+V 21
+(r3) make left branch
 K 10
 svn:author
-V 8
-tallsopp
+V 4
+samv
 K 8
 svn:date
 V 27
-2009-11-12T20:29:42.084439Z
+2009-12-19T16:17:52.768800Z
 PROPS-END
 
 Node-path: branches/left
@@ -190,21 +190,21 @@ Text-copy-source-sha1: 103205ce331f7d64086dba497574734f78439590
 
 
 Revision-number: 4
-Prop-content-length: 120
-Content-length: 120
+Prop-content-length: 121
+Content-length: 121
 
 K 7
 svn:log
-V 17
-make right branch
+V 22
+(r4) make right branch
 K 10
 svn:author
-V 8
-tallsopp
+V 4
+samv
 K 8
 svn:date
 V 27
-2009-11-12T20:29:44.065452Z
+2009-12-19T16:17:53.177879Z
 PROPS-END
 
 Node-path: branches/right
@@ -224,21 +224,21 @@ Text-copy-source-sha1: 103205ce331f7d64086dba497574734f78439590
 
 
 Revision-number: 5
-Prop-content-length: 116
-Content-length: 116
+Prop-content-length: 117
+Content-length: 117
 
 K 7
 svn:log
-V 13
-left update 1
+V 18
+(r5) left update 1
 K 10
 svn:author
-V 8
-tallsopp
+V 4
+samv
 K 8
 svn:date
 V 27
-2009-11-12T20:29:45.066262Z
+2009-12-19T16:17:53.604691Z
 PROPS-END
 
 Node-path: branches/left/Makefile
@@ -329,24 +329,24 @@ backup: clean
 
 
 Revision-number: 6
-Prop-content-length: 115
-Content-length: 115
+Prop-content-length: 118
+Content-length: 118
 
 K 7
 svn:log
-V 12
-trunk update
+V 19
+(r6) right update 1
 K 10
 svn:author
-V 8
-tallsopp
+V 4
+samv
 K 8
 svn:date
 V 27
-2009-11-12T20:29:46.278498Z
+2009-12-19T16:17:54.063555Z
 PROPS-END
 
-Node-path: trunk/Makefile
+Node-path: branches/right/Makefile
 Node-kind: file
 Node-action: change
 Text-content-length: 2521
@@ -437,21 +437,21 @@ backup: clean
 
 
 Revision-number: 7
-Prop-content-length: 116
-Content-length: 116
+Prop-content-length: 117
+Content-length: 117
 
 K 7
 svn:log
-V 13
-left update 2
+V 18
+(r7) left update 2
 K 10
 svn:author
-V 8
-tallsopp
+V 4
+samv
 K 8
 svn:date
 V 27
-2009-11-12T20:29:47.069090Z
+2009-12-19T16:17:54.523904Z
 PROPS-END
 
 Node-path: branches/left/Makefile
@@ -542,21 +542,21 @@ backup: clean
 
 
 Revision-number: 8
-Prop-content-length: 116
-Content-length: 116
+Prop-content-length: 117
+Content-length: 117
 
 K 7
 svn:log
-V 13
-left update 3
+V 18
+(r8) left update 3
 K 10
 svn:author
-V 8
-tallsopp
+V 4
+samv
 K 8
 svn:date
 V 27
-2009-11-12T20:29:48.053835Z
+2009-12-19T16:17:54.975970Z
 PROPS-END
 
 Node-path: branches/left/Makefile
@@ -647,33 +647,285 @@ backup: clean
 
 
 Revision-number: 9
-Prop-content-length: 116
-Content-length: 116
+Prop-content-length: 124
+Content-length: 124
 
 K 7
 svn:log
-V 13
-Merge trunk 1
+V 25
+(r9) make left sub-branch
+K 10
+svn:author
+V 4
+samv
+K 8
+svn:date
+V 27
+2009-12-19T16:17:55.459904Z
+PROPS-END
+
+Node-path: branches/left-sub
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 3
+Node-copyfrom-path: branches/left
+
+
+Node-path: branches/left-sub/Makefile
+Node-kind: file
+Node-action: delete
+
+Node-path: branches/left-sub/Makefile
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 8
+Node-copyfrom-path: branches/left/Makefile
+Text-copy-source-md5: 5ccff689fb290e00b85fe18ee50c54ba
+Text-copy-source-sha1: a13de8e23f1483efca3e57b2b64b0ae6f740ce10
+
+
+
+
+Revision-number: 10
+Prop-content-length: 129
+Content-length: 129
+
+K 7
+svn:log
+V 30
+(r10) left sub-branch update 1
 K 10
 svn:author
-V 8
-tallsopp
+V 4
+samv
 K 8
 svn:date
 V 27
-2009-11-12T20:29:51.098306Z
+2009-12-19T16:17:55.862113Z
+PROPS-END
+
+Node-path: branches/left-sub/README
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 7
+Text-content-md5: fdbcfb6be9afe1121862143f226b51cf
+Text-content-sha1: 1d1f5ea4ceb584337ffe59b8980d92e3b78dfef4
+Content-length: 17
+
+PROPS-END
+crunch
+
+
+Revision-number: 11
+Prop-content-length: 126
+Content-length: 126
+
+K 7
+svn:log
+V 27
+(r11) Merge left to trunk 1
+K 10
+svn:author
+V 4
+samv
+K 8
+svn:date
+V 27
+2009-12-19T16:17:56.413416Z
 PROPS-END
 
 Node-path: trunk
 Node-kind: dir
 Node-action: change
-Prop-content-length: 53
-Content-length: 53
+Prop-content-length: 54
+Content-length: 54
 
 K 13
 svn:mergeinfo
-V 18
-/branches/left:2-8
+V 19
+/branches/left:2-10
+PROPS-END
+
+
+Node-path: trunk/Makefile
+Node-kind: file
+Node-action: change
+Text-content-length: 2593
+Text-content-md5: 5ccff689fb290e00b85fe18ee50c54ba
+Text-content-sha1: a13de8e23f1483efca3e57b2b64b0ae6f740ce10
+Content-length: 2593
+
+# -DCOLLISION_CHECK if you believe that SHA1's
+# 1461501637330902918203684832716283019655932542976 hashes do not give you
+# enough guarantees about no collisions between objects ever hapenning.
+#
+# -DNSEC if you want git to care about sub-second file mtimes and ctimes.
+# Note that you need some new glibc (at least >2.2.4) for this, and it will
+# BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely randomly
+# break unless your underlying filesystem supports those sub-second times
+# (my ext3 doesn't).
+CFLAGS=-g -O3 -Wall
+
+CC=gcc
+
+
+PROG=   update-cache show-diff init-db write-tree read-tree commit-tree \
+	cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \
+	check-files ls-tree merge-base
+
+all: $(PROG)
+
+install: $(PROG)
+	install $(PROG) $(HOME)/bin/
+
+LIBS= -lssl -lz
+
+init-db: init-db.o
+
+update-cache: update-cache.o read-cache.o
+	$(CC) $(CFLAGS) -o update-cache update-cache.o read-cache.o $(LIBS)
+
+show-diff: show-diff.o read-cache.o
+	$(CC) $(CFLAGS) -o show-diff show-diff.o read-cache.o $(LIBS)
+
+write-tree: write-tree.o read-cache.o
+	$(CC) $(CFLAGS) -o write-tree write-tree.o read-cache.o $(LIBS)
+
+read-tree: read-tree.o read-cache.o
+	$(CC) $(CFLAGS) -o read-tree read-tree.o read-cache.o $(LIBS)
+
+commit-tree: commit-tree.o read-cache.o
+	$(CC) $(CFLAGS) -o commit-tree commit-tree.o read-cache.o $(LIBS)
+
+cat-file: cat-file.o read-cache.o
+	$(CC) $(CFLAGS) -o cat-file cat-file.o read-cache.o $(LIBS)
+
+fsck-cache: fsck-cache.o read-cache.o object.o commit.o tree.o blob.o
+	$(CC) $(CFLAGS) -o fsck-cache fsck-cache.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
+
+checkout-cache: checkout-cache.o read-cache.o
+	$(CC) $(CFLAGS) -o checkout-cache checkout-cache.o read-cache.o $(LIBS)
+
+diff-tree: diff-tree.o read-cache.o
+	$(CC) $(CFLAGS) -o diff-tree diff-tree.o read-cache.o $(LIBS)
+
+rev-tree: rev-tree.o read-cache.o object.o commit.o tree.o blob.o
+	$(CC) $(CFLAGS) -o rev-tree rev-tree.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
+
+show-files: show-files.o read-cache.o
+	$(CC) $(CFLAGS) -o show-files show-files.o read-cache.o $(LIBS)
+
+check-files: check-files.o read-cache.o
+	$(CC) $(CFLAGS) -o check-files check-files.o read-cache.o $(LIBS)
+
+ls-tree: ls-tree.o read-cache.o
+	$(CC) $(CFLAGS) -o ls-tree ls-tree.o read-cache.o $(LIBS)
+
+merge-base: merge-base.o read-cache.o object.o commit.o tree.o blob.o
+	$(CC) $(CFLAGS) -o merge-base merge-base.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
+
+read-cache.o: cache.h
+show-diff.o: cache.h
+
+clean:
+	rm -f *.o $(PROG)
+
+backup: clean
+	cd .. ; tar czvf dircache.tar.gz dir-cache
+
+
+Revision-number: 12
+Prop-content-length: 118
+Content-length: 118
+
+K 7
+svn:log
+V 19
+(r12) left update 4
+K 10
+svn:author
+V 4
+samv
+K 8
+svn:date
+V 27
+2009-12-19T16:17:56.831014Z
+PROPS-END
+
+Node-path: branches/left/zlonk
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 7
+Text-content-md5: 8b9d8c7c2aaa6167e7d3407a773bbbba
+Text-content-sha1: 9716527ebd70a75c27625cacbeb2d897c6e86178
+Content-length: 17
+
+PROPS-END
+touche
+
+
+Revision-number: 13
+Prop-content-length: 119
+Content-length: 119
+
+K 7
+svn:log
+V 20
+(r13) right update 2
+K 10
+svn:author
+V 4
+samv
+K 8
+svn:date
+V 27
+2009-12-19T16:17:57.341143Z
+PROPS-END
+
+Node-path: branches/right/bang
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 8
+Text-content-md5: 34c28f1d2dc6a9adeccc4265bf7516cb
+Text-content-sha1: 0bc5bb345c0e71d28f784f12e0bd2d384c283062
+Content-length: 18
+
+PROPS-END
+thwacke
+
+
+Revision-number: 14
+Prop-content-length: 141
+Content-length: 141
+
+K 7
+svn:log
+V 42
+(r14) Cherry-pick right 2 commits to trunk
+K 10
+svn:author
+V 4
+samv
+K 8
+svn:date
+V 27
+2009-12-19T16:17:57.841851Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 75
+Content-length: 75
+
+K 13
+svn:mergeinfo
+V 40
+/branches/left:2-10
+/branches/right:6-13
 PROPS-END
 
 
@@ -767,31 +1019,147 @@ backup: clean
 	cd .. ; tar czvf dircache.tar.gz dir-cache
 
 
-Revision-number: 10
-Prop-content-length: 116
-Content-length: 116
+Node-path: trunk/bang
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 13
+Node-copyfrom-path: branches/right/bang
+Text-copy-source-md5: 34c28f1d2dc6a9adeccc4265bf7516cb
+Text-copy-source-sha1: 0bc5bb345c0e71d28f784f12e0bd2d384c283062
+
+
+Revision-number: 15
+Prop-content-length: 127
+Content-length: 127
 
 K 7
 svn:log
-V 13
-left update 4
+V 28
+(r15) Merge right to trunk 1
 K 10
 svn:author
-V 8
-tallsopp
+V 4
+samv
 K 8
 svn:date
 V 27
-2009-11-12T20:29:52.081644Z
+2009-12-19T16:17:58.368520Z
 PROPS-END
 
-Node-path: branches/left/Makefile
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 75
+Content-length: 75
+
+K 13
+svn:mergeinfo
+V 40
+/branches/left:2-10
+/branches/right:2-14
+PROPS-END
+
+
+Revision-number: 16
+Prop-content-length: 119
+Content-length: 119
+
+K 7
+svn:log
+V 20
+(r16) right update 3
+K 10
+svn:author
+V 4
+samv
+K 8
+svn:date
+V 27
+2009-12-19T16:17:58.779056Z
+PROPS-END
+
+Node-path: branches/right/urkkk
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 6
+Text-content-md5: 5889c8392e16251b0c80927607a03036
+Text-content-sha1: 3934264d277a0cf886b6b1c7f2b9e56da2525302
+Content-length: 16
+
+PROPS-END
+whamm
+
+
+Revision-number: 17
+Prop-content-length: 119
+Content-length: 119
+
+K 7
+svn:log
+V 20
+(r17) trunk update 1
+K 10
+svn:author
+V 4
+samv
+K 8
+svn:date
+V 27
+2009-12-19T16:17:59.221851Z
+PROPS-END
+
+Node-path: trunk/vronk
 Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 4
+Text-content-md5: b2f80fa02a7f1364b9c29d3da44bf9f9
+Text-content-sha1: e994d980c0f2d7a3f76138bf96d57f36f9633828
+Content-length: 14
+
+PROPS-END
+pow
+
+
+Revision-number: 18
+Prop-content-length: 135
+Content-length: 135
+
+K 7
+svn:log
+V 36
+(r18) Merge right to left sub-branch
+K 10
+svn:author
+V 4
+samv
+K 8
+svn:date
+V 27
+2009-12-19T16:17:59.781666Z
+PROPS-END
+
+Node-path: branches/left-sub
+Node-kind: dir
 Node-action: change
-Text-content-length: 2529
-Text-content-md5: f6b197cc3f2e89a83e545d4bb003de73
-Text-content-sha1: 2f656677cfec0bceec85e53036ffb63e25126f8e
-Content-length: 2529
+Prop-content-length: 55
+Content-length: 55
+
+K 13
+svn:mergeinfo
+V 20
+/branches/right:2-17
+PROPS-END
+
+
+Node-path: branches/left-sub/Makefile
+Node-kind: file
+Node-action: change
+Text-content-length: 2713
+Text-content-md5: 0afbe34f244cd662b1f97d708c687f90
+Text-content-sha1: 46d9377d783e67a9b581da110352e799517c8a14
+Content-length: 2713
 
 # -DCOLLISION_CHECK if you believe that SHA1's
 # 1461501637330902918203684832716283019655932542976 hashes do not give you
@@ -809,7 +1177,7 @@ CC=gcc
 
 PROG=   update-cache show-diff init-db write-tree read-tree commit-tree \
 	cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \
-	check-files ls-tree merge-base
+	check-files ls-tree merge-base merge-cache
 
 all: $(PROG)
 
@@ -859,8 +1227,11 @@ check-files: check-files.o read-cache.o
 ls-tree: ls-tree.o read-cache.o
 	$(CC) $(CFLAGS) -o ls-tree ls-tree.o read-cache.o $(LIBS)
 
-merge-base: merge-base.o read-cache.o
-	$(CC) $(CFLAGS) -o merge-base merge-base.o read-cache.o $(LIBS)
+merge-base: merge-base.o read-cache.o object.o commit.o tree.o blob.o
+	$(CC) $(CFLAGS) -o merge-base merge-base.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
+
+merge-cache: merge-cache.o read-cache.o
+	$(CC) $(CFLAGS) -o merge-cache merge-cache.o read-cache.o $(LIBS)
 
 read-cache.o: cache.h
 show-diff.o: cache.h
@@ -872,31 +1243,165 @@ backup: clean
 	cd .. ; tar czvf dircache.tar.gz dir-cache
 
 
-Revision-number: 11
-Prop-content-length: 117
-Content-length: 117
+Node-path: branches/left-sub/bang
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 17
+Node-copyfrom-path: branches/right/bang
+Text-copy-source-md5: 34c28f1d2dc6a9adeccc4265bf7516cb
+Text-copy-source-sha1: 0bc5bb345c0e71d28f784f12e0bd2d384c283062
+
+
+Node-path: branches/left-sub/urkkk
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 17
+Node-copyfrom-path: branches/right/urkkk
+Text-copy-source-md5: 5889c8392e16251b0c80927607a03036
+Text-copy-source-sha1: 3934264d277a0cf886b6b1c7f2b9e56da2525302
+
+
+Revision-number: 19
+Prop-content-length: 129
+Content-length: 129
 
 K 7
 svn:log
-V 14
-right update 1
+V 30
+(r19) left sub-branch update 2
 K 10
 svn:author
-V 8
-tallsopp
+V 4
+samv
 K 8
 svn:date
 V 27
-2009-11-12T20:29:53.059636Z
+2009-12-19T16:18:00.200531Z
 PROPS-END
 
-Node-path: branches/right/Makefile
+Node-path: branches/left-sub/wham_eth
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 6
+Text-content-md5: 757bcd5818572ef3f9580052617c1c8b
+Text-content-sha1: b165019b005c199237ba822c4404e771e93b654a
+Content-length: 16
+
+PROPS-END
+zowie
+
+
+Revision-number: 20
+Prop-content-length: 118
+Content-length: 118
+
+K 7
+svn:log
+V 19
+(r20) left update 5
+K 10
+svn:author
+V 4
+samv
+K 8
+svn:date
+V 27
+2009-12-19T16:18:00.659636Z
+PROPS-END
+
+Node-path: branches/left/glurpp
 Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 8
+Text-content-md5: 14a169f628e0bb59df9c2160649d0a30
+Text-content-sha1: ef7d929e52177767ecfcd28941f6b7f04b4131e3
+Content-length: 18
+
+PROPS-END
+eee_yow
+
+
+Revision-number: 21
+Prop-content-length: 147
+Content-length: 147
+
+K 7
+svn:log
+V 48
+(r21) Cherry-pick left sub-branch commit to left
+K 10
+svn:author
+V 4
+samv
+K 8
+svn:date
+V 27
+2009-12-19T16:18:01.194402Z
+PROPS-END
+
+Node-path: branches/left
+Node-kind: dir
 Node-action: change
-Text-content-length: 2593
-Text-content-md5: 5ccff689fb290e00b85fe18ee50c54ba
-Text-content-sha1: a13de8e23f1483efca3e57b2b64b0ae6f740ce10
-Content-length: 2593
+Prop-content-length: 56
+Content-length: 56
+
+K 13
+svn:mergeinfo
+V 21
+/branches/left-sub:19
+PROPS-END
+
+
+Node-path: branches/left/wham_eth
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 19
+Node-copyfrom-path: branches/left-sub/wham_eth
+Text-copy-source-md5: 757bcd5818572ef3f9580052617c1c8b
+Text-copy-source-sha1: b165019b005c199237ba822c4404e771e93b654a
+
+
+Revision-number: 22
+Prop-content-length: 134
+Content-length: 134
+
+K 7
+svn:log
+V 35
+(r22) Merge left sub-branch to left
+K 10
+svn:author
+V 4
+samv
+K 8
+svn:date
+V 27
+2009-12-19T16:18:01.679218Z
+PROPS-END
+
+Node-path: branches/left
+Node-kind: dir
+Node-action: change
+Prop-content-length: 79
+Content-length: 79
+
+K 13
+svn:mergeinfo
+V 44
+/branches/left-sub:4-19
+/branches/right:2-17
+PROPS-END
+
+
+Node-path: branches/left/Makefile
+Node-kind: file
+Node-action: change
+Text-content-length: 2713
+Text-content-md5: 0afbe34f244cd662b1f97d708c687f90
+Text-content-sha1: 46d9377d783e67a9b581da110352e799517c8a14
+Content-length: 2713
 
 # -DCOLLISION_CHECK if you believe that SHA1's
 # 1461501637330902918203684832716283019655932542976 hashes do not give you
@@ -914,7 +1419,7 @@ CC=gcc
 
 PROG=   update-cache show-diff init-db write-tree read-tree commit-tree \
 	cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \
-	check-files ls-tree merge-base
+	check-files ls-tree merge-base merge-cache
 
 all: $(PROG)
 
@@ -967,6 +1472,9 @@ ls-tree: ls-tree.o read-cache.o
 merge-base: merge-base.o read-cache.o object.o commit.o tree.o blob.o
 	$(CC) $(CFLAGS) -o merge-base merge-base.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
 
+merge-cache: merge-cache.o read-cache.o
+	$(CC) $(CFLAGS) -o merge-cache merge-cache.o read-cache.o $(LIBS)
+
 read-cache.o: cache.h
 show-diff.o: cache.h
 
@@ -977,34 +1485,141 @@ backup: clean
 	cd .. ; tar czvf dircache.tar.gz dir-cache
 
 
-Revision-number: 12
-Prop-content-length: 116
-Content-length: 116
+Node-path: branches/left/README
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 18
+Node-copyfrom-path: branches/left-sub/README
+Text-copy-source-md5: fdbcfb6be9afe1121862143f226b51cf
+Text-copy-source-sha1: 1d1f5ea4ceb584337ffe59b8980d92e3b78dfef4
+
+
+Node-path: branches/left/bang
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 18
+Node-copyfrom-path: branches/left-sub/bang
+Text-copy-source-md5: 34c28f1d2dc6a9adeccc4265bf7516cb
+Text-copy-source-sha1: 0bc5bb345c0e71d28f784f12e0bd2d384c283062
+
+
+Node-path: branches/left/urkkk
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 18
+Node-copyfrom-path: branches/left-sub/urkkk
+Text-copy-source-md5: 5889c8392e16251b0c80927607a03036
+Text-copy-source-sha1: 3934264d277a0cf886b6b1c7f2b9e56da2525302
+
+
+Revision-number: 23
+Prop-content-length: 126
+Content-length: 126
 
 K 7
 svn:log
-V 13
-Merge trunk 2
+V 27
+(r23) Merge left to trunk 2
 K 10
 svn:author
-V 8
-tallsopp
+V 4
+samv
 K 8
 svn:date
 V 27
-2009-11-12T20:29:56.083003Z
+2009-12-19T16:18:02.212349Z
 PROPS-END
 
 Node-path: trunk
 Node-kind: dir
 Node-action: change
-Prop-content-length: 54
-Content-length: 54
+Prop-content-length: 99
+Content-length: 99
 
 K 13
 svn:mergeinfo
-V 19
-/branches/left:2-11
+V 64
+/branches/left:2-22
+/branches/left-sub:4-19
+/branches/right:2-17
+PROPS-END
+
+
+Node-path: trunk/README
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 22
+Node-copyfrom-path: branches/left/README
+Text-copy-source-md5: fdbcfb6be9afe1121862143f226b51cf
+Text-copy-source-sha1: 1d1f5ea4ceb584337ffe59b8980d92e3b78dfef4
+
+
+Node-path: trunk/glurpp
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 22
+Node-copyfrom-path: branches/left/glurpp
+Text-copy-source-md5: 14a169f628e0bb59df9c2160649d0a30
+Text-copy-source-sha1: ef7d929e52177767ecfcd28941f6b7f04b4131e3
+
+
+Node-path: trunk/urkkk
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 22
+Node-copyfrom-path: branches/left/urkkk
+Text-copy-source-md5: 5889c8392e16251b0c80927607a03036
+Text-copy-source-sha1: 3934264d277a0cf886b6b1c7f2b9e56da2525302
+
+
+Node-path: trunk/wham_eth
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 22
+Node-copyfrom-path: branches/left/wham_eth
+Text-copy-source-md5: 757bcd5818572ef3f9580052617c1c8b
+Text-copy-source-sha1: b165019b005c199237ba822c4404e771e93b654a
+
+
+Node-path: trunk/zlonk
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 22
+Node-copyfrom-path: branches/left/zlonk
+Text-copy-source-md5: 8b9d8c7c2aaa6167e7d3407a773bbbba
+Text-copy-source-sha1: 9716527ebd70a75c27625cacbeb2d897c6e86178
+
+
+Revision-number: 24
+Prop-content-length: 131
+Content-length: 131
+
+K 7
+svn:log
+V 32
+(r24) non-merge right to trunk 2
+K 10
+svn:author
+V 4
+samv
+K 8
+svn:date
+V 27
+2009-12-19T16:18:02.672148Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 99
+Content-length: 99
+
+K 13
+svn:mergeinfo
+V 64
+/branches/left:2-22
+/branches/left-sub:4-19
+/branches/right:2-22
 PROPS-END
 
 
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH 3/5] git-svn: fix some mistakes with interpreting SVN mergeinfo commit ranges
From: Sam Vilain @ 2009-12-19 16:33 UTC (permalink / raw)
  To: git; +Cc: Eric Wong, Andrew Myrick, Sam Vilain
In-Reply-To: <1261240435-8948-3-git-send-email-sam@vilain.net>

SVN's list of commit ranges in mergeinfo tickets is inclusive, whereas
git commit ranges are exclusive on the left hand side.  Also, the end
points of the commit ranges may not exist; they simply delineate
ranges of commits which may or may not exist.  Fix these two mistakes.

Signed-off-by: Sam Vilain <sam@vilain.net>
---
 git-svn.perl             |   12 +++---------
 t/t9151-svn-mergeinfo.sh |    2 +-
 2 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index 3b17a83..9cf4a3e 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -2988,14 +2988,8 @@ sub lookup_svn_merge {
 	for my $range ( @ranges ) {
 		my ($bottom, $top) = split "-", $range;
 		$top ||= $bottom;
-		my $bottom_commit =
-			$gs->rev_map_get($bottom, $uuid) ||
-			$gs->rev_map_get($bottom+1, $uuid);
-		my $top_commit;
-		for (; !$top_commit && $top >= $bottom; --$top) {
-			$top_commit =
-				$gs->rev_map_get($top, $uuid);
-		}
+		my $bottom_commit = $gs->find_rev_after( $bottom, 1, $top );
+		my $top_commit = $gs->find_rev_before( $top, 1, $bottom );
 
 		unless ($top_commit and $bottom_commit) {
 			warn "W:unknown path/rev in svn:mergeinfo "
@@ -3004,7 +2998,7 @@ sub lookup_svn_merge {
 		}
 
 		push @merged_commit_ranges,
-			"$bottom_commit..$top_commit";
+			"$bottom_commit^..$top_commit";
 
 		if ( !defined $tip or $top > $tip ) {
 			$tip = $top;
diff --git a/t/t9151-svn-mergeinfo.sh b/t/t9151-svn-mergeinfo.sh
index dc3478f..f6e00ea 100755
--- a/t/t9151-svn-mergeinfo.sh
+++ b/t/t9151-svn-mergeinfo.sh
@@ -33,7 +33,7 @@ test_expect_success 'svn non-merge merge commits did not become git merge commit
 	[ -z "$bad_non_merges" ]
 	'
 
-test_expect_failure 'everything got merged in the end' '
+test_expect_success 'everything got merged in the end' '
 	unmerged=$(git rev-list --all --not master)
 	[ -z "$unmerged" ]
 	'
-- 
1.6.3.3

^ permalink raw reply related

* Efficiency and correctness patches for git-svn mergeinfo support
From: Sam Vilain @ 2009-12-19 16:33 UTC (permalink / raw)
  To: git; +Cc: Eric Wong, Andrew Myrick

This series implements some efficiency enhancements; particularly in
dealing with repositories which have a single trunk branch which
receives many merges of feature branches and/or cherry-picks.  It also
fixes a number of corner cases in the merge conversion code.

It would be nice if the people who have experienced slow git-svn
performance in these situations could test that this fixes the
performance issues, and that the resulting repositories seem to have
correct contents.

Eric, I'm using Alex's trick of a single commit which adds failing
tests - marked as _expect_failure - and then marked them as succeeding
as the series progresses.

^ permalink raw reply

* Re: [PATCH] Introduce the GIT_HOME environment variable
From: Michael J Gruber @ 2009-12-19 16:18 UTC (permalink / raw)
  To: Miklos Vajna; +Cc: Junio C Hamano, Moe, git
In-Reply-To: <20091219153046.GG25474@genesis.frugalware.org>

Miklos Vajna venit, vidit, dixit 19.12.2009 16:30:
> Honor $GIT_HOME that is favoured over $HOME, just like $GIT_EDITOR
> overrides $EDITOR.  That allows us to extend the notion more naturally
> in the future.  For example, when we start reading from
> $HOME/.gitconfig, if the GIT_HOME environment is set, we would instead
> read from $GIT_HOME/.gitconfig.
> 
> Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
> ---
> 
> On Fri, Dec 18, 2009 at 09:55:07PM -0800, Junio C Hamano <gitster@pobox.com> wrote:
>> A possible solution might be for us to honor $GIT_HOME that is favoured
>> over $HOME, just like $GIT_EDITOR overrides $EDITOR.  That allows us to
>> extend the notion more naturally in the future.  For example, when we
>> start reading from $HOME/.git-excludes, if the GIT_HOME environment is
>> set, we would instead read from $GIT_HOME/.git-excludes.  That would be a
>> much cleaner solution than Miklos's patch [*2*].
> 
> Something like this?
> 
> I've stolen most of the commit message from your mail. ;-)

Yes, but it makes less sense this way... Junio wrote "when we start
reading" because we don't do that yet. But we read ~/.gitconfig, of
course, so "when we start reading" sounds funny here.

> 
>  Documentation/config.txt |   14 ++++++++++----
>  builtin-config.c         |    8 ++++++--
>  config.c                 |    4 +++-
>  path.c                   |    4 +++-
>  t/t1300-repo-config.sh   |    7 +++++++
>  5 files changed, 29 insertions(+), 8 deletions(-)
> 
> diff --git a/Documentation/config.txt b/Documentation/config.txt
> index a1e36d7..09cbc71 100644
> --- a/Documentation/config.txt
> +++ b/Documentation/config.txt
> @@ -8,6 +8,10 @@ is used to store the configuration for that repository, and
>  fallback values for the `.git/config` file. The file `/etc/gitconfig`
>  can be used to store a system-wide default configuration.
>  
> +In case you want to store your per-user configuration in a directory
> +different to `$HOME`, you can use the `$GIT_HOME` environment variable

"different from"

> +which has preference.
> +
>  The configuration variables are used by both the git plumbing
>  and the porcelains. The variables are divided into sections, wherein
>  the fully qualified variable name of the variable itself is the last
> @@ -406,8 +410,9 @@ core.excludesfile::
>  	In addition to '.gitignore' (per-directory) and
>  	'.git/info/exclude', git looks into this file for patterns
>  	of files which are not meant to be tracked.  "{tilde}/" is expanded
> -	to the value of `$HOME` and "{tilde}user/" to the specified user's
> -	home directory.  See linkgit:gitignore[5].
> +	to the value of `$GIT_HOME` (or `$HOME` if `$GIT_HOME` is not
> +	set) and "{tilde}user/" to the specified user's home directory.  See
> +	linkgit:gitignore[5].
>  
>  core.editor::
>  	Commands such as `commit` and `tag` that lets you edit
> @@ -707,8 +712,9 @@ color.ui::
>  
>  commit.template::
>  	Specify a file to use as the template for new commit messages.
> -	"{tilde}/" is expanded to the value of `$HOME` and "{tilde}user/" to the
> -	specified user's home directory.
> +	"{tilde}/" is expanded to the value of `$GIT_HOME` (or `$HOME`
> +	if `$GIT_HOME` is not set) and "{tilde}user/" to the specified user's
> +	home directory.
>  
>  diff.autorefreshindex::
>  	When using 'git-diff' to compare with work tree
> diff --git a/builtin-config.c b/builtin-config.c
> index a2d656e..da9ebd4 100644
> --- a/builtin-config.c
> +++ b/builtin-config.c
> @@ -146,7 +146,9 @@ static int get_value(const char *key_, const char *regex_)
>  
>  	local = config_exclusive_filename;
>  	if (!local) {
> -		const char *home = getenv("HOME");
> +		const char *home = getenv("GIT_HOME");
> +		if (!home)
> +			home = getenv("HOME");
>  		local = repo_config = git_pathdup("config");
>  		if (git_config_global() && home)
>  			global = xstrdup(mkpath("%s/.gitconfig", home));
> @@ -326,7 +328,9 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix)
>  	}
>  
>  	if (use_global_config) {
> -		char *home = getenv("HOME");
> +		char *home = getenv("GIT_HOME");
> +		if (!home)
> +			home = getenv("HOME");
>  		if (home) {
>  			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
>  			config_exclusive_filename = user_config;
> diff --git a/config.c b/config.c
> index 37385ce..7e2ccdb 100644
> --- a/config.c
> +++ b/config.c
> @@ -711,7 +711,9 @@ int git_config(config_fn_t fn, void *data)
>  		found += 1;
>  	}
>  
> -	home = getenv("HOME");
> +	home = getenv("GIT_HOME");
> +	if (!home)
> +		home = getenv("HOME");
>  	if (git_config_global() && home) {
>  		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
>  		if (!access(user_config, R_OK)) {
> diff --git a/path.c b/path.c
> index 2ec950b..b42a1b6 100644
> --- a/path.c
> +++ b/path.c
> @@ -236,7 +236,9 @@ char *expand_user_path(const char *path)
>  		const char *username = path + 1;
>  		size_t username_len = first_slash - username;
>  		if (username_len == 0) {
> -			const char *home = getenv("HOME");
> +			const char *home = getenv("GIT_HOME");
> +			if (!home)
> +				home = getenv("HOME");
>  			strbuf_add(&user_path, home, strlen(home));
>  		} else {
>  			struct passwd *pw = getpw_str(username, username_len);
> diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
> index 83b7294..d9818ab 100755
> --- a/t/t1300-repo-config.sh
> +++ b/t/t1300-repo-config.sh
> @@ -18,6 +18,13 @@ EOF
>  
>  test_expect_success 'initial' 'cmp .git/config expect'
>  
> +test_expect_success 'GIT_HOME' '
> +	GIT_HOME="`pwd`" &&
> +	export GIT_HOME &&
> +	git config --global core.penguin "little blue" &&
> +	cmp "$GIT_HOME"/.gitconfig expect
> +'
> +
>  git config Core.Movie BadPhysics
>  
>  cat > expect << EOF

^ permalink raw reply

* [PATCH] Introduce the GIT_HOME environment variable
From: Miklos Vajna @ 2009-12-19 15:30 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Moe, git
In-Reply-To: <7vzl5fik3o.fsf@alter.siamese.dyndns.org>

Honor $GIT_HOME that is favoured over $HOME, just like $GIT_EDITOR
overrides $EDITOR.  That allows us to extend the notion more naturally
in the future.  For example, when we start reading from
$HOME/.gitconfig, if the GIT_HOME environment is set, we would instead
read from $GIT_HOME/.gitconfig.

Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---

On Fri, Dec 18, 2009 at 09:55:07PM -0800, Junio C Hamano <gitster@pobox.com> wrote:
> A possible solution might be for us to honor $GIT_HOME that is favoured
> over $HOME, just like $GIT_EDITOR overrides $EDITOR.  That allows us to
> extend the notion more naturally in the future.  For example, when we
> start reading from $HOME/.git-excludes, if the GIT_HOME environment is
> set, we would instead read from $GIT_HOME/.git-excludes.  That would be a
> much cleaner solution than Miklos's patch [*2*].

Something like this?

I've stolen most of the commit message from your mail. ;-)

 Documentation/config.txt |   14 ++++++++++----
 builtin-config.c         |    8 ++++++--
 config.c                 |    4 +++-
 path.c                   |    4 +++-
 t/t1300-repo-config.sh   |    7 +++++++
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index a1e36d7..09cbc71 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -8,6 +8,10 @@ is used to store the configuration for that repository, and
 fallback values for the `.git/config` file. The file `/etc/gitconfig`
 can be used to store a system-wide default configuration.
 
+In case you want to store your per-user configuration in a directory
+different to `$HOME`, you can use the `$GIT_HOME` environment variable
+which has preference.
+
 The configuration variables are used by both the git plumbing
 and the porcelains. The variables are divided into sections, wherein
 the fully qualified variable name of the variable itself is the last
@@ -406,8 +410,9 @@ core.excludesfile::
 	In addition to '.gitignore' (per-directory) and
 	'.git/info/exclude', git looks into this file for patterns
 	of files which are not meant to be tracked.  "{tilde}/" is expanded
-	to the value of `$HOME` and "{tilde}user/" to the specified user's
-	home directory.  See linkgit:gitignore[5].
+	to the value of `$GIT_HOME` (or `$HOME` if `$GIT_HOME` is not
+	set) and "{tilde}user/" to the specified user's home directory.  See
+	linkgit:gitignore[5].
 
 core.editor::
 	Commands such as `commit` and `tag` that lets you edit
@@ -707,8 +712,9 @@ color.ui::
 
 commit.template::
 	Specify a file to use as the template for new commit messages.
-	"{tilde}/" is expanded to the value of `$HOME` and "{tilde}user/" to the
-	specified user's home directory.
+	"{tilde}/" is expanded to the value of `$GIT_HOME` (or `$HOME`
+	if `$GIT_HOME` is not set) and "{tilde}user/" to the specified user's
+	home directory.
 
 diff.autorefreshindex::
 	When using 'git-diff' to compare with work tree
diff --git a/builtin-config.c b/builtin-config.c
index a2d656e..da9ebd4 100644
--- a/builtin-config.c
+++ b/builtin-config.c
@@ -146,7 +146,9 @@ static int get_value(const char *key_, const char *regex_)
 
 	local = config_exclusive_filename;
 	if (!local) {
-		const char *home = getenv("HOME");
+		const char *home = getenv("GIT_HOME");
+		if (!home)
+			home = getenv("HOME");
 		local = repo_config = git_pathdup("config");
 		if (git_config_global() && home)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
@@ -326,7 +328,9 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix)
 	}
 
 	if (use_global_config) {
-		char *home = getenv("HOME");
+		char *home = getenv("GIT_HOME");
+		if (!home)
+			home = getenv("HOME");
 		if (home) {
 			char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 			config_exclusive_filename = user_config;
diff --git a/config.c b/config.c
index 37385ce..7e2ccdb 100644
--- a/config.c
+++ b/config.c
@@ -711,7 +711,9 @@ int git_config(config_fn_t fn, void *data)
 		found += 1;
 	}
 
-	home = getenv("HOME");
+	home = getenv("GIT_HOME");
+	if (!home)
+		home = getenv("HOME");
 	if (git_config_global() && home) {
 		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 		if (!access(user_config, R_OK)) {
diff --git a/path.c b/path.c
index 2ec950b..b42a1b6 100644
--- a/path.c
+++ b/path.c
@@ -236,7 +236,9 @@ char *expand_user_path(const char *path)
 		const char *username = path + 1;
 		size_t username_len = first_slash - username;
 		if (username_len == 0) {
-			const char *home = getenv("HOME");
+			const char *home = getenv("GIT_HOME");
+			if (!home)
+				home = getenv("HOME");
 			strbuf_add(&user_path, home, strlen(home));
 		} else {
 			struct passwd *pw = getpw_str(username, username_len);
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 83b7294..d9818ab 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -18,6 +18,13 @@ EOF
 
 test_expect_success 'initial' 'cmp .git/config expect'
 
+test_expect_success 'GIT_HOME' '
+	GIT_HOME="`pwd`" &&
+	export GIT_HOME &&
+	git config --global core.penguin "little blue" &&
+	cmp "$GIT_HOME"/.gitconfig expect
+'
+
 git config Core.Movie BadPhysics
 
 cat > expect << EOF
-- 
1.6.5.2

^ permalink raw reply related

* Re: [PATCH] Introduce the GIT_CONFIG_EXTRA environment variable
From: Nanako Shiraishi @ 2009-12-19 14:45 UTC (permalink / raw)
  To: Moe; +Cc: Junio C Hamano, Miklos Vajna, git
In-Reply-To: <4B2C7EC3.6070501@signalbeam.net>

Quoting Moe <moe@signalbeam.net>

> In practice our developers will su or ssh to this user to get working
> and generally they need only a very small set of divertions from the
> common configuration - such as their personal git identity and their
> preferred editor settings.

Do "preferred editor settings" mean $HOME/.vim that was one of 
Junio's examples? How do you handle it?

It sounds like you are only interested in user.name and 
user.email, and you don't need to override $HOME/.gitconfig as 
a whole.  Because you already have a section in $HOME/.bashrc 
that does different things based on the user's SSH key, you 
may want to set variables GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL 
in there without doing anything else if that is the case.

> One may argue that a bunch of host-specific symlinks could achieve a
> similar effect - and that would be correct - but having literally
> everything under version control yields certain advantages that we
> wouldn't want to miss.

Sorry, but I don't understand. What do symlinks have to do 
with keeping everything under version control? git can track 
symbolic links just fine, if that is what is troubling you.

-- 
Nanako Shiraishi
http://ivory.ap.teacup.com/nanako3/

^ permalink raw reply

* Re: [PATCH] Introduce the GIT_CONFIG_EXTRA environment variable
From: Miklos Vajna @ 2009-12-19 14:25 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Junio C Hamano, Moe, git
In-Reply-To: <20091219020947.GB10687@spearce.org>

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

On Fri, Dec 18, 2009 at 06:09:47PM -0800, "Shawn O. Pearce" <spearce@spearce.org> wrote:
> What file does `git config --add` modify?  Should we be able to
> modify the GIT_CONFIG_EXTRA file?

git config --add will still write .git/config (or $GIT_CONFIG) as
before. At the moment there is no way to modify a GIT_CONFIG_EXTRA file
using git-config.

> What order is GIT_CONFIG_EXTRA applied in relative to other files
> that git config would also have read?

The config file from GIT_CONFIG_EXTRA is the last one that is read.

Adding the above feature and documenting the later answer could be done
in a second version of such a patch, but as far as I see it's no good
doing so because then patch solves a non-exsiting problem. ;-)

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* Re: Git as electronic lab notebook
From: Ciprian Dorin, Craciun @ 2009-12-19 13:38 UTC (permalink / raw)
  To: Thomas Johnson; +Cc: git
In-Reply-To: <loom.20091219T130946-844@post.gmane.org>

On Sat, Dec 19, 2009 at 2:23 PM, Thomas Johnson
<thomas.j.johnson@gmail.com> wrote:
> Hello group,
>
> I've been using git on a few different projects over the last couple of months,
> and as a former svn user I really like it. Recently, I've been using it as an
> 'electronic lab notebook' for an empirical project. My workflow looks like this:
> 1. Start with the stable code base on head
> 2. Create  and change to branch 'Experiment123'
> 3. Make some changes
> 4. Run the program, which generates a giant (10MB-4G) output text file,
> Experiment123.log. Update my LabNotebook.txt file.
> 5. Were the new changes helpful?
> 5.yes: Bzip Experiment123.log, and commit it on the branch. Merge the
> Experiment123 branch to head and goto 1.
> 5.no: Bzip Experiment123.log, and commit it on the branch. Merge LabNotebook.txt
> and Experiment123.log back to head. Switch back to head and goto 1.
>
> The thing is, Experiment123.log is going to be very similar to Experiment122.log
> and Experiment124.log except for a few details. My understanding is that git is
> great at compressing groups of files like this, is that correct? Should I not be
> bzipping them myself? On the other hand, I don't want HEAD to contain hundreds
> of gigs of uncompressed files that bzip down to only a few hundred megs.
>
> Any thoughts on the workflow itself would also be very welcome.


    I have used myself such a similar workflow for parametric studies
on some genetic algorithms, and below are my observations related to
your question:
    * saving the entire log file (either zipped or not) in the
repository has some drawbacks with repository clonning; (in my setup
I've runned the tests in parallel on a different machine, and used Git
to synchronize between the development machine and the test machine;)
the problem lies in the fact that when I wanted to "clean" the test
machine and start over I had to clone the repository, which also held
all the unneeded log files;
    * (actually I've used two Git repositories -- one for the actual
source code where I make the commits by hand, and another one which I
use for the synchronization;)
    * even if you prefer having the logs, it's best to let Git handle
the compression; because even if only some small parts change from the
original txt file, I would guess that the BZip-ped file looks quite
different;
    * maybe it would be better than instead of holding the experiment
log, you just keep a sumarization of it (only the important stuff);
and even if you do need the entire log, you could always recreate it
by running the code again; (this was the road I took in the end, by
keeping a small SQLite database of each experiment;)
    * (and of course there is also another little trick I've used:
just put the logs file in a `log` directory which is "git-ignored",
that way you can switch between branches, but Git won't touch the
`log` directory, unless you force it by issuing `git clean -f -d -x`;)

    Hope I've been useful,
    Ciprian.

^ permalink raw reply

* [PATCH/RFCv2 4/6] gitweb: Makefile improvements
From: Jakub Narebski @ 2009-12-19 13:32 UTC (permalink / raw)
  To: J.H.; +Cc: git, John 'Warthog9' Hawley
In-Reply-To: <200912111741.51760.jnareb@gmail.com>

From: John 'Warthog9' Hawley <warthog9@kernel.org>

This commit adjust the main Makefile so you can simply run

     make gitweb

which in turn calls gitweb/Makefile.  This means that in order to
generate gitweb, you can simply run 'make' from gitweb subdirectory:

     cd gitweb
     make

Targets gitweb/gitweb.cgi and (dependent on JSMIN being defined)
gitweb/gitweb.min.js in main Makefile are preserved for backward
compatibility.

Signed-off-by: John 'Warthog9' Hawley <warthog9@kernel.org>
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
This implements separate Makefile for gitweb, with main Makefile calling
it, like for gitk-git/, git-gui/, Documentation/, t/, and templates/
directories.

It is marked as RFC because I don't feel that my make-fu is strong enough
to be sure that there are no errors / mistakes.  Very slightly tested.

 Makefile        |   64 +++++----------------------
 gitweb/Makefile |  129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 141 insertions(+), 52 deletions(-)
 create mode 100644 gitweb/Makefile

diff --git a/Makefile b/Makefile
index 4a1e5bc..50d815e 100644
--- a/Makefile
+++ b/Makefile
@@ -280,29 +280,6 @@ pathsep = :
 # JavaScript minifier invocation that can function as filter
 JSMIN =
 
-# default configuration for gitweb
-GITWEB_CONFIG = gitweb_config.perl
-GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
-GITWEB_HOME_LINK_STR = projects
-GITWEB_SITENAME =
-GITWEB_PROJECTROOT = /pub/git
-GITWEB_PROJECT_MAXDEPTH = 2007
-GITWEB_EXPORT_OK =
-GITWEB_STRICT_EXPORT =
-GITWEB_BASE_URL =
-GITWEB_LIST =
-GITWEB_HOMETEXT = indextext.html
-GITWEB_CSS = gitweb.css
-GITWEB_LOGO = git-logo.png
-GITWEB_FAVICON = git-favicon.png
-ifdef JSMIN
-GITWEB_JS = gitweb.min.js
-else
-GITWEB_JS = gitweb.js
-endif
-GITWEB_SITE_HEADER =
-GITWEB_SITE_FOOTER =
-
 export prefix bindir sharedir sysconfdir
 
 CC = gcc
@@ -1509,6 +1486,11 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
 	chmod +x $@+ && \
 	mv $@+ $@
 
+
+.PHONY: gitweb
+gitweb:
+	$(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
+
 ifdef JSMIN
 OTHER_PROGRAMS += gitweb/gitweb.cgi   gitweb/gitweb.min.js
 gitweb/gitweb.cgi: gitweb/gitweb.perl gitweb/gitweb.min.js
@@ -1516,30 +1498,13 @@ else
 OTHER_PROGRAMS += gitweb/gitweb.cgi
 gitweb/gitweb.cgi: gitweb/gitweb.perl
 endif
-	$(QUIET_GEN)$(RM) $@ $@+ && \
-	sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
-	    -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
-	    -e 's|++GIT_BINDIR++|$(bindir)|g' \
-	    -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
-	    -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
-	    -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
-	    -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
-	    -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
-	    -e 's|"++GITWEB_PROJECT_MAXDEPTH++"|$(GITWEB_PROJECT_MAXDEPTH)|g' \
-	    -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \
-	    -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_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
-	    -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
-	    -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
-	    -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
-	    -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
-	    -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
-	    -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
-	    $< >$@+ && \
-	chmod +x $@+ && \
-	mv $@+ $@
+	$(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
+
+ifdef JSMIN
+gitweb/gitweb.min.js: gitweb/gitweb.js
+	$(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
+endif # JSMIN
+
 
 git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.js
 	$(QUIET_GEN)$(RM) $@ $@+ && \
@@ -1566,11 +1531,6 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh
 	mv $@+ $@
 endif # NO_PERL
 
-ifdef JSMIN
-gitweb/gitweb.min.js: gitweb/gitweb.js
-	$(QUIET_GEN)$(JSMIN) <$< >$@
-endif # JSMIN
-
 configure: configure.ac
 	$(QUIET_GEN)$(RM) $@ $<+ && \
 	sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
diff --git a/gitweb/Makefile b/gitweb/Makefile
new file mode 100644
index 0000000..c9eb1ee
--- /dev/null
+++ b/gitweb/Makefile
@@ -0,0 +1,129 @@
+# The default target of this Makefile is...
+all::
+
+# Define V=1 to have a more verbose compile.
+#
+# Define JSMIN to point to JavaScript minifier that functions as
+# a filter to have gitweb.js minified.
+#
+
+prefix ?= $(HOME)
+bindir ?= $(prefix)/bin
+RM ?= rm -f
+
+# JavaScript minifier invocation that can function as filter
+JSMIN ?=
+
+# default configuration for gitweb
+GITWEB_CONFIG = gitweb_config.perl
+GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
+GITWEB_HOME_LINK_STR = projects
+GITWEB_SITENAME =
+GITWEB_PROJECTROOT = /pub/git
+GITWEB_PROJECT_MAXDEPTH = 2007
+GITWEB_EXPORT_OK =
+GITWEB_STRICT_EXPORT =
+GITWEB_BASE_URL =
+GITWEB_LIST =
+GITWEB_HOMETEXT = indextext.html
+GITWEB_CSS = gitweb.css
+GITWEB_LOGO = git-logo.png
+GITWEB_FAVICON = git-favicon.png
+ifdef JSMIN
+GITWEB_JS = gitweb.min.js
+else
+GITWEB_JS = gitweb.js
+endif
+GITWEB_SITE_HEADER =
+GITWEB_SITE_FOOTER =
+
+# include user config
+-include ../config.mak.autogen
+-include ../config.mak
+
+# determine version
+../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
+	$(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) GIT-VERSION-FILE
+
+-include ../GIT-VERSION-FILE
+
+### Build rules
+
+SHELL_PATH ?= $(SHELL)
+PERL_PATH  ?= /usr/bin/perl
+
+# Shell quote;
+bindir_SQ = $(subst ','\'',$(bindir))         #'
+SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) #'
+PERL_PATH_SQ  = $(subst ','\'',$(PERL_PATH))  #'
+
+# Quiet generation (unless V=1)
+QUIET_SUBDIR0  = +$(MAKE) -C # space to separate -C and subdir
+QUIET_SUBDIR1  =
+
+ifneq ($(findstring $(MAKEFLAGS),w),w)
+PRINT_DIR = --no-print-directory
+else # "make -w"
+NO_SUBDIR = :
+endif
+
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifndef V
+	QUIET          = @
+	QUIET_GEN      = $(QUIET)echo '   ' GEN $@;
+	QUIET_SUBDIR0  = +@subdir=
+	QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
+	                 $(MAKE) $(PRINT_DIR) -C $$subdir
+	export V
+	export QUIET
+	export QUIET_GEN
+	export QUIET_SUBDIR0
+	export QUIET_SUBDIR1
+endif
+endif
+
+all:: gitweb.cgi
+
+ifdef JSMIN
+FILES=gitweb.cgi gitweb.min.js
+gitweb.cgi: gitweb.perl gitweb.min.js
+else # !JSMIN
+FILES=gitweb.cgi
+gitweb.cgi: gitweb.perl
+endif # JSMIN
+
+gitweb.cgi:
+	$(QUIET_GEN)$(RM) $@ $@+ && \
+	sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
+	    -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
+	    -e 's|++GIT_BINDIR++|$(bindir)|g' \
+	    -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
+	    -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
+	    -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
+	    -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
+	    -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
+	    -e 's|"++GITWEB_PROJECT_MAXDEPTH++"|$(GITWEB_PROJECT_MAXDEPTH)|g' \
+	    -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \
+	    -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_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
+	    -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
+	    -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
+	    -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
+	    -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
+	    -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
+	    -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
+	    $< >$@+ && \
+	chmod +x $@+ && \
+	mv $@+ $@
+
+ifdef JSMIN
+gitweb.min.js: gitweb.js
+	$(QUIET_GEN)$(JSMIN) <$< >$@
+endif # JSMIN
+
+clean:
+	$(RM) $(FILES)
+
+.PHONY: all clean .FORCE-GIT-VERSION-FILE
-- 
1.6.5.3

^ permalink raw reply related


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