* 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
* Re: 1.3.2 git-clone segfaults
From: Linus Torvalds @ 2006-05-18 0:54 UTC (permalink / raw)
To: Pavel Roskin; +Cc: Bill Yoder, git, Wolfgang Denk
In-Reply-To: <1147909920.32050.29.camel@dv>
On Wed, 17 May 2006, Pavel Roskin wrote:
>
> Looks like a curl bug to me. curl 7.15.1, glibc 2.4, git master branch.
If the thing is fixed by turning off DAV support (and I thought somebody
reported it was), maybe we should turn that off by default? Ie, make
NO_EXPAT be the default, and you have to explicitly turn it off.
Linus
^ permalink raw reply
* Re: 1.3.2 git-clone segfaults
From: Pavel Roskin @ 2006-05-17 23:52 UTC (permalink / raw)
To: Bill Yoder; +Cc: git, Wolfgang Denk
In-Reply-To: <1147894165.16654.10.camel@dv>
On Wed, 2006-05-17 at 15:29 -0400, Pavel Roskin wrote:
> On Wed, 2006-05-17 at 13:32 -0500, Bill Yoder wrote:
> > /usr/local/downloads/git-1.3.2/git-clone: line 323: 25972
> > Segmentation fault git-http-fetch -v -a -w "$tname" "$name" "$1/"
>
> I've seen git-http-fetch segfaults many times when cloning qgit, but
> it's hard to reproduce on demand.
>
> I think you should compile git without optimizations and allow coredumps
> (ulimit -c unlimited), then load git-http-fetch in gdb with the core
> (gdb --core=core git-http-fetch) and run bt to see the backtrace.
Also comment out both "trap" invocations in git-clone, or the coredump
will be deleted.
That's what I've got on Fedora Core 5 x86_64 with glibc and curl debug
info installed:
#0 __strncasecmp (s1=Variable "s1" is not available.
) at strncase.c:68
68 while ((result = TOLOWER (*p1) - TOLOWER (*p2++)) == 0)
(gdb) where
#0 __strncasecmp (s1=Variable "s1" is not available.
) at strncase.c:68
#1 0x00000031f3e26c09 in curl_strnequal (first=Variable "first" is not available.
) at strequal.c:60
#2 0x00000031f3e0f43a in checkheaders (data=Variable "data" is not available.
) at http.c:119
#3 0x00000031f3e10cf9 in Curl_http (conn=0x1c421c0, done=Variable "done" is not available.
) at http.c:1580
#4 0x00000031f3e1a858 in Curl_do (connp=0x83af88, done=0x7fff29c97ebb "\001\001")
at url.c:3841
#5 0x00000031f3e28f22 in curl_multi_perform (multi_handle=0x53b590,
running_handles=0x7fff29c97ef8) at multi.c:526
#6 0x00000000004040c0 in step_active_slots () at http.c:376
#7 0x000000000040412c in run_active_slot (slot=0x546690) at http.c:400
#8 0x0000000000403e44 in http_cleanup () at http.c:275
#9 0x00000000004077d7 in main (argc=7, argv=0x7fff29c98258) at http-fetch.c:1274
(gdb) p p1
$1 = (const unsigned char *) 0x0
(gdb) p p2
$2 = (const unsigned char *) 0x31f3e2e817 "User-Agent:"
(gdb)
Looks like a curl bug to me. curl 7.15.1, glibc 2.4, git master branch.
--
Regards,
Pavel Roskin
^ permalink raw reply
* Re: [PATCH] Implement git-quiltimport (take 2)
From: Junio C Hamano @ 2006-05-17 23:34 UTC (permalink / raw)
To: Eric W. Biederman; +Cc: git
In-Reply-To: <m1zmhg31cm.fsf@ebiederm.dsl.xmission.com>
ebiederm@xmission.com (Eric W. Biederman) writes:
> Junio C Hamano <junkio@cox.net> writes:
>
>> What's the expected workflow for you to work on a 1300 patch
>> series you get from Andrew in the next installment to deal with
>> 88 unattributed patches? Answer the question 88 times and make
>> sure you get the answers right every time? Or abort and
>> hand-edit them to help mailinfo to notice the correct
>> attribution and re-run?
>
> For the internal consumption case it isn't a big deal. I
> can specify --author with something bogus and it works.
Yes.
>> I know I am guilty of suggesting "going interactive", but I have
>> a feeling that having an optional file that maps patch-name to
>> author might be easier to work with. If the old patches are
>> recycled in the updated -mm set, you probably can reuse the
>> mapping for them, adding entries for newly introduced "unnamed"
>> patches as needed.
>
> Short of getting the script where it has a sane restart in the
> middle mode going interactive and asking questions makes a lot
> of sense. Especially with smaller trees.
Yes perhaps on smaller trees, but that does not mean much. For
smaller trees and/or smaller patch series almost anything would
do.
How about doing something like this, so that the user can record
the fixup information, especially with --dry-run patch? Then
the next round from the updated -mm tree the user would not have
to retype them again ("then..fi" part should be indented in the
final version, but I did not want indentation changes to
distract you):
# Parse the author information
export GIT_AUTHOR_NAME=$(sed -ne 's/Author: //p' "$tmp_info")
export GIT_AUTHOR_EMAIL=$(sed -ne 's/Email: //p' "$tmp_info")
+ already_tried_fixup=
while test -z "$GIT_AUTHOR_EMAIL" && test -z "$GIT_AUTHOR_NAME" ; do
if [ -n "$quilt_author" ] ; then
GIT_AUTHOR_NAME="$quilt_author_name";
GIT_AUTHOR_EMAIL="$quilt_author_email";
else
+ if test -z "$already_tried_fixup"
+ then
+ patch_author=`grep author-fixup "$patch_name"`
+ already_tried_fixup=t
+ fi
+ if test -z "$patch_author"
+ then
echo "No author found in $patch_name";
echo "---"
cat $tmp_msg
echo -n "Author: ";
read patch_author
+ fi
echo "$patch_author"
> For Andrews tree before I play anymore with technical solutions I
> need to talk to Andrew and see if we can improve the situation
> upstream. Possibly with a quilt-audit script that finds problem
> patches.
Yes, that sounds very sensible.
^ permalink raw reply
* Re: [RFC] qgit with tabs
From: Pavel Roskin @ 2006-05-17 23:21 UTC (permalink / raw)
To: Marco Costalba; +Cc: git
In-Reply-To: <e5bfff550605131538u63b87002o3e9b5542c0e15bf7@mail.gmail.com>
Hi, Marco!
On Sun, 2006-05-14 at 00:38 +0200, Marco Costalba wrote:
> Hi Pavel,
>
> >
> > Sure, but I often want to see what changed in a particular file.
> >
> > And of course I only mean the subwindow dislaying the files affected by the
> > patch. The file tree should still have file annotation bound to the double
> > click.
> >
>
> I understand your reasons, but I have some doubts about this change:
>
> 1) The context menu is currently shared between the tree and the file
> list, splitting in two subcases adds some crap to the code (ok, this
> is not the real doubt ;-) )
Actually, "Get revision/patch" and "External diff" shouldn't be in the
popup used in the tree, or at least they should only appear for the
files affected by the currently selected patch.
"External diff" may be a good candidate for the toolbar if you find out
how to feed a multi-file patch to kompare (I guess you'll need two
temporary directories populated with differing files).
> 2) The context menu is currently shared between the file list in main
> view and the file list in patch view. The file list in patch view, of
> course, does not need a double click, a single click is enough to
> select corresponding file's diff. In main view you currently need a
> single click _plus_ a 'p' key press to change the view. So we should
> add another subcase here.
Yes. It should be perfectly OK to have different menus for different
contexts.
> 3) It is true that double clicking on a revision switch to the patch
> view at top position (if no file is selected), but it's also true that
> you can select the file's related diff directly in patch view with a
> single click on the right column file list.
That's true. But I still find myself double clicking on the file in the
file list and expecting to see the patch for the file. It's very
natural.
If I see the list of the recent patches, I see the descriptions and the
affected files. If I'm interested to see what changed in the file, it's
only natural for me to double-click the corresponding entry in the list.
Full history of a file is a much more advanced operation, and it's not
something I need to do often while browsing recently merged changes.
> 4) Once a file is selected, as example with a single click, you can
> browse through rev list and the selection is preserved, it means that
> anytime you switch to patch view page the content will be _already_
> centered on the correct diff.
That's useful, but irrelevant.
> 5) Double clicking on a file name is currently the only way (without
> opening the menu) to show the file content tab, with your suggested
> change we will have two ways to switch to patch view and no one to
> switch to file view.
That's a good thing. That's called consistency. git is about patches,
so showing the patches should be the default whenever practical.
The file viewer is a great feature, and it should be discoverable, but
it doesn't mean it should pop up when users expect something else.
>
> 6) Selecting from the tree view is very slow if you have to search for
> the correct file, it is fast only if the file is already selected, but
> in this case is faster to press 'p' key ;-)
That's true, but we are talking about double click behavior. Every
reasonable person can learn shortcuts, but the software should work
predictably even if operated by the mouse.
--
Regards,
Pavel Roskin
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox