diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
index 10a0ae668fe62418b89fc58da26b0f40172266b2_bWVyY3VyaWFsL2NtZHV0aWwucHk=..894fd1a7c533eb02883b30ebf9ab2d8fec9339ac_bWVyY3VyaWFsL2NtZHV0aWwucHk= 100644
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -2103,3 +2103,32 @@
 
 # a list of (ui, repo) functions called by commands.summary
 summaryhooks = util.hooks()
+
+# A list of state files kept by multistep operations like graft.
+# Since graft cannot be aborted, it is considered 'clearable' by update.
+# note: bisect is intentionally excluded
+# (state file, clearable, error, hint)
+unfinishedstates = [
+    ('graftstate', True, _('graft in progress'),
+     _("use 'hg graft --continue' or 'hg update' to abort"))
+    ]
+
+def checkunfinished(repo):
+    '''Look for an unfinished multistep operation, like graft, and abort
+    if found. It's probably good to check this right before
+    bailifchanged().
+    '''
+    for f, clearable, msg, hint in unfinishedstates:
+        if repo.vfs.exists(f):
+            raise util.Abort(msg, hint=hint)
+
+def clearunfinished(repo):
+    '''Check for unfinished operations (as above), and clear the ones
+    that are clearable.
+    '''
+    for f, clearable, msg, hint in unfinishedstates:
+        if not clearable and repo.vfs.exists(f):
+            raise util.Abort(msg, hint=hint)
+    for f, clearable, msg, hint in unfinishedstates:
+        if clearable and repo.vfs.exists(f):
+            util.unlink(repo.join(f))