{"thread":{"id":"6567","subject":"[PATCH 0/7] [DRAFT 2] StGIT, remotes, and parent information","startedAt":"2007-01-27T17:22:28Z","lastAt":"2007-01-27T17:22:59Z","messageCount":7,"participants":["Yann Dirson"],"isPatch":true,"patchVersion":1,"patchTotal":7},"messages":[{"id":"32849","messageId":"20070127172129.27183.50432.stgit@gandelf.nowhere.earth","threadId":"6567","inReplyTo":null,"subject":"[PATCH 0/7] [DRAFT 2] StGIT, remotes, and parent information","fromName":"Yann Dirson","fromEmail":"ydirson@altern.org","sentAt":"2007-01-27T17:22:28Z","receivedAt":"2007-01-27T17:22:28Z","isPatch":true,"sender":{"key":"ydirson@altern.org","avatar":"https://avatars.githubusercontent.com/u/1190950?v=4"},"body":"Here is a new draft version, which re-implements stgit.config to call\ngit-repo-config (without any caching to get things working right now),\nand with write support.\n\nThe 5 other patches were modified accordingly, so in this state we can\nsee:\n\nstgit$ ./stg branch -c bar origin\nChecking for changes in the working directory... done\nRecording \"refs/heads/origin\" as parent branch.\nUsing \"origin\" remote to pull parent from.  \nBranch \"bar\" created.\nstgit$ git-repo-config --get-regexp 'branch\\.bar\\..*'\nbranch.bar.merge refs/heads/origin\nbranch.bar.remote origin\n\nThere are many rough edges when you shake it, but that should give the\nidea.\n\nIt also applies on yesterday's head.  I'll rebase and adapt the\nnewly-added config parameters.\n\nBest regards,\n-- \nYann Dirson    <ydirson@altern.org> |\nDebian-related: <dirson@debian.org> |   Support Debian GNU/Linux:\n                                    |  Freedom, Power, Stability, Gratis\n     http://ydirson.free.fr/        | Check <http://www.debian.org/>\n"},{"id":"32851","messageId":"20070127172233.27183.7071.stgit@gandelf.nowhere.earth","threadId":"6567","inReplyTo":"20070127172129.27183.50432.stgit@gandelf.nowhere.earth","subject":"[PATCH 1/6] Make stgit.config use git-repo-config.","fromName":"Yann Dirson","fromEmail":"ydirson@altern.org","sentAt":"2007-01-27T17:22:33Z","receivedAt":"2007-01-27T17:22:33Z","isPatch":true,"sender":{"key":"ydirson@altern.org","avatar":"https://avatars.githubusercontent.com/u/1190950?v=4"},"body":"\nThis is an initial implementation without any sort of caching.  If we\nwant that, we could do it with this new API.  We could even just\nsimply generalize the use of ConfigOption instead.\n\nI just copypasted __run from stgit.git to avoid too much work, but\nit's definitely something to cleanup.\n\nSigned-off-by: Yann Dirson <ydirson@altern.org>\n---\n\n stgit/commands/common.py  |    5 +\n stgit/commands/mail.py    |   27 +++-----\n stgit/commands/pull.py    |    9 +--\n stgit/commands/refresh.py |    2 -\n stgit/config.py           |  154 ++++++++++++++++++++++-----------------------\n stgit/git.py              |   10 +--\n stgit/gitmergeonefile.py  |    7 +-\n stgit/stack.py            |    5 +\n 8 files changed, 104 insertions(+), 115 deletions(-)\n\ndiff --git a/stgit/commands/common.py b/stgit/commands/common.py\nindex 2e57824..432edce 100644\n--- a/stgit/commands/common.py\n+++ b/stgit/commands/common.py\n@@ -311,9 +311,10 @@ def address_or_alias(addr_str):\n         if addr.find('@') >= 0:\n             # it's an e-mail address\n             return addr\n-        if config.has_option('mail \"alias\"', addr):\n+        alias = config.get('mail.alias.'+addr)\n+        if alias:\n             # it's an alias\n-            return config.get('mail \"alias\"', addr)\n+            return alias\n \n         raise CmdException, 'unknown e-mail alias: %s' % addr\n \ndiff --git a/stgit/commands/mail.py b/stgit/commands/mail.py\nindex 6f61b83..236b519 100644\n--- a/stgit/commands/mail.py\n+++ b/stgit/commands/mail.py\n@@ -129,9 +129,8 @@ def __get_sender():\n     \"\"\"Return the 'authname <authemail>' string as read from the\n     configuration file\n     \"\"\"\n-    if config.has_option('stgit', 'sender'):\n-        sender = config.get('stgit', 'sender')\n-    else:\n+    sender=config.get('stgit.sender')\n+    if not sender:\n         try:\n             sender = str(git.user())\n         except git.GitException:\n@@ -207,9 +206,8 @@ def __build_address_headers(msg, options, extra_cc = []):\n     cc_addr = ''\n     bcc_addr = ''\n \n-    if config.has_option('stgit', 'autobcc'):\n-        autobcc = config.get('stgit', 'autobcc')\n-    else:\n+    autobcc = config.get('stgit.autobcc')\n+    if not autobcc:\n         autobcc = ''\n \n     if options.to:\n@@ -283,8 +281,9 @@ def __edit_message(msg):\n     f.close()\n \n     # the editor\n-    if config.has_option('stgit', 'editor'):\n-        editor = config.get('stgit', 'editor')\n+    editor = config.get('stgit.editor')\n+    if editor:\n+        pass\n     elif 'EDITOR' in os.environ:\n         editor = os.environ['EDITOR']\n     else:\n@@ -469,14 +468,10 @@ def func(parser, options, args):\n     \"\"\"Send the patches by e-mail using the patchmail.tmpl file as\n     a template\n     \"\"\"\n-    smtpserver = config.get('stgit', 'smtpserver')\n+    smtpserver = config.get('stgit.smtpserver')\n \n-    smtpuser = None\n-    smtppassword = None\n-    if config.has_option('stgit', 'smtpuser'):\n-        smtpuser = config.get('stgit', 'smtpuser')\n-    if config.has_option('stgit', 'smtppassword'):\n-        smtppassword = config.get('stgit', 'smtppassword')\n+    smtpuser = config.get('stgit.smtpuser')\n+    smtppassword = config.get('stgit.smtppassword')\n \n     applied = crt_series.get_applied()\n \n@@ -511,7 +506,7 @@ def func(parser, options, args):\n     if options.sleep != None:\n         sleep = options.sleep\n     else:\n-        sleep = config.getint('stgit', 'smtpdelay')\n+        sleep = config.getint('stgit.smtpdelay')\n \n     # send the cover message (if any)\n     if options.cover or options.edit_cover:\ndiff --git a/stgit/commands/pull.py b/stgit/commands/pull.py\nindex 7c5db22..15ed636 100644\n--- a/stgit/commands/pull.py\n+++ b/stgit/commands/pull.py\n@@ -53,10 +53,8 @@ def func(parser, options, args):\n     if len(args) >= 1:\n         repository = args[0]\n     else:\n-        section = 'branch \"%s\"' % git.get_head_file()\n-        if config.has_option(section, 'remote'):\n-            repository = config.get(section, 'remote')\n-        else:\n+        repository = config.get('branch.%s.remote' % git.get_head_file())\n+        if not repository:\n             repository = 'origin'\n \n     refspec = None\n@@ -88,8 +86,7 @@ def func(parser, options, args):\n         push_patches(applied, options.merged)\n \n     # maybe tidy up\n-    repack = config.get('stgit', 'keepoptimized')\n-    if repack == 'yes':\n+    if config.get('stgit.keepoptimized') == 'yes':\n         git.repack()\n \n     print_crt_patch()\ndiff --git a/stgit/commands/refresh.py b/stgit/commands/refresh.py\nindex 0efe1df..7a9bf7d 100644\n--- a/stgit/commands/refresh.py\n+++ b/stgit/commands/refresh.py\n@@ -77,7 +77,7 @@ options = [make_option('-f', '--force',\n \n \n def func(parser, options, args):\n-    autoresolved = config.get('stgit', 'autoresolved')\n+    autoresolved = config.get('stgit.autoresolved')\n \n     if autoresolved != 'yes':\n         check_conflicts()\ndiff --git a/stgit/config.py b/stgit/config.py\nindex f5fbdab..c2d413b 100644\n--- a/stgit/config.py\n+++ b/stgit/config.py\n@@ -18,90 +18,86 @@ along with this program; if not, write to the Free Software\n Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n \"\"\"\n \n-import os, ConfigParser\n-from StringIO import StringIO\n+import os\n from stgit import basedir\n \n-config = ConfigParser.RawConfigParser()\n-\n-def git_config(filename):\n-    \"\"\"Open a git config file and convert it to be understood by\n-    Python.\"\"\"\n-    try:\n-        f = file(filename)\n-        cont = False\n-        lines = []\n-        for line in f:\n-            line = line.strip()\n-\n-            if cont:\n-                # continued line, add a space at the beginning\n-                line = ' ' + line\n-\n-            if line and line[-1] == '\\\\':\n-                line = line[:-1].rstrip()\n-                cont = True\n-            else:\n-                line = line + '\\n'\n-                cont = False\n-\n-            lines.append(line)\n-\n-        f.close()\n-        cfg_str = ''.join(lines)\n-    except IOError:\n-        cfg_str = ''\n-\n-    strio = StringIO(cfg_str)\n-    strio.name = filename\n-\n-    return strio\n+class GitConfigException(Exception):\n+    pass\n+\n+class GitConfig:\n+    __defaults={\n+        'stgit.autoresolved':\t'no',\n+        'stgit.smtpserver':\t\t'localhost:25',\n+        'stgit.smtpdelay':\t\t'5',\n+        'stgit.pullcmd':\t\t'git-pull',\n+        'stgit.merger':\t\t'diff3 -L current -L ancestor -L patched -m -E ' \\\n+\t\t\t\t'\"%(branch1)s\" \"%(ancestor)s\" \"%(branch2)s\" > \"%(output)s\"',\n+        'stgit.autoimerge':\t\t'no',\n+        'stgit.keeporig':\t\t'yes',\n+        'stgit.keepoptimized':\t'no',\n+        'stgit.extensions':\t\t'.ancestor .current .patched',\n+        }\n+\n+    def __run(self, cmd, args=None):\n+        \"\"\"__run: runs cmd using spawnvp.\n+    \n+        Runs cmd using spawnvp.  The shell is avoided so it won't mess up\n+        our arguments.  If args is very large, the command is run multiple\n+        times; args is split xargs style: cmd is passed on each\n+        invocation.  Unlike xargs, returns immediately if any non-zero\n+        return code is received.  \n+        \"\"\"\n+        \n+        args_l=cmd.split()\n+        if args is None:\n+            args = []\n+        for i in range(0, len(args)+1, 100):\n+            r=os.spawnvp(os.P_WAIT, args_l[0], args_l + args[i:min(i+100, len(args))])\n+        if r:\n+            return r\n+        return 0\n+    \n+    def get(self, name):\n+        stream = os.popen('git repo-config --get %s' % name, 'r')\n+        value = stream.readline().strip()\n+        stream.close()\n+        if len(value) > 0:\n+            return value\n+#         elif found in mergeonefile:\n+#             XXX\n+        elif (self.__defaults.has_key(name)):\n+            return self.__defaults[name]\n+        else:\n+            return None\n+\n+    def getall(self, name):\n+        stream = os.popen('git repo-config --get-all %s' % name, 'r')\n+        values = [line.strip() for line in stream]\n+        stream.close()\n+#        if len(values)==0 and found in mergeonefile:\n+#             XXX\n+        return values\n+\n+    def getint(self, name):\n+        value = self.get(name)\n+        if value.isdigit():\n+            return int(value)\n+        else:\n+            raise GitConfigException, 'Value for \"%s\" is not an integer: \"%s\"' % (name, value)\n+\n+    def set(self, name, value):\n+        self.__run('git-repo-config', [name, value])\n+\n+config=GitConfig()\n \n def config_setup():\n     global config\n \n-    # Set the defaults\n-    config.add_section('stgit')\n-    config.set('stgit', 'autoresolved', 'no')\n-    config.set('stgit', 'smtpserver', 'localhost:25')\n-    config.set('stgit', 'smtpdelay', '5')\n-    config.set('stgit', 'pullcmd', 'git-pull')\n-    config.set('stgit', 'merger',\n-               'diff3 -L current -L ancestor -L patched -m -E ' \\\n-               '\"%(branch1)s\" \"%(ancestor)s\" \"%(branch2)s\" > \"%(output)s\"')\n-    config.set('stgit', 'autoimerge', 'no')\n-    config.set('stgit', 'keeporig', 'yes')\n-    config.set('stgit', 'keepoptimized', 'no')\n-    config.set('stgit', 'extensions', '.ancestor .current .patched')\n-\n-    # Read the configuration files (if any) and override the default settings\n-    # stgitrc are read for backward compatibility\n-    config.read('/etc/stgitrc')\n-    config.read(os.path.expanduser('~/.stgitrc'))\n-    config.read(os.path.join(basedir.get(), 'stgitrc'))\n-\n-    # GIT configuration files can have a [stgit] section\n-    try:\n-        global_config = os.environ['GIT_CONFIG']\n-    except KeyError:\n-        global_config = os.path.expanduser('~/.gitconfig')\n-    try:\n-        local_config = os.environ['GIT_CONFIG_LOCAL']\n-    except KeyError:\n-        local_config = os.path.join(basedir.get(), 'config')\n-    config.readfp(git_config(global_config))\n-    config.readfp(git_config(local_config))\n-\n     # Set the PAGER environment to the config value (if any)\n-    if config.has_option('stgit', 'pager'):\n-        os.environ['PAGER'] = config.get('stgit', 'pager')\n-\n-    # [gitmergeonefile] section is deprecated. In case it exists copy the\n-    # options/values to the [stgit] one\n-    if config.has_section('gitmergeonefile'):\n-        for option, value in config.items('gitmergeonefile'):\n-            config.set('stgit', option, value)\n-\n+    pager = config.get('stgit.pager')\n+    if pager:\n+        os.environ['PAGER'] = pager\n+    # FIXME: handle EDITOR the same way ?\n \n class ConfigOption:\n     \"\"\"Delayed cached reading of a configuration option.\n@@ -113,7 +109,7 @@ class ConfigOption:\n \n     def __str__(self):\n         if not self.__value:\n-            self.__value = config.get(self.__section, self.__option)\n+            self.__value = config.get(self.__section + '.' + self.__option)\n         return self.__value\n \n \n@@ -126,7 +122,7 @@ def file_extensions():\n     global __extensions\n \n     if not __extensions:\n-        cfg_ext = config.get('stgit', 'extensions').split()\n+        cfg_ext = config.get('stgit.extensions').split()\n         if len(cfg_ext) != 3:\n             raise CmdException, '\"extensions\" configuration error'\n \ndiff --git a/stgit/git.py b/stgit/git.py\nindex 4c5685a..c21c074 100644\n--- a/stgit/git.py\n+++ b/stgit/git.py\n@@ -449,10 +449,10 @@ def user():\n     \"\"\"\n     global __user\n     if not __user:\n-        if config.has_option('user', 'name') \\\n-               and config.has_option('user', 'email'):\n-            __user = Person(config.get('user', 'name'),\n-                            config.get('user', 'email'))\n+        name=config.get('user.name')\n+        email=config.get('user.email')\n+        if name and email:\n+            __user = Person(name, email)\n         else:\n             raise GitException, 'unknown user details'\n     return __user;\n@@ -816,7 +816,7 @@ def pull(repository = 'origin', refspec = None):\n     if refspec:\n         args.append(refspec)\n \n-    if __run(config.get('stgit', 'pullcmd'), args) != 0:\n+    if __run(config.get('stgit.pullcmd'), args) != 0:\n         raise GitException, 'Failed \"git-pull %s\"' % repository\n \n def repack():\ndiff --git a/stgit/gitmergeonefile.py b/stgit/gitmergeonefile.py\nindex 587c8c4..b9d02aa 100644\n--- a/stgit/gitmergeonefile.py\n+++ b/stgit/gitmergeonefile.py\n@@ -102,9 +102,8 @@ def interactive_merge(filename):\n     \"\"\"Run the interactive merger on the given file. Note that the\n     index should not have any conflicts.\n     \"\"\"\n-    try:\n-        imerger = config.get('stgit', 'imerger')\n-    except Exception, err:\n+    imerger = config.get('stgit.imerger')\n+    if not imerger:\n         raise GitMergeException, 'Configuration error: %s' % err\n \n     extensions = file_extensions()\n@@ -185,7 +184,7 @@ def merge(orig_hash, file1_hash, file2_hash,\n                     os.system('git-update-index --cacheinfo %s %s %s'\n                               % (file1_mode, file1_hash, path))\n \n-                    if config.get('stgit', 'autoimerge') == 'yes':\n+                    if config.get('stgit.autoimerge') == 'yes':\n                         print >> sys.stderr, \\\n                               'Trying the interactive merge'\n                         try:\ndiff --git a/stgit/stack.py b/stgit/stack.py\nindex 2ae4dd5..087403f 100644\n--- a/stgit/stack.py\n+++ b/stgit/stack.py\n@@ -92,8 +92,9 @@ def edit_file(series, line, comment, show_patch = True):\n     f.close()\n \n     # the editor\n-    if config.has_option('stgit', 'editor'):\n-        editor = config.get('stgit', 'editor')\n+    editor = config.get('stgit.editor')\n+    if editor:\n+        pass\n     elif 'EDITOR' in os.environ:\n         editor = os.environ['EDITOR']\n     else:\n"},{"id":"32850","messageId":"20070127172238.27183.36508.stgit@gandelf.nowhere.earth","threadId":"6567","inReplyTo":"20070127172129.27183.50432.stgit@gandelf.nowhere.earth","subject":"[PATCH 2/6] Move identification of parent branch's remote def up into stack class.","fromName":"Yann Dirson","fromEmail":"ydirson@altern.org","sentAt":"2007-01-27T17:22:38Z","receivedAt":"2007-01-27T17:22:38Z","isPatch":true,"sender":{"key":"ydirson@altern.org","avatar":"https://avatars.githubusercontent.com/u/1190950?v=4"},"body":"\nAlso adds the __set_parent_remote() counterpart method, but only\nprivate since it is expected to be called only through set_parent, to\nbe introduced in subsequent patch.\n\nSigned-off-by: Yann Dirson <ydirson@altern.org>\n---\n\n stgit/commands/pull.py |    4 +---\n stgit/stack.py         |   10 ++++++++++\n 2 files changed, 11 insertions(+), 3 deletions(-)\n\ndiff --git a/stgit/commands/pull.py b/stgit/commands/pull.py\nindex 15ed636..0608fb6 100644\n--- a/stgit/commands/pull.py\n+++ b/stgit/commands/pull.py\n@@ -53,9 +53,7 @@ def func(parser, options, args):\n     if len(args) >= 1:\n         repository = args[0]\n     else:\n-        repository = config.get('branch.%s.remote' % git.get_head_file())\n-        if not repository:\n-            repository = 'origin'\n+        repository = crt_series.get_parent_remote()\n \n     refspec = None\n     if len(args) == 2:\ndiff --git a/stgit/stack.py b/stgit/stack.py\nindex 087403f..026fc36 100644\n--- a/stgit/stack.py\n+++ b/stgit/stack.py\n@@ -398,6 +398,16 @@ class Series(StgitObject):\n     def set_description(self, line):\n         self._set_field('description', line)\n \n+    def get_parent_remote(self):\n+        value = config.get('branch.%s.remote' % self.__name)\n+        if value:\n+            return value\n+        else:\n+            return 'origin'\n+\n+    def __set_parent_remote(self, remote):\n+        value = config.set('branch.%s.remote' % self.__name, remote)\n+\n     def __patch_is_current(self, patch):\n         return patch.get_name() == self.get_current()\n \n"},{"id":"32852","messageId":"20070127172243.27183.90701.stgit@gandelf.nowhere.earth","threadId":"6567","inReplyTo":"20070127172129.27183.50432.stgit@gandelf.nowhere.earth","subject":"[PATCH 3/6] Allows extraction of information about remotes.","fromName":"Yann Dirson","fromEmail":"ydirson@altern.org","sentAt":"2007-01-27T17:22:43Z","receivedAt":"2007-01-27T17:22:43Z","isPatch":true,"sender":{"key":"ydirson@altern.org","avatar":"https://avatars.githubusercontent.com/u/1190950?v=4"},"body":"\nWe want to know the list of declared remotes, the local branches they\nhold, and which remotes holds a given branch.  All this regardless of\nwhere the information is stored.\n\nIf there are any git-1.5 remotes declared in .git/config, we suppose\nyou know what you're doing and they will take precedence on any\npre-1.5 remotes.\n\nThis does not use git-remote for now, since it is 1.5 material not\nreleased yet, does not support legacy branches/ remotes, and does not\nallow yet to query all of the information we need.\n\nSigned-off-by: Yann Dirson <ydirson@altern.org>\n---\n\n stgit/git.py |   75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 75 insertions(+), 0 deletions(-)\n\ndiff --git a/stgit/git.py b/stgit/git.py\nindex c21c074..849a417 100644\n--- a/stgit/git.py\n+++ b/stgit/git.py\n@@ -879,3 +879,78 @@ def modifying_revs(files, base_rev):\n     revs = [line.strip() for line in _output_lines(cmd + files)]\n \n     return revs\n+\n+\n+def __remotes_from_config():\n+    configremotes = []\n+    stream = os.popen('git repo-config --get-regexp \"^remote\\..*\\.url$\"', 'r')\n+    for line in stream:\n+        m = re.match('^remote\\.(.*)\\.url ', line)\n+        if m:\n+            configremotes.append(m.group(1))\n+    stream.close()\n+    return configremotes\n+\n+def __remotes_from_dir(dir):\n+    return os.listdir(os.path.join(basedir.get(), dir))\n+\n+def remotes_list():\n+    \"\"\"Return the list of remotes in the repository\n+    \"\"\"\n+\n+    return set(__remotes_from_config()) | \\\n+           set(__remotes_from_dir('remotes')) | \\\n+           set(__remotes_from_dir('branches'))\n+\n+def remotes_local_branches(remote):\n+    \"\"\"Returns the list of local branches fetched from given remote\n+    \"\"\"\n+\n+    branches = []\n+    if remote in __remotes_from_config():\n+        stream = os.popen('git repo-config --get-all \"remote.%s.fetch\"' % remote, 'r')\n+        for line in stream:\n+            # FIXME: should factorize refspec handling\n+            m = re.match('^[^:]*:([^:]*)\\n$', line)\n+            if m:\n+                branches.append(m.group(1))\n+            else:\n+                raise GitException, 'Cannot parse refspec \"%s\"' % line\n+        stream.close()\n+    elif remote in __remotes_from_dir('remotes'):\n+        stream = open(os.path.join(basedir.get(), 'remotes', remote), 'r')\n+        for line in stream:\n+            # Only consider Pull lines\n+            m = re.match('^Pull: (.*)\\n$', line)\n+            if m:\n+                refspec = m.group(1)\n+                m = re.match('^[^:]*:([^:]*)$', refspec)\n+                if m:\n+                    branches.append(m.group(1))\n+                else:\n+                    raise GitException, 'Cannot parse refspec \"%s\"' % refspec\n+        stream.close()\n+        pass\n+    elif remote in __remotes_from_dir('branches'):\n+        # old-style branches only declare one branch\n+        branches.append('refs/heads/'+remote);\n+        pass\n+    else:\n+        raise GitException, 'Unknown remote \"%s\"' % remote\n+\n+    return branches\n+\n+def identify_remote(branchname):\n+    \"\"\"Return the name for the remote to pull the given branchname\n+    from, or None if we believe it is a local branch.\n+    \"\"\"\n+\n+    for remote in remotes_list():\n+        if branchname in remotes_local_branches(remote):\n+            return remote\n+\n+    # FIXME: in the case of local branch we should maybe set remote to\n+    # \".\" but are we even sure it is the only case left ?\n+\n+    # if we get here we've found nothing\n+    return None\n"},{"id":"32854","messageId":"20070127172248.27183.82154.stgit@gandelf.nowhere.earth","threadId":"6567","inReplyTo":"20070127172129.27183.50432.stgit@gandelf.nowhere.earth","subject":"[PATCH 4/6] Basic support for keeping a ref to the parent branch.","fromName":"Yann Dirson","fromEmail":"ydirson@altern.org","sentAt":"2007-01-27T17:22:48Z","receivedAt":"2007-01-27T17:22:48Z","isPatch":true,"sender":{"key":"ydirson@altern.org","avatar":"https://avatars.githubusercontent.com/u/1190950?v=4"},"body":"\nThis adds a framework to handle the parent branch of a stack, in\naddition to the parent remote, and to set them when creating a stack.\n\nSigned-off-by: Yann Dirson <ydirson@altern.org>\n---\n\n TODO           |    2 --\n stgit/stack.py |   24 +++++++++++++++++++++++-\n 2 files changed, 23 insertions(+), 3 deletions(-)\n\ndiff --git a/TODO b/TODO\nindex 549bc9d..884b831 100644\n--- a/TODO\n+++ b/TODO\n@@ -20,8 +20,6 @@ The future, when time allows or if someone else does them:\n - multiple heads in a patch - useful for forking a patch,\n   synchronising with other patches (diff format or in other\n   repositories)\n-- \"pull\" argument should default to a sane value, \"origin\" is wrong in\n-  many cases\n - commit directly to a patch which is not top\n - patch synchronisation between between branches (as some people,\n   including me have the same patches based on different branches and\ndiff --git a/stgit/stack.py b/stgit/stack.py\nindex 026fc36..603c539 100644\n--- a/stgit/stack.py\n+++ b/stgit/stack.py\n@@ -408,6 +408,26 @@ class Series(StgitObject):\n     def __set_parent_remote(self, remote):\n         value = config.set('branch.%s.remote' % self.__name, remote)\n \n+    def get_parent_branch(self):\n+        value = config.get('branch.%s.merge' % self.__name)\n+        if value:\n+            return value\n+        elif rev_parse('heads/origin'):\n+            return 'heads/origin'\n+        else:\n+            raise StackException, 'Cannot find a parent branch for \"%s\"' % self.__name\n+\n+    def __set_parent_branch(self, name):\n+        config.set('branch.%s.merge' % self.__name, name)\n+\n+    def set_parent(self, remote, localbranch):\n+        if localbranch:\n+            self.__set_parent_branch(localbranch)\n+            if remote:\n+                self.__set_parent_remote(remote)\n+        elif remote:\n+            raise StackException, 'Remote \"%s\" without a branch cannot be used as parent' % remote\n+\n     def __patch_is_current(self, patch):\n         return patch.get_name() == self.get_current()\n \n@@ -456,7 +476,7 @@ class Series(StgitObject):\n         \"\"\"\n         return os.path.isdir(self.__patch_dir)\n \n-    def init(self, create_at=False):\n+    def init(self, create_at=False, parent_remote=None, parent_branch=None):\n         \"\"\"Initialises the stgit series\n         \"\"\"\n         bases_dir = os.path.join(self.__base_dir, 'refs', 'bases')\n@@ -473,6 +493,8 @@ class Series(StgitObject):\n \n         os.makedirs(self.__patch_dir)\n \n+        self.set_parent(parent_remote, parent_branch)\n+        \n         create_dirs(bases_dir)\n \n         self.create_empty_field('applied')\n"},{"id":"32853","messageId":"20070127172253.27183.28126.stgit@gandelf.nowhere.earth","threadId":"6567","inReplyTo":"20070127172129.27183.50432.stgit@gandelf.nowhere.earth","subject":"[PATCH 5/6] Have 'stg branch --create' record parent information.","fromName":"Yann Dirson","fromEmail":"ydirson@altern.org","sentAt":"2007-01-27T17:22:54Z","receivedAt":"2007-01-27T17:22:54Z","isPatch":true,"sender":{"key":"ydirson@altern.org","avatar":"https://avatars.githubusercontent.com/u/1190950?v=4"},"body":"\n\n\nSigned-off-by: Yann Dirson <ydirson@altern.org>\n---\n\n stgit/commands/branch.py |   37 ++++++++++++++++++++++++++++++++++---\n 1 files changed, 34 insertions(+), 3 deletions(-)\n\ndiff --git a/stgit/commands/branch.py b/stgit/commands/branch.py\nindex d348409..f074d47 100644\n--- a/stgit/commands/branch.py\n+++ b/stgit/commands/branch.py\n@@ -123,10 +123,41 @@ def func(parser, options, args):\n         check_head_top_equal()\n \n         tree_id = None\n-        if len(args) == 2:\n+        if len(args) >= 2:\n+            try:\n+                if git.rev_parse(args[1]) == git.rev_parse('refs/heads/' + args[1]):\n+                    # we are for sure refering to a branch\n+                    parentbranch = 'refs/heads/' + args[1]\n+                    print 'Recording \"%s\" as parent branch.' % parentbranch\n+                elif git.rev_parse(args[1]) and re.search('/', args[1]):\n+                    # FIXME: should the test be more strict ?\n+                    parentbranch = args[1]\n+                else:\n+                    # Note: this includes refs to StGIT patches\n+                    print 'Don\\'t know how to determine parent branch from \"%s\".' % args[1]\n+                    parentbranch = None\n+            except git.GitException:\n+                # should use a more specific exception to catch only non-git refs ?\n+                print 'Don\\'t know how to determine parent branch from \"%s\".' % args[1]\n+                parentbranch = None\n+\n             tree_id = git_id(args[1])\n-        \n-        stack.Series(args[0]).init(create_at = tree_id)\n+        else:\n+            # branch stack off current branch\n+            parentbranch = git.get_head_file()\n+\n+        if parentbranch:\n+            parentremote = git.identify_remote(parentbranch)\n+            if parentremote:\n+                print 'Using \"%s\" remote to pull parent from.' % parentremote\n+            else:\n+                print 'Not identified a remote to pull parent from.'\n+        else:\n+            parentremote = None\n+\n+        stack.Series(args[0]).init(create_at = tree_id,\n+                                   parent_remote = parentremote,\n+                                   parent_branch = parentbranch)\n \n         print 'Branch \"%s\" created.' % args[0]\n         return\n"},{"id":"32855","messageId":"20070127172259.27183.95603.stgit@gandelf.nowhere.earth","threadId":"6567","inReplyTo":"20070127172129.27183.50432.stgit@gandelf.nowhere.earth","subject":"[PATCH 6/6] Make 'stg pull' use git-fetch and not git-pull.","fromName":"Yann Dirson","fromEmail":"ydirson@altern.org","sentAt":"2007-01-27T17:22:59Z","receivedAt":"2007-01-27T17:22:59Z","isPatch":true,"sender":{"key":"ydirson@altern.org","avatar":"https://avatars.githubusercontent.com/u/1190950?v=4"},"body":"\nWe introduce a new pull-does-rebase setting, as companion to pullcmd.\nThis allows to use both pullcmd's that need a rebase (like git-fetch)\nand pullcmd's that do not (like git-pull).\n\nTo be able to rebase, we rely on parent information being available\nfor the stack.\n\nSigned-off-by: Yann Dirson <ydirson@altern.org>\n---\n\n examples/gitconfig |    8 +++++++-\n stgit/config.py    |    3 ++-\n stgit/git.py       |   15 ++++++++++-----\n 3 files changed, 19 insertions(+), 7 deletions(-)\n\ndiff --git a/examples/gitconfig b/examples/gitconfig\nindex 5e7b240..e3d9889 100644\n--- a/examples/gitconfig\n+++ b/examples/gitconfig\n@@ -33,8 +33,14 @@\n \t#pager = ~/share/stgit/contrib/diffcol.sh\n \t#pager = filterdiff --annotate | colordiff | less -FRX\n \n-\t# GIT pull command (should take the same arguments as git-pull)\n+\t# GIT pull command (should take the same arguments as\n+\t# git-fetch or git-pull).  By default:\n+\t#pullcmd = git-fetch\n+\t#pull-does-rebase = yes\n+\t# Alternative (old behaviour), less intuitive but maybe useful\n+\t# for some workflows:\n \t#pullcmd = git-pull\n+\t#pull-does-rebase = no\n \n \t# The three-way merge tool. Note that the 'output' file contains the\n \t# same data as 'branch1'. This is useful for tools that do not take an\ndiff --git a/stgit/config.py b/stgit/config.py\nindex c2d413b..9b66686 100644\n--- a/stgit/config.py\n+++ b/stgit/config.py\n@@ -29,7 +29,8 @@ class GitConfig:\n         'stgit.autoresolved':\t'no',\n         'stgit.smtpserver':\t\t'localhost:25',\n         'stgit.smtpdelay':\t\t'5',\n-        'stgit.pullcmd':\t\t'git-pull',\n+        'stgit.pullcmd':\t\t'git-fetch',\n+        'stgit.pull-does-rebase':\t'yes',\n         'stgit.merger':\t\t'diff3 -L current -L ancestor -L patched -m -E ' \\\n \t\t\t\t'\"%(branch1)s\" \"%(ancestor)s\" \"%(branch2)s\" > \"%(output)s\"',\n         'stgit.autoimerge':\t\t'no',\ndiff --git a/stgit/git.py b/stgit/git.py\nindex 849a417..708dd56 100644\n--- a/stgit/git.py\n+++ b/stgit/git.py\n@@ -806,18 +806,23 @@ def reset(files = None, tree_id = None, check_out = True):\n         __set_head(tree_id)\n \n def pull(repository = 'origin', refspec = None):\n-    \"\"\"Pull changes from the remote repository. At the moment, just\n-    use the 'git-pull' command\n+    \"\"\"Pull changes from the remote repository. Uses 'git-fetch'\n+    and moves the stack base.\n     \"\"\"\n-    # 'git-pull' updates the HEAD\n+    # we update the HEAD\n     __clear_head_cache()\n \n     args = [repository]\n     if refspec:\n         args.append(refspec)\n \n-    if __run(config.get('stgit.pullcmd'), args) != 0:\n-        raise GitException, 'Failed \"git-pull %s\"' % repository\n+    command = config.get('stgit.pullcmd')\n+    if __run(command, args) != 0:\n+        raise GitException, 'Failed \"%s %s\"' % (command, repository)\n+\n+    if (config.get('stgit.pull-does-rebase')):\n+        # FIXME!\n+        reset(tree_id = rev_parse(repository))\n \n def repack():\n     \"\"\"Repack all objects into a single pack\n"}]}