--- /dev/null
+# -*- coding: utf-8 -*-
+
+__copyright__ = """
+Copyright (C) 2006, Karl Hasselström <kha@treskal.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+import sys, os
+from optparse import OptionParser, make_option
+
+from stgit.commands.common import *
+from stgit.utils import *
+from stgit import stack, git
+
+help = 'StGIT-ify any GIT commits made on top of your StGIT stack'
+usage = """%prog [options]
+
+If you have made GIT commits on top of your stack of StGIT patches,
+many StGIT commands will refuse to work. This command converts any
+such commits to StGIT patches, preserving their contents.
+
+Only GIT commits with exactly one parent can be assimilated; in other
+words, if you have committed a merge on top of your stack, this
+command cannot help you."""
+
+options = []
+
+def func(parser, options, args):
+ """Assimilate a number of patches.
+ """
+
+ def nothing_to_do():
+ print 'No commits to assimilate'
+
+ top_patch = crt_series.get_current_patch()
+ if not top_patch:
+ return nothing_to_do()
+
+ victims = []
+ victim = git.get_commit(git.get_head())
+ while victim.get_id_hash() != top_patch.get_top():
+ victims.append(victim)
+ parents = victim.get_parents()
+ if not parents:
+ raise CmdException, 'Commit %s has no parents, aborting' % victim
+ elif len(parents) > 1:
+ raise CmdException, 'Commit %s is a merge, aborting' % victim
+ victim = git.get_commit(parents[0])
+
+ if not victims:
+ return nothing_to_do()
+
+ if crt_series.get_protected():
+ raise CmdException(
+ 'This branch is protected. Modification is not permitted')
+
+ patch2name = {}
+ name2patch = {}
+
+ def name_taken(name):
+ return name in name2patch or crt_series.patch_exists(name)
+
+ for victim in victims:
+ patchname = make_patch_name(victim.get_log())
+ if not patchname:
+ patchname = 'patch'
+ if name_taken(patchname):
+ suffix = 0
+ while name_taken('%s-%d' % (patchname, suffix)):
+ suffix += 1
+ patchname = '%s-%d' % (patchname, suffix)
+ patch2name[victim] = patchname
+ name2patch[patchname] = victim
+
+ victims.reverse()
+ for victim in victims:
+ print ('Creating patch "%s" from commit %s'
+ % (patch2name[victim], victim))
+ aname, amail, adate = name_email_date(victim.get_author())
+ cname, cmail, cdate = name_email_date(victim.get_committer())
+ crt_series.new_patch(
+ patch2name[victim],
+ can_edit = False, before_existing = False, refresh = False,
+ top = victim.get_id_hash(), bottom = victim.get_parent(),
+ message = victim.get_log(),
+ author_name = aname, author_email = amail, author_date = adate,
+ committer_name = cname, committer_email = cmail)
def check_head_top_equal():
if not crt_series.head_top_equal():
- raise CmdException, \
- 'HEAD and top are not the same. You probably committed\n' \
- ' changes to the tree outside of StGIT. If you know what you\n' \
- ' are doing, use the "refresh -f" command'
+ raise CmdException(
+ 'HEAD and top are not the same. You probably committed\n'
+ ' changes to the tree outside of StGIT. To bring them\n'
+ ' into StGIT, use the "assimilate" command')
def check_conflicts():
if os.path.exists(os.path.join(basedir.get(), 'conflicts')):
def get_log(self):
return self.__log
+ def __str__(self):
+ return self.get_id_hash()
+
# dictionary of Commit objects, used to avoid multiple calls to git
__commits = dict()
# The commands
import stgit.commands.add
import stgit.commands.applied
+import stgit.commands.assimilate
import stgit.commands.branch
import stgit.commands.delete
import stgit.commands.diff
commands = {
'add': stgit.commands.add,
'applied': stgit.commands.applied,
+ 'assimilate': stgit.commands.assimilate,
'branch': stgit.commands.branch,
'delete': stgit.commands.delete,
'diff': stgit.commands.diff,
)
stackcommands = (
'applied',
+ 'assimilate',
'clean',
'commit',
'float',
"""
return Patch(name, self.__patch_dir, self.__refs_dir)
+ def get_current_patch(self):
+ """Return a Patch object representing the topmost patch, or
+ None if there is no such patch."""
+ crt = self.get_current()
+ if not crt:
+ return None
+ return Patch(crt, self.__patch_dir, self.__refs_dir)
+
def get_current(self):
- """Return a Patch object representing the topmost patch
- """
+ """Return the name of the topmost patch, or None if there is
+ no such patch."""
if os.path.isfile(self.__current_file):
name = read_string(self.__current_file)
else:
"""
return name in self.get_unapplied()
+ def patch_exists(self, name):
+ """Return true if there is a patch with the given name, false
+ otherwise."""
+ return self.__patch_applied(name) or self.__patch_applied(name)
+
def __begin_stack_check(self):
"""Save the current HEAD into .git/refs/heads/base if the stack
is empty
def head_top_equal(self):
"""Return true if the head and the top are the same
"""
- crt = self.get_current()
+ crt = self.get_current_patch()
if not crt:
# we don't care, no patches applied
return True
- return git.get_head() == Patch(crt, self.__patch_dir,
- self.__refs_dir).get_top()
+ return git.get_head() == crt.get_top()
def is_initialised(self):
"""Checks if series is already initialised
top = None, bottom = None,
author_name = None, author_email = None, author_date = None,
committer_name = None, committer_email = None,
- before_existing = False):
+ before_existing = False, refresh = True):
"""Creates a new patch
"""
if self.__patch_applied(name) or self.__patch_unapplied(name):
else:
append_string(self.__applied_file, patch.get_name())
self.__set_current(name)
-
- self.refresh_patch(cache_update = False, log = 'new')
+ if refresh:
+ self.refresh_patch(cache_update = False, log = 'new')
def delete_patch(self, name):
"""Deletes a patch