* Re: [JGIT PATCH (RESEND) 3/3] Fix DirCache.findEntry to work on an empty cache
From: Robin Rosenberg @ 2009-09-03 23:14 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: git, Shawn O. Pearce
In-Reply-To: <1251847010-9992-3-git-send-email-spearce@spearce.org>
onsdag 02 september 2009 01:16:50 skrev "Shawn O. Pearce" <spearce@spearce.org>:
> If the cache has no entries, we want to return -1 rather than throw
> ArrayIndexOutOfBoundsException. This binary search loop was stolen
> from some other code which contained a test before the loop to see if
> the collection was empty or not, but we failed to include that here.
>
> Flipping the loop around to a standard while loop ensures we test
> the condition properly first.
>
> Signed-off-by: Shawn O. Pearce <sop@google.com>
> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Is this a new policy?
-- robin
^ permalink raw reply
* [PATCH] make shallow repository deepening more network efficient
From: Nicolas Pitre @ 2009-09-03 23:08 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
First of all, I can't find any reason why thin pack generation is
explicitly disabled when dealing with a shallow repository. The
possible delta base objects are collected from the edge commits which
are always obtained through history walking with the same shallow refs
as the client, Therefore the client is always going to have those base
objects available. So let's remove that restriction.
Then we can make shallow repository deepening much more efficient by
using the remote's unshallowed commits as edge commits to get preferred
base objects for thin pack generation. On git.git, this makes the data
transfer for the deepening of a shallow repository from depth 1 to depth 2
around 134 KB instead of 3.68 MB.
Signed-off-by: Nicolas Pitre <nico@cam.org>
diff --git a/upload-pack.c b/upload-pack.c
index f73e3c9..c77ab71 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -32,6 +32,7 @@ static int no_progress, daemon_mode;
static int shallow_nr;
static struct object_array have_obj;
static struct object_array want_obj;
+static struct object_array extra_edge_obj;
static unsigned int timeout;
/* 0 for no sideband,
* otherwise maximum packet size (up to 65520 bytes).
@@ -135,6 +136,10 @@ static int do_rev_list(int fd, void *create_full_pack)
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
mark_edges_uninteresting(revs.commits, &revs, show_edge);
+ if (use_thin_pack)
+ for (i = 0; i < extra_edge_obj.nr; i++)
+ fprintf(pack_pipe, "-%s\n", sha1_to_hex(
+ extra_edge_obj.objects[i].item->sha1));
traverse_commit_list(&revs, show_commit, show_object, NULL);
fflush(pack_pipe);
fclose(pack_pipe);
@@ -562,7 +567,6 @@ static void receive_needs(void)
if (!prefixcmp(line, "shallow ")) {
unsigned char sha1[20];
struct object *object;
- use_thin_pack = 0;
if (get_sha1(line + 8, sha1))
die("invalid shallow line: %s", line);
object = parse_object(sha1);
@@ -574,7 +578,6 @@ static void receive_needs(void)
}
if (!prefixcmp(line, "deepen ")) {
char *end;
- use_thin_pack = 0;
depth = strtol(line + 7, &end, 0);
if (end == line + 7 || depth <= 0)
die("Invalid deepen: %s", line);
@@ -657,6 +660,7 @@ static void receive_needs(void)
NULL, &want_obj);
parents = parents->next;
}
+ add_object_array(object, NULL, &extra_edge_obj);
}
/* make sure commit traversal conforms to client */
register_shallow(object->sha1);
^ permalink raw reply related
* Re: [JGIT] Request for help
From: Nasser Grainawi @ 2009-09-03 21:09 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Git Mailing List
In-Reply-To: <20090903194955.GL1033@spearce.org>
Shawn O. Pearce wrote:
> Nasser Grainawi <nasser@codeaurora.org> wrote:
>> Shawn O. Pearce wrote:
>>> Hmm, maybe a method on Patch is reasonable.
>> Going down this route, I'd add a few things to Patch.
>> patchId would be a private field (of type ObjectId?)
>> getPatchId would be a public method that returns patchId
>> and then likely a private method (computePatchId?) that actually
>> generates the patchId
>
> Sure, but getPatchId can compute it on demand on the first call,
> and anyone who modifies the Patch would just need to clear out
> the cached patchId value so the next call (if it ever comes) to
> getPatchId would force it to recompute.
>
> Most users of Patch won't want the patchId, so there is no reason
> to compute it.
>
Works for me, that's even easier. I'll get to work on implementing this,
but between (re-)learning Java and our legal dept, don't know when I'll
have a finished product to share...
I'll continue to post questions as I get them.
Thanks everyone for their help thus far :)
^ permalink raw reply
* [PATCH] git.el: Use git-add-file for unmerged files, remove git-resolve-file
From: Martin Nordholts @ 2009-09-03 20:27 UTC (permalink / raw)
To: git, Junio C Hamano, Alexandre Julliard
Use `git-add-file' to mark unmerged files as resolved in the
*git-status* buffer to be consistent with git's CLI instructions. Also
remove `git-resolve-file' to make it clear that that "R" is a now a
free keybinding.
Signed-off-by: Martin Nordholts <martinn@src.gnome.org>
---
contrib/emacs/git.el | 13 +------------
1 files changed, 1 insertions(+), 12 deletions(-)
diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el
index 8c70ad8..214930a 100644
--- a/contrib/emacs/git.el
+++ b/contrib/emacs/git.el
@@ -1046,7 +1046,7 @@ The FILES list must be sorted."
(defun git-add-file ()
"Add marked file(s) to the index cache."
(interactive)
- (let ((files (git-get-filenames (git-marked-files-state 'unknown 'ignored))))
+ (let ((files (git-get-filenames (git-marked-files-state 'unknown 'ignored 'unmerged))))
;; FIXME: add support for directories
(unless files
(push (file-relative-name (read-file-name "File to add: " nil nil t)) files))
@@ -1119,15 +1119,6 @@ The FILES list must be sorted."
(when buffer (with-current-buffer buffer (revert-buffer t t t)))))
(git-success-message "Reverted" names))))))
-(defun git-resolve-file ()
- "Resolve conflicts in marked file(s)."
- (interactive)
- (let ((files (git-get-filenames (git-marked-files-state 'unmerged))))
- (when files
- (when (apply 'git-call-process-display-error "update-index" "--" files)
- (git-update-status-files files)
- (git-success-message "Resolved" files)))))
-
(defun git-remove-handled ()
"Remove handled files from the status list."
(interactive)
@@ -1556,7 +1547,6 @@ amended version of it."
(define-key map "P" 'git-prev-unmerged-file)
(define-key map "q" 'git-status-quit)
(define-key map "r" 'git-remove-file)
- (define-key map "R" 'git-resolve-file)
(define-key map "t" toggle-map)
(define-key map "T" 'git-toggle-all-marks)
(define-key map "u" 'git-unmark-file)
@@ -1598,7 +1588,6 @@ amended version of it."
("Merge"
["Next Unmerged File" git-next-unmerged-file t]
["Prev Unmerged File" git-prev-unmerged-file t]
- ["Mark as Resolved" git-resolve-file t]
["Interactive Merge File" git-find-file-imerge t]
["Diff Against Common Base File" git-diff-file-base t]
["Diff Combined" git-diff-file-combined t]
--
1.6.2.5
^ permalink raw reply related
* Re: [JGIT] Request for help
From: Shawn O. Pearce @ 2009-09-03 19:49 UTC (permalink / raw)
To: Nasser Grainawi; +Cc: Git Mailing List
In-Reply-To: <4AA01D08.3060400@codeaurora.org>
Nasser Grainawi <nasser@codeaurora.org> wrote:
> Shawn O. Pearce wrote:
>> Hmm, maybe a method on Patch is reasonable.
>
> Going down this route, I'd add a few things to Patch.
> patchId would be a private field (of type ObjectId?)
> getPatchId would be a public method that returns patchId
> and then likely a private method (computePatchId?) that actually
> generates the patchId
Sure, but getPatchId can compute it on demand on the first call,
and anyone who modifies the Patch would just need to clear out
the cached patchId value so the next call (if it ever comes) to
getPatchId would force it to recompute.
Most users of Patch won't want the patchId, so there is no reason
to compute it.
--
Shawn.
^ permalink raw reply
* Re: [JGIT] Request for help
From: Nasser Grainawi @ 2009-09-03 19:46 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Git Mailing List
In-Reply-To: <20090903012315.GG1033@spearce.org>
Shawn O. Pearce wrote:
> Nasser Grainawi <nasser@codeaurora.org> wrote:
>> Should PatchId be a class on its own, or just a method within the Patch
>> class?
>
> Hmm, maybe a method on Patch is reasonable.
>
Going down this route, I'd add a few things to Patch.
patchId would be a private field (of type ObjectId?)
getPatchId would be a public method that returns patchId
and then likely a private method (computePatchId?) that actually
generates the patchId
This way any method in Patch that would potentially change a Patch
object's patch-id would call computePatchId before it returns.
Thoughts?
^ permalink raw reply
* Re: git-svn-Cloning repository with complicate nesting
From: Marc Branchaud @ 2009-09-03 16:50 UTC (permalink / raw)
To: Daniele Segato; +Cc: Git Mailing List
In-Reply-To: <9accb4400909030917y2e8d4c97tef1320c05d4c4e1c@mail.gmail.com>
Daniele Segato wrote:
>
> hum...
> It could be an idea but I don't know how hard could it be to check it:
> how much deep inside the tree should Git search for branch?
Well, as far as it takes. Actually, the search should be fairly well constrained. After checking that the entries under a particular path aren't a copy of the trunk, each entry can only represent either a branch that git-svn already knows about, or a new branch.
> what if there are branches that are completely differents?
Not sure what you mean there. Can you come up with an example of this?
> may be the user could create and pass a "branch model" to git svn to
> make it able to decide what is a branch and what isn't.
>
> I think there are many options
>
> In my case It would have worked defining a structure like:
> BRANCHES/*/root -> remote/svn/branch/*
> BRANCHES/*/*/root -> remote/svn/branch/*/*
>
> But it would be better with something like:
> BRANCHES/\([^\/]+\)/root -> remote/svn/branch/$1
> BRANCHES/\([^\/]+\)/\([^\/]+\)/root -> remote/svn/branch/$1/$2
>
> like a grouped regex.
>
> every branch not matching the regex will be skipped..
> only an idea.. It couln't work in every situation but it would allow a
> greater degree of freedom in the configuration.
Turning the branch refspecs into true regular expressions sounds like a good idea to me, and would probably be easier to implement than the trunk-detection stuff I proposed. Though there'd have to be a way to stay compatible with or upgrade the current non-regex refspecs.
> I don't know if Git developers are interested in thinking on some
> features like this.. it sound like an SVN-only hack to me.
All of git-svn is already a hack for dealing with SVN. :) I'm sure a patch for this would be welcome.
M.
^ permalink raw reply
* Deleted folder keeps showing up?
From: Benjamin Buch @ 2009-09-03 16:59 UTC (permalink / raw)
To: git
I made a branch and deleted a folder there with git rm -rf foldername.
So now i have to branches, A with the folder and B without the folder.
I'm on B, the folder is not there.
Then I check out A, the folder shows up like it should.
When I check out B again, the folder is still there.
A git rm -rf folder gives me:
fatal: pathspec 'folder/' did not match any files
, so git is not tracking the folder.
I can rm -rf the filder without git and start the whole game from the
beginning,
but there has to be a better way?
Strange enough this happens just to two folders I removed,
with others there is no problem.
-benjamin
^ permalink raw reply
* Re: diff-files inconsistency with touched files
From: James Spencer @ 2009-09-03 16:18 UTC (permalink / raw)
To: Jeff King; +Cc: git
In-Reply-To: <20090902192820.GE6900@coredump.intra.peff.net>
Jeff King wrote:
> On Wed, Sep 02, 2009 at 06:27:15PM +0100, James Spencer wrote:
>
>> $ git diff-files
>> $ touch test
>> $ git diff-files
>> :100644 100644 9daeafb9864cf43055ae93beb0afd6c7d144bfa4
>> 0000000000000000000000000000000000000000 M test
>> $ git diff
>> $ git diff-files
>> $
>>
>> I don't understand why git diff-files reports a file is changed when
>> that file is touched nor why running git diff changes this to (what I
>> think is) the correct behaviour.
>
> Git uses the stat information of a file to know whether what we have
> cached in the index is up-to-date or not. So in the first diff-files, we
> don't even have to look at the contents of "test"; we see that it hasn't
> changed since the last time we looked at the contents, and that its
> sha-1 matches what's in the index, so there is no diff.
>
> By running "touch", you have changed the stat information, so we believe
> there may be a difference. But we don't actually know what's _in_ the
> new side, so we just print the null sha1 instead of the actual sha1
> contents.
>
> Diff-files _could_ refresh the cache each time it runs, but we
> intentionally do not do that. Doing so is a little bit expensive, and
> because diff-files is intended as a low-level tool for scripts, we give
> the script the flexibility (and responsibility) of refreshing the cache
> when it wants to. So you could do:
>
> $ git update-index --refresh
> $ git diff-files
>
> and get clean output.
>
> You see different behavior from "git diff" because it is meant for user
> consumption and therefore refreshes the cache automatically at the
> beginning of every run.
>
> -Peff
Thanks for your help!
--James
^ permalink raw reply
* Re: git-svn-Cloning repository with complicate nesting
From: Daniele Segato @ 2009-09-03 16:17 UTC (permalink / raw)
To: Marc Branchaud; +Cc: Git Mailing List
In-Reply-To: <4A9FD34A.7020101@xiplink.com>
On Thu, Sep 3, 2009 at 4:31 PM, Marc Branchaud<marcnarc@xiplink.com> wrote:
> Hi Daniele,
Hi Marc and thank you for your reply.
> I think you're stuck. Someone who knows git-svn better than I might be able to figure out a solution (I haven't played with using wildcards in the middle of branches refspecs), but as far as I can tell git-svn can't support your repository's structure.
>
> The fundamental problem is that the BRANCHES/ hierarchy isn't consistent. git-svn expects the directories under a 'branches' path to be branch names. In your case, you can't specify a configuration that covers your whole repository.
yes..
and developers should be smart enought to keep consistency on their
own.. unfurtunately they oftern aren't
> So I think git-svn would need to be modified to support your situation.
I'm not feeling that lucky but I would be happy about it. :-)
> One possible approach is to make git-svn smart about what it considers a branch's name. In theory, what you'd like is to just specify
> To do this, git-svn could track the current 'trunk' directory structure (just the top-level contents of the root should suffice). Then when it detects a new path under BRANCHES it could search through that path until it finds the same 'trunk' directory structure, and then use the path as the full branch name.
> When a commit creates a new branch:
> git-svn sees that the commit is to a new path under branches/ and looks through branches/some/ and branches/some/path/ to find the trunk's contents, deciding in this case that 'some/path' is the branch's name.
>
> Anyway, this is just an idea of how things might work. There are probably some corner-cases that could make this a bit tricky to implement...
hum...
It could be an idea but I don't know how hard could it be to check it:
how much deep inside the tree should Git search for branch? what if
there are branches that are completely differents?
may be the user could create and pass a "branch model" to git svn to
make it able to decide what is a branch and what isn't.
I think there are many options
In my case It would have worked defining a structure like:
BRANCHES/*/root -> remote/svn/branch/*
BRANCHES/*/*/root -> remote/svn/branch/*/*
But it would be better with something like:
BRANCHES/\([^\/]+\)/root -> remote/svn/branch/$1
BRANCHES/\([^\/]+\)/\([^\/]+\)/root -> remote/svn/branch/$1/$2
like a grouped regex.
every branch not matching the regex will be skipped..
only an idea.. It couln't work in every situation but it would allow a
greater degree of freedom in the configuration.
I don't know if Git developers are interested in thinking on some
features like this.. it sound like an SVN-only hack to me.
Regards,
Daniele
^ permalink raw reply
* Re: jgit diff, was Re: [JGIT] Request for help
From: Christian Halstrick @ 2009-09-03 15:54 UTC (permalink / raw)
To: git
In-Reply-To: <alpine.DEB.1.00.0909030846230.8306@pacific.mpi-cbg.de>
Johannes Schindelin <Johannes.Schindelin <at> gmx.de> writes:
...
> > > This is not really difficult in Java, however, it relies on a working
> > > diff implementation (and IIRC my implementation has not yet been
> > > integrated into JGit).
> >
> > Speaking of... where does that stand?
>
> Same as where I left off. IOW it is a working implementation that saw
> some testing, but I simply lack the time for performance tuning.
I can offer my help here. I looked at Dscho's code before, provided patches to
let it compile and run the tests (IIRC not fully successfully). I started in my
local repo to modify enhance the tests but didn't finished with that yet. I'll
try now to add some performance tests and tests derived from native Git diff
tests.
>
> It should not be all that bad, though.
>
...
> Seems I misremembered a bit. Christian provided a patch to make it
> compileable, but I think that I ran the script to verify that the diffs
> are correct on jgit.git and IIRC it completed fine.
^ permalink raw reply
* Re: [JGIT] Request for help
From: Shawn O. Pearce @ 2009-09-03 15:52 UTC (permalink / raw)
To: Jonas Fonseca; +Cc: Johannes Schindelin, Nasser Grainawi, Git Mailing List
In-Reply-To: <2c6b72b30909030838q10b88705gb8c553f2c2d74379@mail.gmail.com>
Jonas Fonseca <jonas.fonseca@gmail.com> wrote:
> On Thu, Sep 3, 2009 at 10:42, Shawn O. Pearce<spearce@spearce.org> wrote:
> > Actually, now that we have forked out of the egit.git repository,
> > I want to refactor the layout of the JGit project to be more maven
> > like, and have a proper top-level pom to build things.
>
> What kind of module structure do you have in mind? Do you want to move
> some of the modules/subdirectories?
> Some refactoring of the maven setup for JGit back was done back in
> April in sonatype's (a maven company) JGit clone. It is not
> signed-off, but can serve as a reference.
Yea, I was hoping they would contribute this back as patches,
but thus far they haven't.
> The Maven layout in the sonatype clone simply uses the Eclipse project layout.
>
> pom.xml: JGit :: Parent
> |- org.spearce.jgit/pom.xml: JGit :: Core
> |- org.spearce.jgit.pgm/pom.xml: JGit :: Programs
> `- org.spearce.jgit.test/pom.xml: JGit :: Test
>
> However, having tests in a separate module can be both good/bad. For
> example, they will not automatically get run when you only build the
> Core module.
Yea, I know. This is one area where Maven is just whack, by putting
the tests in the same project the Maven plugin for Eclipse puts
them into the same classpath, which means you can see test code
from project code. Wrong. They should be different projects so
the test classpath is isolated.
However. This is a bug in the Eclipse plugin I think, not
necessarily with Maven's approach of trying to keep tests alongside
the code they test. Thus we probably want:
pom.xml: JGit :: Parent
|- jgit-lib/pom.xml: JGit
| src/main/java <-- from org.spearce.jgit/src
| src/test/java <-- from org.spearce.jgit.test/src
|
`- jgit-pgm/pom.xml: JGit pgm
src/main/java <-- from org.spearce.jgit.pgm/src
IIRC there is Maven support to create proper MANIFEST.MF files for
OSGI bundles, which is what we need for the Eclipse plugin support.
That should be able to replace the META-INF/MANIFEST.MF in the top
of each of the current directories.
> Anyway, I would like to help.
Please post patches; formatted with -M. I do want to do this, I just
don't have the patience and Maven-fu to write the new poms myself.
--
Shawn.
^ permalink raw reply
* Re: [JGIT] Request for help
From: Jonas Fonseca @ 2009-09-03 15:38 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Johannes Schindelin, Nasser Grainawi, Git Mailing List
In-Reply-To: <20090903144227.GH1033@spearce.org>
On Thu, Sep 3, 2009 at 10:42, Shawn O. Pearce<spearce@spearce.org> wrote:
> Jonas Fonseca <jonas.fonseca@gmail.com> wrote:
>> BTW, what is your opinion of making it a bit easier to import and use
>> the Maven configuration by putting a pom.xml in the top-level
>> directory? The actual pom.xml file responsible for building the jgit
>> library can still live on in jgit-maven/ if that is preferable.
>>
>> I am also thinking about "mavenizing" the .pgm subproject to make it
>> easier to browse and search the code from within NetBeans.
>
> Actually, now that we have forked out of the egit.git repository,
> I want to refactor the layout of the JGit project to be more maven
> like, and have a proper top-level pom to build things.
What kind of module structure do you have in mind? Do you want to move
some of the modules/subdirectories?
Some refactoring of the maven setup for JGit back was done back in
April in sonatype's (a maven company) JGit clone. It is not
signed-off, but can serve as a reference.
- http://github.com/sonatype/JGit/commit/641ae523c496f381a7673f4acfa0acdff9d3913e
The Maven layout in the sonatype clone simply uses the Eclipse project layout.
pom.xml: JGit :: Parent
|- org.spearce.jgit/pom.xml: JGit :: Core
|- org.spearce.jgit.pgm/pom.xml: JGit :: Programs
`- org.spearce.jgit.test/pom.xml: JGit :: Test
However, having tests in a separate module can be both good/bad. For
example, they will not automatically get run when you only build the
Core module.
Anyway, I would like to help.
--
Jonas Fonseca
^ permalink raw reply
* Re: [JGIT] Request for help
From: Shawn O. Pearce @ 2009-09-03 14:42 UTC (permalink / raw)
To: Jonas Fonseca; +Cc: Johannes Schindelin, Nasser Grainawi, Git Mailing List
In-Reply-To: <2c6b72b30909030545y4465b5c8j4b2b5587a07762c0@mail.gmail.com>
Jonas Fonseca <jonas.fonseca@gmail.com> wrote:
> BTW, what is your opinion of making it a bit easier to import and use
> the Maven configuration by putting a pom.xml in the top-level
> directory? The actual pom.xml file responsible for building the jgit
> library can still live on in jgit-maven/ if that is preferable.
>
> I am also thinking about "mavenizing" the .pgm subproject to make it
> easier to browse and search the code from within NetBeans.
Actually, now that we have forked out of the egit.git repository,
I want to refactor the layout of the JGit project to be more maven
like, and have a proper top-level pom to build things.
Unfortunately it seems that nobody can program a proper Maven pom
for a multi-project project unless they are one of the authors
of Maven itself. I watched the Apache MINA team struggle with it
until the Maven guys wanted to use their code, and fixed their build.
So, this refactoring is waiting for a Maven guru to contribute
an improvement. Unfortunately they are all busy...
So, to answer your original question, yes, we should make this
better, and patches are welcome. My own Maven-fu is just not up
to the task.
--
Shawn.
^ permalink raw reply
* Re: git-svn-Cloning repository with complicate nesting
From: Marc Branchaud @ 2009-09-03 14:31 UTC (permalink / raw)
To: Daniele Segato; +Cc: Git Mailing List
In-Reply-To: <9accb4400908270132vaccc4eegb58e2f0ee8de0797@mail.gmail.com>
Hi Daniele,
I think you're stuck. Someone who knows git-svn better than I might be able to figure out a solution (I haven't played with using wildcards in the middle of branches refspecs), but as far as I can tell git-svn can't support your repository's structure.
The fundamental problem is that the BRANCHES/ hierarchy isn't consistent. git-svn expects the directories under a 'branches' path to be branch names. In your case, you can't specify a configuration that covers your whole repository.
This:
branches = <url>/BRANCHES/DEV/*:refs/remotes/svn/dev/*
branches = <url>/BRANCHES/BUILDS/*:refs/remotes/svn/builds/*
will let you track the stuff under BRANCHES/DEV and BRANCHES/BUILDS, but won't let you see the V*.* branches.
This:
branches = <url>/BRANCHES/*:refs/remotes/svn/*
will let you see the V*.* branches, but will get confused over the DEV and BUILDS stuff (because it's expecting the layout to be DEV/root and BUILDS/root).
So I think git-svn would need to be modified to support your situation.
One possible approach is to make git-svn smart about what it considers a branch's name. In theory, what you'd like is to just specify
branches = <url>/BRANCHES/*:refs/remotes/svn/*
and have git-svn properly identify all the branches:
V1.0
V1.1
V1.2
DEV/FEATURE1
DEV/FEATURE2
DEV/FEATURE3
BUILDS/BUILD1
BUILDS/BUILD2
BUILDS/BUILD3
To do this, git-svn could track the current 'trunk' directory structure (just the top-level contents of the root should suffice). Then when it detects a new path under BRANCHES it could search through that path until it finds the same 'trunk' directory structure, and then use the path as the full branch name.
For example, say a repository's trunk has 3 directories and a file:
trunk/
foo/...
bar/...
baz/...
readme.txt
When a commit creates a new branch:
branches/some/path/
foo/...
bar/...
baz/...
readme.txt
git-svn sees that the commit is to a new path under branches/ and looks through branches/some/ and branches/some/path/ to find the trunk's contents, deciding in this case that 'some/path' is the branch's name.
Anyway, this is just an idea of how things might work. There are probably some corner-cases that could make this a bit tricky to implement...
M.
Daniele Segato wrote:
> Hi, this is my first message in the list: this may be a newbie
> question and my English may not be very good.
>
> I've an SVN repository structured like this:
>
> http://<url>/path/to/repo
> |
> HEAD
> |----- root
> |
> BRANCHES
> |----- V1.0
> | |----- root
> |
> |----- V1.1
> | |----- root
> |
> |----- V1.2
> | |----- root
> |
> |----- DEV
> | |----- FEATURE1
> | | |----- root
> | |
> | |----- FEATURE2
> | | |----- root
> | |
> | |----- FEATURE3
> | |----- root
> |
> |----- BUILDS
> |----- BUILD1
> | |----- root
> |
> |----- BUILD2
> | |----- root
> |
> |----- BUILD3
> |----- root
>
> the same for TAGS.
>
> I did this:
>
> git init
> git svn init <url>
> vim .git/config
>
> [core]
> repositoryformatversion = 0
> filemode = true
> bare = false
> logallrefupdates = true
> [svn-remote "svn"]
> url = <url>
> fetch = <url>/HEAD/root:refs/remotes/trunk
> branches = <url>/BRANCHES/*/root:refs/remotes/branches/*
> branches = <url>/BRANCHES/*/*/root:refs/remotes/devel/*
> tags = <url>/TAGS/*/root:refs/remotes/tags/*
>
>
> git svn fetch
>
>
> It is now cloning the repo (it is a really big repo)
>
>
> It is my configuration ok for the repository structure?
>
> if from another terminal I execute "git branch -r" I get:
> tags/V1.3.0
> tags/V1.3.0@3260
> tags/V1.3.1
> tags/V1.3.1@3359
> tags/V1.3.2
> tags/V1.3.2@4256
> tags/V1.4.0-COMMUNITY-FINAL
> tags/V1.4.0-ENTERPRISE-BETA@4241
> trunk
> trunk@4475
>
> It should have already created some branch but I don't see any...
>
> what are those @XXXX number for some of those branches?
>
> Is the syntax of the svn-remote configuration correct?
>
> with this:
> branches = <url>/BRANCHES/*/*/root:refs/remotes/devel/*
> how does git choose the name of the branch? (
> refs/remotes/devel/WHAT_GOES_HERE ? )
>
> I would like it to use the tuple */* of the directory
>
>
> If the syntax of my configuration is not correct, where can I found a
> documentation about it? I couldn't find one.
>
>
> Thanks
> Regards,
> Daniele
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [JGIT] Request for help
From: Jonas Fonseca @ 2009-09-03 12:45 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Johannes Schindelin, Nasser Grainawi, Git Mailing List
In-Reply-To: <20090903012207.GF1033@spearce.org>
On Wed, Sep 2, 2009 at 21:22, Shawn O. Pearce<spearce@spearce.org> wrote:
> Yea, for the most part I think we use Eclipse, and you just have
> to import JGit's top level directory into Eclipse as it comes with
> Eclipse project files. But I know some folks only use our Maven
> build (under jgit-maven/jgit) or use NetBeans. I have no idea how
> to import the project into the latter or configure its unit tests
> to run.
NetBeans comes with very good support for Maven projects. Importing
JGit into NetBeans is just a matter of using the "Open Project" wizard
and locating jgit-maven/jgit. This will also configure the unit tests
to run.
BTW, what is your opinion of making it a bit easier to import and use
the Maven configuration by putting a pom.xml in the top-level
directory? The actual pom.xml file responsible for building the jgit
library can still live on in jgit-maven/ if that is preferable.
I am also thinking about "mavenizing" the .pgm subproject to make it
easier to browse and search the code from within NetBeans.
--
Jonas Fonseca
^ permalink raw reply
* [PATCH v4] Add script for importing bits-and-pieces to Git.
From: Peter Krefting @ 2009-09-03 12:15 UTC (permalink / raw)
To: git
Allows the user to import version history that is stored in bits and
pieces in the file system, for instance snapshots of old development
trees, or day-by-day backups. A configuration file is used to
describe the relationship between the different files and allow
describing branches and merges, as well as authorship and commit
messages.
Output is created in a format compatible with git-fast-import.
Full documentation is provided inline in perldoc format.
Signed-off-by: Peter Krefting <peter@softwolves.pp.se>
---
This version improves the configuration file parser to allow quoted
strings.
contrib/fast-import/import-directories.perl | 416 +++++++++++++++++++++++++++
1 files changed, 416 insertions(+), 0 deletions(-)
create mode 100755 contrib/fast-import/import-directories.perl
diff --git a/contrib/fast-import/import-directories.perl b/contrib/fast-import/import-directories.perl
new file mode 100755
index 0000000..5782d80
--- /dev/null
+++ b/contrib/fast-import/import-directories.perl
@@ -0,0 +1,416 @@
+#!/usr/bin/perl -w
+#
+# Copyright 2008-2009 Peter Krefting <peter@softwolves.pp.se>
+#
+# ------------------------------------------------------------------------
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# ------------------------------------------------------------------------
+
+=pod
+
+=head1 NAME
+
+import-directories - Import bits and pieces to Git.
+
+=head1 SYNOPSIS
+
+B<import-directories.perl> F<configfile> F<outputfile>
+
+=head1 DESCRIPTION
+
+Script to import arbitrary projects version controlled by the "copy the
+source directory to a new location and edit it there"-version controlled
+projects into version control. Handles projects with arbitrary branching
+and version trees, taking a file describing the inputs and generating a
+file compatible with the L<git-fast-import(1)> format.
+
+=head1 CONFIGURATION FILE
+
+=head2 Format
+
+The configuration file is based on the standard I<.ini> format.
+
+ ; Comments start with semi-colons
+ [section]
+ key=value
+
+Please see below for information on how to escape special characters.
+
+=head2 Global configuration
+
+Global configuration is done in the B<[config]> section, which should be
+the first section in the file. Configuration can be changed by
+repeating configuration sections later on.
+
+ [config]
+ ; configure conversion of CRLFs. "convert" means that all CRLFs
+ ; should be converted into LFs (suitable for the core.autocrlf
+ ; setting set to true in Git). "none" means that all data is
+ ; treated as binary.
+ crlf=convert
+
+=head2 Revision configuration
+
+Each revision that is to be imported is described in three
+sections. Revisions should be defined in topological order, so
+that a revision's parent has always been defined when a new revision
+is introduced. All the sections for one revision must be defined
+before defining the next revision.
+
+Each revision is assigned a unique numerical identifier. The
+numbers do not need to be consecutive, nor monotonically
+increasing.
+
+For instance, if your configuration file contains only the two
+revisions 4711 and 42, where 4711 is the initial commit, the
+only requirement is that 4711 is completely defined before 42.
+
+=pod
+
+=head3 Revision description section
+
+A section whose section name is just an integer gives meta-data
+about the revision.
+
+ [3]
+ ; author sets the author of the revisions
+ author=Peter Krefting <peter@softwolves.pp.se>
+ ; branch sets the branch that the revision should be committed to
+ branch=master
+ ; parent describes the revision that is the parent of this commit
+ ; (optional)
+ parent=1
+ ; merges describes a revision that is merged into this commit
+ ; (optional; can be repeated)
+ merges=2
+ ; selects one file to take the timestamp from
+ ; (optional; if unspecified, the most recent file from the .files
+ ; section is used)
+ timestamp=3/source.c
+
+=head3 Revision contents section
+
+A section whose section name is an integer followed by B<.files>
+describe all the files included in this revision. If a file that
+was available previously is not included in this revision, it will
+be removed.
+
+If an on-disk revision is incomplete, you can point to files from
+a previous revision. There are no restriction as to where the source
+files are located, nor to the names of them.
+
+ [3.files]
+ ; the key is the path inside the repository, the value is the path
+ ; as seen from the importer script.
+ source.c=ver-3.00/source.c
+ source.h=ver-2.99/source.h
+ readme.txt=ver-3.00/introduction to the project.txt
+
+File names are treated as byte strings (but please see below on
+quoting rules), and should be stored in the configuration file in
+the encoding that should be used in the generated repository.
+
+=head3 Revision commit message section
+
+A section whose section name is an integer followed by B<.message>
+gives the commit message. This section is read verbatim, up until
+the beginning of the next section. As such, a commit message may not
+contain a line that begins with an opening square bracket ("[") and
+ends with a closing square bracket ("]"), unless they are surrounded
+by whitespace or other characters.
+
+ [3.message]
+ Implement foobar.
+ ; trailing blank lines are ignored.
+
+=cut
+
+# Globals
+use strict;
+use integer;
+my $crlfmode = 0;
+my @revs;
+my (%revmap, %message, %files, %author, %branch, %parent, %merges, %time, %timesource);
+my $sectiontype = 0;
+my $rev = 0;
+my $mark = 1;
+
+# Check command line
+if ($#ARGV < 1 || $ARGV[0] =~ /^--?h/)
+{
+ exec('perldoc', $0);
+ exit 1;
+}
+
+# Open configuration
+my $config = $ARGV[0];
+open CFG, '<', $config or die "Cannot open configuration file \"$config\": ";
+
+# Open output
+my $output = $ARGV[1];
+open OUT, '>', $output or die "Cannot create output file \"$output\": ";
+binmode OUT;
+
+LINE: while (my $line = <CFG>)
+{
+ $line =~ s/\r?\n$//;
+ next LINE if $sectiontype != 4 && $line eq '';
+ next LINE if $line =~ /^;/;
+ my $oldsectiontype = $sectiontype;
+ my $oldrev = $rev;
+
+ # Sections
+ if ($line =~ m"^\[(config|(\d+)(|\.files|\.message))\]$")
+ {
+ if ($1 eq 'config')
+ {
+ $sectiontype = 1;
+ }
+ elsif ($3 eq '')
+ {
+ $sectiontype = 2;
+ $rev = $2;
+ # Create a new revision
+ die "Duplicate rev: $line\n " if defined $revmap{$rev};
+ print "Reading revision $rev\n";
+ push @revs, $rev;
+ $revmap{$rev} = $mark ++;
+ $time{$revmap{$rev}} = 0;
+ }
+ elsif ($3 eq '.files')
+ {
+ $sectiontype = 3;
+ $rev = $2;
+ die "Revision mismatch: $line\n " unless $rev == $oldrev;
+ }
+ elsif ($3 eq '.message')
+ {
+ $sectiontype = 4;
+ $rev = $2;
+ die "Revision mismatch: $line\n " unless $rev == $oldrev;
+ }
+ else
+ {
+ die "Internal parse error: $line\n ";
+ }
+ next LINE;
+ }
+
+ # Parse data
+ if ($sectiontype != 4)
+ {
+ # Key and value
+ if ($line =~ m"^\s*([^\s].*=.*[^\s])\s*$")
+ {
+ my ($key, $value) = &parsekeyvaluepair($1);
+ # Global configuration
+ if (1 == $sectiontype)
+ {
+ if ($key eq 'crlf')
+ {
+ $crlfmode = 1, next LINE if $value eq 'convert';
+ $crlfmode = 0, next LINE if $value eq 'none';
+ }
+ die "Unknown configuration option: $line\n ";
+ }
+ # Revision specification
+ if (2 == $sectiontype)
+ {
+ my $current = $revmap{$rev};
+ $author{$current} = $value, next LINE if $key eq 'author';
+ $branch{$current} = $value, next LINE if $key eq 'branch';
+ $parent{$current} = $value, next LINE if $key eq 'parent';
+ $timesource{$current} = $value, next LINE if $key eq 'timestamp';
+ push(@{$merges{$current}}, $value), next LINE if $key eq 'merges';
+ die "Unknown revision option: $line\n ";
+ }
+ # Filespecs
+ if (3 == $sectiontype)
+ {
+ # Add the file and create a marker
+ die "File not found: $line\n " unless -f $value;
+ my $current = $revmap{$rev};
+ ${$files{$current}}{$key} = $mark;
+ my $time = &fileblob($value, $crlfmode, $mark ++);
+
+ # Update revision timestamp if more recent than other
+ # files seen, or if this is the file we have selected
+ # to take the time stamp from using the "timestamp"
+ # directive.
+ if ((defined $timesource{$current} && $timesource{$current} eq $value)
+ || $time > $time{$current})
+ {
+ $time{$current} = $time;
+ }
+ }
+ }
+ else
+ {
+ die "Parse error: $line\n ";
+ }
+ }
+ else
+ {
+ # Commit message
+ my $current = $revmap{$rev};
+ if (defined $message{$current})
+ {
+ $message{$current} .= "\n";
+ }
+ $message{$current} .= $line;
+ }
+}
+close CFG;
+
+# Start spewing out data for git-fast-import
+foreach my $commit (@revs)
+{
+ # Progress
+ print OUT "progress Creating revision $commit\n";
+
+ # Create commit header
+ my $mark = $revmap{$commit};
+
+ # Branch and commit id
+ print OUT "commit refs/heads/", $branch{$mark}, "\nmark :", $mark, "\n";
+
+ # Author and timestamp
+ die "No timestamp defined for $commit (no files?)\n" unless defined $time{$mark};
+ print OUT "committer ", $author{$mark}, " ", $time{$mark}, " +0100\n";
+
+ # Commit message
+ die "No message defined for $commit\n" unless defined $message{$mark};
+ my $message = $message{$mark};
+ $message =~ s/\n$//; # Kill trailing empty line
+ print OUT "data ", length($message), "\n", $message, "\n";
+
+ # Parent and any merges
+ print OUT "from :", $revmap{$parent{$mark}}, "\n" if defined $parent{$mark};
+ if (defined $merges{$mark})
+ {
+ foreach my $merge (@{$merges{$mark}})
+ {
+ print OUT "merge :", $revmap{$merge}, "\n";
+ }
+ }
+
+ # Output file marks
+ print OUT "deleteall\n"; # start from scratch
+ foreach my $file (sort keys %{$files{$mark}})
+ {
+ print OUT "M 644 :", ${$files{$mark}}{$file}, " $file\n";
+ }
+ print OUT "\n";
+}
+
+# Create one file blob
+sub fileblob
+{
+ my ($filename, $crlfmode, $mark) = @_;
+
+ # Import the file
+ print OUT "progress Importing $filename\nblob\nmark :$mark\n";
+ open FILE, '<', $filename or die "Cannot read $filename\n ";
+ binmode FILE;
+ my ($size, $mtime) = (stat(FILE))[7,9];
+ my $file;
+ read FILE, $file, $size;
+ close FILE;
+ $file =~ s/\r\n/\n/g if $crlfmode;
+ print OUT "data ", length($file), "\n", $file, "\n";
+
+ return $mtime;
+}
+
+# Parse a key=value pair
+sub parsekeyvaluepair
+{
+=pod
+
+=head2 Escaping special characters
+
+Key and value strings may be enclosed in quotes, in which case
+whitespace inside the quotes is preserved. Additionally, an equal
+sign may be included in the key by preceeding it with a backslash.
+For example:
+
+ "key1 "=value1
+ key2=" value2"
+ key\=3=value3
+ key4=value=4
+ "key5""=value5
+
+Here the first key is "key1 " (note the trailing white-space) and the
+second value is " value2" (note the leading white-space). The third
+key contains an equal sign "key=3" and so does the fourth value, which
+does not need to be escaped. The fifth key contains a trailing quote,
+which does not need to be escaped since it is inside a surrounding
+quote.
+
+=cut
+ my $pair = shift;
+
+ # Separate key and value by the first non-quoted equal sign
+ my ($key, $value);
+ if ($pair =~ /^(.*[^\\])=(.*)$/)
+ {
+ ($key, $value) = ($1, $2)
+ }
+ else
+ {
+ die "Parse error: $pair\n ";
+ }
+
+ # Unquote and unescape the key and value separately
+ return (&unescape($key), &unescape($value));
+}
+
+# Unquote and unescape
+sub unescape
+{
+ my $string = shift;
+
+ # First remove enclosing quotes. Backslash before the trailing
+ # quote leaves both.
+ if ($string =~ /^"(.*[^\\])"$/)
+ {
+ $string = $1;
+ }
+
+ # Second remove any backslashes inside the unquoted string.
+ # For later: Handle special sequences like \t ?
+ $string =~ s/\\(.)/$1/g;
+
+ return $string;
+}
+
+__END__
+
+=pod
+
+=head1 EXAMPLES
+
+B<import-directories.perl> F<project.import>
+
+=head1 AUTHOR
+
+Copyright 2008-2009 Peter Krefting E<lt>peter@softwolves.pp.se>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation.
+
+=cut
--
1.6.3.3
^ permalink raw reply related
* [PATCH v5] import-tars: Allow per-tar author and commit message.
From: Peter Krefting @ 2009-09-03 12:15 UTC (permalink / raw)
To: git
If the "--metainfo=<ext>" option is given on the command line, a file
called "<filename.tar>.<ext>" will be used to create the commit message
for "<filename.tar>", instead of using "Imported from filename.tar".
The author and committer of the tar ball can also be overridden by
embedding an "Author:" or "Committer:" header in the metainfo file.
Signed-off-by: Peter Krefting <peter@softwolves.pp.se>
---
Fixed script to allow an empty line to stop parsing message for
header lines, and fixed indentation style to match the rest of the
script.
contrib/fast-import/import-tars.perl | 50 +++++++++++++++++++++++++++++++---
1 files changed, 46 insertions(+), 4 deletions(-)
diff --git a/contrib/fast-import/import-tars.perl b/contrib/fast-import/import-tars.perl
index 78e40d2..a909716 100755
--- a/contrib/fast-import/import-tars.perl
+++ b/contrib/fast-import/import-tars.perl
@@ -8,9 +8,20 @@
## perl import-tars.perl *.tar.bz2
## git whatchanged import-tars
##
+## Use --metainfo to specify the extension for a meta data file, where
+## import-tars can read the commit message and optionally author and
+## committer information.
+##
+## echo 'This is the commit message' > myfile.tar.bz2.msg
+## perl import-tars.perl --metainfo=msg myfile.tar.bz2
use strict;
-die "usage: import-tars *.tar.{gz,bz2,Z}\n" unless @ARGV;
+use Getopt::Long;
+
+my $metaext = '';
+
+die "usage: import-tars [--metainfo=extension] *.tar.{gz,bz2,Z}\n"
+ unless GetOptions('metainfo=s' => \$metaext) && @ARGV;
my $branch_name = 'import-tars';
my $branch_ref = "refs/heads/$branch_name";
@@ -109,12 +120,43 @@ foreach my $tar_file (@ARGV)
$have_top_dir = 0 if $top_dir ne $1;
}
+ my $commit_msg = "Imported from $tar_file.";
+ my $this_committer_name = $committer_name;
+ my $this_committer_email = $committer_email;
+ my $this_author_name = $author_name;
+ my $this_author_email = $author_email;
+ if ($metaext ne '') {
+ # Optionally read a commit message from <filename.tar>.msg
+ # Add a line on the form "Committer: name <e-mail>" to override
+ # the committer and "Author: name <e-mail>" to override the
+ # author for this tar ball.
+ if (open MSG, '<', "${tar_file}.${metaext}") {
+ my $header_done = 0;
+ $commit_msg = '';
+ while (<MSG>) {
+ if (!$header_done && /^Committer:\s+([^<>]*)\s+<(.*)>\s*$/i) {
+ $this_committer_name = $1;
+ $this_committer_email = $2;
+ } elsif (!$header_done && /^Author:\s+([^<>]*)\s+<(.*)>\s*$/i) {
+ $this_author_name = $1;
+ $this_author_email = $2;
+ } elsif (!$header_done && /^$/ { # empty line ends header.
+ $header_done = 1;
+ } else {
+ $commit_msg .= $_;
+ $header_done = 1;
+ }
+ }
+ close MSG;
+ }
+ }
+
print FI <<EOF;
commit $branch_ref
-author $author_name <$author_email> $author_time +0000
-committer $committer_name <$committer_email> $commit_time +0000
+author $this_author_name <$this_author_email> $author_time +0000
+committer $this_committer_name <$this_committer_email> $commit_time +0000
data <<END_OF_COMMIT_MESSAGE
-Imported from $tar_file.
+$commit_msg
END_OF_COMMIT_MESSAGE
deleteall
--
1.6.3.3
^ permalink raw reply related
* [PATCH] git-clone: add missing coma in --reference documentation
From: Miklos Vajna @ 2009-09-03 11:24 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
Documentation/git-clone.txt | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index b14de6c..87c13ab 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -76,7 +76,7 @@ then the cloned repository will become corrupt.
--reference <repository>::
- If the reference repository is on the local machine
+ If the reference repository is on the local machine,
automatically setup .git/objects/info/alternates to
obtain objects from the reference repository. Using
an already existing repository as an alternate will
--
1.6.4
^ permalink raw reply related
* Re: [JGIT PATCH 0/5] jgit diff
From: Johannes Schindelin @ 2009-09-03 10:48 UTC (permalink / raw)
To: git, spearce
In-Reply-To: <cover.1251974493u.git.johannes.schindelin@gmx.de>
Hi,
On Thu, 3 Sep 2009, Johannes Schindelin wrote:
> This patch series provides a rudimentary, working implementation of
> "jgit diff". It does not provide all modes of "git diff" -- by far! --
> but it is robust, and should provide a good starting point for further
> work.
I forgot to mention that this is rebased to current jgit.git's master (and
tested there, too; took 713 seconds on this here machine).
Ciao,
Dscho
^ permalink raw reply
* [JGIT PATCH 5/5] Add the "jgit diff" command
From: Johannes Schindelin @ 2009-09-03 10:47 UTC (permalink / raw)
To: git, spearce
In-Reply-To: <cover.1251974493u.git.johannes.schindelin@gmx.de>
This commit contains fixes provided by Christian Halstrick.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
.../services/org.spearce.jgit.pgm.TextBuiltin | 1 +
.../src/org/spearce/jgit/pgm/Diff.java | 133 ++++++++++++++++++++
.../src/org/spearce/jgit/diff/DiffFormatter.java | 2 +-
3 files changed, 135 insertions(+), 1 deletions(-)
create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Diff.java
diff --git a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
index 3a8cc09..107ef38 100644
--- a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
+++ b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
@@ -1,6 +1,7 @@
org.spearce.jgit.pgm.Branch
org.spearce.jgit.pgm.Clone
org.spearce.jgit.pgm.Daemon
+org.spearce.jgit.pgm.Diff
org.spearce.jgit.pgm.DiffTree
org.spearce.jgit.pgm.Fetch
org.spearce.jgit.pgm.Glog
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Diff.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Diff.java
new file mode 100644
index 0000000..56e352d
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Diff.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2009, Johannes E. Schindelin
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.pgm;
+
+import java.io.IOException;
+import java.io.PrintStream;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.ExampleMode;
+import org.kohsuke.args4j.Option;
+
+import org.spearce.jgit.diff.DiffFormatter;
+import org.spearce.jgit.diff.MyersDiff;
+import org.spearce.jgit.diff.RawText;
+
+import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.lib.FileMode;
+import org.spearce.jgit.lib.ObjectId;
+import org.spearce.jgit.lib.Ref;
+
+import org.spearce.jgit.pgm.opt.CmdLineParser;
+import org.spearce.jgit.pgm.opt.PathTreeFilterHandler;
+
+import org.spearce.jgit.treewalk.AbstractTreeIterator;
+import org.spearce.jgit.treewalk.TreeWalk;
+
+import org.spearce.jgit.treewalk.filter.AndTreeFilter;
+import org.spearce.jgit.treewalk.filter.TreeFilter;
+
+@Command(common = true, usage = "Show diffs")
+class Diff extends TextBuiltin {
+ @Argument(index = 0, metaVar = "tree-ish", required = true)
+ void tree_0(final AbstractTreeIterator c) {
+ trees.add(c);
+ }
+
+ @Argument(index = 1, metaVar = "tree-ish", required = true)
+ private final List<AbstractTreeIterator> trees = new ArrayList<AbstractTreeIterator>();
+
+ @Option(name = "--", metaVar = "path", multiValued = true, handler = PathTreeFilterHandler.class)
+ private TreeFilter pathFilter = TreeFilter.ALL;
+
+ private DiffFormatter fmt = new DiffFormatter();
+
+ @Override
+ protected void run() throws Exception {
+ final TreeWalk walk = new TreeWalk(db);
+ walk.reset();
+ walk.setRecursive(true);
+ for (final AbstractTreeIterator i : trees)
+ walk.addTree(i);
+ walk.setFilter(AndTreeFilter.create(TreeFilter.ANY_DIFF, pathFilter));
+
+ final int nTree = walk.getTreeCount();
+ while (walk.next())
+ outputDiff(System.out, walk.getPathString(),
+ walk.getObjectId(0), walk.getFileMode(0),
+ walk.getObjectId(1), walk.getFileMode(1));
+ }
+
+ protected void outputDiff(PrintStream out, String path,
+ ObjectId id1, FileMode mode1, ObjectId id2, FileMode mode2) throws IOException {
+ String name1 = "a/" + path;
+ String name2 = "b/" + path;
+ out.println("diff --git " + name1 + " " + name2);
+ boolean isNew=false;
+ boolean isDelete=false;
+ if (id1.equals(id1.zeroId())) {
+ out.println("new file mode " + mode2);
+ isNew=true;
+ } else if (id2.equals(id2.zeroId())) {
+ out.println("deleted file mode " + mode1);
+ isDelete=true;
+ } else if (!mode1.equals(mode2)) {
+ out.println("old mode " + mode1);
+ out.println("new mode " + mode2);
+ }
+ out.println("index " + id1.abbreviate(db, 7).name()
+ + ".." + id2.abbreviate(db, 7).name()
+ + (mode1.equals(mode2) ? " " + mode1 : ""));
+ out.println("--- " + (isNew ? "/dev/null" : name1));
+ out.println("+++ " + (isDelete ? "/dev/null" : name2));
+ RawText a = getRawText(id1);
+ RawText b = getRawText(id2);
+ MyersDiff diff = new MyersDiff(a, b);
+ fmt.formatEdits(out, a, b, diff.getEdits());
+ }
+
+ private RawText getRawText(ObjectId id) throws IOException {
+ if (id.equals(id.zeroId()))
+ return new RawText(new byte[] { });
+ return new RawText(db.openBlob(id).getCachedBytes());
+ }
+}
+
diff --git a/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java b/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java
index fa86737..fda3f4c 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java
@@ -108,7 +108,7 @@ public void format(final OutputStream out, final FileHeader head,
formatEdits(out, a, b, head.toEditList());
}
- private void formatEdits(final OutputStream out, final RawText a,
+ public void formatEdits(final OutputStream out, final RawText a,
final RawText b, final EditList edits) throws IOException {
for (int curIdx = 0; curIdx < edits.size();) {
Edit curEdit = edits.get(curIdx);
--
1.6.4.297.gcb4cc
^ permalink raw reply related
* [JGIT PATCH 4/5] Prepare RawText for diff-index and diff-files
From: Johannes Schindelin @ 2009-09-03 10:47 UTC (permalink / raw)
To: git, spearce
In-Reply-To: <cover.1251974493u.git.johannes.schindelin@gmx.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
.../src/org/spearce/jgit/diff/RawText.java | 28 +++++++++++++++++++-
1 files changed, 27 insertions(+), 1 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java b/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java
index 9886d36..15d1c12 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java
@@ -38,6 +38,8 @@
package org.spearce.jgit.diff;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -81,6 +83,18 @@ public RawText(final byte[] input) {
hashes = computeHashes();
}
+ /**
+ * Create a new sequence from a file.
+ * <p>
+ * The entire file contents are used.
+ *
+ * @param file
+ * the text file.
+ */
+ public RawText(File file) throws IOException {
+ this(readFile(file));
+ }
+
public int size() {
// The line map is always 2 entries larger than the number of lines in
// the file. Index 0 is padded out/unused. The last index is the total
@@ -181,4 +195,16 @@ protected int hashLine(final byte[] raw, int ptr, final int end) {
hash = (hash << 5) ^ (raw[ptr] & 0xff);
return hash;
}
-}
\ No newline at end of file
+
+ private static byte[] readFile(File file) throws IOException {
+ byte[] result = new byte[(int)file.length()];
+ FileInputStream in = new FileInputStream(file);
+ for (int off = 0; off < result.length; ) {
+ int read = in.read(result, off, result.length - off);
+ if (read < 0)
+ throw new IOException("Early EOF");
+ off += read;
+ }
+ return result;
+ }
+}
--
1.6.4.297.gcb4cc
^ permalink raw reply related
* [JGIT PATCH 3/5] Add a test class for Myers' diff algorithm
From: Johannes Schindelin @ 2009-09-03 10:46 UTC (permalink / raw)
To: git, spearce
In-Reply-To: <cover.1251974493u.git.johannes.schindelin@gmx.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
.../tst/org/spearce/jgit/diff/MyersDiffTest.java | 103 ++++++++++++++++++++
1 files changed, 103 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/diff/MyersDiffTest.java
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/diff/MyersDiffTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/diff/MyersDiffTest.java
new file mode 100644
index 0000000..0d62790
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/diff/MyersDiffTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2009, Johannes E. Schindelin
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.diff;
+
+import junit.framework.TestCase;
+
+public class MyersDiffTest extends TestCase {
+ public void testAtEnd() {
+ assertDiff("HELLO", "HELL", " -4,1 +4,0");
+ }
+
+ public void testAtStart() {
+ assertDiff("Git", "JGit", " -0,0 +0,1");
+ }
+
+ public void testSimple() {
+ assertDiff("HELLO WORLD", "LOW",
+ " -0,3 +0,0 -5,1 +2,0 -7,4 +3,0");
+ // is ambiguous, could be this, too:
+ // " -0,2 +0,0 -3,1 +1,0 -5,1 +2,0 -7,4 +3,0"
+ }
+
+ public void assertDiff(String a, String b, String edits) {
+ MyersDiff diff = new MyersDiff(toCharArray(a), toCharArray(b));
+System.err.println("edits: " + diff.getEdits());
+ assertEquals(edits, toString(diff.getEdits()));
+ }
+
+ private static String toString(EditList list) {
+ StringBuilder builder = new StringBuilder();
+ for (Edit e : list)
+ builder.append(" -" + e.beginA
+ + "," + (e.endA - e.beginA)
+ + " +" + e.beginB + "," + (e.endB - e.beginB));
+ return builder.toString();
+ }
+
+ private static CharArray toCharArray(String s) {
+ return new CharArray(s);
+ }
+
+ protected static String toString(Sequence seq, int begin, int end) {
+ CharArray a = (CharArray)seq;
+ return new String(a.array, begin, end - begin);
+ }
+
+ protected static String toString(CharArray a, CharArray b,
+ int x, int k) {
+ return "(" + x + "," + (k + x)
+ + (x < 0 ? '<' :
+ (x >= a.array.length ?
+ '>' : a.array[x]))
+ + (k + x < 0 ? '<' :
+ (k + x >= b.array.length ?
+ '>' : b.array[k + x]))
+ + ")";
+ }
+
+ private static class CharArray implements Sequence {
+ char[] array;
+ public CharArray(String s) { array = s.toCharArray(); }
+ public int size() { return array.length; }
+ public boolean equals(int i, Sequence other, int j) {
+ CharArray o = (CharArray)other;
+ return array[i] == o.array[j];
+ }
+ }
+}
--
1.6.4.297.gcb4cc
^ permalink raw reply related
* [JGIT PATCH 2/5] Add Myers' algorithm to generate diff scripts
From: Johannes Schindelin @ 2009-09-03 10:46 UTC (permalink / raw)
To: git, spearce
In-Reply-To: <cover.1251974493u.git.johannes.schindelin@gmx.de>
Myers' algorithm is the standard way to generate diff scripts in an
efficient manner (especially memory-wise).
The source contains extensive documentation about the principal
ideas of the algorithm.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
.../src/org/spearce/jgit/diff/MyersDiff.java | 515 ++++++++++++++++++++
1 files changed, 515 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/MyersDiff.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/diff/MyersDiff.java b/org.spearce.jgit/src/org/spearce/jgit/diff/MyersDiff.java
new file mode 100644
index 0000000..e19cea4
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/diff/MyersDiff.java
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2008-2009 Johannes E. Schindelin <johannes.schindelin@gmx.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Diff algorithm, based on "An O(ND) Difference Algorithm and its
+ * Variations", by Eugene Myers.
+ *
+ * The basic idea is to put the line numbers of text A as columns ("x") and the
+ * lines of text B as rows ("y"). Now you try to find the shortest "edit path"
+ * from the upper left corner to the lower right corner, where you can
+ * always go horizontally or vertically, but diagonally from (x,y) to
+ * (x+1,y+1) only if line x in text A is identical to line y in text B.
+ *
+ * Myers' fundamental concept is the "furthest reaching D-path on diagonal k":
+ * a D-path is an edit path starting at the upper left corner and containing
+ * exactly D non-diagonal elements ("differences"). The furthest reaching
+ * D-path on diagonal k is the one that contains the most (diagonal) elements
+ * which ends on diagonal k (where k = y - x).
+ *
+ * Example:
+ *
+ * H E L L O W O R L D
+ * ____
+ * L \___
+ * O \___
+ * W \________
+ *
+ * Since every D-path has exactly D horizontal or vertical elements, it can
+ * only end on the diagonals -D, -D+2, ..., D-2, D.
+ *
+ * Since every furthest reaching D-path contains at least one furthest
+ * reaching (D-1)-path (except for D=0), we can construct them recursively.
+ *
+ * Since we are really interested in the shortest edit path, we can start
+ * looking for a 0-path, then a 1-path, and so on, until we find a path that
+ * ends in the lower right corner.
+ *
+ * To save space, we do not need to store all paths (which has quadratic space
+ * requirements), but generate the D-paths simultaneously from both sides.
+ * When the ends meet, we will have found "the middle" of the path. From the
+ * end points of that diagonal part, we can generate the rest recursively.
+ *
+ * This only requires linear space.
+ *
+ * The overall (runtime) complexity is
+ *
+ * O(N * D^2 + 2 * N/2 * (D/2)^2 + 4 * N/4 * (D/4)^2 + ...)
+ * = O(N * D^2 * 5 / 4) = O(N * D^2),
+ *
+ * (With each step, we have to find the middle parts of twice as many regions
+ * as before, but the regions (as well as the D) are halved.)
+ *
+ * So the overall runtime complexity stays the same with linear space,
+ * albeit with a larger constant factor.
+ */
+
+package org.spearce.jgit.diff;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spearce.jgit.util.IntList;
+
+public class MyersDiff {
+ protected EditList edits;
+ protected Sequence a, b;
+
+ public MyersDiff(Sequence a, Sequence b) {
+ this.a = a;
+ this.b = b;
+ calculateEdits();
+ }
+
+ public EditList getEdits() {
+ return edits;
+ }
+
+ // TODO: use ThreadLocal for future multi-threaded operations
+ MiddleEdit middle = new MiddleEdit();
+
+ protected void calculateEdits() {
+ edits = new EditList();
+
+ middle.initialize(0, a.size(), 0, b.size());
+ if (middle.beginA >= middle.endA &&
+ middle.beginB >= middle.endB)
+ return;
+
+ calculateEdits(middle.beginA, middle.endA,
+ middle.beginB, middle.endB);
+ }
+
+ protected void calculateEdits(int beginA, int endA,
+ int beginB, int endB) {
+ Edit edit = middle.calculate(beginA, endA, beginB, endB);
+
+ if (beginA < edit.beginA || beginB < edit.beginB) {
+ int k = edit.beginB - edit.beginA;
+ int x = middle.backward.snake(k, edit.beginA);
+ calculateEdits(beginA, x, beginB, k + x);
+ }
+
+ if (edit.getType() != Edit.Type.EMPTY)
+ edits.add(edits.size(), edit);
+
+ // after middle
+ if (endA > edit.endA || endB > edit.endB) {
+ int k = edit.endB - edit.endA;
+ int x = middle.forward.snake(k, edit.endA);
+ calculateEdits(x, endA, k + x, endB);
+ }
+ }
+
+ /**
+ * A class to help bisecting the sequences a and b to find minimal
+ * edit paths.
+ *
+ * As the arrays are reused for space efficiency, you will need one
+ * instance per thread.
+ *
+ * The entry function is the calculate() method.
+ */
+ class MiddleEdit {
+ void initialize(int beginA, int endA, int beginB, int endB) {
+ this.beginA = beginA; this.endA = endA;
+ this.beginB = beginB; this.endB = endB;
+
+ // strip common parts on either end
+ int k = beginB - beginA;
+ this.beginA = forward.snake(k, beginA);
+ this.beginB = k + this.beginA;
+
+ k = endB - endA;
+ this.endA = backward.snake(k, endA);
+ this.endB = k + this.endA;
+ }
+
+ /*
+ * This function calculates the "middle" Edit of the shortest
+ * edit path between the given subsequences of a and b.
+ *
+ * Once a forward path and a backward path meet, we found the
+ * middle part. From the last snake end point on both of them,
+ * we construct the Edit.
+ *
+ * It is assumed that there is at least one edit in the range.
+ */
+ // TODO: measure speed impact when this is synchronized
+ Edit calculate(int beginA, int endA, int beginB, int endB) {
+ if (beginA == endA || beginB == endB)
+ return new Edit(beginA, endA, beginB, endB);
+ this.beginA = beginA; this.endA = endA;
+ this.beginB = beginB; this.endB = endB;
+
+ /*
+ * Following the conventions in Myers' paper, "k" is
+ * the difference between the index into "b" and the
+ * index into "a".
+ */
+ int minK = beginB - endA;
+ int maxK = endB - beginA;
+
+ forward.initialize(beginB - beginA, beginA, minK, maxK);
+ backward.initialize(endB - endA, endA, minK, maxK);
+
+ for (int d = 1; ; d++)
+ if (forward.calculate(d) ||
+ backward.calculate(d))
+ return edit;
+ }
+
+ /*
+ * For each d, we need to hold the d-paths for the diagonals
+ * k = -d, -d + 2, ..., d - 2, d. These are stored in the
+ * forward (and backward) array.
+ *
+ * As we allow subsequences, too, this needs some refinement:
+ * the forward paths start on the diagonal forwardK =
+ * beginB - beginA, and backward paths start on the diagonal
+ * backwardK = endB - endA.
+ *
+ * So, we need to hold the forward d-paths for the diagonals
+ * k = forwardK - d, forwardK - d + 2, ..., forwardK + d and
+ * the analogue for the backward d-paths. This means that
+ * we can turn (k, d) into the forward array index using this
+ * formula:
+ *
+ * i = (d + k - forwardK) / 2
+ *
+ * There is a further complication: the edit paths should not
+ * leave the specified subsequences, so k is bounded by
+ * minK = beginB - endA and maxK = endB - beginA. However,
+ * (k - forwardK) _must_ be odd whenever d is odd, and it
+ * _must_ be even when d is even.
+ *
+ * The values in the "forward" and "backward" arrays are
+ * positions ("x") in the sequence a, to get the corresponding
+ * positions ("y") in the sequence b, you have to calculate
+ * the appropriate k and then y:
+ *
+ * k = forwardK - d + i * 2
+ * y = k + x
+ *
+ * (substitute backwardK for forwardK if you want to get the
+ * y position for an entry in the "backward" array.
+ */
+ EditPaths forward = new ForwardEditPaths();
+ EditPaths backward = new BackwardEditPaths();
+
+ /* Some variables which are shared between methods */
+ protected int beginA, endA, beginB, endB;
+ protected Edit edit;
+
+ abstract class EditPaths {
+ private IntList x = new IntList();
+ private IntList snake = new IntList();
+ int beginK, endK, middleK;
+ int prevBeginK, prevEndK;
+ /* if we hit one end early, no need to look further */
+ int minK, maxK; // TODO: better explanation
+
+ final int getIndex(int d, int k) {
+// TODO: remove
+if (((d + k - middleK) % 2) == 1)
+ throw new RuntimeException("odd: " + d + " + " + k + " - " + middleK);
+ return (d + k - middleK) / 2;
+ }
+
+ final int getX(int d, int k) {
+// TODO: remove
+if (k < beginK || k > endK)
+ throw new RuntimeException("k " + k + " not in " + beginK + " - " + endK);
+ return x.get(getIndex(d, k));
+ }
+
+ final int getSnake(int d, int k) {
+// TODO: remove
+if (k < beginK || k > endK)
+ throw new RuntimeException("k " + k + " not in " + beginK + " - " + endK);
+ return snake.get(getIndex(d, k));
+ }
+
+ private int forceKIntoRange(int k) {
+ /* if k is odd, so must be the result */
+ if (k < minK)
+ return minK + ((k ^ minK) & 1);
+ else if (k > maxK)
+ return maxK - ((k ^ maxK) & 1);
+ return k;
+ }
+
+ void initialize(int k, int x, int minK, int maxK) {
+ this.minK = minK;
+ this.maxK = maxK;
+ beginK = endK = middleK = k;
+ this.x.clear();
+ this.x.add(x);
+ snake.clear();
+ snake.add(newSnake(k, x));
+ }
+
+ abstract int snake(int k, int x);
+ abstract int getLeft(int x);
+ abstract int getRight(int x);
+ abstract boolean isBetter(int left, int right);
+ abstract void adjustMinMaxK(final int k, final int x);
+ abstract boolean meets(int d, int k, int x, int snake);
+
+ final int newSnake(int k, int x) {
+ int y = k + x;
+ return x + (endA + 1) * y;
+ }
+
+ final int snake2x(int snake) {
+ return snake % (endA + 1);
+ }
+
+ final int snake2y(int snake) {
+ return snake / (endA + 1);
+ }
+
+ final boolean makeEdit(int snake1, int snake2) {
+ int x1 = snake2x(snake1), x2 = snake2x(snake2);
+ int y1 = snake2y(snake1), y2 = snake2y(snake2);
+ /*
+ * Check for incompatible partial edit paths:
+ * when there are ambiguities, we might have
+ * hit incompatible (i.e. non-overlapping)
+ * forward/backward paths.
+ *
+ * In that case, just pretend that we have
+ * an empty edit at the end of one snake; this
+ * will force a decision which path to take
+ * in the next recursion step.
+ */
+ if (x1 > x2 || y1 > y2) {
+ x1 = x2;
+ y1 = y2;
+ }
+ edit = new Edit(x1, x2, y1, y2);
+ return true;
+ }
+
+ boolean calculate(int d) {
+ prevBeginK = beginK;
+ prevEndK = endK;
+ beginK = forceKIntoRange(middleK - d);
+ endK = forceKIntoRange(middleK + d);
+ // TODO: handle i more efficiently
+ // TODO: walk snake(k, getX(d, k)) only once per (d, k)
+ // TODO: move end points out of the loop to avoid conditionals inside the loop
+ // go backwards so that we can avoid temp vars
+ for (int k = endK; k >= beginK; k -= 2) {
+ int left = -1, right = -1;
+ int leftSnake = -1, rightSnake = -1;
+ // TODO: refactor into its own function
+ if (k > prevBeginK) {
+ int i = getIndex(d - 1, k - 1);
+ left = x.get(i);
+ int end = snake(k - 1, left);
+ leftSnake = left != end ?
+ newSnake(k - 1, end) :
+ snake.get(i);
+ if (meets(d, k - 1, end, leftSnake))
+ return true;
+ left = getLeft(end);
+ }
+ if (k < prevEndK) {
+ int i = getIndex(d - 1, k + 1);
+ right = x.get(i);
+ int end = snake(k + 1, right);
+ rightSnake = right != end ?
+ newSnake(k + 1, end) :
+ snake.get(i);
+ if (meets(d, k + 1, end, rightSnake))
+ return true;
+ right = getRight(end);
+ }
+ int newX, newSnake;
+ if (k >= prevEndK ||
+ (k > prevBeginK &&
+ isBetter(left, right))) {
+ newX = left;
+ newSnake = leftSnake;
+ }
+ else {
+ newX = right;
+ newSnake = rightSnake;
+ }
+ if (meets(d, k, newX, newSnake))
+ return true;
+ adjustMinMaxK(k, newX);
+ int i = getIndex(d, k);
+ x.set(i, newX);
+ snake.set(i, newSnake);
+ }
+ return false;
+ }
+ }
+
+ class ForwardEditPaths extends EditPaths {
+ final int snake(int k, int x) {
+ for (; x < endA && k + x < endB; x++)
+ if (!a.equals(x, b, k + x))
+ break;
+ return x;
+ }
+
+ final int getLeft(final int x) {
+ return x;
+ }
+
+ final int getRight(final int x) {
+ return x + 1;
+ }
+
+ final boolean isBetter(final int left, final int right) {
+ return left > right;
+ }
+
+ final void adjustMinMaxK(final int k, final int x) {
+ if (x >= endA || k + x >= endB) {
+ if (k > backward.middleK)
+ maxK = k;
+ else
+ minK = k;
+ }
+ }
+
+ final boolean meets(int d, int k, int x, int snake) {
+ if (k < backward.beginK || k > backward.endK)
+ return false;
+ // TODO: move out of loop
+ if (((d - 1 + k - backward.middleK) % 2) == 1)
+ return false;
+ if (x < backward.getX(d - 1, k))
+ return false;
+ makeEdit(snake, backward.getSnake(d - 1, k));
+ return true;
+ }
+ }
+
+ class BackwardEditPaths extends EditPaths {
+ final int snake(int k, int x) {
+ for (; x > beginA && k + x > beginB; x--)
+ if (!a.equals(x - 1, b, k + x - 1))
+ break;
+ return x;
+ }
+
+ final int getLeft(final int x) {
+ return x - 1;
+ }
+
+ final int getRight(final int x) {
+ return x;
+ }
+
+ final boolean isBetter(final int left, final int right) {
+ return left < right;
+ }
+
+ final void adjustMinMaxK(final int k, final int x) {
+ if (x <= beginA || k + x <= beginB) {
+ if (k > forward.middleK)
+ maxK = k;
+ else
+ minK = k;
+ }
+ }
+
+ final boolean meets(int d, int k, int x, int snake) {
+ if (k < forward.beginK || k > forward.endK)
+ return false;
+ // TODO: move out of loop
+ if (((d + k - forward.middleK) % 2) == 1)
+ return false;
+ if (x > forward.getX(d, k))
+ return false;
+ makeEdit(forward.getSnake(d, k), snake);
+ return true;
+ }
+ }
+ }
+
+ // debugging (TODO: remove)
+ public void print(Sequence s, int begin, int end) {
+ RawText raw = (RawText)s;
+ try {
+ while (begin < end) {
+ System.err.print("" + begin + ": ");
+ raw.writeLine(System.err, begin++);
+ System.err.println("");
+ }
+ } catch (Exception e) { e.printStackTrace(); }
+ }
+
+ public void print(int beginA, int endA, int beginB, int endB) {
+ System.err.println("<<<<<<");
+ print(a, beginA, endA);
+ System.err.println("======");
+ print(b, beginB, endB);
+ System.err.println(">>>>>>");
+ }
+
+ public static void main(String[] args) {
+ if (args.length != 2) {
+ System.err.println("Need 2 arguments");
+ System.exit(1);
+ }
+ try {
+ RawText a = new RawText(new java.io.File(args[0]));
+ RawText b = new RawText(new java.io.File(args[1]));
+ MyersDiff diff = new MyersDiff(a, b);
+ System.out.println(diff.getEdits().toString());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
--
1.6.4.297.gcb4cc
^ permalink raw reply related
* [JGIT PATCH 1/5] Add set to IntList
From: Johannes Schindelin @ 2009-09-03 10:46 UTC (permalink / raw)
To: git, spearce
In-Reply-To: <cover.1251974493u.git.johannes.schindelin@gmx.de>
Some applications may wish to modify an int list.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
.../tst/org/spearce/jgit/util/IntListTest.java | 21 ++++++++++++++++++++
.../src/org/spearce/jgit/util/IntList.java | 17 ++++++++++++++++
2 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/util/IntListTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/util/IntListTest.java
index c470d55..a7a12cd 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/util/IntListTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/util/IntListTest.java
@@ -144,6 +144,27 @@ public void testClear() {
}
}
+ public void testSet() {
+ final IntList i = new IntList();
+ i.add(1);
+ assertEquals(1, i.size());
+ assertEquals(1, i.get(0));
+
+ i.set(0, 5);
+ assertEquals(5, i.get(0));
+
+ try {
+ i.set(5, 5);
+ fail("accepted set of 5 beyond end of list");
+ } catch (ArrayIndexOutOfBoundsException e){
+ assertTrue(true);
+ }
+
+ i.set(1, 2);
+ assertEquals(2, i.size());
+ assertEquals(2, i.get(1));
+ }
+
public void testToString() {
final IntList i = new IntList();
i.add(1);
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/IntList.java b/org.spearce.jgit/src/org/spearce/jgit/util/IntList.java
index 0a84793..32d24fc 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/IntList.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/IntList.java
@@ -94,6 +94,23 @@ public void add(final int n) {
}
/**
+ * Assign an entry in the list.
+ *
+ * @param index
+ * index to set, must be in the range [0, {@link #size()}).
+ * @param n
+ * value to store at the position.
+ */
+ public void set(final int index, final int n) {
+ if (count < index)
+ throw new ArrayIndexOutOfBoundsException(index);
+ else if (count == index)
+ add(n);
+ else
+ entries[index] = n;
+ }
+
+ /**
* Pad the list with entries.
*
* @param toIndex
--
1.6.4.297.gcb4cc
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox