Git development
 help / color / mirror / Atom feed
* Re: [PATCH] Provide a way to flush git-diff-tree's output
From: Paul Mackerras @ 2006-05-18  9:43 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vmzdf6bj5.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano writes:

> Sounds low impact and sane.
> 
> I suspect the usual caveat on bidirectional pipe deadlock
> applies to the caller.  Does gitk do that?  The current code

Gitk will use non-blocking mode on the pipes to/from the git-diff-tree
process, so there isn't a possibility of deadlock that I can see.

> seems to feed a pre-generated list with "open | cmd <<"
> construct to the command, so perhaps you are planning to change
> that?

That's for the "Find" function.  I'm in the process of adding the code
to let users enter a list of paths and have gitk highlight the commits
affecting those paths.  That will involve a separate invocation of
git-diff-tree.  To make it responsive, I'm only going to ask
git-diff-tree about the commits that are visible on the screen - but I
need git-diff-tree to give me an answer quickly, i.e. in less time
than a human can perceive.

Thanks,
Paul.

^ permalink raw reply

* Re: Shipping man pages?
From: Mark Rosenstand @ 2006-05-18  9:41 UTC (permalink / raw)
  To: git
In-Reply-To: <7vac9f69la.fsf@assigned-by-dhcp.cox.net>

On Thu, 2006-05-18 at 01:06 -0700, Junio C Hamano wrote:
> Tilman Sauerbeck <tilman@code-monkey.de> writes:
> 
> > atm, the git release tarballs don't contain man pages.
> 
> I ship *source* tarball.

Which is great for generating binaries and other things that are likely
to be incompatible across systems.

> I also happen to do RPM for people who do not want to build from
> the source (btw, I do that from pure inertia). In addition,
> preformatted manual pages and html docs are available from man
> and html branches of the git.git repository.
> 
> If you are building from the source, please build from the
> source.  Everything you need is right there.

But asciidoc is a royal PITA to package or install - it doesn't even
provide a Makefile: http://www.methods.co.nz/asciidoc/userguide.html#X38

Additionally it carries the whole docbook dependency chain with it.

> If you don't build from the source, please use whatever binary
> distribution available out there.  RPM happens to be available
> from kernel.org.  If you are on Debian/Ubuntu/Gentoo/others,
> please ask your distribution packager to include the manpages
> and html docs, if they don't already.

Even the packagers are likely to hate the unneccessary asciidoc
dependency. As a result some of the small distributions that don't have
the manpower to support 1000+ packages choose to ship git without the
man pages, which is a shame, IMO.

> Why does this have to come up so often, and everybody who asks
> for them never supplies the patch to do so?

Because it seems like a political decision rather than a technical one
(it's trivial to add the docs as a prerequisite for the dist target.)

> > Or maybe offer them in a separate tarball?
> 
> Things that are buildable from the source do not belong in the
> source tarball.  If somebody wants to do this as a patch, I can
> be talked into accepting it, but the build procedure should
> build a separate tarball (or two; one for man and another for
> woman^Whtml).

That would be great! I'd love to submit a patch, but I wouldn't be able
to test it, because I'd need asciidoc.

^ permalink raw reply

* Re: cvsimport weird
From: Bertrand Jacquin @ 2006-05-18  9:33 UTC (permalink / raw)
  To: Pavel Roskin; +Cc: Martin Langhoff, Git Mailing List
In-Reply-To: <1147931094.32050.51.camel@dv>

On 5/18/06, Pavel Roskin <proski@gnu.org> wrote:
> On Wed, 2006-05-17 at 23:59 -0400, Pavel Roskin wrote:
> > I'm quite sure that it's a bug in cvsps.  It displays such things on
> > x86_64, but works properly on 32-bit PowerPC.
>
> Address resolution is broken in cvsps on 64-bit machines.  This patch to
> cvsps is needed:

Ah Thanks, I'm running it on a x86_64.

-- 
Beber
#e.fr@freenode

^ permalink raw reply

* [WARNING] Please be careful when using "git add" from "next" branch
From: Junio C Hamano @ 2006-05-18  8:52 UTC (permalink / raw)
  To: git; +Cc: linux-kernel
In-Reply-To: <7vwtcj4tp6.fsf@assigned-by-dhcp.cox.net>

There is still a small breakage in the built-in "git add" on the
"next" branch that ends up creating nonsense tree objects.

        $ mkdir foo
        $ date >bar
        $ git-add foo/../bar
        $ git ls-files
        foo/../bar
        $ git ls-tree -r -t $(git-write-tree)
        040000 tree ef5562cd3a9bf66d41a8d4f42f159e8c694ce7e3	foo
        040000 tree 6e1612248e8da43fc5f91592e559da1ad5f9a852	foo/..
        100644 blob 53ab446c3f4e42ce9bb728a0ccb283a101be4979	foo/../bar

If you do not do funky things like foo/../bar, I do not think
you have to worry, but scripted use might break.  It used to
warn and ignore such bogus input, but now it happily accepts it
and produces bogus index which results in bogus trees.

"git update-index --add" is not affected by this breakage.

^ permalink raw reply

* Re: Do "git add" as a builtin
From: Junio C Hamano @ 2006-05-18  8:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7v64k3698l.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> writes:

> Linus Torvalds <torvalds@osdl.org> writes:
>
>> On Wed, 17 May 2006, Junio C Hamano wrote:
>>> 
>>> By "not seeing the point", do you mean you do not agree with
>>> what bba319b5 and 45e48120 tried to do to help users?
>>
>> Naah, I just didn't see why, and didn't bother to go exploring.
>>
>> How about this patch on top of the previous one?
>
> Well, not good as-is.  This makes it barf on this sequence:
>...

Ouch, things are worse than I thought...

	$ mkdir foo
        $ date >bar
        $ git-add foo/../bar
	$ git ls-files
        foo/../bar

Huh?

^ permalink raw reply

* Re: Fwd: [OT] Re: Git via a proxy server?
From: Jan-Benedict Glaw @ 2006-05-18  8:31 UTC (permalink / raw)
  To: Sam Song; +Cc: Petr Vandrovec, git
In-Reply-To: <20060518034428.42456.qmail@web32002.mail.mud.yahoo.com>

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

On Wed, 2006-05-17 20:44:28 -0700, Sam Song <samlinuxkernel@yahoo.com> wrote:
> Petr Vandrovec <petr@vmware.com> wrote:
> > Jan-Benedict Glaw <jbglaw@lug-owl.de> wrote:
> > > Well, install some package to have `socket'
> > > available? Debian calls
> > > the packet `socket', too, so I guess Fedora may
> > > have something similar.
> > 
> > Surprisingly they do not...  You should be able to
> > replace 'socket' with 
> > 'netcat' - and I believe that netcat/nc package is
> > available for Fedora.  For 
> > this purpose they have same command line & behavior.
> 
> Ummm, I am trying on that. nc is avaiable for Fedora.
> But what could be the replacement for CONNECT in
> Fedora? :-)

Erm, you haven't understood what you're doing there, have you?

With the GIT_PROXY_COMMAND helper, you're expected to create a clean
tunnel which in turn git can use to transfer its data.

You've only got some limited internet connectivity via a HTTP proxy
available, so you need to use this. This means:

  * The proxy administrator needs to allos outgoing connections for
    the CONNECT method with git's TCP port.
  * You need to have some minimalistic program to initially speak HTTP
    with the proxy and later on just stream the raw git protocol
    through the link.
  * You may or may not need to strip anything that came into the git
    stream by accident because you tunnled it through a HTTP proxy. A
    reply message from the proxy server is an example for this.

So this little script (using "CONNECT" and netcat or socket) does the
first part: it talks in the language HTTP with the proxy server. It
may be enough to just use CONNECT, but you may need to speak some more
lines, eg. for proxy authorization.

The first `cat' in there is just for pushing the git protocol though the
HTTP proxy connection later on (hopefully after the proxy was made to
accept the the CONNECT request.)  Once the proxy accepted it, it'll
send you a HTTP/200 message (or something like that) and an empty
line. This is what the two reads are for; the next `cat' simply again
transfers all the rest (the git protocol).

To draw the line, there's not _one_ solution to HTTP proxy tunneling,
there are many, and you'll need to design one that fits your network.
It should be quite simple, given that you've got nice tools like
`strace' and `tcpdump', which will help you to understand how the
proxy reacts and so on.

MfG, JBG

-- 
Jan-Benedict Glaw       jbglaw@lug-owl.de    . +49-172-7608481             _ O _
"Eine Freie Meinung in  einem Freien Kopf    | Gegen Zensur | Gegen Krieg  _ _ O
 für einen Freien Staat voll Freier Bürger"  | im Internet! |   im Irak!   O O O
ret = do_actions((curr | FREE_SPEECH) & ~(NEW_COPYRIGHT_LAW | DRM | TCPA));

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

^ permalink raw reply

* Re: Do "git add" as a builtin
From: Junio C Hamano @ 2006-05-18  8:13 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0605171321020.10823@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> On Wed, 17 May 2006, Junio C Hamano wrote:
>> 
>> By "not seeing the point", do you mean you do not agree with
>> what bba319b5 and 45e48120 tried to do to help users?
>
> Naah, I just didn't see why, and didn't bother to go exploring.
>
> How about this patch on top of the previous one?

Well, not good as-is.  This makes it barf on this sequence:

	$ rm -f junk
        $ cd junk
        $ git init-db
        $ date >frotz
        $ mkdir nitfol
        $ date >nitfol/rezrov
	$ git add .		;# OK up to this point - added everything.

	$ git add .		;# This is bogus because...
        fatal: pathspec '' did not match any files
	$ git add nitfol	;# ...this does not barf.

I admit I did not spot it when I read the code, but this part
gets an empty string for 'match' when pathspec is '.'.

> +		/* Existing file? We must have ignored it */
> +		match = pathspec[i];
> +		if (!lstat(match, &st))
> +			continue;
> +		die("pathspec '%s' did not match any files", match);

That's why '.' barfs but nitfol doesn't.

^ permalink raw reply

* Re: Shipping man pages?
From: Fernando J. Pereda @ 2006-05-18  8:10 UTC (permalink / raw)
  To: Tilman Sauerbeck; +Cc: git
In-Reply-To: <20060518074630.GA2994@code-monkey.de>

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

On Thu, May 18, 2006 at 09:46:32AM +0200, Tilman Sauerbeck wrote:
> Hi,
> atm, the git release tarballs don't contain man pages. They can be
> generated from the asciidoc source files, which makes the build depend
> on python and asciidoc.
> 
> That's *very* inconvenient; would it be possible to include the man
> pages in the release tarball?
> 
> Or maybe offer them in a separate tarball?

Hi Tilman,

Actually Junio has 'html' and 'man' branches in his git.git repository
so you just have to use git tar-tree on them.

I do this for the Gentoo packages, you can grab a tarball from any of
our mirrors, the files are called git-{html,man}-VERSION.tar.bz2

- ferdy

-- 
Fernando J. Pereda Garcimartín
Gentoo Developer (Alpha,net-mail,mutt,git)
20BB BDC3 761A 4781 E6ED  ED0B 0A48 5B0C 60BD 28D4

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

^ permalink raw reply

* Re: Shipping man pages?
From: Junio C Hamano @ 2006-05-18  8:06 UTC (permalink / raw)
  To: Tilman Sauerbeck; +Cc: git
In-Reply-To: <20060518074630.GA2994@code-monkey.de>

Tilman Sauerbeck <tilman@code-monkey.de> writes:

> atm, the git release tarballs don't contain man pages.

I ship *source* tarball.

I also happen to do RPM for people who do not want to build from
the source (btw, I do that from pure inertia). In addition,
preformatted manual pages and html docs are available from man
and html branches of the git.git repository.

If you are building from the source, please build from the
source.  Everything you need is right there.

If you don't build from the source, please use whatever binary
distribution available out there.  RPM happens to be available
from kernel.org.  If you are on Debian/Ubuntu/Gentoo/others,
please ask your distribution packager to include the manpages
and html docs, if they don't already.

Why does this have to come up so often, and everybody who asks
for them never supplies the patch to do so?

> Or maybe offer them in a separate tarball?

Things that are buildable from the source do not belong in the
source tarball.  If somebody wants to do this as a patch, I can
be talked into accepting it, but the build procedure should
build a separate tarball (or two; one for man and another for
woman^Whtml).

^ permalink raw reply

* Shipping man pages?
From: Tilman Sauerbeck @ 2006-05-18  7:46 UTC (permalink / raw)
  To: git

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

Hi,
atm, the git release tarballs don't contain man pages. They can be
generated from the asciidoc source files, which makes the build depend
on python and asciidoc.

That's *very* inconvenient; would it be possible to include the man
pages in the release tarball?

Or maybe offer them in a separate tarball?

Thanks,
Tilman

-- 
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

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

^ permalink raw reply

* Re: [PATCH] Provide a way to flush git-diff-tree's output
From: Junio C Hamano @ 2006-05-18  7:24 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: git
In-Reply-To: <17516.6955.282732.460675@cargo.ozlabs.ibm.com>

Paul Mackerras <paulus@samba.org> writes:

> The --stdin flag to git-diff-tree is suitable for this, but the main
> difficulty is that the output of git-diff-tree gets buffered and
> doesn't get sent until the buffer is full.
>
> This provides a way to get git-diff-tree to flush its output buffers.
> If a blank line is supplied on git-diff-tree's standard input, it will
> flush its output buffers and then accept further input.

Sounds low impact and sane.

I suspect the usual caveat on bidirectional pipe deadlock
applies to the caller.  Does gitk do that?  The current code
seems to feed a pre-generated list with "open | cmd <<"
construct to the command, so perhaps you are planning to change
that?

^ permalink raw reply

* [PATCH] Provide a way to flush git-diff-tree's output
From: Paul Mackerras @ 2006-05-18  6:58 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Gitk wants to use git-diff-tree as a filter to tell it which ids from
a given list affect a set of files or directories.  We don't want to
fork and exec a new git-diff-tree process for each batch of ids, since
there could be a lot of relatively small batches.  For example, a
batch could contain as many ids as fit in gitk's headline display
window, i.e. 20 or so, and we would be processing a new batch every
time the user scrolls that window.

The --stdin flag to git-diff-tree is suitable for this, but the main
difficulty is that the output of git-diff-tree gets buffered and
doesn't get sent until the buffer is full.

This provides a way to get git-diff-tree to flush its output buffers.
If a blank line is supplied on git-diff-tree's standard input, it will
flush its output buffers and then accept further input.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
diff --git a/diff-tree.c b/diff-tree.c
index 7207867..69bb74b 100644
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -138,7 +138,10 @@ int main(int argc, const char **argv)
 		opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
 				       DIFF_SETUP_USE_CACHE);
 	while (fgets(line, sizeof(line), stdin))
-		diff_tree_stdin(line);
+		if (line[0] == '\n')
+			fflush(stdout);
+		else
+			diff_tree_stdin(line);
 
 	return 0;
 }

^ permalink raw reply related

* [PATCH] Handle branch names with slashes
From: Karl Hasselström @ 2006-05-18  6:50 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Catalin Marinas
In-Reply-To: <20060518064214.GA10390@backpacker.hemma.treskal.com>

Teach stgit to handle branch names with slashes in them; that is,
branches living in a subdirectory of .git/refs/heads.

I had to change the patch@branch/top command-line syntax to
patch@branch//top, in order to get sane parsing. The /top variant is
still available for repositories that have no slashy branches; it is
disabled as soon as there exists at least one subdirectory of
refs/heads. Preferably, this compatibility hack can be killed some
time in the future.

Signed-off-by: Karl Hasselström <kha@treskal.com>


---

Oh yeah, remember to change % to // in the commit comment as well . . .

Catalin, I hope you're paying attention when trying to pick the
correct three patches out of the salvos I've sent you. :-)

 stgit/commands/branch.py |    5 ++
 stgit/commands/common.py |  108 +++++++++++++++++++++++++++-------------------
 stgit/commands/diff.py   |   16 ++++---
 stgit/commands/files.py  |    4 +-
 stgit/commands/id.py     |    2 -
 stgit/commands/mail.py   |    8 ++-
 stgit/git.py             |   42 +++++++++---------
 stgit/stack.py           |   21 ++++++---
 stgit/utils.py           |   88 +++++++++++++++++++++++++++++++++++--
 9 files changed, 202 insertions(+), 92 deletions(-)

4ce56cd9e2d39f3a98b6dd010d11beb6037f8ff3
diff --git a/stgit/commands/branch.py b/stgit/commands/branch.py
index 2218bbb..d348409 100644
--- a/stgit/commands/branch.py
+++ b/stgit/commands/branch.py
@@ -172,7 +172,10 @@ def func(parser, options, args):
         if len(args) != 0:
             parser.error('incorrect number of arguments')
 
-        branches = os.listdir(os.path.join(basedir.get(), 'refs', 'heads'))
+        branches = []
+        basepath = os.path.join(basedir.get(), 'refs', 'heads')
+        for path, files, dirs in walk_tree(basepath):
+            branches += [os.path.join(path, f) for f in files]
         branches.sort()
 
         if branches:
diff --git a/stgit/commands/common.py b/stgit/commands/common.py
index c6ca514..93344aa 100644
--- a/stgit/commands/common.py
+++ b/stgit/commands/common.py
@@ -18,7 +18,7 @@ along with this program; if not, write t
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
-import sys, os, re
+import sys, os, os.path, re
 from optparse import OptionParser, make_option
 
 from stgit.utils import *
@@ -34,54 +34,74 @@ class CmdException(Exception):
 
 
 # Utility functions
+class RevParseException(Exception):
+    """Revision spec parse error."""
+    pass
+
+def parse_rev(rev):
+    """Parse a revision specification into its
+    patchname@branchname//patch_id parts. If no branch name has a slash
+    in it, also accept / instead of //."""
+    files, dirs = list_files_and_dirs(os.path.join(basedir.get(),
+                                                   'refs', 'heads'))
+    if len(dirs) != 0:
+        # We have branch names with / in them.
+        branch_chars = r'[^@]'
+        patch_id_mark = r'//'
+    else:
+        # No / in branch names.
+        branch_chars = r'[^@%/]'
+        patch_id_mark = r'(/|//)'
+    patch_re = r'(?P<patch>[^@/]+)'
+    branch_re = r'@(?P<branch>%s+)' % branch_chars
+    patch_id_re = r'%s(?P<patch_id>[a-z.]*)' % patch_id_mark
+
+    # Try //patch_id.
+    m = re.match(r'^%s$' % patch_id_re, rev)
+    if m:
+        return None, None, m.group('patch_id')
+
+    # Try path[@branch]//patch_id.
+    m = re.match(r'^%s(%s)?%s$' % (patch_re, branch_re, patch_id_re), rev)
+    if m:
+        return m.group('patch'), m.group('branch'), m.group('patch_id')
+
+    # Try patch[@branch].
+    m = re.match(r'^%s(%s)?$' % (patch_re, branch_re), rev)
+    if m:
+        return m.group('patch'), m.group('branch'), None
+
+    # No, we can't parse that.
+    raise RevParseException
+
 def git_id(rev):
     """Return the GIT id
     """
     if not rev:
         return None
-    
-    rev_list = rev.split('/')
-    if len(rev_list) == 2:
-        patch_id = rev_list[1]
-        if not patch_id:
-            patch_id = 'top'
-    elif len(rev_list) == 1:
-        patch_id = 'top'
-    else:
-        patch_id = None
-
-    patch_branch = rev_list[0].split('@')
-    if len(patch_branch) == 1:
-        series = crt_series
-    elif len(patch_branch) == 2:
-        series = stack.Series(patch_branch[1])
-    else:
-        raise CmdException, 'Unknown id: %s' % rev
-
-    patch_name = patch_branch[0]
-    if not patch_name:
-        patch_name = series.get_current()
-        if not patch_name:
-            raise CmdException, 'No patches applied'
-
-    # patch
-    if patch_name in series.get_applied() \
-           or patch_name in series.get_unapplied():
-        if patch_id == 'top':
-            return series.get_patch(patch_name).get_top()
-        elif patch_id == 'bottom':
-            return series.get_patch(patch_name).get_bottom()
-        # Note we can return None here.
-        elif patch_id == 'top.old':
-            return series.get_patch(patch_name).get_old_top()
-        elif patch_id == 'bottom.old':
-            return series.get_patch(patch_name).get_old_bottom()
-
-    # base
-    if patch_name == 'base' and len(rev_list) == 1:
-        return read_string(series.get_base_file())
-
-    # anything else failed
+    try:
+        patch, branch, patch_id = parse_rev(rev)
+        if branch == None:
+            series = crt_series
+        else:
+            series = stack.Series(branch)
+        if patch == None:
+            patch = series.get_current()
+            if not patch:
+                raise CmdException, 'No patches applied'
+        if patch in series.get_applied() or patch in series.get_unapplied():
+            if patch_id in ['top', '', None]:
+                return series.get_patch(patch).get_top()
+            elif patch_id == 'bottom':
+                return series.get_patch(patch).get_bottom()
+            elif patch_id == 'top.old':
+                return series.get_patch(patch).get_old_top()
+            elif patch_id == 'bottom.old':
+                return series.get_patch(patch).get_old_bottom()
+        if patch == 'base' and patch_id == None:
+            return read_string(series.get_base_file())
+    except RevParseException:
+        pass
     return git.rev_parse(rev + '^{commit}')
 
 def check_local_changes():
diff --git a/stgit/commands/diff.py b/stgit/commands/diff.py
index 7dc6c5d..d765784 100644
--- a/stgit/commands/diff.py
+++ b/stgit/commands/diff.py
@@ -33,12 +33,12 @@ or a tree-ish object and another tree-is
 be given to restrict the diff output. The tree-ish object can be a
 standard git commit, tag or tree. In addition to these, the command
 also supports 'base', representing the bottom of the current stack,
-and '[patch]/[bottom | top]' for the patch boundaries (defaulting to
+and '[patch][//[bottom | top]]' for the patch boundaries (defaulting to
 the current one):
 
-rev = '([patch]/[bottom | top]) | <tree-ish> | base'
+rev = '([patch][//[bottom | top]]) | <tree-ish> | base'
 
-If neither bottom or top are given but a '/' is present, the command
+If neither bottom nor top are given but a '//' is present, the command
 shows the specified patch (defaulting to the current one)."""
 
 options = [make_option('-r', metavar = 'rev1[:[rev2]]', dest = 'revs',
@@ -55,10 +55,14 @@ def func(parser, options, args):
         rev_list = options.revs.split(':')
         rev_list_len = len(rev_list)
         if rev_list_len == 1:
-            if rev_list[0][-1] == '/':
+            rev = rev_list[0]
+            if rev[-1] == '/':
                 # the whole patch
-                rev1 = rev_list[0] + 'bottom'
-                rev2 = rev_list[0] + 'top'
+                rev = rev[:-1]
+                if rev[-1] == '/':
+                    rev = rev[:-1]
+                rev1 = rev + '//bottom'
+                rev2 = rev + '//top'
             else:
                 rev1 = rev_list[0]
                 rev2 = None
diff --git a/stgit/commands/files.py b/stgit/commands/files.py
index 0694d83..b33bd2a 100644
--- a/stgit/commands/files.py
+++ b/stgit/commands/files.py
@@ -53,8 +53,8 @@ def func(parser, options, args):
     else:
         parser.error('incorrect number of arguments')
 
-    rev1 = git_id('%s/bottom' % patch)
-    rev2 = git_id('%s/top' % patch)
+    rev1 = git_id('%s//bottom' % patch)
+    rev2 = git_id('%s//top' % patch)
 
     if options.stat:
         print git.diffstat(rev1 = rev1, rev2 = rev2)
diff --git a/stgit/commands/id.py b/stgit/commands/id.py
index 1cf6ea6..284589a 100644
--- a/stgit/commands/id.py
+++ b/stgit/commands/id.py
@@ -28,7 +28,7 @@ usage = """%prog [options] [id]
 
 Print the hash value of a GIT id (defaulting to HEAD). In addition to
 the standard GIT id's like heads and tags, this command also accepts
-'base[@<branch>]' and '[<patch>[@<branch>]][/(bottom | top)]'. If no
+'base[@<branch>]' and '[<patch>[@<branch>]][//[bottom | top]]'. If no
 'top' or 'bottom' are passed and <patch> is a valid patch name, 'top'
 will be used by default."""
 
diff --git a/stgit/commands/mail.py b/stgit/commands/mail.py
index 5e01ea1..3928b81 100644
--- a/stgit/commands/mail.py
+++ b/stgit/commands/mail.py
@@ -324,10 +324,10 @@ def __build_message(tmpl, patch, patch_n
                  'shortdescr':   short_descr,
                  'longdescr':    long_descr,
                  'endofheaders': headers_end,
-                 'diff':         git.diff(rev1 = git_id('%s/bottom' % patch),
-                                          rev2 = git_id('%s/top' % patch)),
-                 'diffstat':     git.diffstat(rev1 = git_id('%s/bottom'%patch),
-                                              rev2 = git_id('%s/top' % patch)),
+                 'diff':         git.diff(rev1 = git_id('%s//bottom' % patch),
+                                          rev2 = git_id('%s//top' % patch)),
+                 'diffstat':     git.diffstat(rev1 = git_id('%s//bottom'%patch),
+                                              rev2 = git_id('%s//top' % patch)),
                  'date':         email.Utils.formatdate(localtime = True),
                  'version':      version_str,
                  'patchnr':      patch_nr_str,
diff --git a/stgit/git.py b/stgit/git.py
index 2884f36..716609c 100644
--- a/stgit/git.py
+++ b/stgit/git.py
@@ -225,7 +225,8 @@ def get_head():
 def get_head_file():
     """Returns the name of the file pointed to by the HEAD link
     """
-    return os.path.basename(_output_one_line('git-symbolic-ref HEAD'))
+    return strip_prefix('refs/heads/',
+                        _output_one_line('git-symbolic-ref HEAD'))
 
 def set_head_file(ref):
     """Resets HEAD to point to a new ref
@@ -233,7 +234,8 @@ def set_head_file(ref):
     # head cache flushing is needed since we might have a different value
     # in the new head
     __clear_head_cache()
-    if __run('git-symbolic-ref HEAD', [ref]) != 0:
+    if __run('git-symbolic-ref HEAD',
+             [os.path.join('refs', 'heads', ref)]) != 0:
         raise GitException, 'Could not set head to "%s"' % ref
 
 def __set_head(val):
@@ -272,6 +274,7 @@ def rev_parse(git_id):
 def branch_exists(branch):
     """Existence check for the named branch
     """
+    branch = os.path.join('refs', 'heads', branch)
     for line in _output_lines('git-rev-parse --symbolic --all 2>&1'):
         if line.strip() == branch:
             return True
@@ -282,12 +285,11 @@ def branch_exists(branch):
 def create_branch(new_branch, tree_id = None):
     """Create a new branch in the git repository
     """
-    new_head = os.path.join('refs', 'heads', new_branch)
-    if branch_exists(new_head):
+    if branch_exists(new_branch):
         raise GitException, 'Branch "%s" already exists' % new_branch
 
     current_head = get_head()
-    set_head_file(new_head)
+    set_head_file(new_branch)
     __set_head(current_head)
 
     # a checkout isn't needed if new branch points to the current head
@@ -297,22 +299,22 @@ def create_branch(new_branch, tree_id = 
     if os.path.isfile(os.path.join(basedir.get(), 'MERGE_HEAD')):
         os.remove(os.path.join(basedir.get(), 'MERGE_HEAD'))
 
-def switch_branch(name):
+def switch_branch(new_branch):
     """Switch to a git branch
     """
     global __head
 
-    new_head = os.path.join('refs', 'heads', name)
-    if not branch_exists(new_head):
-        raise GitException, 'Branch "%s" does not exist' % name
+    if not branch_exists(new_branch):
+        raise GitException, 'Branch "%s" does not exist' % new_branch
 
-    tree_id = rev_parse(new_head + '^{commit}')
+    tree_id = rev_parse(os.path.join('refs', 'heads', new_branch)
+                        + '^{commit}')
     if tree_id != get_head():
         refresh_index()
         if __run('git-read-tree -u -m', [get_head(), tree_id]) != 0:
             raise GitException, 'git-read-tree failed (local changes maybe?)'
         __head = tree_id
-    set_head_file(new_head)
+    set_head_file(new_branch)
 
     if os.path.isfile(os.path.join(basedir.get(), 'MERGE_HEAD')):
         os.remove(os.path.join(basedir.get(), 'MERGE_HEAD'))
@@ -320,25 +322,23 @@ def switch_branch(name):
 def delete_branch(name):
     """Delete a git branch
     """
-    branch_head = os.path.join('refs', 'heads', name)
-    if not branch_exists(branch_head):
+    if not branch_exists(name):
         raise GitException, 'Branch "%s" does not exist' % name
-    os.remove(os.path.join(basedir.get(), branch_head))
+    remove_file_and_dirs(os.path.join(basedir.get(), 'refs', 'heads'),
+                         name)
 
 def rename_branch(from_name, to_name):
     """Rename a git branch
     """
-    from_head = os.path.join('refs', 'heads', from_name)
-    if not branch_exists(from_head):
+    if not branch_exists(from_name):
         raise GitException, 'Branch "%s" does not exist' % from_name
-    to_head = os.path.join('refs', 'heads', to_name)
-    if branch_exists(to_head):
+    if branch_exists(to_name):
         raise GitException, 'Branch "%s" already exists' % to_name
 
     if get_head_file() == from_name:
-        set_head_file(to_head)
-    os.rename(os.path.join(basedir.get(), from_head), \
-              os.path.join(basedir.get(), to_head))
+        set_head_file(to_name)
+    rename(os.path.join(basedir.get(), 'refs', 'heads'),
+           from_name, to_name)
 
 def add(names):
     """Add the files or recursively add the directory contents
diff --git a/stgit/stack.py b/stgit/stack.py
index f83161b..49b50e7 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -443,8 +443,7 @@ class Series:
 
         os.makedirs(self.__patch_dir)
 
-        if not os.path.isdir(bases_dir):
-            os.makedirs(bases_dir)
+        create_dirs(bases_dir)
 
         create_empty_file(self.__applied_file)
         create_empty_file(self.__unapplied_file)
@@ -502,11 +501,14 @@ class Series:
         git.rename_branch(self.__name, to_name)
 
         if os.path.isdir(self.__series_dir):
-            os.rename(self.__series_dir, to_stack.__series_dir)
+            rename(os.path.join(self.__base_dir, 'patches'),
+                   self.__name, to_stack.__name)
         if os.path.exists(self.__base_file):
-            os.rename(self.__base_file, to_stack.__base_file)
+            rename(os.path.join(self.__base_dir, 'refs', 'bases'),
+                   self.__name, to_stack.__name)
         if os.path.exists(self.__refs_dir):
-            os.rename(self.__refs_dir, to_stack.__refs_dir)
+            rename(os.path.join(self.__base_dir, 'refs', 'patches'),
+                   self.__name, to_stack.__name)
 
         self.__init__(to_name)
 
@@ -560,16 +562,19 @@ class Series:
             else:
                 print 'Patch directory %s is not empty.' % self.__name
             if not os.listdir(self.__series_dir):
-                os.rmdir(self.__series_dir)
+                remove_dirs(os.path.join(self.__base_dir, 'patches'),
+                            self.__name)
             else:
                 print 'Series directory %s is not empty.' % self.__name
             if not os.listdir(self.__refs_dir):
-                os.rmdir(self.__refs_dir)
+                remove_dirs(os.path.join(self.__base_dir, 'refs', 'patches'),
+                            self.__name)
             else:
                 print 'Refs directory %s is not empty.' % self.__refs_dir
 
         if os.path.exists(self.__base_file):
-            os.remove(self.__base_file)
+            remove_file_and_dirs(
+                os.path.join(self.__base_dir, 'refs', 'bases'), self.__name)
 
     def refresh_patch(self, files = None, message = None, edit = False,
                       show_patch = False,
diff --git a/stgit/utils.py b/stgit/utils.py
index 5749b3b..68b8f58 100644
--- a/stgit/utils.py
+++ b/stgit/utils.py
@@ -1,6 +1,8 @@
 """Common utility functions
 """
 
+import errno, os, os.path
+
 __copyright__ = """
 Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
 
@@ -18,6 +20,12 @@ along with this program; if not, write t
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
+def mkdir_file(filename, mode):
+    """Opens filename with the given mode, creating the directory it's
+    in if it doesn't already exist."""
+    create_dirs(os.path.dirname(filename))
+    return file(filename, mode)
+
 def read_string(filename, multiline = False):
     """Reads the first line from a file
     """
@@ -32,7 +40,7 @@ def read_string(filename, multiline = Fa
 def write_string(filename, line, multiline = False):
     """Writes 'line' to file and truncates it
     """
-    f = file(filename, 'w+')
+    f = mkdir_file(filename, 'w+')
     if multiline:
         f.write(line)
     else:
@@ -42,7 +50,7 @@ def write_string(filename, line, multili
 def append_strings(filename, lines):
     """Appends 'lines' sequence to file
     """
-    f = file(filename, 'a+')
+    f = mkdir_file(filename, 'a+')
     for line in lines:
         print >> f, line
     f.close()
@@ -50,14 +58,14 @@ def append_strings(filename, lines):
 def append_string(filename, line):
     """Appends 'line' to file
     """
-    f = file(filename, 'a+')
+    f = mkdir_file(filename, 'a+')
     print >> f, line
     f.close()
 
 def insert_string(filename, line):
     """Inserts 'line' at the beginning of the file
     """
-    f = file(filename, 'r+')
+    f = mkdir_file(filename, 'r+')
     lines = f.readlines()
     f.seek(0); f.truncate()
     print >> f, line
@@ -67,4 +75,74 @@ def insert_string(filename, line):
 def create_empty_file(name):
     """Creates an empty file
     """
-    file(name, 'w+').close()
+    mkdir_file(name, 'w+').close()
+
+def list_files_and_dirs(path):
+    """Return the sets of filenames and directory names in a
+    directory."""
+    files, dirs = [], []
+    for fd in os.listdir(path):
+        full_fd = os.path.join(path, fd)
+        if os.path.isfile(full_fd):
+            files.append(fd)
+        elif os.path.isdir(full_fd):
+            dirs.append(fd)
+    return files, dirs
+
+def walk_tree(basedir):
+    """Starting in the given directory, iterate through all its
+    subdirectories. For each subdirectory, yield the name of the
+    subdirectory (relative to the base directory), the list of
+    filenames in the subdirectory, and the list of directory names in
+    the subdirectory."""
+    subdirs = ['']
+    while subdirs:
+        subdir = subdirs.pop()
+        files, dirs = list_files_and_dirs(os.path.join(basedir, subdir))
+        for d in dirs:
+            subdirs.append(os.path.join(subdir, d))
+        yield subdir, files, dirs
+
+def strip_prefix(prefix, string):
+    """Return string, without the prefix. Blow up if string doesn't
+    start with prefix."""
+    assert string.startswith(prefix)
+    return string[len(prefix):]
+
+def remove_dirs(basedir, dirs):
+    """Starting at join(basedir, dirs), remove the directory if empty,
+    and try the same with its parent, until we find a nonempty
+    directory or reach basedir."""
+    path = dirs
+    while path:
+        try:
+            os.rmdir(os.path.join(basedir, path))
+        except OSError:
+            return # can't remove nonempty directory
+        path = os.path.dirname(path)
+
+def remove_file_and_dirs(basedir, file):
+    """Remove join(basedir, file), and then remove the directory it
+    was in if empty, and try the same with its parent, until we find a
+    nonempty directory or reach basedir."""
+    os.remove(os.path.join(basedir, file))
+    remove_dirs(basedir, os.path.dirname(file))
+
+def create_dirs(directory):
+    """Create the given directory, if the path doesn't already exist."""
+    if directory:
+        create_dirs(os.path.dirname(directory))
+        try:
+            os.mkdir(directory)
+        except OSError, e:
+            if e.errno != errno.EEXIST:
+                raise e
+
+def rename(basedir, file1, file2):
+    """Rename join(basedir, file1) to join(basedir, file2), not
+    leaving any empty directories behind and creating any directories
+    necessary."""
+    full_file2 = os.path.join(basedir, file2)
+    create_dirs(os.path.dirname(full_file2))
+    os.rename(os.path.join(basedir, file1), full_file2)
+    remove_dirs(basedir, os.path.dirname(file1))
-- 
1.3.2.g639c


-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply related

* Re: Necessity of "evil" merge and topic branches
From: Junio C Hamano @ 2006-05-18  6:44 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7vy7wz6e8c.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> writes:

> Now, unlike "pu", I never rewind "next", so once I did this
> "evil merge", I do not have to worry about this anymore while
> the topic is still on "next".

Side note.  If an evil merge or other hand resolution needs to
be done on a path that results in automerge conflicts, rerere
often helps.  I really should start advertising it a bit more.

Unfortunatly, rerere does not even kick in in this case.

^ permalink raw reply

* [PATCH 2/2] Tests for branch names with slashes
From: Karl Hasselström @ 2006-05-18  6:43 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Catalin Marinas
In-Reply-To: <20060516074504.GA27234@diana.vm.bytemark.co.uk>

Test a number of operations on a repository that has branch names
containing slashes (that is, branches living in a subdirectory of
.git/refs/heads).

Signed-off-by: Karl Hasselström <kha@treskal.com>


---

 t/t0001-subdir-branches.sh |   59 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 59 insertions(+), 0 deletions(-)
 create mode 100644 t/t0001-subdir-branches.sh

d54c84917b40b1e8b05081f0c063fd99b2bbb1ad
diff --git a/t/t0001-subdir-branches.sh b/t/t0001-subdir-branches.sh
new file mode 100644
index 0000000..ddde238
--- /dev/null
+++ b/t/t0001-subdir-branches.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Karl Hasselström
+#
+
+test_description='Branch names containing slashes
+
+Test a number of operations on a repository that has branch names
+containing slashes (that is, branches living in a subdirectory of
+.git/refs/heads).'
+
+. ./test-lib.sh
+
+test_expect_success 'Create a patch' \
+  'stg init &&
+   echo "foo" > foo.txt &&
+   stg add foo.txt &&
+   stg new foo -m "Add foo.txt" &&
+   stg refresh'
+
+test_expect_success 'Old and new id with non-slashy branch' \
+  'stg id foo &&
+   stg id foo// &&
+   stg id foo/ &&
+   stg id foo//top &&
+   stg id foo/top &&
+   stg id foo@master &&
+   stg id foo@master//top &&
+   stg id foo@master/top'
+
+test_expect_success 'Clone branch to slashier name' \
+  'stg branch --clone x/y/z'
+
+test_expect_success 'Try new form of id with slashy branch' \
+  'stg id foo &&
+   stg id foo// &&
+   stg id foo//top &&
+   stg id foo@x/y/z &&
+   stg id foo@x/y/z//top'
+
+test_expect_failure 'Try old id with slashy branch' \
+  'stg id foo/ ||
+   stg id foo/top ||
+   stg id foo@x/y/z/top'
+
+test_expect_success 'Create patch in slashy branch' \
+  'echo "bar" >> foo.txt &&
+   stg new bar -m "Add another line" &&
+   stg refresh'
+
+test_expect_success 'Rename branches' \
+  'stg branch --rename master goo/gaa &&
+   test ! -e .git/refs/heads/master &&
+   stg branch --rename goo/gaa x1/x2/x3/x4 &&
+   test ! -e .git/refs/heads/goo &&
+   stg branch --rename x1/x2/x3/x4 servant &&
+   test ! -e .git/refs/heads/x1'
+
+test_done
-- 
1.3.2.g639c


-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply related

* [PATCH 1/2] Handle branch names with slashes
From: Karl Hasselström @ 2006-05-18  6:42 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Catalin Marinas
In-Reply-To: <20060516074504.GA27234@diana.vm.bytemark.co.uk>

Teach stgit to handle branch names with slashes in them; that is,
branches living in a subdirectory of .git/refs/heads.

I had to change the patch@branch/top command-line syntax to
patch@branch%top, in order to get sane parsing. The /top variant is
still available for repositories that have no slashy branches; it is
disabled as soon as there exists at least one subdirectory of
refs/heads. Preferably, this compatibility hack can be killed some
time in the future.

Signed-off-by: Karl Hasselström <kha@treskal.com>


---

 stgit/commands/branch.py |    5 ++
 stgit/commands/common.py |  108 +++++++++++++++++++++++++++-------------------
 stgit/commands/diff.py   |   16 ++++---
 stgit/commands/files.py  |    4 +-
 stgit/commands/id.py     |    2 -
 stgit/commands/mail.py   |    8 ++-
 stgit/git.py             |   42 +++++++++---------
 stgit/stack.py           |   21 ++++++---
 stgit/utils.py           |   88 +++++++++++++++++++++++++++++++++++--
 9 files changed, 202 insertions(+), 92 deletions(-)

fb5b39c8867474f4b23f0b52c4090c76aee6b1e8
diff --git a/stgit/commands/branch.py b/stgit/commands/branch.py
index 2218bbb..d348409 100644
--- a/stgit/commands/branch.py
+++ b/stgit/commands/branch.py
@@ -172,7 +172,10 @@ def func(parser, options, args):
         if len(args) != 0:
             parser.error('incorrect number of arguments')
 
-        branches = os.listdir(os.path.join(basedir.get(), 'refs', 'heads'))
+        branches = []
+        basepath = os.path.join(basedir.get(), 'refs', 'heads')
+        for path, files, dirs in walk_tree(basepath):
+            branches += [os.path.join(path, f) for f in files]
         branches.sort()
 
         if branches:
diff --git a/stgit/commands/common.py b/stgit/commands/common.py
index c6ca514..93344aa 100644
--- a/stgit/commands/common.py
+++ b/stgit/commands/common.py
@@ -18,7 +18,7 @@ along with this program; if not, write t
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
-import sys, os, re
+import sys, os, os.path, re
 from optparse import OptionParser, make_option
 
 from stgit.utils import *
@@ -34,54 +34,74 @@ class CmdException(Exception):
 
 
 # Utility functions
+class RevParseException(Exception):
+    """Revision spec parse error."""
+    pass
+
+def parse_rev(rev):
+    """Parse a revision specification into its
+    patchname@branchname//patch_id parts. If no branch name has a slash
+    in it, also accept / instead of //."""
+    files, dirs = list_files_and_dirs(os.path.join(basedir.get(),
+                                                   'refs', 'heads'))
+    if len(dirs) != 0:
+        # We have branch names with / in them.
+        branch_chars = r'[^@]'
+        patch_id_mark = r'//'
+    else:
+        # No / in branch names.
+        branch_chars = r'[^@%/]'
+        patch_id_mark = r'(/|//)'
+    patch_re = r'(?P<patch>[^@/]+)'
+    branch_re = r'@(?P<branch>%s+)' % branch_chars
+    patch_id_re = r'%s(?P<patch_id>[a-z.]*)' % patch_id_mark
+
+    # Try //patch_id.
+    m = re.match(r'^%s$' % patch_id_re, rev)
+    if m:
+        return None, None, m.group('patch_id')
+
+    # Try path[@branch]//patch_id.
+    m = re.match(r'^%s(%s)?%s$' % (patch_re, branch_re, patch_id_re), rev)
+    if m:
+        return m.group('patch'), m.group('branch'), m.group('patch_id')
+
+    # Try patch[@branch].
+    m = re.match(r'^%s(%s)?$' % (patch_re, branch_re), rev)
+    if m:
+        return m.group('patch'), m.group('branch'), None
+
+    # No, we can't parse that.
+    raise RevParseException
+
 def git_id(rev):
     """Return the GIT id
     """
     if not rev:
         return None
-    
-    rev_list = rev.split('/')
-    if len(rev_list) == 2:
-        patch_id = rev_list[1]
-        if not patch_id:
-            patch_id = 'top'
-    elif len(rev_list) == 1:
-        patch_id = 'top'
-    else:
-        patch_id = None
-
-    patch_branch = rev_list[0].split('@')
-    if len(patch_branch) == 1:
-        series = crt_series
-    elif len(patch_branch) == 2:
-        series = stack.Series(patch_branch[1])
-    else:
-        raise CmdException, 'Unknown id: %s' % rev
-
-    patch_name = patch_branch[0]
-    if not patch_name:
-        patch_name = series.get_current()
-        if not patch_name:
-            raise CmdException, 'No patches applied'
-
-    # patch
-    if patch_name in series.get_applied() \
-           or patch_name in series.get_unapplied():
-        if patch_id == 'top':
-            return series.get_patch(patch_name).get_top()
-        elif patch_id == 'bottom':
-            return series.get_patch(patch_name).get_bottom()
-        # Note we can return None here.
-        elif patch_id == 'top.old':
-            return series.get_patch(patch_name).get_old_top()
-        elif patch_id == 'bottom.old':
-            return series.get_patch(patch_name).get_old_bottom()
-
-    # base
-    if patch_name == 'base' and len(rev_list) == 1:
-        return read_string(series.get_base_file())
-
-    # anything else failed
+    try:
+        patch, branch, patch_id = parse_rev(rev)
+        if branch == None:
+            series = crt_series
+        else:
+            series = stack.Series(branch)
+        if patch == None:
+            patch = series.get_current()
+            if not patch:
+                raise CmdException, 'No patches applied'
+        if patch in series.get_applied() or patch in series.get_unapplied():
+            if patch_id in ['top', '', None]:
+                return series.get_patch(patch).get_top()
+            elif patch_id == 'bottom':
+                return series.get_patch(patch).get_bottom()
+            elif patch_id == 'top.old':
+                return series.get_patch(patch).get_old_top()
+            elif patch_id == 'bottom.old':
+                return series.get_patch(patch).get_old_bottom()
+        if patch == 'base' and patch_id == None:
+            return read_string(series.get_base_file())
+    except RevParseException:
+        pass
     return git.rev_parse(rev + '^{commit}')
 
 def check_local_changes():
diff --git a/stgit/commands/diff.py b/stgit/commands/diff.py
index 7dc6c5d..d765784 100644
--- a/stgit/commands/diff.py
+++ b/stgit/commands/diff.py
@@ -33,12 +33,12 @@ or a tree-ish object and another tree-is
 be given to restrict the diff output. The tree-ish object can be a
 standard git commit, tag or tree. In addition to these, the command
 also supports 'base', representing the bottom of the current stack,
-and '[patch]/[bottom | top]' for the patch boundaries (defaulting to
+and '[patch][//[bottom | top]]' for the patch boundaries (defaulting to
 the current one):
 
-rev = '([patch]/[bottom | top]) | <tree-ish> | base'
+rev = '([patch][//[bottom | top]]) | <tree-ish> | base'
 
-If neither bottom or top are given but a '/' is present, the command
+If neither bottom nor top are given but a '//' is present, the command
 shows the specified patch (defaulting to the current one)."""
 
 options = [make_option('-r', metavar = 'rev1[:[rev2]]', dest = 'revs',
@@ -55,10 +55,14 @@ def func(parser, options, args):
         rev_list = options.revs.split(':')
         rev_list_len = len(rev_list)
         if rev_list_len == 1:
-            if rev_list[0][-1] == '/':
+            rev = rev_list[0]
+            if rev[-1] == '/':
                 # the whole patch
-                rev1 = rev_list[0] + 'bottom'
-                rev2 = rev_list[0] + 'top'
+                rev = rev[:-1]
+                if rev[-1] == '/':
+                    rev = rev[:-1]
+                rev1 = rev + '//bottom'
+                rev2 = rev + '//top'
             else:
                 rev1 = rev_list[0]
                 rev2 = None
diff --git a/stgit/commands/files.py b/stgit/commands/files.py
index 0694d83..b33bd2a 100644
--- a/stgit/commands/files.py
+++ b/stgit/commands/files.py
@@ -53,8 +53,8 @@ def func(parser, options, args):
     else:
         parser.error('incorrect number of arguments')
 
-    rev1 = git_id('%s/bottom' % patch)
-    rev2 = git_id('%s/top' % patch)
+    rev1 = git_id('%s//bottom' % patch)
+    rev2 = git_id('%s//top' % patch)
 
     if options.stat:
         print git.diffstat(rev1 = rev1, rev2 = rev2)
diff --git a/stgit/commands/id.py b/stgit/commands/id.py
index 1cf6ea6..284589a 100644
--- a/stgit/commands/id.py
+++ b/stgit/commands/id.py
@@ -28,7 +28,7 @@ usage = """%prog [options] [id]
 
 Print the hash value of a GIT id (defaulting to HEAD). In addition to
 the standard GIT id's like heads and tags, this command also accepts
-'base[@<branch>]' and '[<patch>[@<branch>]][/(bottom | top)]'. If no
+'base[@<branch>]' and '[<patch>[@<branch>]][//[bottom | top]]'. If no
 'top' or 'bottom' are passed and <patch> is a valid patch name, 'top'
 will be used by default."""
 
diff --git a/stgit/commands/mail.py b/stgit/commands/mail.py
index 5e01ea1..3928b81 100644
--- a/stgit/commands/mail.py
+++ b/stgit/commands/mail.py
@@ -324,10 +324,10 @@ def __build_message(tmpl, patch, patch_n
                  'shortdescr':   short_descr,
                  'longdescr':    long_descr,
                  'endofheaders': headers_end,
-                 'diff':         git.diff(rev1 = git_id('%s/bottom' % patch),
-                                          rev2 = git_id('%s/top' % patch)),
-                 'diffstat':     git.diffstat(rev1 = git_id('%s/bottom'%patch),
-                                              rev2 = git_id('%s/top' % patch)),
+                 'diff':         git.diff(rev1 = git_id('%s//bottom' % patch),
+                                          rev2 = git_id('%s//top' % patch)),
+                 'diffstat':     git.diffstat(rev1 = git_id('%s//bottom'%patch),
+                                              rev2 = git_id('%s//top' % patch)),
                  'date':         email.Utils.formatdate(localtime = True),
                  'version':      version_str,
                  'patchnr':      patch_nr_str,
diff --git a/stgit/git.py b/stgit/git.py
index 2884f36..716609c 100644
--- a/stgit/git.py
+++ b/stgit/git.py
@@ -225,7 +225,8 @@ def get_head():
 def get_head_file():
     """Returns the name of the file pointed to by the HEAD link
     """
-    return os.path.basename(_output_one_line('git-symbolic-ref HEAD'))
+    return strip_prefix('refs/heads/',
+                        _output_one_line('git-symbolic-ref HEAD'))
 
 def set_head_file(ref):
     """Resets HEAD to point to a new ref
@@ -233,7 +234,8 @@ def set_head_file(ref):
     # head cache flushing is needed since we might have a different value
     # in the new head
     __clear_head_cache()
-    if __run('git-symbolic-ref HEAD', [ref]) != 0:
+    if __run('git-symbolic-ref HEAD',
+             [os.path.join('refs', 'heads', ref)]) != 0:
         raise GitException, 'Could not set head to "%s"' % ref
 
 def __set_head(val):
@@ -272,6 +274,7 @@ def rev_parse(git_id):
 def branch_exists(branch):
     """Existence check for the named branch
     """
+    branch = os.path.join('refs', 'heads', branch)
     for line in _output_lines('git-rev-parse --symbolic --all 2>&1'):
         if line.strip() == branch:
             return True
@@ -282,12 +285,11 @@ def branch_exists(branch):
 def create_branch(new_branch, tree_id = None):
     """Create a new branch in the git repository
     """
-    new_head = os.path.join('refs', 'heads', new_branch)
-    if branch_exists(new_head):
+    if branch_exists(new_branch):
         raise GitException, 'Branch "%s" already exists' % new_branch
 
     current_head = get_head()
-    set_head_file(new_head)
+    set_head_file(new_branch)
     __set_head(current_head)
 
     # a checkout isn't needed if new branch points to the current head
@@ -297,22 +299,22 @@ def create_branch(new_branch, tree_id = 
     if os.path.isfile(os.path.join(basedir.get(), 'MERGE_HEAD')):
         os.remove(os.path.join(basedir.get(), 'MERGE_HEAD'))
 
-def switch_branch(name):
+def switch_branch(new_branch):
     """Switch to a git branch
     """
     global __head
 
-    new_head = os.path.join('refs', 'heads', name)
-    if not branch_exists(new_head):
-        raise GitException, 'Branch "%s" does not exist' % name
+    if not branch_exists(new_branch):
+        raise GitException, 'Branch "%s" does not exist' % new_branch
 
-    tree_id = rev_parse(new_head + '^{commit}')
+    tree_id = rev_parse(os.path.join('refs', 'heads', new_branch)
+                        + '^{commit}')
     if tree_id != get_head():
         refresh_index()
         if __run('git-read-tree -u -m', [get_head(), tree_id]) != 0:
             raise GitException, 'git-read-tree failed (local changes maybe?)'
         __head = tree_id
-    set_head_file(new_head)
+    set_head_file(new_branch)
 
     if os.path.isfile(os.path.join(basedir.get(), 'MERGE_HEAD')):
         os.remove(os.path.join(basedir.get(), 'MERGE_HEAD'))
@@ -320,25 +322,23 @@ def switch_branch(name):
 def delete_branch(name):
     """Delete a git branch
     """
-    branch_head = os.path.join('refs', 'heads', name)
-    if not branch_exists(branch_head):
+    if not branch_exists(name):
         raise GitException, 'Branch "%s" does not exist' % name
-    os.remove(os.path.join(basedir.get(), branch_head))
+    remove_file_and_dirs(os.path.join(basedir.get(), 'refs', 'heads'),
+                         name)
 
 def rename_branch(from_name, to_name):
     """Rename a git branch
     """
-    from_head = os.path.join('refs', 'heads', from_name)
-    if not branch_exists(from_head):
+    if not branch_exists(from_name):
         raise GitException, 'Branch "%s" does not exist' % from_name
-    to_head = os.path.join('refs', 'heads', to_name)
-    if branch_exists(to_head):
+    if branch_exists(to_name):
         raise GitException, 'Branch "%s" already exists' % to_name
 
     if get_head_file() == from_name:
-        set_head_file(to_head)
-    os.rename(os.path.join(basedir.get(), from_head), \
-              os.path.join(basedir.get(), to_head))
+        set_head_file(to_name)
+    rename(os.path.join(basedir.get(), 'refs', 'heads'),
+           from_name, to_name)
 
 def add(names):
     """Add the files or recursively add the directory contents
diff --git a/stgit/stack.py b/stgit/stack.py
index f83161b..49b50e7 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -443,8 +443,7 @@ class Series:
 
         os.makedirs(self.__patch_dir)
 
-        if not os.path.isdir(bases_dir):
-            os.makedirs(bases_dir)
+        create_dirs(bases_dir)
 
         create_empty_file(self.__applied_file)
         create_empty_file(self.__unapplied_file)
@@ -502,11 +501,14 @@ class Series:
         git.rename_branch(self.__name, to_name)
 
         if os.path.isdir(self.__series_dir):
-            os.rename(self.__series_dir, to_stack.__series_dir)
+            rename(os.path.join(self.__base_dir, 'patches'),
+                   self.__name, to_stack.__name)
         if os.path.exists(self.__base_file):
-            os.rename(self.__base_file, to_stack.__base_file)
+            rename(os.path.join(self.__base_dir, 'refs', 'bases'),
+                   self.__name, to_stack.__name)
         if os.path.exists(self.__refs_dir):
-            os.rename(self.__refs_dir, to_stack.__refs_dir)
+            rename(os.path.join(self.__base_dir, 'refs', 'patches'),
+                   self.__name, to_stack.__name)
 
         self.__init__(to_name)
 
@@ -560,16 +562,19 @@ class Series:
             else:
                 print 'Patch directory %s is not empty.' % self.__name
             if not os.listdir(self.__series_dir):
-                os.rmdir(self.__series_dir)
+                remove_dirs(os.path.join(self.__base_dir, 'patches'),
+                            self.__name)
             else:
                 print 'Series directory %s is not empty.' % self.__name
             if not os.listdir(self.__refs_dir):
-                os.rmdir(self.__refs_dir)
+                remove_dirs(os.path.join(self.__base_dir, 'refs', 'patches'),
+                            self.__name)
             else:
                 print 'Refs directory %s is not empty.' % self.__refs_dir
 
         if os.path.exists(self.__base_file):
-            os.remove(self.__base_file)
+            remove_file_and_dirs(
+                os.path.join(self.__base_dir, 'refs', 'bases'), self.__name)
 
     def refresh_patch(self, files = None, message = None, edit = False,
                       show_patch = False,
diff --git a/stgit/utils.py b/stgit/utils.py
index 5749b3b..68b8f58 100644
--- a/stgit/utils.py
+++ b/stgit/utils.py
@@ -1,6 +1,8 @@
 """Common utility functions
 """
 
+import errno, os, os.path
+
 __copyright__ = """
 Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
 
@@ -18,6 +20,12 @@ along with this program; if not, write t
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
+def mkdir_file(filename, mode):
+    """Opens filename with the given mode, creating the directory it's
+    in if it doesn't already exist."""
+    create_dirs(os.path.dirname(filename))
+    return file(filename, mode)
+
 def read_string(filename, multiline = False):
     """Reads the first line from a file
     """
@@ -32,7 +40,7 @@ def read_string(filename, multiline = Fa
 def write_string(filename, line, multiline = False):
     """Writes 'line' to file and truncates it
     """
-    f = file(filename, 'w+')
+    f = mkdir_file(filename, 'w+')
     if multiline:
         f.write(line)
     else:
@@ -42,7 +50,7 @@ def write_string(filename, line, multili
 def append_strings(filename, lines):
     """Appends 'lines' sequence to file
     """
-    f = file(filename, 'a+')
+    f = mkdir_file(filename, 'a+')
     for line in lines:
         print >> f, line
     f.close()
@@ -50,14 +58,14 @@ def append_strings(filename, lines):
 def append_string(filename, line):
     """Appends 'line' to file
     """
-    f = file(filename, 'a+')
+    f = mkdir_file(filename, 'a+')
     print >> f, line
     f.close()
 
 def insert_string(filename, line):
     """Inserts 'line' at the beginning of the file
     """
-    f = file(filename, 'r+')
+    f = mkdir_file(filename, 'r+')
     lines = f.readlines()
     f.seek(0); f.truncate()
     print >> f, line
@@ -67,4 +75,74 @@ def insert_string(filename, line):
 def create_empty_file(name):
     """Creates an empty file
     """
-    file(name, 'w+').close()
+    mkdir_file(name, 'w+').close()
+
+def list_files_and_dirs(path):
+    """Return the sets of filenames and directory names in a
+    directory."""
+    files, dirs = [], []
+    for fd in os.listdir(path):
+        full_fd = os.path.join(path, fd)
+        if os.path.isfile(full_fd):
+            files.append(fd)
+        elif os.path.isdir(full_fd):
+            dirs.append(fd)
+    return files, dirs
+
+def walk_tree(basedir):
+    """Starting in the given directory, iterate through all its
+    subdirectories. For each subdirectory, yield the name of the
+    subdirectory (relative to the base directory), the list of
+    filenames in the subdirectory, and the list of directory names in
+    the subdirectory."""
+    subdirs = ['']
+    while subdirs:
+        subdir = subdirs.pop()
+        files, dirs = list_files_and_dirs(os.path.join(basedir, subdir))
+        for d in dirs:
+            subdirs.append(os.path.join(subdir, d))
+        yield subdir, files, dirs
+
+def strip_prefix(prefix, string):
+    """Return string, without the prefix. Blow up if string doesn't
+    start with prefix."""
+    assert string.startswith(prefix)
+    return string[len(prefix):]
+
+def remove_dirs(basedir, dirs):
+    """Starting at join(basedir, dirs), remove the directory if empty,
+    and try the same with its parent, until we find a nonempty
+    directory or reach basedir."""
+    path = dirs
+    while path:
+        try:
+            os.rmdir(os.path.join(basedir, path))
+        except OSError:
+            return # can't remove nonempty directory
+        path = os.path.dirname(path)
+
+def remove_file_and_dirs(basedir, file):
+    """Remove join(basedir, file), and then remove the directory it
+    was in if empty, and try the same with its parent, until we find a
+    nonempty directory or reach basedir."""
+    os.remove(os.path.join(basedir, file))
+    remove_dirs(basedir, os.path.dirname(file))
+
+def create_dirs(directory):
+    """Create the given directory, if the path doesn't already exist."""
+    if directory:
+        create_dirs(os.path.dirname(directory))
+        try:
+            os.mkdir(directory)
+        except OSError, e:
+            if e.errno != errno.EEXIST:
+                raise e
+
+def rename(basedir, file1, file2):
+    """Rename join(basedir, file1) to join(basedir, file2), not
+    leaving any empty directories behind and creating any directories
+    necessary."""
+    full_file2 = os.path.join(basedir, file2)
+    create_dirs(os.path.dirname(full_file2))
+    os.rename(os.path.join(basedir, file1), full_file2)
+    remove_dirs(basedir, os.path.dirname(file1))
-- 
1.3.2.g639c


-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply related

* Necessity of "evil" merge and topic branches
From: Junio C Hamano @ 2006-05-18  6:25 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0605172120160.10823@g5.osdl.org>

When you are maintaining two codebases (one is slightly ahead of
the other, e.g. "master" and "next"), you would expect that a
topic branch based on "master" would apply well to "next".

So your "make guts of ls-files accessible from others, and make
git-add a built-in" is stored in "lt/dirwalk" topic branch,
based on a commit on "master".  By itself, it passes all tests.

When it is merged into "next", which has other stuff, literal
merging did not really work (not your fault).  Many tests that
involve writing trees (typically to create new commits) fail
miserably.

   o---o---o---o---o---o---o---o master
  .     \
  .      o---o---o lt/dirwalk -- contains builtin-add
  \               \ 
   o---o---o---o---o next -- up to date with "master" but
                             has many other stuff in it.

This is because the rule to manupulate the index is a bit
different on "next" branch, where it has jc/cache-tree topic.

With cache-tree, when you modify the index, you need to either
invalidate the path (and its parent directories up to root) in
the cached tree information, or discard the whole cache-tree,
whichever is easier [*1*].  So I have an "evil merge" that
merges the lt/dirwalk topic to next (it is ae12e59a).  It
changes the code like this:

        $ git diff lt/dirwalk next -- builtin-add.c
        diff --git a/builtin-add.c b/builtin-add.c
        index 089c7a8..7083820 100644
        --- a/builtin-add.c
        +++ b/builtin-add.c
        @@ -8,6 +8,7 @@ #include <fnmatch.h>
         #include "cache.h"
         #include "builtin.h"
         #include "dir.h"
        +#include "cache-tree.h"

         static const char builtin_add_usage[] =
         "git-add [-n] [-v] <filepattern>...";
        @@ -197,6 +198,7 @@ static int add_file_to_index(const char 
                        die("unable to add %s to index",path);
                if (verbose)
                        printf("add '%s'\n", path);
        +	cache_tree_invalidate_path(active_cache_tree, path);
                return 0;
         }

Obviously, this is a semantic adjustment, not a simple textual
merge, so no automated merge algorithm would help doing this for
me.  I literally edited the automerged builtin-add.c (the merge
is "one adds a new file, the other does not do anything" case,
so it trivially automerges at the tree level) and amended the
commit when I made the merge.

Now, unlike "pu", I never rewind "next", so once I did this
"evil merge", I do not have to worry about this anymore while
the topic is still on "next".  However, when jc/cache-tree topic
and lt/dirwalk topic both graduate to "master", I will somehow
need to remember to do this again.  That sounds somewhat painful
and quite error prone.

I am not going to rewind "next", so this evil merge will stay
there, but I am wondering if there was a better way I could have
handled this.

If I _know_ lt/dirwalk is going to graduate first (and I think
that is the case), I could have pulled lt/dirwalk into
jc/cache-tree topic, done an equivalent "evil merge" as the
above on jc/cache-tree topic, and pulled the result into "next".
That way, when lt/dirwalk alone graduates, I can just pull it
into "master".  Later, when the jc/cache-tree graduates, the
necessary "evil merge" will be pulled along with it, so I can
truly forget and not worry about it after I do the evil merge
once.

But in general, you would not know which one will graduate
first, so pulling one topic into another is not always a good
idea.  If I pull lt/dirwalk into jc/cache-tree, making
jc/cache-tree graduate alone becomes impossible.  Depending on
the readiness of these two topics, it may not be acceptable to
create such a dependency between topics.

One possibility I can think of is that I could have created
another topic branch that merged jc/cache-tree and lt/dirwalk in
the evil way, and pulled that into "next".  Then either one of
the topics can independently graduate to "master" without
waiting for the other.  I still have to remember that I need to
merge the third topic with evil merge when I make both of them
graduate to "master", but at least I do not have to remember the
details of how that evil merge should look like when I do so.  I
only need to remember that it needs to be done.

In practice, when I merge a topic branch into "master", I note
the paths that merge touches from "master", and run diff between
"master" and "next" for them to see if the remaining changes on
them are reasonable.  I will hopefully remember the need for
(and the details of) the evil merge that way when I pull these
two branches to "master", so what I did would not cause trouble
down the road (with some luck ;-), but I feel there should be a
better way to handle this situation.

Thoughts?


[Footnotes]

*1* In this message, let's not discuss if cache-tree is a good
  idea to begin with, if we should rip it out and/or if we
  should replace it with tree objects in the index.  I'd like to
  discuss SCM issue to handle somewhat interrelated topic
  branches here, not cache-tree.

^ permalink raw reply

* Re: cvsimport weird
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2006-05-18  5:56 UTC (permalink / raw)
  To: proski; +Cc: martin.langhoff, beber.mailing, git, yoshfuji
In-Reply-To: <1147931094.32050.51.camel@dv>

In article <1147931094.32050.51.camel@dv> (at Thu, 18 May 2006 01:44:54 -0400), Pavel Roskin <proski@gnu.org> says:

> Address resolution is broken in cvsps on 64-bit machines.  This patch to
> cvsps is needed:
> 
> --- cbtcommon/tcpsocket.c
> +++ cbtcommon/tcpsocket.c
> @@ -198,7 +198,7 @@ convert_address(long *dest, const char *
>      memcpy(dest, &ip.s_addr, sizeof(ip.s_addr));
>    }
>  #else
> -  if ( (*dest = inet_addr(addr_str)) != -1)
> +  if ( (*dest = inet_addr(addr_str)) != INADDR_NONE)
>    {
>      /* nothing */
>    }

You need to define INADDR_NONE on some platforms; e.g. Solaris.

--yoshfuji

^ permalink raw reply

* Re: cvsimport weird
From: Pavel Roskin @ 2006-05-18  5:44 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: Bertrand Jacquin, Git Mailing List
In-Reply-To: <1147924771.32050.40.camel@dv>

On Wed, 2006-05-17 at 23:59 -0400, Pavel Roskin wrote:
> I'm quite sure that it's a bug in cvsps.  It displays such things on
> x86_64, but works properly on 32-bit PowerPC.

Address resolution is broken in cvsps on 64-bit machines.  This patch to
cvsps is needed:

--- cbtcommon/tcpsocket.c
+++ cbtcommon/tcpsocket.c
@@ -198,7 +198,7 @@ convert_address(long *dest, const char *
     memcpy(dest, &ip.s_addr, sizeof(ip.s_addr));
   }
 #else
-  if ( (*dest = inet_addr(addr_str)) != -1)
+  if ( (*dest = inet_addr(addr_str)) != INADDR_NONE)
   {
     /* nothing */
   }


However, it's not sufficient to fix the original problem of empty CVS
server version string.  For some reason cvsps fails to authenticate with
pserver.  The ext protocol is working.

It's interesting that both git-cvsimport and cvsps have code to
authenticate over the pserver protocol.  I think maybe git-cvsimport
shouldn't do it, or maybe it should close some sockets before running
cvsps.

-- 
Regards,
Pavel Roskin

^ permalink raw reply

* Re: [Patch] git-cvsimport: tiny fix
From: Martin Langhoff @ 2006-05-18  4:53 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Elrond
In-Reply-To: <7vd5eccvns.fsf@assigned-by-dhcp.cox.net>

On 5/18/06, Junio C Hamano <junkio@cox.net> wrote:
> Could somebody who actually works with CVS import Ack this?
> Pretty please?

Sounds sane. It would be interesting to hear about what repo (and
server) this was seen against. Elrond, can you tell us more about
this?

cheers,


martin

^ permalink raw reply

* Remove old "git-add.sh" remnants
From: Linus Torvalds @ 2006-05-18  4:21 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


Repeat after me: "It's now a built-in"

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

diff --git a/Makefile b/Makefile
index a1d2e08..3a28580 100644
--- a/Makefile
+++ b/Makefile
@@ -113,7 +113,7 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powe
 ### --- END CONFIGURATION SECTION ---
 
 SCRIPT_SH = \
-	git-add.sh git-bisect.sh git-branch.sh git-checkout.sh \
+	git-bisect.sh git-branch.sh git-checkout.sh \
 	git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \
 	git-fetch.sh \
 	git-format-patch.sh git-ls-remote.sh \
@@ -170,7 +170,7 @@ PROGRAMS = \
 
 BUILT_INS = git-log$X git-whatchanged$X git-show$X \
 	git-count-objects$X git-diff$X git-push$X \
-	git-grep$X
+	git-grep$X git-add$X
 
 # what 'all' will build and 'install' will install, in gitexecdir
 ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
diff --git a/git-add.sh b/git-add.sh
deleted file mode 100755
index d6a4bc7..0000000
--- a/git-add.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-
-USAGE='[-n] [-v] <file>...'
-SUBDIRECTORY_OK='Yes'
-. git-sh-setup
-
-show_only=
-verbose=
-while : ; do
-  case "$1" in
-    -n)
-	show_only=true
-	;;
-    -v)
-	verbose=--verbose
-	;;
-    --)
-	shift
-	break
-	;;
-    -*)
-	usage
-	;;
-    *)
-	break
-	;;
-  esac
-  shift
-done
-
-# Check misspelled pathspec
-case "$#" in
-0)	;;
-*)
-	git-ls-files --error-unmatch --others --cached -- "$@" >/dev/null || {
-		echo >&2 "Maybe you misspelled it?"
-		exit 1
-	}
-	;;
-esac
-
-if test -f "$GIT_DIR/info/exclude"
-then
-	git-ls-files -z \
-	--exclude-from="$GIT_DIR/info/exclude" \
-	--others --exclude-per-directory=.gitignore -- "$@"
-else
-	git-ls-files -z \
-	--others --exclude-per-directory=.gitignore -- "$@"
-fi |
-case "$show_only" in
-true)
-	xargs -0 echo ;;
-*)
-	git-update-index --add $verbose -z --stdin ;;
-esac

^ permalink raw reply related

* Re: cvsimport weird
From: Pavel Roskin @ 2006-05-18  3:59 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: Bertrand Jacquin, Git Mailing List
In-Reply-To: <46a038f90605171954n7e75ee64t412b22e8d405d909@mail.gmail.com>

On Thu, 2006-05-18 at 14:54 +1200, Martin Langhoff wrote:
> On 5/18/06, Bertrand Jacquin <beber.mailing@gmail.com> wrote:
> >
> The cvs server is strange -- buggy probably. cvsps thinks it is old,
> but it is not even returning a version string. Is it really cvs?

The version reporting is working for me:

$ cvs -d :pserver:anonymous@anoncvs.enlightenment.org:/var/cvs/e version
Client: Concurrent Versions System (CVS) 1.11.21 (client/server)
Server: Concurrent Versions System (CVS) 1.11.17 (client/server)

But I can reproduce the problem with git-cvsimport.  git main branch,
cvsps 2.1.

I'm quite sure that it's a bug in cvsps.  It displays such things on
x86_64, but works properly on 32-bit PowerPC.

x86_64:
$ cvsps --cvs-direct -A -u --root :pserver:anonymous@anoncvs.enlightenment.org:/var/cvs/e e17
connect error: Network is unreachable
WARNING: malformed CVS version: no data
WARNING: malformed CVS version str: (UNKNOWN CLIENT)
WARNING: Your CVS client version:
[(UNKNOWN CLIENT)]
and/or server version:
[(UNKNOWN SERVER)]

ppc:
$ cvsps --cvs-direct -A -u --root :pserver:anonymous@anoncvs.enlightenment.org:/var/cvs/e e17
cvs_direct initialized to CVSROOT /var/cvs/e
cvs rlog: Logging e17
cvs rlog: Logging e17/CVSROOT
cvs rlog: Logging e17/apps
cvs rlog: Logging e17/apps/e
cvs rlog: Logging e17/apps/e/client
...

Both are cvsps 2.1 on Fedora Core 5.

-- 
Regards,
Pavel Roskin

^ permalink raw reply

* Re: Fwd: [OT] Re: Git via a proxy server?
From: Sam Song @ 2006-05-18  3:44 UTC (permalink / raw)
  To: Petr Vandrovec; +Cc: Jan-Benedict Glaw, git
In-Reply-To: <446B00CE.9000609@vmware.com>

Petr Vandrovec <petr@vmware.com> wrote:
> Jan-Benedict Glaw <jbglaw@lug-owl.de> wrote:
> > Well, install some package to have `socket'
> > available? Debian calls
> > the packet `socket', too, so I guess Fedora may
> > have something similar.
> 
> Surprisingly they do not...  You should be able to
> replace 'socket' with 
> 'netcat' - and I believe that netcat/nc package is
> available for Fedora.  For 
> this purpose they have same command line & behavior.

Ummm, I am trying on that. nc is avaiable for Fedora.
But what could be the replacement for CONNECT in
Fedora? :-)

Thanks for your kind support,

Sam



__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 

^ permalink raw reply

* Re: cvsimport weird
From: Martin Langhoff @ 2006-05-18  2:54 UTC (permalink / raw)
  To: Bertrand Jacquin; +Cc: Git Mailing List
In-Reply-To: <4fb292fa0605171800n4f041dd2l8af06d82bdbe6bff@mail.gmail.com>

On 5/18/06, Bertrand Jacquin <beber.mailing@gmail.com> wrote:
> Hi,
>
> I would like to make some git-cvsimport test on a public repo. And I
> get some problem and don't know if it's a remote server
> (enlightenment) problem or a git-cvsimport one.
>
> Here is the log :
>
> /mnt/data/src/e-tmp % git-cvsimport -v
> -d:pserver:anonymous@anoncvs.enlightenment.org:/var/cvs/e e17
> connect error: Network is unreachable
> WARNING: malformed CVS version str: Server:
> WARNING: Your CVS client version:
> [Client: Concurrent Versions System (CVS) 1.12.12 (client)]
> and/or server version:
> [Server: ]
> are too old to properly support the rlog command.
> This command was introduced in 1.11.1.  Cvsps
> will use log instead, but PatchSet numbering
> may become unstable due to pruned empty
> directories.

The cvs server is strange -- buggy probably. cvsps thinks it is old,
but it is not even returning a version string. Is it really cvs?

> cvs [log aborted]: end of file from server (consult above messages if any)

The remote end is dying on you.

> I don't why it tell me that Network is unreachable as I can do normal
> cvs checkout.

I think it is the remote end that is saying Network unreachable.
Perhaps it is a cvs proxy that only allows some commands?

> Also, I have the repo in another directory, and I don't know how to
> use a :local: CVSROOT

   git-cvsimport -d /tmp/cvsrepo/ modulename

should work ok. You should also try parsecvs ;-)



m

^ permalink raw reply

* cvsimport weird
From: Bertrand Jacquin @ 2006-05-18  1:00 UTC (permalink / raw)
  To: Git Mailing List

Hi,

I would like to make some git-cvsimport test on a public repo. And I
get some problem and don't know if it's a remote server
(enlightenment) problem or a git-cvsimport one.

Here is the log :

/mnt/data/src/e-tmp % git-cvsimport -v
-d:pserver:anonymous@anoncvs.enlightenment.org:/var/cvs/e e17
connect error: Network is unreachable
WARNING: malformed CVS version str: Server:
WARNING: Your CVS client version:
[Client: Concurrent Versions System (CVS) 1.12.12 (client)]
and/or server version:
[Server: ]
are too old to properly support the rlog command.
This command was introduced in 1.11.1.  Cvsps
will use log instead, but PatchSet numbering
may become unstable due to pruned empty
directories.

cvs [log aborted]: end of file from server (consult above messages if any)
DONE.
Already up-to-date.
/mnt/data/src/e-tmp %

I use cvs 1.12.12, cvsps 2.1, git 1.3.3

I don't why it tell me that Network is unreachable as I can do normal
cvs checkout.

Also, I have the repo in another directory, and I don't know how to
use a :local: CVSROOT

-- 
Beber
#e.fr@freenode

^ permalink raw reply


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