diff --git a/hgext/histedit.py b/hgext/histedit.py
--- a/hgext/histedit.py
+++ b/hgext/histedit.py
@@ -149,6 +149,13 @@ configuration file::
 
   [histedit]
   linelen = 120      # truncate rule lines at 120 characters
+
+``hg histedit`` attempts to automatically choose an appropriate base
+revision to use. To change which base revision is used, define a
+revset in your configuration file::
+
+  [histedit]
+  defaultrev = only(.) & draft()
 """
 
 try:
@@ -166,6 +173,7 @@ from mercurial import discovery
 from mercurial import error
 from mercurial import copies
 from mercurial import context
+from mercurial import destutil
 from mercurial import exchange
 from mercurial import extensions
 from mercurial import hg
@@ -786,13 +794,19 @@ def findoutgoing(ui, repo, remote=None, 
      ('f', 'force', False,
       _('force outgoing even for unrelated repositories')),
      ('r', 'rev', [], _('first revision to be edited'), _('REV'))],
-     _("ANCESTOR | --outgoing [URL]"))
+     _("[ANCESTOR] | --outgoing [URL]"))
 def histedit(ui, repo, *freeargs, **opts):
     """interactively edit changeset history
 
-    This command edits changesets between ANCESTOR and the parent of
+    This command edits changesets between an ANCESTOR and the parent of
     the working directory.
 
+    The value from the "histedit.defaultrev" config option is used as a
+    revset to select the base revision when ANCESTOR is not specified.
+    The first revision returned by the revset is used. By default, this
+    selects the editable history that is unique to the ancestry of the
+    working directory.
+
     With --outgoing, this edits changesets not found in the
     destination repository. If URL of the destination is omitted, the
     'default-push' (or 'default') path will be used.
@@ -917,10 +931,10 @@ def _histedit(ui, repo, state, *freeargs
         else:
             revs.extend(freeargs)
             if len(revs) == 0:
-                # experimental config: histedit.defaultrev
-                histeditdefault = ui.config('histedit', 'defaultrev')
-                if histeditdefault:
-                    revs.append(histeditdefault)
+                defaultrev = destutil.desthistedit(ui, repo)
+                if defaultrev is not None:
+                    revs.append(defaultrev)
+
             if len(revs) != 1:
                 raise error.Abort(
                     _('histedit requires exactly one ancestor revision'))
diff --git a/mercurial/destutil.py b/mercurial/destutil.py
--- a/mercurial/destutil.py
+++ b/mercurial/destutil.py
@@ -198,3 +198,18 @@ def destmerge(repo):
     else:
         node = _destmergebranch(repo)
     return repo[node].rev()
+
+histeditdefaultrevset = 'reverse(only(.) and not public() and not ::merge())'
+
+def desthistedit(ui, repo):
+    """Default base revision to edit for `hg histedit`."""
+    default = ui.config('histedit', 'defaultrev', histeditdefaultrevset)
+    if default:
+        revs = repo.revs(default)
+        if revs:
+            # The revset supplied by the user may not be in ascending order nor
+            # take the first revision. So do this manually.
+            revs.sort()
+            return revs.first()
+
+    return None
diff --git a/tests/test-histedit-arguments.t b/tests/test-histedit-arguments.t
--- a/tests/test-histedit-arguments.t
+++ b/tests/test-histedit-arguments.t
@@ -347,3 +347,101 @@ Histedit state has been exited
   commit: 1 added, 1 unknown (new branch head)
   update: 4 new changesets (update)
 
+  $ cd ..
+
+Set up default base revision tests
+
+  $ hg init defaultbase
+  $ cd defaultbase
+  $ touch foo
+  $ hg -q commit -A -m root
+  $ echo 1 > foo
+  $ hg commit -m 'public 1'
+  $ hg phase --force --public -r .
+  $ echo 2 > foo
+  $ hg commit -m 'draft after public'
+  $ hg -q up -r 1
+  $ echo 3 > foo
+  $ hg commit -m 'head 1 public'
+  created new head
+  $ hg phase --force --public -r .
+  $ echo 4 > foo
+  $ hg commit -m 'head 1 draft 1'
+  $ echo 5 > foo
+  $ hg commit -m 'head 1 draft 2'
+  $ hg -q up -r 2
+  $ echo 6 > foo
+  $ hg commit -m 'head 2 commit 1'
+  $ echo 7 > foo
+  $ hg commit -m 'head 2 commit 2'
+  $ hg -q up -r 2
+  $ echo 8 > foo
+  $ hg commit -m 'head 3'
+  created new head
+  $ hg -q up -r 2
+  $ echo 9 > foo
+  $ hg commit -m 'head 4'
+  created new head
+  $ hg merge --tool :local -r 8
+  0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg commit -m 'merge head 3 into head 4'
+  $ echo 11 > foo
+  $ hg commit -m 'commit 1 after merge'
+  $ echo 12 > foo
+  $ hg commit -m 'commit 2 after merge'
+
+  $ hg log -G -T '{rev}:{node|short} {phase} {desc}\n'
+  @  12:8cde254db839 draft commit 2 after merge
+  |
+  o  11:6f2f0241f119 draft commit 1 after merge
+  |
+  o    10:90506cc76b00 draft merge head 3 into head 4
+  |\
+  | o  9:f8607a373a97 draft head 4
+  | |
+  o |  8:0da92be05148 draft head 3
+  |/
+  | o  7:4c35cdf97d5e draft head 2 commit 2
+  | |
+  | o  6:931820154288 draft head 2 commit 1
+  |/
+  | o  5:8cdc02b9bc63 draft head 1 draft 2
+  | |
+  | o  4:463b8c0d2973 draft head 1 draft 1
+  | |
+  | o  3:23a0c4eefcbf public head 1 public
+  | |
+  o |  2:4117331c3abb draft draft after public
+  |/
+  o  1:4426d359ea59 public public 1
+  |
+  o  0:54136a8ddf32 public root
+  
+
+Default base revision should stop at public changesets
+
+  $ hg -q up 8cdc02b9bc63
+  $ hg histedit --commands - <<EOF
+  > pick 463b8c0d2973
+  > pick 8cdc02b9bc63
+  > EOF
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Default base revision should stop at branchpoint
+
+  $ hg -q up 4c35cdf97d5e
+  $ hg histedit --commands - <<EOF
+  > pick 931820154288
+  > pick 4c35cdf97d5e
+  > EOF
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Default base revision should stop at merge commit
+
+  $ hg -q up 8cde254db839
+  $ hg histedit --commands - <<EOF
+  > pick 6f2f0241f119
+  > pick 8cde254db839
+  > EOF
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved