* Re: [PATCH] git-am: initialize variable $resume on startup
From: Junio C Hamano @ 2007-08-06 23:16 UTC (permalink / raw)
To: Gerrit Pape; +Cc: git
In-Reply-To: <20070806141530.10422.qmail@8bd9c2a0b9ecab.315fe32.mid.smarden.org>
Thanks.
^ permalink raw reply
* Re: [PATCH] check_repository_format_version(): run git_default_config() again
From: Johannes Schindelin @ 2007-08-06 23:26 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Brian Gernhardt, Git Mailing List
In-Reply-To: <7vy7go9s84.fsf@assigned-by-dhcp.cox.net>
Hi,
On Mon, 6 Aug 2007, Junio C Hamano wrote:
> This is a minimum change in the sense that it restores the old
> behaviour of not even reading config in setup_git_directory(),
> but have the core.pager honored when we know it matters.
Looks obviously correct to me, and much better than relying on other sites
reading the config.
ACK.
Ciao,
Dscho
^ permalink raw reply
* Re: [PATCH] (Really) Fix install-doc-quick target
From: Mark Levedahl @ 2007-08-06 23:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: Johannes Schindelin, Mark Levedahl, Git Mailing List, Ren Scharfe
In-Reply-To: <7vzm149s8s.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano wrote:
> Yes. And 00d8c51 obviously "works for me", so there is
> something different between what Mark and I are doing. I cannot
> tell what it is.
>
GZ=1 make quick-install-doc
...fails because git-ls-tree is called when cwd=$mandir which is nowhere
under or related to $GIT_DIR.
Mark
^ permalink raw reply
* Re: [PATCH] (Really) Fix install-doc-quick target
From: Johannes Schindelin @ 2007-08-06 23:43 UTC (permalink / raw)
To: Mark Levedahl
Cc: Junio C Hamano, Mark Levedahl, Git Mailing List, Ren Scharfe
In-Reply-To: <46B7B10F.4060402@gmail.com>
Hi,
On Mon, 6 Aug 2007, Mark Levedahl wrote:
> Junio C Hamano wrote:
> > Yes. And 00d8c51 obviously "works for me", so there is
> > something different between what Mark and I are doing. I cannot
> > tell what it is.
> >
> GZ=1 make quick-install-doc
>
> ...fails because git-ls-tree is called when cwd=$mandir which is nowhere under
> or related to $GIT_DIR.
Ah, I suspect you do not have the latest 'master' installed?
Ciao,
Dscho
^ permalink raw reply
* Re: [PATCH] (Really) Fix install-doc-quick target
From: Mark Levedahl @ 2007-08-06 23:49 UTC (permalink / raw)
To: Johannes Schindelin
Cc: Junio C Hamano, Mark Levedahl, Git Mailing List, Ren Scharfe
In-Reply-To: <Pine.LNX.4.64.0708070042450.14781@racer.site>
Johannes Schindelin wrote:
> Ah, I suspect you do not have the latest 'master' installed?
>
> Ciao,
> Dscho
>
>
git>git fetch origin
git>git show-ref origin/master
a76c2acb28146f5630592f2ba738c0ebf0f3c1c4 refs/remotes/origin/master
git>git checkout -b test origin/master
Branch test set up to track remote branch refs/remotes/origin/master.
Switched to a new branch "test"
git>GZ=1 make prefix=/usr quick-install-doc
GIT_VERSION = 1.5.3.rc4.16.ga76c2
make -C Documentation quick-install
make[1]: Entering directory `/usr/src/git/Documentation'
rm -f doc.dep+ doc.dep
perl ./build-docdep.perl >doc.dep+
mv doc.dep+ doc.dep
make -C ../ GIT-VERSION-FILE
make[2]: Entering directory `/usr/src/git'
make[2]: `GIT-VERSION-FILE' is up to date.
make[2]: Leaving directory `/usr/src/git'
make[1]: Leaving directory `/usr/src/git/Documentation'
make[1]: Entering directory `/usr/src/git/Documentation'
make -C ../ GIT-VERSION-FILE
make[2]: Entering directory `/usr/src/git'
make[2]: `GIT-VERSION-FILE' is up to date.
make[2]: Leaving directory `/usr/src/git'
sh ./install-doc-quick.sh origin/man /usr/share/man
fatal: Not a git repository
make[1]: Leaving directory `/usr/src/git/Documentation'
git>
^ permalink raw reply
* Re: way to automatically add untracked files?
From: Miles Bader @ 2007-08-07 0:08 UTC (permalink / raw)
To: David Kastrup; +Cc: Junio C Hamano, Shawn O. Pearce, git
In-Reply-To: <85tzrcfrue.fsf@lola.goethe.zz>
David Kastrup <dak@gnu.org> writes:
>> I am not opposed to have "git add -a $paths"
>> which would do something like "git add $paths && git add -u $paths".
>
> I'm all for it.
Me too... :-)
[I think it's good that it be part of the "add" command (instead of a
separate command/alias), because a new user stands a better chance of
finding it in the documentation... when I was trying to figure out how
to do this by myself, I certainly started by reading the man page for
git-add!]
Thanks,
-Miles
--
((lambda (x) (list x x)) (lambda (x) (list x x)))
^ permalink raw reply
* Re: Another question about importing SVN with fast-import
From: Shawn O. Pearce @ 2007-08-07 1:08 UTC (permalink / raw)
To: Julian Phillips; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0708061408470.18641@reaper.quantumfyre.co.uk>
Julian Phillips <julian@quantumfyre.co.uk> wrote:
> On Mon, 16 Jul 2007, Shawn O. Pearce wrote:
>
> >Julian Phillips <julian@quantumfyre.co.uk> wrote:
> >>However, how do you copy a file from a
> >>particular revision?
> >
> >and sometimes not so much. You can't do that right now. I've wanted
> >to open up the data subcommand to allow another form that lets you
> >specify data from a branch and file path (thus selecting a blob
> >from another revision) but I haven't gotten around to it. I also
> >don't have time to do it during the earlier part of this week.
> >Maybe I'll get to it later near the end of the week.
>
> I was wondering if this was still a vague todo item, or if it was being
> worked on? It really is the biggest thing blocking my import at the
> moment and I'm willing to have a bash at it myself, but I didn't want to
> start messing around inside the fast-import code if someone else was
> already there ...
No, its not vague. I'm still working on it. Actually its on
my to-do list for tonight, and if I don't finish it tonight then
Thursday.
--
Shawn.
^ permalink raw reply
* [PATCH] Add support for SMTP over Transport Layer Security (TLS)
From: Pavel Roskin @ 2007-08-07 1:16 UTC (permalink / raw)
To: Catalin Marinas, git
Signed-off-by: Pavel Roskin <proski@gnu.org>
---
examples/gitconfig | 1 +
stgit/commands/mail.py | 22 +++++++++++++++++-----
2 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/examples/gitconfig b/examples/gitconfig
index bbb943f..3abbe6a 100644
--- a/examples/gitconfig
+++ b/examples/gitconfig
@@ -21,6 +21,7 @@
#smtpserver = localhost:25
#smtpuser = username
#smtppassword = password
+ #smtptls = no
# delay between messages in seconds (defaults to 5)
#smtpdelay = 5
diff --git a/stgit/commands/mail.py b/stgit/commands/mail.py
index cb8dc74..7ed5c27 100644
--- a/stgit/commands/mail.py
+++ b/stgit/commands/mail.py
@@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
-import sys, os, re, time, datetime, smtplib
+import sys, os, re, time, datetime, socket, smtplib
import email, email.Utils, email.Header
from optparse import OptionParser, make_option
@@ -53,7 +53,8 @@ replies to a different e-mail by using the '--refid' option.
SMTP authentication is also possible with '--smtp-user' and
'--smtp-password' options, also available as configuration settings:
-'smtpuser' and 'smtppassword'.
+'smtpuser' and 'smtppassword'. TLS encryption can be enabled by
+'--smtp-tls' option and 'smtptls' setting.
The patch e-mail template accepts the following variables:
@@ -121,6 +122,9 @@ options = [make_option('-a', '--all',
help = 'username for SMTP authentication'),
make_option('-p', '--smtp-password', metavar = 'PASSWORD',
help = 'username for SMTP authentication'),
+ make_option('-T', '--smtp-tls',
+ help = 'use SMTP with TLS encryption',
+ action = 'store_true'),
make_option('-b', '--branch',
help = 'use BRANCH instead of the default one'),
make_option('-O', '--diff-opts',
@@ -165,7 +169,7 @@ def __parse_addresses(msg):
return (from_addr_list[0], to_addr_list)
def __send_message(smtpserver, from_addr, to_addr_list, msg, sleep,
- smtpuser, smtppassword):
+ smtpuser, smtppassword, use_tls):
"""Send the message using the given SMTP server
"""
try:
@@ -177,6 +181,11 @@ def __send_message(smtpserver, from_addr, to_addr_list, msg, sleep,
try:
if smtpuser and smtppassword:
s.ehlo()
+ if use_tls:
+ if not hasattr(socket, 'ssl'):
+ raise CmdException, "cannot use TLS - no SSL support in Python"
+ s.starttls()
+ s.ehlo()
s.login(smtpuser, smtppassword)
result = s.sendmail(from_addr, to_addr_list, msg)
@@ -479,11 +488,14 @@ def func(parser, options, args):
smtppassword = options.smtp_password or config.get('stgit.smtppassword')
smtpuser = options.smtp_user or config.get('stgit.smtpuser')
+ smtpusetls = options.smtp_tls or config.get('stgit.smtptls') == 'yes'
if (smtppassword and not smtpuser):
raise CmdException, 'SMTP password supplied, username needed'
if (smtpuser and not smtppassword):
raise CmdException, 'SMTP username supplied, password needed'
+ if (smtpusetls and not smtpuser):
+ raise CmdException, 'SMTP over TLS requested, username needed'
total_nr = len(patches)
if total_nr == 0:
@@ -527,7 +539,7 @@ def func(parser, options, args):
else:
out.start('Sending the cover message')
__send_message(smtpserver, from_addr, to_addr_list, msg_string,
- sleep, smtpuser, smtppassword)
+ sleep, smtpuser, smtppassword, smtpusetls)
out.done()
# send the patches
@@ -555,5 +567,5 @@ def func(parser, options, args):
else:
out.start('Sending patch "%s"' % p)
__send_message(smtpserver, from_addr, to_addr_list, msg_string,
- sleep, smtpuser, smtppassword)
+ sleep, smtpuser, smtppassword, smtpusetls)
out.done()
^ permalink raw reply related
* Re: [PATCH] (Really) Fix install-doc-quick target
From: Junio C Hamano @ 2007-08-07 1:28 UTC (permalink / raw)
To: Mark Levedahl
Cc: Johannes Schindelin, Mark Levedahl, Git Mailing List, Ren Scharfe
In-Reply-To: <46B7B10F.4060402@gmail.com>
Mark Levedahl <mlevedahl@gmail.com> writes:
> Junio C Hamano wrote:
>> Yes. And 00d8c51 obviously "works for me", so there is
>> something different between what Mark and I are doing. I cannot
>> tell what it is.
>>
> GZ=1 make quick-install-doc
>
> ...fails because git-ls-tree is called when cwd=$mandir which is
> nowhere under or related to $GIT_DIR.
Oops. I am blind. That's right. That command does a chdir on
its own.
How does this sound?
---
diff --git a/Documentation/install-doc-quick.sh b/Documentation/install-doc-quick.sh
index 07d227f..bc170f0 100755
--- a/Documentation/install-doc-quick.sh
+++ b/Documentation/install-doc-quick.sh
@@ -24,10 +24,10 @@ git read-tree $head
git checkout-index -a -f --prefix="$mandir"/
if test -n "$GZ"; then
- cd "$mandir"
- for i in `git ls-tree -r --name-only $head`
+ git ls-tree -r --name-only $head |
+ while read path
do
- gzip < $i > $i.gz && rm $i
+ gzip "$mandir/$path"
done
fi
rm -f "$GIT_INDEX_FILE"
^ permalink raw reply related
* [PATCH] git checkout's reflog: even when detaching the HEAD, say from where
From: Johannes Schindelin @ 2007-08-07 1:42 UTC (permalink / raw)
To: gitster, git
When checking out another ref, the reflogs already record from which
branch you switched. Do that also when switching to a detached HEAD.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
git-checkout.sh | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/git-checkout.sh b/git-checkout.sh
index 17f4392..f427718 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -272,7 +272,8 @@ if [ "$?" -eq 0 ]; then
fi
elif test -n "$detached"
then
- git update-ref --no-deref -m "checkout: moving to $arg" HEAD "$detached" ||
+ old_branch_name=`expr "z$oldbranch" : 'zrefs/heads/\(.*\)'`
+ git update-ref --no-deref -m "checkout: moving from $old_branch_name to $arg" HEAD "$detached" ||
die "Cannot detach HEAD"
if test -n "$detach_warn"
then
--
1.5.3.rc4.17.gb980
^ permalink raw reply related
* Re: Problem with bisect
From: Christian Couder @ 2007-08-07 1:50 UTC (permalink / raw)
To: Larry Finger; +Cc: git
In-Reply-To: <46B5F48D.7020907@lwfinger.net>
Le dimanche 5 août 2007 18:02, Larry Finger a écrit :
> I'm helping someone find what looks like a regression in bcm43xx-mac80211
> between v2.6.22 and v2.6.23-rc1. This driver is not in the mainstream
> kernel, but is found in John Linville's wireless-dev git tree. When we do
> the first bisection between the current state and v2.6.22, we obtain a
> kernel whose Makefile says it is v2.6.22; however, it's code is based on
> a state before bcm43xx-mac80211 was introduced into this tree.
You use "git bisect good v2.6.22", but this is not true because the
tag "v2.6.22" is on the mainstream kernel branch and the driver is not
there.
If the v2.6.22 kernel that used to work came directly from John Linville's
wireless-dev git tree, not from a patch, then you should find the exact
commit in John Linville's tree that worked and say "git bisect good <this
commit>".
But if the driver that worked with a mainstream v2.6.22 kernel had been
patched, and now doesn't work when the same patch is applied to mainstream
v2.6.23-rc1 kernel, then you can perhaps use:
git bisect start
git bisect bad v2.6.23-rc1
git bisect good v2.6.22
and then:
1) patch the kernel with the driver patch,
2) test the patched kernel,
3) remove the patch,
4) say "git bisect good" or "git bisect bad"
5) go to step 1) until the commit that broke the driver is found
Best regards,
Christian.
^ permalink raw reply
* Re: [PATCH] (Really) Fix install-doc-quick target
From: Mark Levedahl @ 2007-08-07 1:55 UTC (permalink / raw)
To: Junio C Hamano
Cc: Johannes Schindelin, Mark Levedahl, Git Mailing List, Ren Scharfe
In-Reply-To: <7vhcnc9lpm.fsf@assigned-by-dhcp.cox.net>
Subject: Re: [PATCH] (Really) Fix install-doc-quick target
To: Junio C Hamano <gitster@pobox.com>
Cc: Johannes Schindelin <Johannes.Schindelin@gmx.de>,Mark
Levedahl <mdl123@verizon.net>,Git Mailing List <git@vger.kernel.org>,Ren
Scharfe <rene.scharfe@lsrfire.ath.cx>
Bcc:
Reply-To:
Newsgroup:
-=-=-=-=-=-=-=-=-=# Don't remove this line #=-=-=-=-=-=-=-=-=-
Junio C Hamano wrote:
> Mark Levedahl <mlevedahl@gmail.com> writes:
>
>
> How does this sound?
>
> ---
> diff --git a/Documentation/install-doc-quick.sh
b/Documentation/install-doc-quick.sh
> index 07d227f..bc170f0 100755
> --- a/Documentation/install-doc-quick.sh
> +++ b/Documentation/install-doc-quick.sh
> @@ -24,10 +24,10 @@ git read-tree $head
> git checkout-index -a -f --prefix="$mandir"/
>
> if test -n "$GZ"; then
> - cd "$mandir"
> - for i in `git ls-tree -r --name-only $head`
> + git ls-tree -r --name-only $head |
> + while read path
> do
> - gzip < $i > $i.gz && rm $i
> + gzip "$mandir/$path"
> done
> fi
> rm -f "$GIT_INDEX_FILE"
>
>
Maybe this instead, many fewer gzip invocations, happily overwrites the
old man pages already installed...
---
diff --git a/Documentation/install-doc-quick.sh
b/Documentation/install-doc-quick.sh
index 07d227f..45f78fa 100755
--- a/Documentation/install-doc-quick.sh
+++ b/Documentation/install-doc-quick.sh
@@ -24,10 +24,6 @@ git read-tree $head
git checkout-index -a -f --prefix="$mandir"/
if test -n "$GZ"; then
- cd "$mandir"
- for i in `git ls-tree -r --name-only $head`
- do
- gzip < $i > $i.gz && rm $i
- done
+ printf "$mandir/%s\n" $(git ls-tree -r --name-only $head) | xargs
gzip -f
fi
rm -f "$GIT_INDEX_FILE"
^ permalink raw reply related
* [PATCH] Ask for SMTP password if it's not provided
From: Pavel Roskin @ 2007-08-07 2:16 UTC (permalink / raw)
To: Catalin Marinas, git
Mention this in examples/gitconfig, explain SMTP options in more detail.
Signed-off-by: Pavel Roskin <proski@gnu.org>
---
examples/gitconfig | 9 ++++++++-
stgit/commands/mail.py | 6 +++---
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/examples/gitconfig b/examples/gitconfig
index 3abbe6a..e402208 100644
--- a/examples/gitconfig
+++ b/examples/gitconfig
@@ -18,10 +18,17 @@
# 'refresh' will automatically mark the conflicts as resolved
#autoresolved = no
+ # SMTP server for sending patches
#smtpserver = localhost:25
+
+ # Set to 'yes' to use SMTP over TLS
+ #smtptls = no
+
+ # Username for SMTP authentication, required if TLS is used
#smtpuser = username
+
+ # Password for SMTP. If not provided, it will be asked
#smtppassword = password
- #smtptls = no
# delay between messages in seconds (defaults to 5)
#smtpdelay = 5
diff --git a/stgit/commands/mail.py b/stgit/commands/mail.py
index 7ed5c27..69712cb 100644
--- a/stgit/commands/mail.py
+++ b/stgit/commands/mail.py
@@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
-import sys, os, re, time, datetime, socket, smtplib
+import sys, os, re, time, datetime, socket, smtplib, getpass
import email, email.Utils, email.Header
from optparse import OptionParser, make_option
@@ -492,10 +492,10 @@ def func(parser, options, args):
if (smtppassword and not smtpuser):
raise CmdException, 'SMTP password supplied, username needed'
- if (smtpuser and not smtppassword):
- raise CmdException, 'SMTP username supplied, password needed'
if (smtpusetls and not smtpuser):
raise CmdException, 'SMTP over TLS requested, username needed'
+ if (smtpuser and not smtppassword):
+ smtppassword = getpass.getpass("Please enter SMTP password: ")
total_nr = len(patches)
if total_nr == 0:
^ permalink raw reply related
* 'pu' branch for StGIT
From: Karl Hasselström @ 2007-08-07 2:20 UTC (permalink / raw)
To: git; +Cc: Pavel Roskin, Catalin Marinas, Yann Dirson
So I finally got my act together and published a 'pu'-like branch for
StGIT. Get it at git://repo.or.cz/stgit/kha.git; gitweb at
http://repo.or.cz/w/stgit/kha.git.
The idea is that I grab the StGIT patches that are posted to the list,
put each series in its own topic branch (based on Catalin's master),
and publish a merge of them. _After_ having made sure that the test
suite passes, naturally. It then becomes much easier for everyone to
test these patches.
This should lessen the pressure on Catalin to include patches in his
master branch as soon as possible, which should in turn reduce the
number of reverts in the official history.
Here's what's currently in there:
Karl Hasselström (8):
Teach StGIT about core.excludesfile
New test: make sure that popping doesn't change patch order
Verify patch status during the test
Make use of the get_patch() utility function
Compute patch appliedness from commit DAG
Test the new DAG appliedness machinery
Fix bash completion after the DAG appliedness patch
Speed up the appliedness test
Pavel Roskin (1):
Add support for SMTP over Transport Layer Security (TLS)
Yann Dirson (7):
Include contrib scripts in the release tarball.
Improve stg-fold-files-from doc.
New contrib scripts: stg-dispatch and stg-show.
Add -O flag to stg-fold-files-from.
Add a no-act flag to stg-dispatch and stg-fold-file-from.
Provide file completion for add/resolved/refresh based on status.
Fixed completion function hardcoding .git/.
(Does anyone know the incantation for Junio's status mails, with topic
branches grouped nicely?)
NOTE: The DAG appliedness patch series is in there. They will upgrade
the format of any stgit branch they touch, and there's no convenient
way to change it back if you change your mind.
--
Karl Hasselström, kha@treskal.com
www.treskal.com/kalle
^ permalink raw reply
* Re: 'pu' branch for StGIT
From: Shawn O. Pearce @ 2007-08-07 2:38 UTC (permalink / raw)
To: Karl Hasselström; +Cc: git, Pavel Roskin, Catalin Marinas, Yann Dirson
In-Reply-To: <20070807022043.GA8482@diana.vm.bytemark.co.uk>
Karl Hasselstrm <kha@treskal.com> wrote:
> (Does anyone know the incantation for Junio's status mails, with topic
> branches grouped nicely?)
Look at his todo branch; one of those scripts does the magic.
Start with todo:WC, apparently it calls todo:git-topic.perl.
Junio checks out the todo branch in a Meta/ subdirectory. :-)
--
Shawn.
^ permalink raw reply
* [StGIT PATCH] Teach StGIT about core.excludesfile
From: Karl Hasselström @ 2007-08-07 2:40 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
If there is a core.excludesfile option specified, let StGIT take
exclude patterns from that file, since that's what the docs say, and
what everyone else is already doing.
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
stgit/git.py | 27 +++++++++++++++------------
1 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/stgit/git.py b/stgit/git.py
index 72bf889..57c156e 100644
--- a/stgit/git.py
+++ b/stgit/git.py
@@ -216,6 +216,13 @@ def __run(cmd, args=None):
return r
return 0
+def exclude_files():
+ files = [os.path.join(basedir.get(), 'info', 'exclude')]
+ user_exclude = config.get('core.excludesfile')
+ if user_exclude:
+ files.append(user_exclude)
+ return files
+
def tree_status(files = None, tree_id = 'HEAD', unknown = False,
noexclude = True, verbose = False, diff_flags = []):
"""Returns a list of pairs - [status, filename]
@@ -231,20 +238,16 @@ def tree_status(files = None, tree_id = 'HEAD', unknown = False,
# unknown files
if unknown:
- exclude_file = os.path.join(basedir.get(), 'info', 'exclude')
- base_exclude = ['--exclude=%s' % s for s in
- ['*.[ao]', '*.pyc', '.*', '*~', '#*', 'TAGS', 'tags']]
- base_exclude.append('--exclude-per-directory=.gitignore')
-
- if os.path.exists(exclude_file):
- extra_exclude = ['--exclude-from=%s' % exclude_file]
- else:
- extra_exclude = []
if noexclude:
- extra_exclude = base_exclude = []
-
+ exclude = []
+ else:
+ exclude = (['--exclude=%s' % s for s in
+ ['*.[ao]', '*.pyc', '.*', '*~', '#*', 'TAGS', 'tags']]
+ + ['--exclude-per-directory=.gitignore']
+ + ['--exclude-from=%s' % fn for fn in exclude_files()
+ if os.path.exists(fn)])
lines = _output_lines(['git-ls-files', '--others', '--directory']
- + base_exclude + extra_exclude)
+ + exclude)
cache_files += [('?', line.strip()) for line in lines]
# conflicted files
^ permalink raw reply related
* [StGIT PATCH 0/2] New and improved tests
From: Karl Hasselström @ 2007-08-07 2:43 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
One new and one improved test, both primarily useful for making sure
the DAG pseries doesn't break anything, since no one else has managed
to produce bugs that mess up the patch order.
This far. So they might be worth having anyway. :-)
--
Karl Hasselström, kha@treskal.com
www.treskal.com/kalle
^ permalink raw reply
* [StGIT PATCH 1/2] New test: make sure that popping doesn't change patch order
From: Karl Hasselström @ 2007-08-07 2:43 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20070807024147.11174.87229.stgit@yoghurt>
This is mostly useful in conjunction with the DAG appliedness patches,
since getting this right with a plain series file _ought_ to be
trivial. Nevertheless ...
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
t/t1203-pop.sh | 33 +++++++++++++++++++++++++++++++++
1 files changed, 33 insertions(+), 0 deletions(-)
diff --git a/t/t1203-pop.sh b/t/t1203-pop.sh
new file mode 100755
index 0000000..0a311d4
--- /dev/null
+++ b/t/t1203-pop.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Copyright (c) 2007 Karl Hasselström
+test_description='Test the pop command'
+. ./test-lib.sh
+
+test_expect_success \
+ 'Initialize the StGIT repository' \
+ 'stg init'
+
+test_expect_success \
+ 'Create ten patches' '
+ for i in 0 1 2 3 4 5 6 7 8 9; do
+ stg new p$i -m p$i;
+ done &&
+ [ "$(echo $(stg applied))" = "p0 p1 p2 p3 p4 p5 p6 p7 p8 p9" ] &&
+ [ "$(echo $(stg unapplied))" = "" ]
+'
+
+test_expect_success \
+ 'Pop half the patches' '
+ stg pop -n 5 &&
+ [ "$(echo $(stg applied))" = "p0 p1 p2 p3 p4" ] &&
+ [ "$(echo $(stg unapplied))" = "p5 p6 p7 p8 p9" ]
+'
+
+test_expect_success \
+ 'Pop the remaining patches' '
+ stg pop -a &&
+ [ "$(echo $(stg applied))" = "" ] &&
+ [ "$(echo $(stg unapplied))" = "p0 p1 p2 p3 p4 p5 p6 p7 p8 p9" ]
+'
+
+test_done
^ permalink raw reply related
* [StGIT PATCH 2/2] Verify patch status during the test
From: Karl Hasselström @ 2007-08-07 2:43 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20070807024147.11174.87229.stgit@yoghurt>
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
t/t1200-push-modified.sh | 55 +++++++++++++++++++++++++++-------------------
1 files changed, 32 insertions(+), 23 deletions(-)
diff --git a/t/t1200-push-modified.sh b/t/t1200-push-modified.sh
index 324b3b0..0e408d0 100755
--- a/t/t1200-push-modified.sh
+++ b/t/t1200-push-modified.sh
@@ -19,23 +19,26 @@ specify --merged, then rollback and retry with the correct flag.'
test_create_repo foo
test_expect_success \
- 'Clone tree and setup changes' \
- "stg clone foo bar &&
- (cd bar && stg new p1 -m p1 &&
- printf 'a\nc\n' > file && stg add file && stg refresh &&
- stg new p2 -m p2 &&
- printf 'a\nb\nc\n' > file && stg refresh
- )
-"
+ 'Clone tree and setup changes' '
+ stg clone foo bar &&
+ (
+ cd bar && stg new p1 -m p1 &&
+ printf "a\nc\n" > file && stg add file && stg refresh &&
+ stg new p2 -m p2 &&
+ printf "a\nb\nc\n" > file && stg refresh &&
+ [ "$(echo $(stg applied))" = "p1 p2" ] &&
+ [ "$(echo $(stg unapplied))" = "" ]
+ )
+'
test_expect_success \
- 'Port those patches to orig tree' \
- '(cd foo &&
- GIT_DIR=../bar/.git git-format-patch --stdout \
- $(cd ../bar && stg id base@master)..HEAD |
- git-am -3 -k
- )
- '
+ 'Port those patches to orig tree' '
+ (
+ cd foo &&
+ GIT_DIR=../bar/.git git-format-patch --stdout \
+ $(cd ../bar && stg id base@master)..HEAD | git-am -3 -k
+ )
+'
test_expect_success \
'Pull to sync with parent, preparing for the problem' \
@@ -51,15 +54,21 @@ test_expect_failure \
"
test_expect_success \
- 'Rollback the push' \
- "(cd bar && stg push --undo
- )
-"
+ 'Rollback the push' '
+ (
+ cd bar && stg push --undo &&
+ [ "$(echo $(stg applied))" = "" ] &&
+ [ "$(echo $(stg unapplied))" = "p1 p2" ]
+ )
+'
test_expect_success \
- 'Push those patches while checking they were merged upstream' \
- "(cd bar && stg push --merged --all
- )
-"
+ 'Push those patches while checking they were merged upstream' '
+ (
+ cd bar && stg push --merged --all
+ [ "$(echo $(stg applied))" = "p1 p2" ] &&
+ [ "$(echo $(stg unapplied))" = "" ]
+ )
+'
test_done
^ permalink raw reply related
* [StGIT PATCH 0/5] Compute patch appliedness using the commit DAG
From: Karl Hasselström @ 2007-08-07 2:47 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
This is the same old series, now rebased against 0.13. It's in my
repo.or.cz repository, so I have high hopes of tricking people into
actually trying it out so that it can be merged eventually.
--
Karl Hasselström, kha@treskal.com
www.treskal.com/kalle
^ permalink raw reply
* [StGIT PATCH 1/5] Make use of the get_patch() utility function
From: Karl Hasselström @ 2007-08-07 2:47 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20070807024508.11373.62875.stgit@yoghurt>
We already had it, but no one was using it
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
stgit/stack.py | 27 +++++++++++++--------------
1 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/stgit/stack.py b/stgit/stack.py
index dbd7ea4..6f87f28 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -466,7 +466,7 @@ class Series(PatchSet):
crt = self.get_current()
if not crt:
return None
- return Patch(crt, self.__patch_dir, self.__refs_dir)
+ return self.get_patch(crt)
def get_current(self):
"""Return the name of the topmost patch, or None if there is
@@ -684,7 +684,7 @@ class Series(PatchSet):
raise StackException, \
'Cannot delete: the series still contains patches'
for p in patches:
- Patch(p, self.__patch_dir, self.__refs_dir).delete()
+ self.get_patch(p).delete()
# remove the trash directory if any
if os.path.exists(self.__trash_dir):
@@ -741,7 +741,7 @@ class Series(PatchSet):
if not name:
raise StackException, 'No patches applied'
- patch = Patch(name, self.__patch_dir, self.__refs_dir)
+ patch = self.get_patch(name)
descr = patch.get_description()
if not (message or descr):
@@ -807,7 +807,7 @@ class Series(PatchSet):
name = self.get_current()
assert(name)
- patch = Patch(name, self.__patch_dir, self.__refs_dir)
+ patch = self.get_patch(name)
old_bottom = patch.get_old_bottom()
old_top = patch.get_old_top()
@@ -848,7 +848,7 @@ class Series(PatchSet):
if name == None:
name = make_patch_name(descr, self.patch_exists)
- patch = Patch(name, self.__patch_dir, self.__refs_dir)
+ patch = self.get_patch(name)
patch.create()
if not bottom:
@@ -936,7 +936,7 @@ class Series(PatchSet):
for name in names:
assert(name in unapplied)
- patch = Patch(name, self.__patch_dir, self.__refs_dir)
+ patch = self.get_patch(name)
head = top
bottom = patch.get_bottom()
@@ -1002,8 +1002,7 @@ class Series(PatchSet):
patches detected to have been applied. The state of the tree
is restored to the original one
"""
- patches = [Patch(name, self.__patch_dir, self.__refs_dir)
- for name in names]
+ patches = [self.get_patch(name) for name in names]
patches.reverse()
merged = []
@@ -1022,7 +1021,7 @@ class Series(PatchSet):
unapplied = self.get_unapplied()
assert(name in unapplied)
- patch = Patch(name, self.__patch_dir, self.__refs_dir)
+ patch = self.get_patch(name)
head = git.get_head()
bottom = patch.get_bottom()
@@ -1096,7 +1095,7 @@ class Series(PatchSet):
name = self.get_current()
assert(name)
- patch = Patch(name, self.__patch_dir, self.__refs_dir)
+ patch = self.get_patch(name)
old_bottom = patch.get_old_bottom()
old_top = patch.get_old_top()
@@ -1122,7 +1121,7 @@ class Series(PatchSet):
applied.reverse()
assert(name in applied)
- patch = Patch(name, self.__patch_dir, self.__refs_dir)
+ patch = self.get_patch(name)
if git.get_head_file() == self.get_name():
if keep and not git.apply_diff(git.get_head(), patch.get_bottom()):
@@ -1148,7 +1147,7 @@ class Series(PatchSet):
"""Returns True if the patch is empty
"""
self.__patch_name_valid(name)
- patch = Patch(name, self.__patch_dir, self.__refs_dir)
+ patch = self.get_patch(name)
bottom = patch.get_bottom()
top = patch.get_top()
@@ -1173,11 +1172,11 @@ class Series(PatchSet):
raise StackException, 'Patch "%s" already exists' % newname
if oldname in unapplied:
- Patch(oldname, self.__patch_dir, self.__refs_dir).rename(newname)
+ self.get_patch(oldname).rename(newname)
unapplied[unapplied.index(oldname)] = newname
write_strings(self.__unapplied_file, unapplied)
elif oldname in applied:
- Patch(oldname, self.__patch_dir, self.__refs_dir).rename(newname)
+ self.get_patch(oldname).rename(newname)
applied[applied.index(oldname)] = newname
write_strings(self.__applied_file, applied)
^ permalink raw reply related
* [StGIT PATCH 2/5] Compute patch appliedness from commit DAG
From: Karl Hasselström @ 2007-08-07 2:47 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20070807024508.11373.62875.stgit@yoghurt>
Don't rely on cached metadata in the "applied" and "unapplied" files
to tell which patches are applied. Instead, consider the patches
reachable from the branch head to be applied, and the rest unapplied.
The order of the applied patches is also taken from the DAG, but we
can't do that for the unapplied patches. So the patch order is saved
to a file whenever it changes, and that file is consulted whenever we
need to compute the order of the unapplied patches.
The point of this excercise is to let users do things such as "git
reset" without confusing stgit. This gives incrased flexibility to
power users, and increased safety to other users. The advantages come
from the removal of redundant metadata: it is no longer possible for
StGIT's appliedness status to get out of sync with the underlying git
commit DAG.
This is how the appliedness and order is computed:
* First, a single call to git-show-ref gives the hashes of all
patches and the branch head.
* Then, "git-rev-list patch1 patch2 patch3 ^branch" lists a small
set of hashes that contains all the unapplied patches and none of
the applied patches.
* Last, "git-rev-list head" lists all commits in the branch. The
applied patches are listed in the correct order.
This is efficient because none of the two rev-list calls need to look
at more than a small part of the DAG. The first call returns a small
set of commits, and the last call is abandoned before it has time to
look far back in the DAG.
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
stgit/commands/commit.py | 8 -
stgit/commands/float.py | 2
stgit/commands/imprt.py | 2
stgit/commands/refresh.py | 2
stgit/commands/sync.py | 2
stgit/git.py | 5 +
stgit/stack.py | 300 +++++++++++++++++++++++++++++++--------------
t/t4000-upgrade.sh | 6 +
8 files changed, 223 insertions(+), 104 deletions(-)
diff --git a/stgit/commands/commit.py b/stgit/commands/commit.py
index 2b8d7ce..5450112 100644
--- a/stgit/commands/commit.py
+++ b/stgit/commands/commit.py
@@ -52,14 +52,8 @@ def func(parser, options, args):
if crt_series.get_protected():
raise CmdException, 'This branch is protected. Commit is not permitted'
- crt_head = git.get_head()
-
out.start('Committing %d patches' % len(applied))
-
- crt_series.pop_patch(applied[0])
- git.switch(crt_head)
-
for patch in applied:
- crt_series.delete_patch(patch)
+ crt_series.delete_patch_data(patch)
out.done()
diff --git a/stgit/commands/float.py b/stgit/commands/float.py
index 0e32f6b..8ba76d5 100644
--- a/stgit/commands/float.py
+++ b/stgit/commands/float.py
@@ -48,7 +48,7 @@ def func(parser, options, args):
check_head_top_equal()
unapplied = crt_series.get_unapplied()
- applied = crt_series.get_applied()
+ applied = list(crt_series.get_applied()) # a copy, since we'll modify it
all = unapplied + applied
if options.series:
diff --git a/stgit/commands/imprt.py b/stgit/commands/imprt.py
index f972b89..555e160 100644
--- a/stgit/commands/imprt.py
+++ b/stgit/commands/imprt.py
@@ -293,7 +293,7 @@ def __create_patch(filename, message, author_name, author_email,
git.apply_patch(diff = diff, base = git_id(options.base))
else:
git.apply_patch(diff = diff)
- crt_series.refresh_patch(edit = options.edit,
+ crt_series.refresh_patch(patch, edit = options.edit,
show_patch = options.showpatch)
out.done()
diff --git a/stgit/commands/refresh.py b/stgit/commands/refresh.py
index 8277388..75799c0 100644
--- a/stgit/commands/refresh.py
+++ b/stgit/commands/refresh.py
@@ -147,7 +147,7 @@ def func(parser, options, args):
if autoresolved == 'yes':
resolved_all()
- crt_series.refresh_patch(files = files,
+ crt_series.refresh_patch(patch, files = files,
message = options.message,
edit = options.edit,
show_patch = options.showpatch,
diff --git a/stgit/commands/sync.py b/stgit/commands/sync.py
index 5e33324..d8af046 100644
--- a/stgit/commands/sync.py
+++ b/stgit/commands/sync.py
@@ -156,7 +156,7 @@ def func(parser, options, args):
if git.local_changes(verbose = False):
# index (cache) already updated by the git merge. The
# backup information was already reset above
- crt_series.refresh_patch(cache_update = False, backup = False,
+ crt_series.refresh_patch(p, cache_update = False, backup = False,
log = 'sync')
out.done('updated')
else:
diff --git a/stgit/git.py b/stgit/git.py
index 72bf889..13d3e8d 100644
--- a/stgit/git.py
+++ b/stgit/git.py
@@ -189,8 +189,11 @@ def _output_one_line(cmd, file_desc = None):
p.childerr.read().strip())
return output
-def _output_lines(cmd):
+def _output_lines(cmd, input = []):
p=popen2.Popen3(cmd, True)
+ for line in input:
+ p.tochild.write(line)
+ p.tochild.close()
lines = p.fromchild.readlines()
if p.wait():
raise GitException, '%s failed (%s)' % (' '.join(cmd),
diff --git a/stgit/stack.py b/stgit/stack.py
index 6f87f28..4186ba9 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -18,13 +18,13 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
-import sys, os, re
+import sys, os, popen2, re
from stgit.utils import *
from stgit import git, basedir, templates
from stgit.config import config
from shutil import copyfile
-
+from sets import Set
# stack exception class
class StackException(Exception):
@@ -274,7 +274,7 @@ class Patch(StgitObject):
self.__update_log_ref(value)
# The current StGIT metadata format version.
-FORMAT_VERSION = 2
+FORMAT_VERSION = 3
class PatchSet(StgitObject):
def __init__(self, name = None):
@@ -346,6 +346,153 @@ class PatchSet(StgitObject):
return bool(config.get(self.format_version_key()))
+class PatchorderCache:
+ """An object that keeps track of the patch order for a series, as
+ saved in its patchorder file."""
+ def __init__(self, series):
+ self.__series = series
+ self.__invalidate()
+ def __invalidate(self):
+ self.__patchnames = None
+ self.__position = None
+ def __cache(self):
+ if self.__patchnames != None:
+ return # already cached
+
+ self.__patchnames = []
+ self.__position = {}
+ pof = os.path.join(self.__series._dir(), 'patchorder')
+ if os.path.isfile(pof):
+ for line in file(pof):
+ name = line.strip()
+ assert not name in self.__position
+ self.__position[name] = len(self.__patchnames)
+ self.__patchnames.append(name)
+ def set_patchorder(self, new_order):
+ self.__invalidate()
+ f = file(os.path.join(self.__series._dir(), 'patchorder'), 'w')
+ for name in new_order:
+ f.write('%s\n' % name)
+ f.close()
+ def cmp(self, name1, name2):
+ """Compare two patch names to see which patch comes first. If
+ both patches are listed in the patchorder file, sort them by
+ the order they appear there; if one is listed and the other
+ not, the listed patch goes first; and if neither is listed,
+ sort them by their names."""
+ self.__cache()
+ largepos = len(self.__patchnames)
+ pos1 = self.__position.get(name1, largepos)
+ pos2 = self.__position.get(name2, largepos)
+ return cmp((pos1, name1), (pos2, name2))
+
+def read_refs(branch):
+ """Return a mapping from patches and branch head to hashes for a
+ given branch. The patches are listed by name; the branch head is
+ None."""
+ refs = {}
+ patchpat = re.compile(r'^refs/patches/%s/([^\.]+)$' % branch)
+ for line in git._output_lines('git-show-ref'):
+ sha1, ref = line.split()
+ m = re.match(patchpat, ref)
+ if m:
+ refs[m.group(1)] = sha1
+ elif ref == 'refs/heads/%s' % branch:
+ refs[None] = sha1
+ return refs
+
+def unapplied_patches(ref2hash):
+ """Given a map of patch names (and the branch head, keyed by None)
+ to hashes, return the set of unapplied patches."""
+ hash2refs = {}
+ for r, h in ref2hash.iteritems():
+ hash2refs.setdefault(h, Set()).add(r)
+
+ unapplied = Set()
+ for line in git._output_lines(
+ 'git-rev-list --stdin',
+ ('%s%s\n' % (['', '^'][ref == None], sha1)
+ for ref, sha1 in ref2hash.iteritems())):
+ for ref in hash2refs.get(line.strip(), []):
+ unapplied.add(ref)
+ return unapplied
+
+def sort_applied_patches(ref2hash):
+ """Given a map of patch names (and the branch head, keyed by None)
+ to hashes, return a list with the applied patches in stack order.
+ All patches in the map must be applied."""
+ hash2refs = {}
+ for r, h in ref2hash.iteritems():
+ if r != None:
+ hash2refs.setdefault(h, Set()).add(r)
+
+ missing = Set(ref for ref in ref2hash.iterkeys() if ref != None)
+ if not missing:
+ return []
+ applied = []
+ grl = popen2.Popen3('git-rev-list %s' % ref2hash[None], True)
+ for line in grl.fromchild:
+ for ref in hash2refs.get(line.strip(), []):
+ applied.append(ref)
+ missing.remove(ref)
+ if not missing:
+ applied.reverse()
+ return applied
+
+ raise StackException, 'Could not find patches: %s' % ', '.join(missing)
+
+class AppliedCache:
+ """An object that keeps track of the appliedness and order of the
+ patches in a patch series."""
+ def __init__(self, series):
+ self.__series = series
+ self.__order = PatchorderCache(series)
+ self.__invalidate()
+ def get_applied(self):
+ self.__cache()
+ return self.__applied
+ def get_unapplied(self):
+ self.__cache()
+ return self.__unapplied
+ def rename(self, oldname, newname):
+ """Rename a patch."""
+ self.__cache()
+ for lst in (self.__applied, self.__unapplied):
+ try:
+ lst[lst.index(oldname)] = newname
+ except ValueError:
+ pass # lst.index() couldn't find the index
+ else:
+ self.__write_patchorder()
+ return
+ raise StackException, 'Unknown patch "%s"' % oldname
+ def __write_patchorder(self):
+ self.__order.set_patchorder(self.get_applied() + self.get_unapplied())
+ def set_patchorder(self, new_order):
+ self.__order.set_patchorder(new_order)
+ self.refresh()
+ def refresh(self):
+ """Re-read patch appliedness info, and write patch order to
+ disk."""
+ self.__invalidate()
+ self.__write_patchorder()
+ def __invalidate(self):
+ self.__applied = None
+ self.__unapplied = None
+ def __cached(self):
+ return (self.__applied != None)
+ def __cache(self):
+ if self.__cached():
+ return
+ patches = read_refs(self.__series.get_name())
+ unapplied = unapplied_patches(patches)
+ for patch in unapplied:
+ del patches[patch]
+ self.__applied = sort_applied_patches(patches)
+ self.__unapplied = list(unapplied)
+ self.__unapplied.sort(self.__order.cmp)
+
+
class Series(PatchSet):
"""Class including the operations on series
"""
@@ -361,8 +508,6 @@ class Series(PatchSet):
self.__refs_dir = os.path.join(self._basedir(), 'refs', 'patches',
self.get_name())
- self.__applied_file = os.path.join(self._dir(), 'applied')
- self.__unapplied_file = os.path.join(self._dir(), 'unapplied')
self.__hidden_file = os.path.join(self._dir(), 'hidden')
# where this series keeps its patches
@@ -371,6 +516,8 @@ class Series(PatchSet):
# trash directory
self.__trash_dir = os.path.join(self._dir(), 'trash')
+ self.__applied_cache = AppliedCache(self)
+
def format_version_key(self):
return 'branch.%s.stgit.stackformatversion' % self.get_name()
@@ -444,6 +591,21 @@ class Series(PatchSet):
rm(os.path.join(self._basedir(), 'refs', 'bases', self.get_name()))
set_format_version(2)
+ # Update 2 -> 3.
+ if get_format_version() == 2:
+ patchorder = file(os.path.join(branch_dir, 'patchorder'), 'w')
+ for pf in ['applied', 'unapplied']:
+ pfn = os.path.join(branch_dir, pf)
+ if not os.path.isfile(pfn):
+ continue
+ for line in file(pfn):
+ line = line.strip()
+ if line:
+ patchorder.write(line + '\n')
+ rm(pfn)
+ patchorder.close()
+ set_format_version(3)
+
# Make sure we're at the latest version.
if not get_format_version() in [None, FORMAT_VERSION]:
raise StackException('Branch %s is at format version %d, expected %d'
@@ -471,11 +633,7 @@ class Series(PatchSet):
def get_current(self):
"""Return the name of the topmost patch, or None if there is
no such patch."""
- try:
- applied = self.get_applied()
- except StackException:
- # No "applied" file: branch is not initialized.
- return None
+ applied = self.get_applied()
try:
return applied[-1]
except IndexError:
@@ -483,14 +641,10 @@ class Series(PatchSet):
return None
def get_applied(self):
- if not os.path.isfile(self.__applied_file):
- raise StackException, 'Branch "%s" not initialised' % self.get_name()
- return read_strings(self.__applied_file)
+ return self.__applied_cache.get_applied()
def get_unapplied(self):
- if not os.path.isfile(self.__unapplied_file):
- raise StackException, 'Branch "%s" not initialised' % self.get_name()
- return read_strings(self.__unapplied_file)
+ return self.__applied_cache.get_unapplied()
def get_hidden(self):
if not os.path.isfile(self.__hidden_file):
@@ -498,13 +652,12 @@ class Series(PatchSet):
return read_strings(self.__hidden_file)
def get_base(self):
- # Return the parent of the bottommost patch, if there is one.
- if os.path.isfile(self.__applied_file):
- bottommost = file(self.__applied_file).readline().strip()
- if bottommost:
- return self.get_patch(bottommost).get_bottom()
- # No bottommost patch, so just return HEAD
- return git.get_head()
+ applied = self.get_applied()
+ if applied:
+ return self.get_patch(applied[0]).get_bottom()
+ else:
+ # No bottommost patch, so just return HEAD
+ return git.get_head()
def get_parent_remote(self):
value = config.get('branch.%s.remote' % self.get_name())
@@ -591,8 +744,6 @@ class Series(PatchSet):
self.set_parent(parent_remote, parent_branch)
- self.create_empty_field('applied')
- self.create_empty_field('unapplied')
os.makedirs(self.__refs_dir)
self._set_field('orig-base', git.get_head())
@@ -694,10 +845,6 @@ class Series(PatchSet):
# FIXME: find a way to get rid of those manual removals
# (move functionality to StgitObject ?)
- if os.path.exists(self.__applied_file):
- os.remove(self.__applied_file)
- if os.path.exists(self.__unapplied_file):
- os.remove(self.__unapplied_file)
if os.path.exists(self.__hidden_file):
os.remove(self.__hidden_file)
if os.path.exists(self._dir()+'/orig-base'):
@@ -727,7 +874,7 @@ class Series(PatchSet):
config.unset('branch.%s.stgit.parentbranch' % self.get_name())
config.unset(self.format_version_key())
- def refresh_patch(self, files = None, message = None, edit = False,
+ def refresh_patch(self, name, files = None, message = None, edit = False,
show_patch = False,
cache_update = True,
author_name = None, author_email = None,
@@ -737,10 +884,6 @@ class Series(PatchSet):
notes = None):
"""Generates a new commit for the given patch
"""
- name = self.get_current()
- if not name:
- raise StackException, 'No patches applied'
-
patch = self.get_patch(name)
descr = patch.get_description()
@@ -830,9 +973,10 @@ class Series(PatchSet):
"""Creates a new patch
"""
+ appl, unappl = self.get_applied(), self.get_unapplied()
if name != None:
self.__patch_name_valid(name)
- if self.patch_exists(name):
+ if name in appl or name in unappl:
raise StackException, 'Patch "%s" already exists' % name
if not message and can_edit:
@@ -866,17 +1010,12 @@ class Series(PatchSet):
patch.set_commemail(committer_email)
if before_existing:
- insert_string(self.__applied_file, patch.get_name())
+ order = [patch.get_name()] + appl + unappl
# no need to commit anything as the object is already
# present (mainly used by 'uncommit')
commit = False
- elif unapplied:
- patches = [patch.get_name()] + self.get_unapplied()
- write_strings(self.__unapplied_file, patches)
- set_head = False
else:
- append_string(self.__applied_file, patch.get_name())
- set_head = True
+ order = appl + [patch.get_name()] + unappl
if commit:
# create a commit for the patch (may be empty if top == bottom);
@@ -886,7 +1025,7 @@ class Series(PatchSet):
commit_id = git.commit(message = descr, parents = [bottom],
cache_update = False,
tree_id = top_commit.get_tree(),
- allowempty = True, set_head = set_head,
+ allowempty = True, set_head = not unapplied,
author_name = author_name,
author_email = author_email,
author_date = author_date,
@@ -897,15 +1036,27 @@ class Series(PatchSet):
self.log_patch(patch, 'new')
+ self.__applied_cache.set_patchorder(order)
+ return patch
+
+ def delete_patch_data(self, name):
+ """Deletes the stgit data for a patch."""
+ patch = Patch(name, self.__patch_dir, self.__refs_dir)
+
+ # save the commit id to a trash file
+ write_string(os.path.join(self.__trash_dir, name), patch.get_top())
+
+ patch.delete()
+ if self.patch_hidden(name):
+ self.unhide_patch(name)
+
return patch
def delete_patch(self, name):
"""Deletes a patch
"""
self.__patch_name_valid(name)
- patch = Patch(name, self.__patch_dir, self.__refs_dir)
-
- if self.__patch_is_current(patch):
+ if self.get_current() == name:
self.pop_patch(name)
elif self.patch_applied(name):
raise StackException, 'Cannot remove an applied patch, "%s", ' \
@@ -913,14 +1064,8 @@ class Series(PatchSet):
elif not name in self.get_unapplied():
raise StackException, 'Unknown patch "%s"' % name
- # save the commit id to a trash file
- write_string(os.path.join(self.__trash_dir, name), patch.get_top())
-
- patch.delete()
-
- unapplied = self.get_unapplied()
- unapplied.remove(name)
- write_strings(self.__unapplied_file, unapplied)
+ self.delete_patch_data(name)
+ self.__applied_cache.refresh()
def forward_patches(self, names):
"""Try to fast-forward an array of patches.
@@ -984,16 +1129,12 @@ class Series(PatchSet):
break
forwarded+=1
- unapplied.remove(name)
if forwarded == 0:
return 0
git.switch(top)
-
- append_strings(self.__applied_file, names[0:forwarded])
- write_strings(self.__unapplied_file, unapplied)
-
+ self.__applied_cache.refresh()
return forwarded
def merged_patches(self, names):
@@ -1066,11 +1207,6 @@ class Series(PatchSet):
'Use "refresh" after fixing the conflicts or'
' revert the operation with "push --undo".')
- append_string(self.__applied_file, name)
-
- unapplied.remove(name)
- write_strings(self.__unapplied_file, unapplied)
-
# head == bottom case doesn't need to refresh the patch
if empty or head != bottom:
if not ex:
@@ -1080,15 +1216,17 @@ class Series(PatchSet):
log = 'push(m)'
else:
log = 'push'
- self.refresh_patch(cache_update = False, log = log)
+ self.refresh_patch(name, cache_update = False, log = log)
else:
# we store the correctly merged files only for
# tracking the conflict history. Note that the
# git.merge() operations should always leave the index
# in a valid state (i.e. only stage 0 files)
- self.refresh_patch(cache_update = False, log = 'push(c)')
+ self.refresh_patch(name, cache_update = False, log = 'push(c)')
raise StackException, str(ex)
+ self.__applied_cache.refresh()
+
return modified
def undo_push(self):
@@ -1117,10 +1255,7 @@ class Series(PatchSet):
def pop_patch(self, name, keep = False):
"""Pops the top patch from the stack
"""
- applied = self.get_applied()
- applied.reverse()
- assert(name in applied)
-
+ assert(name in self.get_applied())
patch = self.get_patch(name)
if git.get_head_file() == self.get_name():
@@ -1131,17 +1266,7 @@ class Series(PatchSet):
else:
git.set_branch(self.get_name(), patch.get_bottom())
- # save the new applied list
- idx = applied.index(name) + 1
-
- popped = applied[:idx]
- popped.reverse()
- unapplied = popped + self.get_unapplied()
- write_strings(self.__unapplied_file, unapplied)
-
- del applied[:idx]
- applied.reverse()
- write_strings(self.__applied_file, applied)
+ self.__applied_cache.refresh()
def empty_patch(self, name):
"""Returns True if the patch is empty
@@ -1171,17 +1296,8 @@ class Series(PatchSet):
if newname in applied or newname in unapplied:
raise StackException, 'Patch "%s" already exists' % newname
- if oldname in unapplied:
- self.get_patch(oldname).rename(newname)
- unapplied[unapplied.index(oldname)] = newname
- write_strings(self.__unapplied_file, unapplied)
- elif oldname in applied:
- self.get_patch(oldname).rename(newname)
-
- applied[applied.index(oldname)] = newname
- write_strings(self.__applied_file, applied)
- else:
- raise StackException, 'Unknown patch "%s"' % oldname
+ self.get_patch(oldname).rename(newname)
+ self.__applied_cache.rename(oldname, newname)
def log_patch(self, patch, message, notes = None):
"""Generate a log commit for a patch
diff --git a/t/t4000-upgrade.sh b/t/t4000-upgrade.sh
index 8a308fb..01be50d 100755
--- a/t/t4000-upgrade.sh
+++ b/t/t4000-upgrade.sh
@@ -34,6 +34,12 @@ for ver in 0.12 0.8; do
! git show-ref --verify --quiet refs/bases/master
'
+ test_expect_success \
+ "v$ver: Make sure the applied and unapplied files are gone" '
+ [ ! -e .git/patches/master/applied ] &&
+ [ ! -e .git/patches/master/unapplied ]
+'
+
cd ..
done
^ permalink raw reply related
* [StGIT PATCH 3/5] Test the new DAG appliedness machinery
From: Karl Hasselström @ 2007-08-07 2:47 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20070807024508.11373.62875.stgit@yoghurt>
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
t/t3000-git-interop.sh | 60 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 60 insertions(+), 0 deletions(-)
diff --git a/t/t3000-git-interop.sh b/t/t3000-git-interop.sh
new file mode 100755
index 0000000..44414b9
--- /dev/null
+++ b/t/t3000-git-interop.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# Copyright (c) 2007 Karl Hasselström
+test_description='Test git/StGIT interoperability'
+. ./test-lib.sh
+
+test_expect_success \
+ 'Create some git-only history' '
+ echo foo > foo.txt &&
+ git add foo.txt &&
+ git commit -a -m foo &&
+ git tag foo-tag &&
+ for i in 0 1 2 3 4; do
+ echo foo$i >> foo.txt &&
+ git commit -a -m foo$i;
+ done
+'
+
+test_expect_success \
+ 'Initialize the StGIT repository' '
+ stg init
+'
+
+test_expect_success \
+ 'Create five patches' '
+ for i in 0 1 2 3 4; do
+ stg new p$i -m p$i;
+ done &&
+ [ "$(echo $(stg applied))" = "p0 p1 p2 p3 p4" ] &&
+ [ "$(echo $(stg unapplied))" = "" ]
+'
+
+test_expect_success \
+ 'Pop two patches with git-reset' '
+ git reset --hard HEAD~2 &&
+ [ "$(echo $(stg applied))" = "p0 p1 p2" ] &&
+ [ "$(echo $(stg unapplied))" = "p3 p4" ]
+'
+
+test_expect_success \
+ 'Create a new patch' '
+ stg new q0 -m q0 &&
+ [ "$(echo $(stg applied))" = "p0 p1 p2 q0" ] &&
+ [ "$(echo $(stg unapplied))" = "p3 p4" ]
+'
+
+test_expect_success \
+ 'Go to an unapplied patch with with git-reset' '
+ git reset --hard $(stg id p3) &&
+ [ "$(echo $(stg applied))" = "p0 p1 p2 p3" ] &&
+ [ "$(echo $(stg unapplied))" = "q0 p4" ]
+'
+
+test_expect_success \
+ 'Go back to below the stack base with git-reset' '
+ git reset --hard foo-tag &&
+ [ "$(echo $(stg applied))" = "" ] &&
+ [ "$(echo $(stg unapplied))" = "p0 p1 p2 q0 p3 p4" ]
+'
+
+test_done
^ permalink raw reply related
* [StGIT PATCH 4/5] Fix bash completion after the DAG appliedness patch
From: Karl Hasselström @ 2007-08-07 2:48 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20070807024508.11373.62875.stgit@yoghurt>
The bash tab completion used the "applied", "unapplied" and "current"
files to generate completions. Since these don't exist anymore, use
stg applied/unapplied/series to obtain the same info. It's a bit
slower, but not terribly much so.
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
contrib/stgit-completion.bash | 15 ++++-----------
1 files changed, 4 insertions(+), 11 deletions(-)
diff --git a/contrib/stgit-completion.bash b/contrib/stgit-completion.bash
index a843db4..842f0b1 100644
--- a/contrib/stgit-completion.bash
+++ b/contrib/stgit-completion.bash
@@ -70,15 +70,13 @@ _current_branch ()
# List of all applied patches.
_applied_patches ()
{
- local g=$(_gitdir)
- [ "$g" ] && cat "$g/patches/$(_current_branch)/applied"
+ stg applied 2> /dev/null
}
# List of all unapplied patches.
_unapplied_patches ()
{
- local g=$(_gitdir)
- [ "$g" ] && cat "$g/patches/$(_current_branch)/unapplied"
+ stg unapplied 2> /dev/null
}
# List of all applied patches.
@@ -91,18 +89,13 @@ _hidden_patches ()
# List of all patches.
_all_patches ()
{
- local b=$(_current_branch)
- local g=$(_gitdir)
- [ "$g" ] && cat "$g/patches/$b/applied" "$g/patches/$b/unapplied"
+ stg series --noprefix 2> /dev/null
}
# List of all patches except the current patch.
_all_other_patches ()
{
- local b=$(_current_branch)
- local g=$(_gitdir)
- [ "$g" ] && cat "$g/patches/$b/applied" "$g/patches/$b/unapplied" \
- | grep -v "^$(cat $g/patches/$b/current 2> /dev/null)$"
+ stg series 2> /dev/null | grep -v '^>' | cut -f 2 -d ' '
}
_all_branches ()
^ permalink raw reply related
* [StGIT PATCH 5/5] Speed up the appliedness test
From: Karl Hasselström @ 2007-08-07 2:48 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20070807024508.11373.62875.stgit@yoghurt>
The appliedness test was too slow if at least one patch, applied or
unapplied, was too far away from HEAD, since we had to visit the whole
intervening part of the commit DAG.
This patch fixes that problem by maintaining a cache of uninteresting
commits that are known to not reach any patches in the commit DAG.
(Specifically, this is at all times the set of commits that are
parents to patch commits and do not have a patch commit as their
ancestor.) By exlcuding these commits when walking the graph, we only
have to visit the interesting places.
As a nice side effect, the cache of uninteresting commits makes it
possible to use just one git-rev-list call instead of two, since we
can list the applied patches without first computing the unapplied
patches; the unapplied patches are then simply all patches except
those that are applied.
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
stgit/stack.py | 272 ++++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 221 insertions(+), 51 deletions(-)
diff --git a/stgit/stack.py b/stgit/stack.py
index 4186ba9..5a51329 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -155,7 +155,7 @@ class Patch(StgitObject):
os.mkdir(self._dir())
self.create_empty_field('bottom')
self.create_empty_field('top')
-
+
def delete(self):
for f in os.listdir(self._dir()):
os.remove(os.path.join(self._dir(), f))
@@ -351,7 +351,11 @@ class PatchorderCache:
saved in its patchorder file."""
def __init__(self, series):
self.__series = series
+ self.__file = os.path.join(self.__series._dir(), 'patchorder')
self.__invalidate()
+ def delete_file(self):
+ if os.path.isfile(self.__file):
+ os.remove(self.__file)
def __invalidate(self):
self.__patchnames = None
self.__position = None
@@ -361,9 +365,8 @@ class PatchorderCache:
self.__patchnames = []
self.__position = {}
- pof = os.path.join(self.__series._dir(), 'patchorder')
- if os.path.isfile(pof):
- for line in file(pof):
+ if os.path.isfile(self.__file):
+ for line in file(self.__file):
name = line.strip()
assert not name in self.__position
self.__position[name] = len(self.__patchnames)
@@ -386,60 +389,200 @@ class PatchorderCache:
pos2 = self.__position.get(name2, largepos)
return cmp((pos1, name1), (pos2, name2))
+class UninterestingCache:
+ """Keeps track of a set of commits that do not reach any patches.
+ These are used to speed up the detection of unapplied patches.
+
+ Specifically, this is at all times the set of commits c that
+ fulfill the following two criteria:
+
+ * c does not reach any patch
+
+ * c is the parent of a patch
+
+ """
+ def __init__(self, series):
+ self.__series = series
+ self.__uninteresting = None
+ self.__filename = os.path.join(self.__series._dir(), 'uninteresting')
+ def __invalidate(self):
+ self.__uninteresting = None
+ self.delete_file()
+ def delete_file(self):
+ if os.path.isfile(self.__filename):
+ os.remove(self.__filename)
+ def __other_patches(self, patchname):
+ """All patches except the named one."""
+ ref2hash = read_refs(self.__series.get_name())
+ return [self.__series.get_patch(ref)
+ for ref in ref2hash.iterkeys()
+ if ref and ref != patchname]
+ def __write_file(self):
+ """Write the uninteresting commits to file."""
+ try:
+ f = file(self.__filename, 'w')
+ for u in self.__uninteresting:
+ f.write('%s\n' % u)
+ f.close()
+ except IOError:
+ pass # this isn't fatal -- the directory is probably missing
+ def __read_file(self):
+ """Read the uninteresting commits from file. Return true on
+ success, false on failure."""
+ if not os.path.isfile(self.__filename):
+ return False
+ self.__uninteresting = Set()
+ for line in file(self.__filename):
+ self.__uninteresting.add(line.strip())
+ return True
+ def __cache_file(self):
+ """Try to cache the uninteresting commits using only the cache
+ file. Return true on success, false on failure."""
+ if self.__uninteresting != None:
+ return True # already cached
+ return self.__read_file()
+ def __cache(self):
+ """Cache the uninteresting commits, recomputing them if
+ necessary."""
+ if self.__cache_file():
+ return
+ self.__compute_uninteresting()
+ self.__write_file()
+ def __compute_uninteresting(self):
+ """Compute a reasonable set of uninteresting commits from
+ scratch. This is expensive."""
+ out.start('Finding uninteresting commits')
+ ref2hash = read_refs(self.__series.get_name())
+ patches = Set([sha1 for ref, sha1 in ref2hash.iteritems() if ref])
+ interesting, uninteresting = Set(), Set()
+
+ # Iterate over all commits. We are guaranteed to see each
+ # commit before any of its children.
+ for line in git._output_lines(
+ 'git-rev-list --topo-order --reverse --parents --all'):
+ commits = line.split()
+ commit, parents = commits[0], Set(commits[1:])
+
+ # Patches are interesting.
+ if commit in patches:
+ interesting.add(commit)
+
+ # The parents of a patch are uninteresting unless they
+ # are interesting.
+ for p in parents:
+ if not p in interesting:
+ uninteresting.add(p)
+ continue
+
+ # Commits with interesting parents are interesting.
+ if interesting.intersection(parents):
+ interesting.add(commit)
+ self.__uninteresting = uninteresting
+ out.done()
+ def create_patch(self, name, top, bottom):
+ """The given patch has been created. Update the uninterested
+ state to maintain the invariant."""
+ if not self.__cache_file():
+ return # not cached
+
+ # New patch inserted just below an existing bottommost patch:
+ # need to move the uninteresting commit down one step.
+ if top in self.__uninteresting:
+ self.__uninteresting.remove(top)
+ self.__uninteresting.add(bottom)
+ self.__write_file()
+ return
+
+ # New patch inserted next to an existing non-bottommost patch:
+ # don't need to do anything.
+ existing_patches = self.__other_patches(name)
+ tops = Set([p.get_top() for p in existing_patches])
+ bottoms = Set([p.get_bottom() for p in existing_patches])
+ if bottom in bottoms or bottom in tops or top in bottoms:
+ return
+
+ # The new patch is not adjacent to an existing patch. We'd
+ # need to first get rid of any uninteresting commit that
+ # reaches this patch, and then mark the patch's bottom
+ # uninteresting if it doesn't reach any other patch. This is a
+ # lot of work, so we chicken out and blow the whole cache
+ # instead.
+ self.__invalidate()
+ def delete_patch(self, name, top, bottom):
+ """The given patch has been deleted. Update the uninterested
+ state to maintain the invariant."""
+ if not self.__cache_file():
+ return # not cached
+
+ # If this patch reaches another patch, there's nothing to do.
+ if not bottom in self.__uninteresting:
+ return
+
+ # If another patch has the same bottom, it's still
+ # uninteresting and there's nothing more to do.
+ other_patches = self.__other_patches(name)
+ for p in other_patches:
+ if p.get_bottom() == bottom:
+ return
+
+ # If there are other patches on top of this one, their bottoms
+ # (this patch's top) become uninteresting in place of this
+ # patch's bottom.
+ for p in other_patches:
+ if p.get_bottom() == top:
+ self.__uninteresting.remove(bottom)
+ self.__uninteresting.add(top)
+ self.__write_file()
+ return
+
+ # The bottom of this patch is no longer uninteresting. But
+ # there might be other patches that reach it, whose bottoms
+ # would need to be marked uninteresting. That would require an
+ # expensive reachability analysis.
+ self.__invalidate()
+ def get(self):
+ self.__cache()
+ return self.__uninteresting
+
def read_refs(branch):
"""Return a mapping from patches and branch head to hashes for a
given branch. The patches are listed by name; the branch head is
None."""
refs = {}
patchpat = re.compile(r'^refs/patches/%s/([^\.]+)$' % branch)
+ head = 'refs/heads/%s' % branch
for line in git._output_lines('git-show-ref'):
sha1, ref = line.split()
m = re.match(patchpat, ref)
if m:
refs[m.group(1)] = sha1
- elif ref == 'refs/heads/%s' % branch:
+ elif ref == head:
refs[None] = sha1
+ if not None in refs:
+ raise StackException, 'Could not find %s' % head
return refs
-def unapplied_patches(ref2hash):
+def get_patches(ref2hash, uninteresting):
"""Given a map of patch names (and the branch head, keyed by None)
- to hashes, return the set of unapplied patches."""
- hash2refs = {}
- for r, h in ref2hash.iteritems():
- hash2refs.setdefault(h, Set()).add(r)
-
+ to hashes, return the list of applied patches and the set of
+ unapplied patches. The second parameter is a set of commit objects
+ that do not reach any patch."""
+ applied = []
unapplied = Set()
- for line in git._output_lines(
- 'git-rev-list --stdin',
- ('%s%s\n' % (['', '^'][ref == None], sha1)
- for ref, sha1 in ref2hash.iteritems())):
- for ref in hash2refs.get(line.strip(), []):
- unapplied.add(ref)
- return unapplied
-
-def sort_applied_patches(ref2hash):
- """Given a map of patch names (and the branch head, keyed by None)
- to hashes, return a list with the applied patches in stack order.
- All patches in the map must be applied."""
- hash2refs = {}
+ hash2patches = {}
for r, h in ref2hash.iteritems():
- if r != None:
- hash2refs.setdefault(h, Set()).add(r)
+ if r:
+ hash2patches.setdefault(h, Set()).add(r)
+ unapplied.add(r)
- missing = Set(ref for ref in ref2hash.iterkeys() if ref != None)
- if not missing:
- return []
- applied = []
- grl = popen2.Popen3('git-rev-list %s' % ref2hash[None], True)
- for line in grl.fromchild:
- for ref in hash2refs.get(line.strip(), []):
+ for line in git._output_lines(
+ 'git-rev-list --topo-order --stdin', ['%s\n' % ref2hash[None]]
+ + ['^%s\n' % u for u in uninteresting]):
+ for ref in hash2patches.get(line.strip(), []):
applied.append(ref)
- missing.remove(ref)
- if not missing:
- applied.reverse()
- return applied
-
- raise StackException, 'Could not find patches: %s' % ', '.join(missing)
+ unapplied.remove(ref)
+ applied.reverse()
+ return applied, unapplied
class AppliedCache:
"""An object that keeps track of the appliedness and order of the
@@ -447,7 +590,11 @@ class AppliedCache:
def __init__(self, series):
self.__series = series
self.__order = PatchorderCache(series)
+ self.__uninteresting = UninterestingCache(series)
self.__invalidate()
+ def delete_files(self):
+ for sub in [self.__uninteresting, self.__order]:
+ sub.delete_file()
def get_applied(self):
self.__cache()
return self.__applied
@@ -466,6 +613,17 @@ class AppliedCache:
self.__write_patchorder()
return
raise StackException, 'Unknown patch "%s"' % oldname
+ def new(self, name, top, bottom):
+ """Create new patch."""
+ self.__uninteresting.create_patch(name, top, bottom)
+ def delete(self, name, top, bottom):
+ """Delete a patch."""
+ self.__uninteresting.delete_patch(name, top, bottom)
+ def change(self, name, old_top, old_bottom, new_top, new_bottom):
+ """Change a patch."""
+ if (new_top, new_bottom) != (old_top, old_bottom):
+ self.new(name, new_top, new_bottom)
+ self.delete(name, old_top, old_bottom)
def __write_patchorder(self):
self.__order.set_patchorder(self.get_applied() + self.get_unapplied())
def set_patchorder(self, new_order):
@@ -484,11 +642,8 @@ class AppliedCache:
def __cache(self):
if self.__cached():
return
- patches = read_refs(self.__series.get_name())
- unapplied = unapplied_patches(patches)
- for patch in unapplied:
- del patches[patch]
- self.__applied = sort_applied_patches(patches)
+ self.__applied, unapplied = get_patches(
+ read_refs(self.__series.get_name()), self.__uninteresting.get())
self.__unapplied = list(unapplied)
self.__unapplied.sort(self.__order.cmp)
@@ -849,6 +1004,7 @@ class Series(PatchSet):
os.remove(self.__hidden_file)
if os.path.exists(self._dir()+'/orig-base'):
os.remove(self._dir()+'/orig-base')
+ self.__applied_cache.delete_files()
if not os.listdir(self.__patch_dir):
os.rmdir(self.__patch_dir)
@@ -953,16 +1109,20 @@ class Series(PatchSet):
patch = self.get_patch(name)
old_bottom = patch.get_old_bottom()
old_top = patch.get_old_top()
+ curr_bottom = patch.get_bottom()
+ curr_top = patch.get_top()
# the bottom of the patch is not changed by refresh. If the
# old_bottom is different, there wasn't any previous 'refresh'
# command (probably only a 'push')
- if old_bottom != patch.get_bottom() or old_top == patch.get_top():
+ if old_bottom != curr_bottom or old_top == curr_top:
raise StackException, 'No undo information available'
git.reset(tree_id = old_top, check_out = False)
if patch.restore_old_boundaries():
self.log_patch(patch, 'undo')
+ self.__applied_cache.change(name, curr_top, curr_bottom,
+ old_top, old_bottom)
def new_patch(self, name, message = None, can_edit = True,
unapplied = False, show_patch = False,
@@ -995,10 +1155,9 @@ class Series(PatchSet):
patch = self.get_patch(name)
patch.create()
- if not bottom:
- bottom = head
- if not top:
- top = head
+ bottom = bottom or head
+ top = top or head
+ self.__applied_cache.new(name, top, bottom)
patch.set_bottom(bottom)
patch.set_top(top)
@@ -1042,15 +1201,16 @@ class Series(PatchSet):
def delete_patch_data(self, name):
"""Deletes the stgit data for a patch."""
patch = Patch(name, self.__patch_dir, self.__refs_dir)
+ top, bottom = patch.get_top(), patch.get_bottom()
# save the commit id to a trash file
- write_string(os.path.join(self.__trash_dir, name), patch.get_top())
+ write_string(os.path.join(self.__trash_dir, name), top)
patch.delete()
if self.patch_hidden(name):
self.unhide_patch(name)
- return patch
+ self.__applied_cache.delete(name, top, bottom)
def delete_patch(self, name):
"""Deletes a patch
@@ -1109,6 +1269,7 @@ class Series(PatchSet):
top_tree = git.get_commit(top).get_tree()
+ old_top = top
top = git.commit(message = descr, parents = [head],
cache_update = False,
tree_id = top_tree,
@@ -1122,6 +1283,9 @@ class Series(PatchSet):
patch.set_bottom(head, backup = True)
patch.set_top(top, backup = True)
+ self.__applied_cache.change(
+ name, old_top = old_top, old_bottom = bottom,
+ new_top = top, new_bottom = head)
self.log_patch(patch, 'push(f)')
else:
top = head
@@ -1179,6 +1343,7 @@ class Series(PatchSet):
# need an empty commit
patch.set_bottom(head, backup = True)
patch.set_top(head, backup = True)
+ self.__applied_cache.change(name, top, bottom, head, head)
modified = True
elif head == bottom:
# reset the backup information. No need for logging
@@ -1191,6 +1356,7 @@ class Series(PatchSet):
# The current patch is empty after merge.
patch.set_bottom(head, backup = True)
patch.set_top(head, backup = True)
+ self.__applied_cache.change(name, top, bottom, head, head)
# Try the fast applying first. If this fails, fall back to the
# three-way merge
@@ -1236,6 +1402,8 @@ class Series(PatchSet):
patch = self.get_patch(name)
old_bottom = patch.get_old_bottom()
old_top = patch.get_old_top()
+ curr_bottom = patch.get_bottom()
+ curr_top = patch.get_top()
# the top of the patch is changed by a push operation only
# together with the bottom (otherwise the top was probably
@@ -1247,6 +1415,8 @@ class Series(PatchSet):
git.reset()
self.pop_patch(name)
ret = patch.restore_old_boundaries()
+ self.__applied_cache.change(name, curr_top, curr_bottom,
+ old_top, old_bottom)
if ret:
self.log_patch(patch, 'undo')
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox