git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[StGit PATCH 05/14] New command: stg reset

From
Karl Hasselström <kha@treskal.com>
Date
Jun 12, 2008, 05:34 UTC
Message-ID
<20080612053438.23549.85715.stgit@yoghurt>
In-Reply-To
<20080612052913.23549.69687.stgit@yoghurt>

Given a commit object from the log, resets the stack (or just the named patches) to the state given by that log entry.

Signed-off-by: Karl Hasselström <kha@treskal.com>
---
 stgit/commands/reset.py |  116 ++++++++++++++++++++++++++++++++++++
 stgit/main.py           |    2 +
 t/t3100-reset.sh        |  151 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 269 insertions(+), 0 deletions(-)
 create mode 100644 stgit/commands/reset.py
 create mode 100755 t/t3100-reset.sh
diff --git a/stgit/commands/reset.py b/stgit/commands/reset.py
new file mode 100644
index 0000000..b2643b1
--- /dev/null
+++ b/stgit/commands/reset.py
@@ -0,0 +1,116 @@
+# -*- coding: utf-8 -*-
+
+__copyright__ = """
+Copyright (C) 2008, 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
+"""
+
+from stgit.commands import common
+from stgit.lib import git, log, transaction
+from stgit.out import out
+
+help = 'reset the patch stack to an earlier state'
+usage = """%prog <state> [<patchnames>]
+
+Reset the patch stack to an earlier state. The state is specified with
+a commit from a stack log; for a branch foo, StGit stores the stack
+log in foo.stgit^. So to undo the last N StGit commands (or rather,
+the last N log entries; there is not an exact one-to-one
+relationship), you would say
+
+  stg reset foo.stgit^~N
+
+or, if you are not sure how many steps to undo, you can view the log
+with "git log" or gitk
+
+  gitk foo.stgit^
+
+and then reset to any sha1 you see in the log.
+
+If one or more patch names are given, reset only those patches, and
+leave the rest alone."""
+
+directory = common.DirectoryHasRepositoryLib()
+options = []
+
+def reset_stack(stack, iw, state, only_patches):
+    only_patches = set(only_patches)
+    def mask(s):
+        if only_patches:
+            return s & only_patches
+        else:
+            return s
+    patches_to_reset = mask(set(state.applied + state.unapplied))
+    existing_patches = set(stack.patchorder.all)
+    to_delete = mask(existing_patches - patches_to_reset)
+    trans = transaction.StackTransaction(stack, 'reset')
+
+    # If we have to change the stack base, we need to pop all patches
+    # first.
+    if not only_patches and trans.base != state.base:
+        trans.pop_patches(lambda pn: True)
+        out.info('Setting stack base to %s' % state.base.sha1)
+        trans.base = state.base
+
+    # In one go, do all the popping we have to in order to pop the
+    # patches we're going to delete or modify.
+    def mod(pn):
+        if only_patches and not pn in only_patches:
+            return False
+        if pn in to_delete:
+            return True
+        if stack.patches.get(pn).commit != state.patches.get(pn, None):
+            return True
+        return False
+    trans.pop_patches(mod)
+
+    # Delete and modify/create patches. We've previously popped all
+    # patches that we touch in this step.
+    trans.delete_patches(lambda pn: pn in to_delete)
+    for pn in patches_to_reset:
+        if pn in existing_patches:
+            if trans.patches[pn] == state.patches[pn]:
+                continue
+            else:
+                out.info('Resetting %s' % pn)
+        else:
+            trans.unapplied.append(pn)
+            out.info('Resurrecting %s' % pn)
+        trans.patches[pn] = state.patches[pn]
+
+    # Push/pop patches as necessary.
+    try:
+        if only_patches:
+            # Push all the patches that we've popped, if they still
+            # exist.
+            pushable = set(trans.unapplied)
+            for pn in stack.patchorder.applied:
+                if pn in pushable:
+                    trans.push_patch(pn, iw)
+        else:
+            # Recreate the exact order specified by the goal state.
+            trans.reorder_patches(state.applied, state.unapplied, iw)
+    except transaction.TransactionHalted:
+        pass
+    return trans.run(iw)
+
+def func(parser, options, args):
+    stack = directory.repository.current_stack
+    if len(args) >= 1:
+        ref, patches = args[0], args[1:]
+        state = log.Log(stack.repository, ref, stack.repository.rev_parse(ref))
+    else:
+        raise common.CmdException('Wrong number of arguments')
+    return reset_stack(stack, stack.repository.default_iw, state, patches)
diff --git a/stgit/main.py b/stgit/main.py
index ec0e840..83e6b08 100644
--- a/stgit/main.py
+++ b/stgit/main.py
@@ -89,6 +89,7 @@ commands = Commands({
     'refresh':          'refresh',
     'rename':           'rename',
     'repair':           'repair',
+    'reset':            'reset',
     'resolved':         'resolved',
     'series':           'series',
     'show':             'show',
@@ -122,6 +123,7 @@ stackcommands = (
     'push',
     'rebase',
     'repair',
+    'reset',
     'series',
     'sink',
     'top',
diff --git a/t/t3100-reset.sh b/t/t3100-reset.sh
new file mode 100755
index 0000000..1805091
--- /dev/null
+++ b/t/t3100-reset.sh
@@ -0,0 +1,151 @@
+#!/bin/sh
+
+test_description='Simple test cases for "stg reset"'
+
+. ./test-lib.sh
+
+# Ignore our own output files.
+cat > .git/info/exclude <<EOF
+/expected.txt
+EOF
+
+test_expect_success 'Initialize StGit stack with three patches' '
+    stg init &&
+    echo 000 >> a &&
+    git add a &&
+    git commit -m a &&
+    echo 111 >> a &&
+    git commit -a -m p1 &&
+    echo 222 >> a &&
+    git commit -a -m p2 &&
+    echo 333 >> a &&
+    git commit -a -m p3 &&
+    stg uncommit -n 3 &&
+    stg pop
+'
+
+cat > expected.txt <<EOF
+000
+111
+EOF
+test_expect_success 'Pop one patch ...' '
+    stg pop &&
+    test "$(echo $(stg applied))" = "p1" &&
+    test "$(echo $(stg unapplied))" = "p2 p3" &&
+    test_cmp expected.txt a
+'
+
+cat > expected.txt <<EOF
+000
+111
+222
+EOF
+test_expect_success '... and undo it' '
+    stg reset master.stgit^~1 &&
+    test "$(echo $(stg applied))" = "p1 p2" &&
+    test "$(echo $(stg unapplied))" = "p3" &&
+    test_cmp expected.txt a
+'
+
+cat > expected.txt <<EOF
+000
+111
+222
+333
+EOF
+test_expect_success 'Push one patch ...' '
+    stg push &&
+    test "$(echo $(stg applied))" = "p1 p2 p3" &&
+    test "$(echo $(stg unapplied))" = "" &&
+    test_cmp expected.txt a
+'
+
+cat > expected.txt <<EOF
+000
+111
+222
+EOF
+test_expect_success '... and undo it' '
+    stg reset master.stgit^~1 &&
+    test "$(echo $(stg applied))" = "p1 p2" &&
+    test "$(echo $(stg unapplied))" = "p3" &&
+    test_cmp expected.txt a
+'
+
+test_expect_success 'Commit one patch ...' '
+    stg commit &&
+    test "$(echo $(stg applied))" = "p2" &&
+    test "$(echo $(stg unapplied))" = "p3"
+'
+
+test_expect_success '... and undo it' '
+    stg reset master.stgit^~1 &&
+    test "$(echo $(stg applied))" = "p1 p2" &&
+    test "$(echo $(stg unapplied))" = "p3"
+'
+
+cat > expected.txt <<EOF
+000
+111
+EOF
+test_expect_success 'Delete two patches ...' '
+    stg delete p2 p3 &&
+    test "$(echo $(stg applied))" = "p1" &&
+    test "$(echo $(stg unapplied))" = "" &&
+    test_cmp expected.txt a
+'
+
+test_expect_success '... and undo one of the deletions ...' '
+    stg reset master.stgit^~1 p3 &&
+    test "$(echo $(stg applied))" = "p1" &&
+    test "$(echo $(stg unapplied))" = "p3" &&
+    test_cmp expected.txt a
+'
+
+test_expect_success '... then undo the first undo ...' '
+    stg reset master.stgit^~1 &&
+    test "$(echo $(stg applied))" = "p1" &&
+    test "$(echo $(stg unapplied))" = "" &&
+    test_cmp expected.txt a
+'
+
+cat > expected.txt <<EOF
+000
+111
+222
+EOF
+test_expect_success '... and undo the other deletion' '
+    stg reset master.stgit^~3 p2 &&
+    stg push p2 &&
+    test "$(echo $(stg applied))" = "p1 p2" &&
+    test "$(echo $(stg unapplied))" = "" &&
+    test_cmp expected.txt a
+'
+
+cat > expected.txt <<EOF
+000
+111
+222
+ggg
+EOF
+test_expect_success 'Refresh a patch ...' '
+    echo ggg >> a &&
+    stg refresh &&
+    test "$(echo $(stg applied))" = "p1 p2" &&
+    test "$(echo $(stg unapplied))" = "" &&
+    test_cmp expected.txt a
+'
+
+cat > expected.txt <<EOF
+000
+111
+222
+EOF
+test_expect_success '... and undo the refresh' '
+    stg reset master.stgit^~1 &&
+    test "$(echo $(stg applied))" = "p1 p2" &&
+    test "$(echo $(stg unapplied))" = "" &&
+    test_cmp expected.txt a
+'
+
+test_done
Previous: Karl HasselströmNext: Karl Hasselström
Message 23 of 32 in “Undo series”
  1. 00/14 Undo seriesKarl Hasselström, Jun 12, 2008
  2. 01/14 Fix typoKarl Hasselström, Jun 12, 2008
  3. 02/14 Library functions for tree and blob manipulationKarl Hasselström, Jun 12, 2008
  4. 03/14 Write to a stack log when stack is modifiedKarl Hasselström, Jun 12, 2008
  5. Catalin MarinasJun 17, 2008
  6. Karl HasselströmJun 17, 2008
  7. Karl HasselströmJun 17, 2008
  8. Catalin MarinasJun 17, 2008
  9. Karl HasselströmJun 17, 2008
  10. Catalin MarinasJun 18, 2008
  11. Karl HasselströmJun 18, 2008
  12. Catalin MarinasJun 18, 2008
  13. Karl HasselströmJun 18, 2008
  14. Catalin MarinasJun 19, 2008
  15. Karl HasselströmJun 19, 2008
  16. Catalin MarinasJun 20, 2008
  17. Karl HasselströmJun 23, 2008
  18. Catalin MarinasJul 12, 2008
  19. Karl HasselströmJul 14, 2008
  20. Karl HasselströmJul 1, 2008
  21. Catalin MarinasJul 3, 2008
  22. 04/14 Add utility function for reordering patchesKarl Hasselström, Jun 12, 2008
  23. 05/14 New command: stg resetKarl Hasselström, Jun 12, 2008
  24. 06/14 Log conflicts separatelyKarl Hasselström, Jun 12, 2008
  25. 07/14 Log conflicts separately for all commandsKarl Hasselström, Jun 12, 2008
  26. 08/14 Add a --hard flag to stg resetKarl Hasselström, Jun 12, 2008
  27. 09/14 Don't write a log entry if there were no changesKarl Hasselström, Jun 12, 2008
  28. 10/14 Move stack reset function to a shared locationKarl Hasselström, Jun 12, 2008
  29. 11/14 New command: stg undoKarl Hasselström, Jun 12, 2008
  30. 12/14 New command: stg redoKarl Hasselström, Jun 12, 2008
  31. 13/14 Log and undo external modificationsKarl Hasselström, Jun 12, 2008
  32. 14/14 Make "stg log" show stack log instead of patch logKarl Hasselström, Jun 12, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.