Author: julianfoad
Date: Fri Nov 17 22:02:35 2017
New Revision: 1815634

URL: http://svn.apache.org/viewvc?rev=1815634&view=rev
Log:
On the 'shelve-checkpoint' branch: Implement a step towards a new v1 design.

It includes: basic shelve/save, unshelve/restore, deleting and listing.

It does not: detect whether any paths that are about to be restored are
already modified in the WC; avoid storing a version containing no changes or
changes identical to the previous version; integrate with changelists.

Removed:
    subversion/branches/shelve-checkpoint/subversion/libsvn_client/checkpoint.c
    subversion/branches/shelve-checkpoint/subversion/svn/checkpoint-cmd.c
Modified:
    subversion/branches/shelve-checkpoint/subversion/include/svn_client.h
    subversion/branches/shelve-checkpoint/subversion/include/svn_opt.h
    subversion/branches/shelve-checkpoint/subversion/libsvn_client/shelve.c
    subversion/branches/shelve-checkpoint/subversion/svn/cl.h
    subversion/branches/shelve-checkpoint/subversion/svn/shelve-cmd.c
    subversion/branches/shelve-checkpoint/subversion/svn/svn.c
    subversion/branches/shelve-checkpoint/tools/client-side/bash_completion

Modified: subversion/branches/shelve-checkpoint/subversion/include/svn_client.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint/subversion/include/svn_client.h?rev=1815634&r1=1815633&r2=1815634&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint/subversion/include/svn_client.h 
(original)
+++ subversion/branches/shelve-checkpoint/subversion/include/svn_client.h Fri 
Nov 17 22:02:35 2017
@@ -6715,148 +6715,170 @@ svn_client_cat(svn_stream_t *out,
 
 
 
-/** Checkpointing commands
+/** Shelves and checkpoints
  *
- * @defgroup svn_client_checkpoint_funcs Client Checkpointing Functions
+ * @defgroup svn_client_shelve_checkpoint Shelves and checkpoints
  * @{
  */
 
-/**
+/** A shelf.
  *
- * @since New in 1.11.
+ * @since New in 1.X.
  */
-svn_error_t *
-svn_client_checkpoint_get_current(int *checkpoint_number_p,
-                                  const char *local_abspath,
-                                  svn_client_ctx_t *ctx,
-                                  apr_pool_t *scratch_pool);
+typedef struct svn_client_shelf_t
+{
+    /* Public fields (read-only for public use) */
+    const char *name;
+    const char *log_message;
+    int max_version;
 
-/**
+    /* Private fields */
+    const char *wc_root_abspath;
+    const char *shelves_dir;
+    svn_client_ctx_t *ctx;
+    apr_pool_t *pool;
+} svn_client_shelf_t;
+
+/** Open an existing shelf or create a new shelf.
  *
- * @since New in 1.11.
+ * @since New in 1.X.
  */
+SVN_EXPERIMENTAL
 svn_error_t *
-svn_client_checkpoint_save(int *checkpoint_number,
-                           const char *local_abspath,
-                           /*const apr_array_header_t *paths,
-                           svn_depth_t depth,
-                           const apr_array_header_t *changelists,*/
-                           svn_client_ctx_t *ctx,
-                           apr_pool_t *scratch_pool);
+svn_client_shelf_open(svn_client_shelf_t **shelf_p,
+                      const char *name,
+                      const char *local_abspath,
+                      svn_client_ctx_t *ctx,
+                      apr_pool_t *result_pool);
 
-/**
+/** Close @a shelf.
  *
- * @since New in 1.11.
+ * @since New in 1.X.
  */
+SVN_EXPERIMENTAL
 svn_error_t *
-svn_client_checkpoint_restore(int checkpoint_number,
-                              const char *local_abspath,
-                              svn_boolean_t dry_run,
-                              svn_client_ctx_t *ctx,
-                              apr_pool_t *scratch_pool);
+svn_client_shelf_close(svn_client_shelf_t *shelf,
+                       apr_pool_t *scratch_pool);
 
-/**
+/** Delete a shelf, by name.
  *
- * @since New in 1.11.
+ * @since New in 1.X.
  */
+SVN_EXPERIMENTAL
 svn_error_t *
-svn_client_checkpoint_delete(int checkpoint_number,
-                             const char *local_abspath,
-                             svn_boolean_t dry_run,
-                             svn_client_ctx_t *ctx,
-                             apr_pool_t *scratch_pool);
+svn_client_shelf_delete(const char *name,
+                        const char *local_abspath,
+                        svn_boolean_t dry_run,
+                        svn_client_ctx_t *ctx,
+                        apr_pool_t *scratch_pool);
 
-/**
+/** Save the local modifications found by @a paths, @a depth,
+ * @a changelists as a new version of @a shelf.
  *
- * @since New in 1.11.
+ * @since New in 1.X.
  */
+SVN_EXPERIMENTAL
 svn_error_t *
-svn_client_checkpoint_list(apr_array_header_t **checkpoints,
-                           const char *local_abspath,
-                           svn_client_ctx_t *ctx,
-                           apr_pool_t *result_pool,
-                           apr_pool_t *scratch_pool);
-
-/** @} */
-
+svn_client_shelf_save_new_version(svn_client_shelf_t *shelf,
+                                  const apr_array_header_t *paths,
+                                  svn_depth_t depth,
+                                  const apr_array_header_t *changelists,
+                                  apr_pool_t *scratch_pool);
 
-/** Shelving commands
+/** Apply version @a version of @a shelf to the WC.
  *
- * @defgroup svn_client_shelve_funcs Client Shelving Functions
- * @{
+ * @since New in 1.X.
  */
+SVN_EXPERIMENTAL
+svn_error_t *
+svn_client_shelf_apply(svn_client_shelf_t *shelf,
+                       int version,
+                       svn_boolean_t dry_run,
+                       apr_pool_t *scratch_pool);
 
-/** Shelve a change.
- *
- * Shelve as @a name the local modifications found by @a paths, @a depth,
- * @a changelists. Revert the shelved change from the WC unless @a keep_local
- * is true.
+/** Reverse-apply the current version of @a shelf to the WC.
  *
- * If @a dry_run is true, don't actually do it.
- *
- * @since New in 1.11.
+ * @since New in 1.X.
  */
+SVN_EXPERIMENTAL
 svn_error_t *
-svn_client_shelve(const char *name,
-                  const apr_array_header_t *paths,
-                  svn_depth_t depth,
-                  const apr_array_header_t *changelists,
-                  svn_boolean_t keep_local,
-                  svn_boolean_t dry_run,
-                  svn_client_ctx_t *ctx,
-                  apr_pool_t *pool);
+svn_client_shelf_unapply(svn_client_shelf_t *shelf,
+                         int version,
+                         svn_boolean_t dry_run,
+                         apr_pool_t *scratch_pool);
 
-/** Unshelve the shelved change @a name.
- *
- * @a local_abspath is any path in the WC and is used to find the WC root.
- * Rename the shelved patch to add a '.bak' extension unless @a keep is true.
+/** Set the current version of @a shelf. Delete all newer versions.
  *
- * If @a dry_run is true, don't actually do it.
+ * @since New in 1.X.
+ */
+SVN_EXPERIMENTAL
+svn_error_t *
+svn_client_shelf_set_current_version(svn_client_shelf_t *shelf,
+                                     int version,
+                                     apr_pool_t *scratch_pool);
+
+/** Set @a *wc_abspaths_p to the files affected by version @a version
+ * of @a shelf.
  *
- * @since New in 1.11.
+ * @since New in 1.X.
  */
+SVN_EXPERIMENTAL
 svn_error_t *
-svn_client_unshelve(const char *name,
-                    const char *local_abspath,
-                    svn_boolean_t keep,
-                    svn_boolean_t dry_run,
-                    svn_client_ctx_t *ctx,
-                    apr_pool_t *pool);
+svn_client_shelf_get_files(apr_array_header_t **wc_abspaths_p,
+                           svn_client_shelf_t *shelf,
+                           int version,
+                           apr_pool_t *scratch_pool);
 
-/** Delete the shelved patch @a name.
+/** Information about one version.
  *
- * @a local_abspath is any path in the WC and is used to find the WC root.
+ * @since New in 1.X.
+ */
+typedef struct svn_client_shelf_version_info_t
+{
+  const char *patch_abspath;  /* abspath of the patch file */
+  apr_time_t mtime;  /* mtime of the patch file */
+} svn_client_shelf_version_info_t;
+
+/** Set @a *info to the files affected by the current version of SHELF.
  *
- * If @a dry_run is true, don't actually do it.
+ * @since New in 1.X.
+ */
+SVN_EXPERIMENTAL
+svn_error_t *
+svn_client_shelf_version_get_info(svn_client_shelf_version_info_t **info,
+                                  svn_client_shelf_t *shelf,
+                                  int version,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool);
+
+/** Set the log message in SHELF, using the log message callbacks in
+ * the client context.
  *
- * @since New in 1.11.
+ * @since New in 1.X.
  */
+SVN_EXPERIMENTAL
 svn_error_t *
-svn_client_shelves_delete(const char *name,
-                          const char *local_abspath,
-                          svn_boolean_t dry_run,
-                          svn_client_ctx_t *ctx,
-                          apr_pool_t *pool);
+svn_client_shelf_set_log_message(svn_client_shelf_t *shelf,
+                                 svn_boolean_t dry_run,
+                                 apr_pool_t *scratch_pool);
 
-/** Information about a shelved patch.
+/** Information about a shelf.
  *
- * @since New in 1.11.
+ * @since New in 1.X.
  */
-typedef struct svn_client_shelved_patch_info_t
+typedef struct svn_client_shelf_info_t
 {
-  const char *message;  /* first line of log message */
-  const char *patch_path;  /* abspath of the patch file */
-  svn_io_dirent2_t *dirent;  /* info about the patch file */
-  apr_time_t mtime;  /* a copy of dirent->mtime */
-} svn_client_shelved_patch_info_t;
+  apr_time_t mtime;  /* mtime of the latest change */
+} svn_client_shelf_info_t;
 
-/** Set *shelved_patches to a hash, keyed by patch name, of pointers to
- * @c svn_client_shelved_patch_info_t structures.
+/** Set *shelved_patches to a hash, keyed by shelf name, of pointers to
+ * @c svn_client_shelf_info_t structures.
  *
  * @a local_abspath is any path in the WC and is used to find the WC root.
  *
- * @since New in 1.11.
+ * @since New in 1.X.
  */
+SVN_EXPERIMENTAL
 svn_error_t *
 svn_client_shelves_list(apr_hash_t **shelved_patch_infos,
                         const char *local_abspath,
@@ -6874,56 +6896,15 @@ svn_client_shelves_list(apr_hash_t **she
  *
  * @a local_abspath is any path in the WC and is used to find the WC root.
  *
- * @since New in 1.11.
+ * @since New in 1.X.
  */
+SVN_EXPERIMENTAL
 svn_error_t *
 svn_client_shelves_any(svn_boolean_t *any_shelved,
                        const char *local_abspath,
                        svn_client_ctx_t *ctx,
                        apr_pool_t *scratch_pool);
 
-/** Write local changes to a patch file for shelved change @a name.
- *
- * @a message: An optional log message.
- * @a wc_root_abspath: The WC root dir.
- * @a overwrite_existing: If a file at @a patch_abspath exists, overwrite it.
- * @a paths, @a depth, @a changelists: The selection of local paths to diff.
- */
-svn_error_t *
-svn_client_shelf_write_patch(const char *name,
-                             const char *message,
-                             const char *wc_root_abspath,
-                             svn_boolean_t overwrite_existing,
-                             const apr_array_header_t *paths,
-                             svn_depth_t depth,
-                             const apr_array_header_t *changelists,
-                             svn_client_ctx_t *ctx,
-                             apr_pool_t *scratch_pool);
-
-/** Apply the patch file for shelved change @a name to the WC.
- *
- * @a wc_root_abspath: The WC root dir.
- * @a reverse: Apply the patch in reverse.
- * @a dry_run: Don't really apply the changes, just notify what would be done.
- */
-svn_error_t *
-svn_client_shelf_apply_patch(const char *name,
-                             const char *wc_root_abspath,
-                             svn_boolean_t reverse,
-                             svn_boolean_t dry_run,
-                             svn_client_ctx_t *ctx,
-                             apr_pool_t *scratch_pool);
-
-/** Delete the patch file for shelved change @a name.
- *
- * @a wc_root_abspath: The WC root dir.
- */
-svn_error_t *
-svn_client_shelf_delete_patch(const char *name,
-                              const char *wc_root_abspath,
-                              svn_client_ctx_t *ctx,
-                              apr_pool_t *scratch_pool);
-
 /** @} */
 
 /** Changelist commands

Modified: subversion/branches/shelve-checkpoint/subversion/include/svn_opt.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint/subversion/include/svn_opt.h?rev=1815634&r1=1815633&r2=1815634&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint/subversion/include/svn_opt.h 
(original)
+++ subversion/branches/shelve-checkpoint/subversion/include/svn_opt.h Fri Nov 
17 22:02:35 2017
@@ -64,7 +64,7 @@ typedef svn_error_t *(svn_opt_subcommand
 
 
 /** The maximum number of aliases a subcommand can have. */
-#define SVN_OPT_MAX_ALIASES 3
+#define SVN_OPT_MAX_ALIASES 4
 
 /** The maximum number of options that can be accepted by a subcommand. */
 #define SVN_OPT_MAX_OPTIONS 50

Modified: 
subversion/branches/shelve-checkpoint/subversion/libsvn_client/shelve.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint/subversion/libsvn_client/shelve.c?rev=1815634&r1=1815633&r2=1815634&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint/subversion/libsvn_client/shelve.c 
(original)
+++ subversion/branches/shelve-checkpoint/subversion/libsvn_client/shelve.c Fri 
Nov 17 22:02:35 2017
@@ -23,9 +23,9 @@
 
 /* ==================================================================== */
 
-
-
-/*** Includes. ***/
+/* We define this here to remove any further warnings about the usage of
+   experimental functions in this file. */
+#define SVN_EXPERIMENTAL
 
 #include "svn_client.h"
 #include "svn_wc.h"
@@ -37,6 +37,7 @@
 
 #include "client.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_sorts_private.h"
 #include "svn_private_config.h"
 
 
@@ -52,39 +53,188 @@ validate_name(const char *name,
   return SVN_NO_ERROR;
 }
 
-/* Set *PATCH_ABSPATH to the abspath of the patch file for shelved change
- * NAME, no matter whether it exists.
+/* Set *PATCH_ABSPATH to the abspath of the patch file for SHELF
+ * version VERSION, no matter whether it exists.
  */
 static svn_error_t *
-get_patch_abspath(char **patch_abspath,
-                  const char *name,
-                  const char *wc_root_abspath,
-                  svn_client_ctx_t *ctx,
+get_patch_abspath(const char **abspath,
+                  svn_client_shelf_t *shelf,
+                  int version,
                   apr_pool_t *result_pool,
                   apr_pool_t *scratch_pool)
 {
-  char *dir;
   const char *filename;
 
-  SVN_ERR(svn_wc__get_shelves_dir(&dir, ctx->wc_ctx, wc_root_abspath,
-                                  scratch_pool, scratch_pool));
-  filename = apr_pstrcat(scratch_pool, name, ".patch", SVN_VA_NULL);
-  *patch_abspath = svn_dirent_join(dir, filename, result_pool);
+  filename = apr_psprintf(scratch_pool, "%s-%03d.patch", shelf->name, version);
+  *abspath = svn_dirent_join(shelf->shelves_dir, filename, result_pool);
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_client_shelf_write_patch(const char *name,
-                             const char *message,
-                             const char *wc_root_abspath,
-                             svn_boolean_t overwrite_existing,
-                             const apr_array_header_t *paths,
-                             svn_depth_t depth,
-                             const apr_array_header_t *changelists,
-                             svn_client_ctx_t *ctx,
-                             apr_pool_t *scratch_pool)
+/* Set *PATCH_ABSPATH to the abspath of the patch file for SHELF
+ * version VERSION. Error if VERSION is invalid or nonexistent.
+ */
+static svn_error_t *
+get_existing_patch_abspath(const char **abspath,
+                           svn_client_shelf_t *shelf,
+                           int version,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  if (shelf->max_version <= 0)
+    return svn_error_createf(SVN_ERR_CLIENT_BAD_REVISION, NULL,
+                             _("shelf '%s': no versions available"),
+                             shelf->name);
+  if (version <= 0 || version > shelf->max_version)
+    return svn_error_createf(SVN_ERR_CLIENT_BAD_REVISION, NULL,
+                             _("shelf '%s' has no version %d: max version is 
%d"),
+                             shelf->name, version, shelf->max_version);
+
+  SVN_ERR(get_patch_abspath(abspath, shelf, version,
+                            result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+shelf_delete_patch_file(svn_client_shelf_t *shelf,
+                        int version,
+                        apr_pool_t *scratch_pool)
+{
+  const char *patch_abspath;
+
+  SVN_ERR(get_existing_patch_abspath(&patch_abspath, shelf, version,
+                                     scratch_pool, scratch_pool));
+  SVN_ERR(svn_io_remove_file2(patch_abspath, TRUE /*ignore_enoent*/,
+                              scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/*  */
+static svn_error_t *
+get_log_abspath(char **log_abspath,
+                svn_client_shelf_t *shelf,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  const char *filename;
+
+  filename = apr_pstrcat(scratch_pool, shelf->name, ".log", SVN_VA_NULL);
+  *log_abspath = svn_dirent_join(shelf->shelves_dir, filename, result_pool);
+  return SVN_NO_ERROR;
+}
+
+/* Set SHELF->log_message by reading from its file storage.
+ *
+ * ### Currently just reads the first line.
+ */
+static svn_error_t *
+shelf_read_log_message(svn_client_shelf_t *shelf,
+                       apr_pool_t *result_pool)
+{
+  char *log_abspath;
+  apr_file_t *file;
+  svn_error_t *err;
+  svn_stream_t *stream;
+  svn_boolean_t eof;
+  svn_stringbuf_t *line;
+
+  SVN_ERR(get_log_abspath(&log_abspath, shelf, result_pool, result_pool));
+
+  err = svn_io_file_open(&file, log_abspath,
+                         APR_FOPEN_READ,
+                         APR_FPROT_OS_DEFAULT, result_pool);
+  if (err && err->apr_err == APR_ENOENT)
+    {
+      shelf->log_message = "";
+      return SVN_NO_ERROR;
+    }
+  else
+    SVN_ERR(err);
+  stream = svn_stream_from_aprfile2(file, FALSE /*disown*/, result_pool);
+
+  SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, result_pool));
+  SVN_ERR(svn_stream_close(stream));
+  shelf->log_message = line->data;
+  return SVN_NO_ERROR;
+}
+
+/* Write SHELF->log_message to its file storage.
+ */
+static svn_error_t *
+shelf_write_log_message(svn_client_shelf_t *shelf,
+                        apr_pool_t *scratch_pool)
+{
+  char *log_abspath;
+  apr_file_t *file;
+  svn_stream_t *stream;
+
+  SVN_ERR(get_log_abspath(&log_abspath, shelf, scratch_pool, scratch_pool));
+
+  SVN_ERR(svn_io_file_open(&file, log_abspath,
+                           APR_FOPEN_WRITE | APR_FOPEN_CREATE,
+                           APR_FPROT_OS_DEFAULT, scratch_pool));
+  stream = svn_stream_from_aprfile2(file, FALSE /*disown*/, scratch_pool);
+
+  SVN_ERR(svn_stream_puts(stream, shelf->log_message));
+  SVN_ERR(svn_stream_close(stream));
+  return SVN_NO_ERROR;
+}
+
+/*  */
+static char *
+get_current_abspath(svn_client_shelf_t *shelf,
+                    apr_pool_t *result_pool)
+{
+  const char *current_filename
+    = apr_psprintf(result_pool, "%s.current", shelf->name);
+  return svn_dirent_join(shelf->shelves_dir, current_filename, result_pool);
+}
+
+/*  */
+static svn_error_t *
+shelf_read_current(svn_client_shelf_t *shelf,
+                   apr_pool_t *scratch_pool)
+{
+  const char *current_abspath = get_current_abspath(shelf, scratch_pool);
+  FILE *fp = fopen(current_abspath, "r");
+
+  if (! fp)
+    {
+      shelf->max_version = 0;
+      return SVN_NO_ERROR;
+    }
+  fscanf(fp, "%d", &shelf->max_version);
+  fclose(fp);
+  return SVN_NO_ERROR;
+}
+
+/*  */
+static svn_error_t *
+shelf_write_current(svn_client_shelf_t *shelf,
+                    apr_pool_t *scratch_pool)
+{
+  const char *current_abspath = get_current_abspath(shelf, scratch_pool);
+  FILE *fp = fopen(current_abspath, "w");
+
+  fprintf(fp, "%d", shelf->max_version);
+  fclose(fp);
+  return SVN_NO_ERROR;
+}
+
+/** Write local changes to a patch file.
+ *
+ * @a paths, @a depth, @a changelists: The selection of local paths to diff.
+ *
+ * ### TODO: Ignore any external diff cmd as configured in config file.
+ *     This might also solve the buffering problem.
+ */
+static svn_error_t *
+write_patch(const char *patch_abspath,
+            const apr_array_header_t *paths,
+            svn_depth_t depth,
+            const apr_array_header_t *changelists,
+            svn_client_ctx_t *ctx,
+            apr_pool_t *scratch_pool)
 {
-  char *patch_abspath;
   apr_int32_t flag;
   apr_file_t *outfile;
   svn_stream_t *outstream;
@@ -95,34 +245,16 @@ svn_client_shelf_write_patch(const char
   svn_opt_revision_t start_revision = {svn_opt_revision_base, {0}};
   svn_opt_revision_t end_revision = {svn_opt_revision_working, {0}};
 
-  printf("writing '%s.patch'\n", name);
-
-  SVN_ERR(get_patch_abspath(&patch_abspath, name, wc_root_abspath,
-                            ctx, scratch_pool, scratch_pool));
-
   /* Get streams for the output and any error output of the diff. */
   /* ### svn_stream_open_writable() doesn't work here: the buffering
          goes wrong so that diff headers appear after their hunks.
          For now, fix by opening the file without APR_BUFFERED. */
   flag = APR_FOPEN_WRITE | APR_FOPEN_CREATE;
-  if (! overwrite_existing)
-    flag |= APR_FOPEN_EXCL;
   SVN_ERR(svn_io_file_open(&outfile, patch_abspath,
                            flag, APR_FPROT_OS_DEFAULT, scratch_pool));
   outstream = svn_stream_from_aprfile2(outfile, FALSE /*disown*/, 
scratch_pool);
   SVN_ERR(svn_stream_for_stderr(&errstream, scratch_pool));
 
-  /* Write the patch file header (log message, etc.) */
-  if (message)
-    {
-      SVN_ERR(svn_stream_printf(outstream, scratch_pool, "%s\n",
-                                message));
-    }
-  SVN_ERR(svn_stream_printf(outstream, scratch_pool,
-                            "--This line, and those below, will be 
ignored--\n\n"));
-  SVN_ERR(svn_stream_printf(outstream, scratch_pool,
-                            "--This patch was generated by 'svn 
shelve'--\n\n"));
-
   for (i = 0; i < paths->nelts; i++)
     {
       const char *path = APR_ARRAY_IDX(paths, i, const char *);
@@ -160,210 +292,188 @@ svn_client_shelf_write_patch(const char
 }
 
 svn_error_t *
-svn_client_shelf_apply_patch(const char *name,
-                             const char *wc_root_abspath,
-                             svn_boolean_t reverse,
-                             svn_boolean_t dry_run,
-                             svn_client_ctx_t *ctx,
-                             apr_pool_t *scratch_pool)
-{
-  char *patch_abspath;
-
-  SVN_ERR(get_patch_abspath(&patch_abspath, name, wc_root_abspath,
-                            ctx, scratch_pool, scratch_pool));
-  SVN_ERR(svn_client_patch(patch_abspath, wc_root_abspath,
-                           dry_run, 0 /*strip*/,
-                           reverse,
-                           FALSE /*ignore_whitespace*/,
-                           TRUE /*remove_tempfiles*/, NULL, NULL,
-                           ctx, scratch_pool));
+svn_client_shelf_open(svn_client_shelf_t **shelf_p,
+                      const char *name,
+                      const char *local_abspath,
+                      svn_client_ctx_t *ctx,
+                      apr_pool_t *result_pool)
+{
+  svn_client_shelf_t *shelf = apr_palloc(result_pool, sizeof(*shelf));
+  char *shelves_dir;
+
+  SVN_ERR(validate_name(name, result_pool));
+
+  SVN_ERR(svn_client_get_wc_root(&shelf->wc_root_abspath,
+                                 local_abspath, ctx,
+                                 result_pool, result_pool));
+  SVN_ERR(svn_wc__get_shelves_dir(&shelves_dir,
+                                  ctx->wc_ctx, local_abspath,
+                                  result_pool, result_pool));
+  shelf->shelves_dir = shelves_dir;
+  shelf->ctx = ctx;
+  shelf->pool = result_pool;
+
+  shelf->name = apr_pstrdup(result_pool, name);
+  SVN_ERR(shelf_read_log_message(shelf, result_pool));
+  SVN_ERR(shelf_read_current(shelf, result_pool));
 
+  *shelf_p = shelf;
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
-svn_client_shelf_delete_patch(const char *name,
-                              const char *wc_root_abspath,
-                              svn_client_ctx_t *ctx,
-                              apr_pool_t *scratch_pool)
+svn_client_shelf_close(svn_client_shelf_t *shelf,
+                       apr_pool_t *scratch_pool)
 {
-  char *patch_abspath, *to_abspath;
-
-  SVN_ERR(get_patch_abspath(&patch_abspath, name, wc_root_abspath,
-                            ctx, scratch_pool, scratch_pool));
-  to_abspath = apr_pstrcat(scratch_pool, patch_abspath, ".bak", SVN_VA_NULL);
-
-  /* remove any previous backup */
-  SVN_ERR(svn_io_remove_file2(to_abspath, TRUE /*ignore_enoent*/,
-                              scratch_pool));
-
-  /* move the patch to a backup file */
-  printf("moving '%s.patch' to '%s.patch.bak'\n", name, name);
-  SVN_ERR(svn_io_file_rename2(patch_abspath, to_abspath, FALSE 
/*flush_to_disk*/,
-                              scratch_pool));
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
-svn_client_shelve(const char *name,
-                  const apr_array_header_t *paths,
-                  svn_depth_t depth,
-                  const apr_array_header_t *changelists,
-                  svn_boolean_t keep_local,
-                  svn_boolean_t dry_run,
-                  svn_client_ctx_t *ctx,
-                  apr_pool_t *pool)
+svn_client_shelf_delete(const char *name,
+                        const char *local_abspath,
+                        svn_boolean_t dry_run,
+                        svn_client_ctx_t *ctx,
+                        apr_pool_t *scratch_pool)
 {
-  const char *local_abspath;
-  const char *wc_root_abspath;
-  const char *message = "";
-  svn_error_t *err;
+  svn_client_shelf_t *shelf;
+  int i;
+  char *abspath;
 
-  SVN_ERR(validate_name(name, pool));
+  SVN_ERR(validate_name(name, scratch_pool));
 
-  /* ### TODO: check all paths are in same WC; for now use first path */
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath,
-                                  APR_ARRAY_IDX(paths, 0, char *), pool));
-  SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
-                                 local_abspath, ctx, pool, pool));
+  SVN_ERR(svn_client_shelf_open(&shelf,
+                                name, local_abspath, ctx, scratch_pool));
 
-  /* Fetch the log message and any other revprops */
-  if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx))
+  /* Remove the patches. */
+  for (i = shelf->max_version; i > 0; i--)
     {
-      const char *tmp_file;
-      apr_array_header_t *commit_items = apr_array_make(pool, 1, sizeof(void 
*));
-
-      SVN_ERR(svn_client__get_log_msg(&message, &tmp_file, commit_items,
-                                      ctx, pool));
-      if (! message)
-        return SVN_NO_ERROR;
+      SVN_ERR(shelf_delete_patch_file(shelf, i, scratch_pool));
     }
 
-  err = svn_client_shelf_write_patch(name, message, wc_root_abspath,
-                                     FALSE /*overwrite_existing*/,
-                                     paths, depth, changelists,
-                                     ctx, pool);
-  if (err && APR_STATUS_IS_EEXIST(err->apr_err))
-    {
-      return svn_error_quick_wrapf(err,
-                                   "Shelved change '%s' already exists",
-                                   name);
-    }
-  else
-    SVN_ERR(err);
-
-  if (!keep_local)
-    {
-      /* Reverse-apply the patch. This should be a safer way to remove those
-         changes from the WC than running a 'revert' operation. */
-      SVN_ERR(svn_client_shelf_apply_patch(name, wc_root_abspath,
-                                           TRUE /*reverse*/, dry_run,
-                                           ctx, pool));
-    }
-
-  if (dry_run)
-    {
-      SVN_ERR(svn_client_shelf_delete_patch(name, wc_root_abspath,
-                                            ctx, pool));
-    }
+  /* Remove the other files */
+  SVN_ERR(get_log_abspath(&abspath, shelf, scratch_pool, scratch_pool));
+  SVN_ERR(svn_io_remove_file2(abspath, TRUE /*ignore_enoent*/, scratch_pool));
+  abspath = get_current_abspath(shelf, scratch_pool);
+  SVN_ERR(svn_io_remove_file2(abspath, TRUE /*ignore_enoent*/, scratch_pool));
 
+  SVN_ERR(svn_client_shelf_close(shelf, scratch_pool));
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
-svn_client_unshelve(const char *name,
-                    const char *local_abspath,
-                    svn_boolean_t keep,
-                    svn_boolean_t dry_run,
-                    svn_client_ctx_t *ctx,
-                    apr_pool_t *pool)
+svn_client_shelf_apply(svn_client_shelf_t *shelf,
+                       int version,
+                       svn_boolean_t dry_run,
+                       apr_pool_t *scratch_pool)
 {
-  const char *wc_root_abspath;
-  svn_error_t *err;
-
-  SVN_ERR(validate_name(name, pool));
+  const char *patch_abspath;
 
-  SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
-                                 local_abspath, ctx, pool, pool));
+  SVN_ERR(get_existing_patch_abspath(&patch_abspath, shelf, version,
+                                     scratch_pool, scratch_pool));
+  SVN_ERR(svn_client_patch(patch_abspath, shelf->wc_root_abspath,
+                           dry_run, 0 /*strip*/,
+                           FALSE /*reverse*/,
+                           FALSE /*ignore_whitespace*/,
+                           TRUE /*remove_tempfiles*/, NULL, NULL,
+                           shelf->ctx, scratch_pool));
 
-  /* Apply the patch. */
-  err = svn_client_shelf_apply_patch(name, wc_root_abspath,
-                                     FALSE /*reverse*/, dry_run,
-                                     ctx, pool);
-  if (err && err->apr_err == SVN_ERR_ILLEGAL_TARGET)
-    {
-      return svn_error_quick_wrapf(err,
-                                   "Shelved change '%s' not found",
-                                   name);
-    }
-  else
-    SVN_ERR(err);
+  return SVN_NO_ERROR;
+}
 
-  /* Remove the patch. */
-  if (! keep && ! dry_run)
-    {
-      SVN_ERR(svn_client_shelf_delete_patch(name, wc_root_abspath,
-                                            ctx, pool));
-    }
+svn_error_t *
+svn_client_shelf_unapply(svn_client_shelf_t *shelf,
+                         int version,
+                         svn_boolean_t dry_run,
+                         apr_pool_t *scratch_pool)
+{
+  const char *patch_abspath;
+
+  SVN_ERR(get_existing_patch_abspath(&patch_abspath, shelf, version,
+                                     scratch_pool, scratch_pool));
+  SVN_ERR(svn_client_patch(patch_abspath, shelf->wc_root_abspath,
+                           dry_run, 0 /*strip*/,
+                           TRUE /*reverse*/,
+                           FALSE /*ignore_whitespace*/,
+                           TRUE /*remove_tempfiles*/, NULL, NULL,
+                           shelf->ctx, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
-svn_client_shelves_delete(const char *name,
-                          const char *local_abspath,
-                          svn_boolean_t dry_run,
-                          svn_client_ctx_t *ctx,
-                          apr_pool_t *pool)
+svn_client_shelf_set_current_version(svn_client_shelf_t *shelf,
+                                     int version,
+                                     apr_pool_t *scratch_pool)
 {
-  const char *wc_root_abspath;
+  int i;
 
-  SVN_ERR(validate_name(name, pool));
+  /* Delete any newer checkpoints */
+  for (i = shelf->max_version; i > version; i--)
+    {
+      SVN_ERR(shelf_delete_patch_file(shelf, i, scratch_pool));
+    }
 
-  SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
-                                 local_abspath, ctx, pool, pool));
+  shelf->max_version = version;
+  SVN_ERR(shelf_write_current(shelf, scratch_pool));
+  return SVN_NO_ERROR;
+}
 
-  /* Remove the patch. */
-  if (! dry_run)
-    {
-      svn_error_t *err;
+svn_error_t *
+svn_client_shelf_get_files(apr_array_header_t **wc_abspaths_p,
+                           svn_client_shelf_t *shelf,
+                           int version,
+                           apr_pool_t *scratch_pool)
+{
 
-      err = svn_client_shelf_delete_patch(name, wc_root_abspath,
-                                          ctx, pool);
-      if (err && APR_STATUS_IS_ENOENT(err->apr_err))
-        {
-          return svn_error_quick_wrapf(err,
-                                       "Shelved change '%s' not found",
-                                       name);
-        }
-      else
-        SVN_ERR(err);
-    }
+  return SVN_NO_ERROR;
+}
 
+svn_error_t *
+svn_client_shelf_save_new_version(svn_client_shelf_t *shelf,
+                                  const apr_array_header_t *paths,
+                                  svn_depth_t depth,
+                                  const apr_array_header_t *changelists,
+                                  apr_pool_t *scratch_pool)
+{
+  int next_version = shelf->max_version + 1;
+  const char *patch_abspath;
+
+  SVN_ERR(get_patch_abspath(&patch_abspath, shelf, next_version,
+                            scratch_pool, scratch_pool));
+  SVN_ERR(write_patch(patch_abspath,
+                      paths, depth, changelists,
+                      shelf->ctx, scratch_pool));
+  SVN_ERR(svn_client_shelf_set_current_version(shelf, next_version,
+                                               scratch_pool));
   return SVN_NO_ERROR;
 }
 
-/* Set *LOGMSG to the log message stored in the file PATCH_ABSPATH.
- *
- * ### Currently just reads the first line.
- */
-static svn_error_t *
-read_logmsg_from_patch(const char **logmsg,
-                       const char *patch_abspath,
-                       apr_pool_t *result_pool,
-                       apr_pool_t *scratch_pool)
+svn_error_t *
+svn_client_shelf_set_log_message(svn_client_shelf_t *shelf,
+                                 svn_boolean_t dry_run,
+                                 apr_pool_t *scratch_pool)
 {
-  apr_file_t *file;
-  svn_stream_t *stream;
-  svn_boolean_t eof;
-  svn_stringbuf_t *line;
+  svn_client_ctx_t *ctx = shelf->ctx;
+  const char *message = "";
+
+  /* Fetch the log message and any other revprops */
+  if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx))
+    {
+      const char *tmp_file;
+      apr_array_header_t *commit_items
+        = apr_array_make(scratch_pool, 1, sizeof(void *));
+
+      SVN_ERR(svn_client__get_log_msg(&message, &tmp_file, commit_items,
+                                      ctx, scratch_pool));
+      if (! message)
+        return SVN_NO_ERROR;
+    }
+  if (message && !dry_run)
+    {
+      shelf->log_message = apr_pstrdup(shelf->pool, message);
+      SVN_ERR(shelf_write_log_message(shelf, scratch_pool));
+    }
 
-  SVN_ERR(svn_io_file_open(&file, patch_abspath,
-                           APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, 
scratch_pool));
-  stream = svn_stream_from_aprfile2(file, FALSE /*disown*/, scratch_pool);
-  SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, result_pool));
-  SVN_ERR(svn_stream_close(stream));
-  *logmsg = line->data;
   return SVN_NO_ERROR;
 }
 
@@ -374,10 +484,13 @@ svn_client_shelves_list(apr_hash_t **she
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool)
 {
+  const char *wc_root_abspath;
   char *shelves_dir;
   apr_hash_t *dirents;
   apr_hash_index_t *hi;
 
+  SVN_ERR(svn_wc__get_wcroot(&wc_root_abspath, ctx->wc_ctx, local_abspath,
+                             scratch_pool, scratch_pool));
   SVN_ERR(svn_wc__get_shelves_dir(&shelves_dir, ctx->wc_ctx, local_abspath,
                                   scratch_pool, scratch_pool));
   SVN_ERR(svn_io_get_dirents3(&dirents, shelves_dir, FALSE /*only_check_type*/,
@@ -389,21 +502,16 @@ svn_client_shelves_list(apr_hash_t **she
   for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
     {
       const char *filename = apr_hash_this_key(hi);
+      svn_io_dirent2_t *dirent = apr_hash_this_val(hi);
       int len = strlen(filename);
 
-      if (len > 6 && strcmp(filename + len - 6, ".patch") == 0)
+      if (len > 6 && strcmp(filename + len - 8, ".current") == 0)
         {
-          const char *name = apr_pstrndup(result_pool, filename, len - 6);
-          svn_client_shelved_patch_info_t *info
+          const char *name = apr_pstrndup(result_pool, filename, len - 8);
+          svn_client_shelf_info_t *info
             = apr_palloc(result_pool, sizeof(*info));
 
-          info->dirent = apr_hash_this_val(hi);
-          info->mtime = info->dirent->mtime;
-          info->patch_path
-            = svn_dirent_join(shelves_dir, filename, result_pool);
-          SVN_ERR(read_logmsg_from_patch(&info->message, info->patch_path,
-                                         result_pool, scratch_pool));
-
+          info->mtime = dirent->mtime;
           svn_hash_sets(*shelved_patch_infos, name, info);
         }
     }
@@ -424,3 +532,26 @@ svn_client_shelves_any(svn_boolean_t *an
   *any_shelved = apr_hash_count(shelved_patch_infos) != 0;
   return SVN_NO_ERROR;
 }
+
+svn_error_t *
+svn_client_shelf_version_get_info(svn_client_shelf_version_info_t **info_p,
+                                  svn_client_shelf_t *shelf,
+                                  int version,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool)
+{
+  svn_client_shelf_version_info_t *info
+    = apr_palloc(result_pool, sizeof(*info));
+  const svn_io_dirent2_t *dirent;
+
+  SVN_ERR(get_patch_abspath(&info->patch_abspath, shelf, version,
+                            result_pool, scratch_pool));
+  SVN_ERR(svn_io_stat_dirent2(&dirent,
+                              info->patch_abspath,
+                              FALSE /*verify_truename*/,
+                              TRUE /*ignore_enoent*/,
+                              result_pool, scratch_pool));
+  info->mtime = dirent->mtime;
+  *info_p = info;
+  return SVN_NO_ERROR;
+}
\ No newline at end of file

Modified: subversion/branches/shelve-checkpoint/subversion/svn/cl.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint/subversion/svn/cl.h?rev=1815634&r1=1815633&r2=1815634&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint/subversion/svn/cl.h (original)
+++ subversion/branches/shelve-checkpoint/subversion/svn/cl.h Fri Nov 17 
22:02:35 2017
@@ -278,7 +278,6 @@ svn_opt_subcommand_t
   svn_cl__changelist,
   svn_cl__checkout,
   svn_cl__checkpoint,
-  svn_cl__checkpoints,
   svn_cl__cleanup,
   svn_cl__commit,
   svn_cl__copy,

Modified: subversion/branches/shelve-checkpoint/subversion/svn/shelve-cmd.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint/subversion/svn/shelve-cmd.c?rev=1815634&r1=1815633&r2=1815634&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint/subversion/svn/shelve-cmd.c (original)
+++ subversion/branches/shelve-checkpoint/subversion/svn/shelve-cmd.c Fri Nov 
17 22:02:35 2017
@@ -21,6 +21,10 @@
  * ====================================================================
  */
 
+/* We define this here to remove any further warnings about the usage of
+   experimental functions in this file. */
+#define SVN_EXPERIMENTAL
+
 #include "svn_client.h"
 #include "svn_error_codes.h"
 #include "svn_error.h"
@@ -33,36 +37,53 @@
 #include "private/svn_sorts_private.h"
 
 
-/* First argument should be the name of a shelved change. */
+/* Fetch the next argument. */
 static svn_error_t *
-get_name(const char **name,
-         apr_getopt_t *os,
-         apr_pool_t *result_pool,
-         apr_pool_t *scratch_pool)
+get_next_argument(const char **arg,
+                  apr_getopt_t *os,
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
 {
   apr_array_header_t *args;
 
   SVN_ERR(svn_opt_parse_num_args(&args, os, 1, scratch_pool));
-  SVN_ERR(svn_utf_cstring_to_utf8(name,
+  SVN_ERR(svn_utf_cstring_to_utf8(arg,
                                   APR_ARRAY_IDX(args, 0, const char *),
                                   result_pool));
   return SVN_NO_ERROR;
 }
 
+/* Return a human-friendly description of the time duration MINUTES.
+ */
+static char *
+friendly_duration_str(int minutes,
+                      apr_pool_t *result_pool)
+{
+  char *s;
+
+  if (minutes >= 60 * 24)
+    s = apr_psprintf(result_pool, _("%d days"), minutes / 60 / 24);
+  else if (minutes >= 60)
+    s = apr_psprintf(result_pool, _("%d hours"), minutes / 60);
+  else
+    s = apr_psprintf(result_pool, _("%d minutes"), minutes);
+  return s;
+}
+
 /* A comparison function for svn_sort__hash(), comparing the mtime of two
    svn_client_shelved_patch_info_t's. */
 static int
 compare_shelved_patch_infos_by_mtime(const svn_sort__item_t *a,
                                      const svn_sort__item_t *b)
 {
-  svn_client_shelved_patch_info_t *a_val = a->value;
-  svn_client_shelved_patch_info_t *b_val = b->value;
+  svn_client_shelf_info_t *a_val = a->value;
+  svn_client_shelf_info_t *b_val = b->value;
 
-  return (a_val->dirent->mtime < b_val->dirent->mtime)
-           ? -1 : (a_val->dirent->mtime > b_val->dirent->mtime) ? 1 : 0;
+  return (a_val->mtime < b_val->mtime)
+           ? -1 : (a_val->mtime > b_val->mtime) ? 1 : 0;
 }
 
-/* Return a list of shelved changes sorted by patch file mtime, oldest first.
+/* Return a list of shelves sorted by patch file mtime, oldest first.
  */
 static svn_error_t *
 list_sorted_by_date(apr_array_header_t **list,
@@ -80,10 +101,11 @@ list_sorted_by_date(apr_array_header_t *
   return SVN_NO_ERROR;
 }
 
-/* Display a list of shelved changes */
+/* Display a list of shelves */
 static svn_error_t *
 shelves_list(const char *local_abspath,
-             svn_boolean_t diffstat,
+             svn_boolean_t with_logmsg,
+             svn_boolean_t with_diffstat,
              svn_client_ctx_t *ctx,
              apr_pool_t *scratch_pool)
 {
@@ -97,26 +119,87 @@ shelves_list(const char *local_abspath,
     {
       const svn_sort__item_t *item = &APR_ARRAY_IDX(list, i, svn_sort__item_t);
       const char *name = item->key;
-      svn_client_shelved_patch_info_t *info = item->value;
-      int age = (apr_time_now() - info->mtime) / 1000000 / 60;
+      svn_client_shelf_t *shelf;
+      svn_client_shelf_version_info_t *info;
+      int age_mins;
+      char *age_str;
+
+      SVN_ERR(svn_client_shelf_open(&shelf,
+                                    name, local_abspath, ctx, scratch_pool));
+      SVN_ERR(svn_client_shelf_version_get_info(&info,
+                                                shelf, shelf->max_version,
+                                                scratch_pool, scratch_pool));
+      age_mins = (apr_time_now() - info->mtime) / 1000000 / 60;
+      age_str = friendly_duration_str(age_mins, scratch_pool);
+
+      SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                 _("%-30s %s ago,  %d versions\n"),
+                                 name, age_str, shelf->max_version));
+      if (with_logmsg)
+        {
+          SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                     _(" %.50s\n"),
+                                     shelf->log_message));
+        }
+
+      if (with_diffstat)
+        {
+#ifndef WIN32
+          system(apr_psprintf(scratch_pool, "diffstat %s 2> /dev/null",
+                              info->patch_abspath));
+          SVN_ERR(svn_cmdline_printf(scratch_pool, "\n"));
+#endif
+        }
+      SVN_ERR(svn_client_shelf_close(shelf, scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Print info about each checkpoint of the shelf named NAME.
+ */
+static svn_error_t *
+checkpoint_list(const char *name,
+                const char *local_abspath,
+                svn_boolean_t diffstat,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *scratch_pool)
+{
+  svn_client_shelf_t *shelf;
+  int i;
 
-      printf("%-30s %6d mins old %10ld bytes\n",
-             name, age, (long)info->dirent->filesize);
-      printf(" %.50s\n",
-             info->message);
+  SVN_ERR(svn_client_shelf_open(&shelf, name, local_abspath,
+                                ctx, scratch_pool));
+
+  for (i = 1; i <= shelf->max_version; i++)
+    {
+      svn_client_shelf_version_info_t *info;
+      int age_mins;
+      char *age_str;
+
+      SVN_ERR(svn_client_shelf_version_get_info(&info,
+                                                shelf, i,
+                                                scratch_pool, scratch_pool));
+      age_mins = (apr_time_now() - info->mtime) / 1000000 / 60;
+      age_str = friendly_duration_str(age_mins, scratch_pool);
+
+      SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                 _("version %d: %s ago\n"),
+                                 i, age_str));
 
       if (diffstat)
         {
           system(apr_psprintf(scratch_pool, "diffstat %s 2> /dev/null",
-                              info->patch_path));
-          printf("\n");
+                              info->patch_abspath));
+          SVN_ERR(svn_cmdline_printf(scratch_pool, "\n"));
         }
     }
 
+  SVN_ERR(svn_client_shelf_close(shelf, scratch_pool));
   return SVN_NO_ERROR;
 }
 
-/* Find the name of the youngest shelved change.
+/* Find the name of the youngest shelf.
  */
 static svn_error_t *
 name_of_youngest(const char **name_p,
@@ -132,10 +215,125 @@ name_of_youngest(const char **name_p,
                               local_abspath, ctx, scratch_pool));
   if (list->nelts == 0)
     return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
-                            _("No shelved changes found"));
+                            _("No shelves found"));
 
   youngest_item = &APR_ARRAY_IDX(list, list->nelts - 1, svn_sort__item_t);
-  *name_p = youngest_item->key;
+  *name_p = apr_pstrdup(result_pool, youngest_item->key);
+  return SVN_NO_ERROR;
+}
+
+/** Shelve/save a new version of changes.
+ *
+ * Shelve in shelf @a name the local modifications found by @a paths,
+ * @a depth, @a changelists. Revert the shelved changes from the WC
+ * unless @a keep_local is true.
+ *
+ * If @a dry_run is true, don't actually do it.
+ */
+static svn_error_t *
+shelve(int *new_version_p,
+       const char *name,
+       const apr_array_header_t *paths,
+       svn_depth_t depth,
+       const apr_array_header_t *changelists,
+       svn_boolean_t keep_local,
+       svn_boolean_t dry_run,
+       const char *local_abspath,
+       svn_client_ctx_t *ctx,
+       apr_pool_t *scratch_pool)
+{
+  svn_client_shelf_t *shelf;
+
+  SVN_ERR(svn_client_shelf_open(&shelf,
+                                name, local_abspath, ctx, scratch_pool));
+
+  SVN_ERR(svn_client_shelf_save_new_version(shelf,
+                                            paths, depth, changelists,
+                                            scratch_pool));
+  if (!keep_local)
+    {
+      /* Reverse-apply the patch. This should be a safer way to remove those
+         changes from the WC than running a 'revert' operation. */
+      SVN_ERR(svn_client_shelf_unapply(shelf, shelf->max_version,
+                                       dry_run, scratch_pool));
+    }
+
+  SVN_ERR(svn_client_shelf_set_log_message(shelf, dry_run, scratch_pool));
+
+  if (new_version_p)
+    *new_version_p = shelf->max_version;
+
+  if (dry_run)
+    {
+      SVN_ERR(svn_client_shelf_set_current_version(shelf,
+                                                   shelf->max_version - 1,
+                                                   scratch_pool));
+    }
+
+  SVN_ERR(svn_client_shelf_close(shelf, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/** Restore/unshelve a given or newest version of changes.
+ *
+ * Restore local modifications from shelf @a name version @a arg,
+ * or the newest version is @a arg is null.
+ *
+ * If @a dry_run is true, don't actually do it.
+ */
+static svn_error_t *
+restore(const char *name,
+        const char *arg,
+        svn_boolean_t dry_run,
+        svn_boolean_t quiet,
+        const char *local_abspath,
+        svn_client_ctx_t *ctx,
+        apr_pool_t *scratch_pool)
+{
+  int version, old_version;
+  svn_client_shelf_t *shelf;
+
+  SVN_ERR(svn_client_shelf_open(&shelf, name, local_abspath,
+                                ctx, scratch_pool));
+  if (shelf->max_version <= 0)
+    {
+      return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                               _("Shelf '%s' not found"),
+                               name);
+    }
+
+  old_version = shelf->max_version;
+  if (arg)
+    {
+      SVN_ERR(svn_cstring_atoi(&version, arg));
+    }
+  else
+    {
+      version = shelf->max_version;
+    }
+
+  SVN_ERR(svn_client_shelf_apply(shelf, version,
+                                 dry_run, scratch_pool));
+
+  if (! dry_run)
+    {
+      SVN_ERR(svn_client_shelf_set_current_version(shelf, version,
+                                                   scratch_pool));
+    }
+
+  if (!quiet)
+    {
+      if (version < old_version)
+        SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                   _("restored '%s' version %d and deleted %d 
newer versions\n"),
+                                   name, version, old_version - version));
+      else
+        SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                   _("restored '%s' version %d (the newest 
version)\n"),
+                                   name, version));
+    }
+
+  SVN_ERR(svn_client_shelf_close(shelf, scratch_pool));
   return SVN_NO_ERROR;
 }
 
@@ -162,23 +360,25 @@ svn_cl__shelve(apr_getopt_t *os,
         return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);
 
       SVN_ERR(shelves_list(local_abspath,
-                           ! opt_state->quiet /*diffstat*/,
+                           ! opt_state->quiet /*with_logmsg*/,
+                           ! opt_state->quiet /*with_diffstat*/,
                            ctx, pool));
       return SVN_NO_ERROR;
     }
 
-  SVN_ERR(get_name(&name, os, pool, pool));
+  SVN_ERR(get_next_argument(&name, os, pool, pool));
 
   if (opt_state->remove)
     {
       if (os->ind < os->argc)
         return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);
 
-      SVN_ERR(svn_client_shelves_delete(name, local_abspath,
-                                        opt_state->dry_run,
-                                        ctx, pool));
+      SVN_ERR(svn_client_shelf_delete(name, local_abspath,
+                                      opt_state->dry_run, ctx, pool));
       if (! opt_state->quiet)
-        SVN_ERR(svn_cmdline_printf(pool, "deleted '%s'\n", name));
+        SVN_ERR(svn_cmdline_printf(pool,
+                                   _("deleted '%s'\n"),
+                                   name));
       return SVN_NO_ERROR;
     }
 
@@ -190,28 +390,28 @@ svn_cl__shelve(apr_getopt_t *os,
 
   {
       svn_depth_t depth = opt_state->depth;
+      int new_version;
       svn_error_t *err;
 
-      /* shelve has no implicit dot-target `.', so don't you put that
-         code here! */
-      if (!targets->nelts)
-        return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
-
       SVN_ERR(svn_cl__check_targets_are_local_paths(targets));
 
       if (depth == svn_depth_unknown)
         depth = svn_depth_infinity;
 
       SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));
+      /* ### TODO: check all paths are in same WC; for now use first path */
+      SVN_ERR(svn_dirent_get_absolute(&local_abspath,
+                                      APR_ARRAY_IDX(targets, 0, char *),
+                                      pool));
 
       if (ctx->log_msg_func3)
         SVN_ERR(svn_cl__make_log_msg_baton(&ctx->log_msg_baton3,
                                            opt_state, NULL, ctx->config,
                                            pool));
-      err = svn_client_shelve(name,
-                              targets, depth, opt_state->changelists,
-                              opt_state->keep_local, opt_state->dry_run,
-                              ctx, pool);
+      err = shelve(&new_version, name,
+                   targets, depth, opt_state->changelists,
+                   opt_state->keep_local, opt_state->dry_run,
+                   local_abspath, ctx, pool);
       if (ctx->log_msg_func3)
         SVN_ERR(svn_cl__cleanup_log_msg(ctx->log_msg_baton3,
                                         err, pool));
@@ -219,7 +419,9 @@ svn_cl__shelve(apr_getopt_t *os,
         SVN_ERR(err);
 
       if (! opt_state->quiet)
-        SVN_ERR(svn_cmdline_printf(pool, "shelved '%s'\n", name));
+        SVN_ERR(svn_cmdline_printf(pool,
+                                   _("shelved '%s' version %d\n"),
+                                   name, new_version));
   }
 
   return SVN_NO_ERROR;
@@ -229,7 +431,7 @@ svn_cl__shelve(apr_getopt_t *os,
 svn_error_t *
 svn_cl__unshelve(apr_getopt_t *os,
                  void *baton,
-                 apr_pool_t *pool)
+                 apr_pool_t *scratch_pool)
 {
   svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
@@ -237,7 +439,7 @@ svn_cl__unshelve(apr_getopt_t *os,
   const char *name;
   apr_array_header_t *targets;
 
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, "", pool));
+  SVN_ERR(svn_dirent_get_absolute(&local_abspath, "", scratch_pool));
 
   if (opt_state->list)
     {
@@ -245,36 +447,38 @@ svn_cl__unshelve(apr_getopt_t *os,
         return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);
 
       SVN_ERR(shelves_list(local_abspath,
-                           ! opt_state->quiet /*diffstat*/,
-                           ctx, pool));
+                           ! opt_state->quiet /*with_logmsg*/,
+                           ! opt_state->quiet /*with_diffstat*/,
+                           ctx, scratch_pool));
       return SVN_NO_ERROR;
     }
 
   if (os->ind < os->argc)
     {
-      SVN_ERR(get_name(&name, os, pool, pool));
+      SVN_ERR(get_next_argument(&name, os, scratch_pool, scratch_pool));
     }
   else
     {
-      SVN_ERR(name_of_youngest(&name, local_abspath, ctx, pool, pool));
-      printf("unshelving the youngest change, '%s'\n", name);
+      SVN_ERR(name_of_youngest(&name,
+                               local_abspath, ctx, scratch_pool, 
scratch_pool));
+      SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                 _("unshelving the youngest change, '%s'\n"),
+                                 name));
     }
 
   /* There should be no remaining arguments. */
   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                       opt_state->targets,
-                                                      ctx, FALSE, pool));
+                                                      ctx, FALSE, 
scratch_pool));
   if (targets->nelts)
     return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);
 
   if (opt_state->quiet)
     ctx->notify_func2 = NULL; /* Easy out: avoid unneeded work */
 
-  SVN_ERR(svn_client_unshelve(name, local_abspath,
-                              opt_state->keep_local, opt_state->dry_run,
-                              ctx, pool));
-  if (! opt_state->quiet)
-    SVN_ERR(svn_cmdline_printf(pool, "unshelved '%s'\n", name));
+  SVN_ERR(restore(name, NULL,
+                  opt_state->dry_run, opt_state->quiet,
+                  local_abspath, ctx, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -285,6 +489,7 @@ svn_cl__shelves(apr_getopt_t *os,
                 void *baton,
                 apr_pool_t *pool)
 {
+  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
   const char *local_abspath;
 
@@ -293,7 +498,113 @@ svn_cl__shelves(apr_getopt_t *os,
     return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);
 
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, "", pool));
-  SVN_ERR(shelves_list(local_abspath, TRUE /*diffstat*/, ctx, pool));
+  SVN_ERR(shelves_list(local_abspath,
+                       ! opt_state->quiet /*with_logmsg*/,
+                       ! opt_state->quiet /*with_diffstat*/,
+                       ctx, pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_cl__checkpoint(apr_getopt_t *os,
+                   void *baton,
+                   apr_pool_t *pool)
+{
+  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
+  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
+  const char *subsubcommand;
+  apr_array_header_t *targets;
+  const char *local_abspath;
+  const char *name;
+
+  if (opt_state->list)
+    subsubcommand = "list";
+  else
+    SVN_ERR(get_next_argument(&subsubcommand, os, pool, pool));
+
+  SVN_ERR(get_next_argument(&name, os, pool, pool));
+
+  /* Parse the remaining arguments as paths. */
+  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
+                                                      opt_state->targets,
+                                                      ctx, FALSE, pool));
+  SVN_ERR(svn_dirent_get_absolute(&local_abspath, "", pool));
+
+  if (opt_state->quiet)
+    ctx->notify_func2 = NULL;
+
+  if (strcmp(subsubcommand, "list") == 0)
+    {
+      if (targets->nelts)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("Too many arguments"));
+
+      SVN_ERR(checkpoint_list(name, local_abspath,
+                              ! opt_state->quiet /*diffstat*/,
+                              ctx, pool));
+    }
+  else if (strcmp(subsubcommand, "save") == 0)
+    {
+      svn_depth_t depth
+        = (opt_state->depth == svn_depth_unknown) ? svn_depth_infinity
+                                                  : opt_state->depth;
+      int new_version;
+      svn_error_t *err;
+
+      svn_opt_push_implicit_dot_target(targets, pool);
+      SVN_ERR(svn_cl__check_targets_are_local_paths(targets));
+      SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));
+      /* ### TODO: check all paths are in same WC; for now use first path */
+      SVN_ERR(svn_dirent_get_absolute(&local_abspath,
+                                      APR_ARRAY_IDX(targets, 0, char *),
+                                      pool));
+
+      if (ctx->log_msg_func3)
+        SVN_ERR(svn_cl__make_log_msg_baton(&ctx->log_msg_baton3,
+                                           opt_state, NULL, ctx->config,
+                                           pool));
+      err = shelve(&new_version,
+                   name, targets, depth, opt_state->changelists,
+                   TRUE /*keep_local*/, opt_state->dry_run,
+                   local_abspath, ctx, pool);
+      if (ctx->log_msg_func3)
+        SVN_ERR(svn_cl__cleanup_log_msg(ctx->log_msg_baton3,
+                                        err, pool));
+      else
+        SVN_ERR(err);
+
+      if (!opt_state->quiet)
+        SVN_ERR(svn_cmdline_printf(pool,
+                                   _("saved '%s' version %d\n"),
+                                   name, new_version));
+    }
+  else if (strcmp(subsubcommand, "restore") == 0)
+    {
+      const char *arg;
+
+      if (targets->nelts > 1)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("Too many arguments"));
+
+      /* Which checkpoint number? */
+      if (targets->nelts != 1)
+        arg = NULL;
+      else
+        arg = APR_ARRAY_IDX(targets, 0, char *);
+
+      SVN_ERR(restore(name, arg,
+                      opt_state->dry_run, opt_state->quiet,
+                      local_abspath, ctx, pool));
+    }
+  else
+    {
+      return svn_error_createf(SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
+                               _("checkpoint: Unknown checkpoint command '%s'; 
"
+                                 "try 'svn help checkpoint'"),
+                               subsubcommand);
+    }
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/shelve-checkpoint/subversion/svn/svn.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint/subversion/svn/svn.c?rev=1815634&r1=1815633&r2=1815634&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint/subversion/svn/svn.c (original)
+++ subversion/branches/shelve-checkpoint/subversion/svn/svn.c Fri Nov 17 
22:02:35 2017
@@ -146,7 +146,6 @@ typedef enum svn_cl__longopt_t {
   opt_adds_as_modification,
   opt_vacuum_pristines,
   opt_delete,
-  opt_keep_shelved,
   opt_list
 } svn_cl__longopt_t;
 
@@ -468,9 +467,8 @@ const apr_getopt_option_t svn_cl__option
   {"vacuum-pristines", opt_vacuum_pristines, 0,
                        N_("remove unreferenced pristines from .svn 
directory")},
 
-  {"list", opt_list, 0, N_("list shelved patches")},
-  {"keep-shelved", opt_keep_shelved, 0, N_("do not delete the shelved patch")},
-  {"delete", opt_delete, 0, N_("delete the shelved patch")},
+  {"list", opt_list, 0, N_("list shelves or checkpoints")},
+  {"delete", opt_delete, 0, N_("delete a shelf")},
 
   /* Long-opt Aliases
    *
@@ -617,31 +615,6 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "  reporting the action taken.\n"),
     {'r', 'q', 'N', opt_depth, opt_force, opt_ignore_externals} },
 
-  { "checkpoint", svn_cl__checkpoint, {0}, N_
-    ("Checkpoint the local changes.\n"
-     "usage: 1. checkpoint save\n"
-     "       2. checkpoint revert\n"
-     "       3. checkpoint rollback NUMBER\n"
-     "       4. checkpoint list|--list\n"
-     "\n"
-     "  1. Save the working state as a new checkpoint.\n"
-     "  2. Revert the working state to the current checkpoint.\n"
-     "  3. Roll back the working state to checkpoint NUMBER.\n"
-     "  4. List all checkpoints. A synonym for 'svn checkpoints'.\n"),
-    {'q',
-     /*'-N', opt_depth, opt_targets, opt_changelist,*/
-     SVN_CL__LOG_MSG_OPTIONS,
-     opt_list},
-    { {opt_list, N_("list all checkpoints")} }
-    },
-
-  { "checkpoints", svn_cl__checkpoints, {0}, N_
-    ("List all checkpoints.\n"
-     "usage: checkpoints\n"
-     "\n"
-     "  A synonym for 'svn checkpoint list'.\n"),
-    {} },
-
   { "cleanup", svn_cl__cleanup, {0}, N_
     ("Either recover from an interrupted operation that left the working copy 
locked,\n"
      "or remove unwanted files.\n"
@@ -1680,22 +1653,48 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "  the output of 'svn help merge' for 'undo'.\n"),
     {opt_targets, 'R', opt_depth, 'q', opt_changelist} },
 
+  { "savepoint", svn_cl__checkpoint, {"sp", "checkpoint"}, N_
+    ("Save and restore local changes.\n"
+     "usage: 1. savepoint save NAME [PATH...]\n"
+     "       2. savepoint restore NAME [VERSION]\n"
+     "       3. savepoint list|--list NAME\n"
+     "\n"
+     "  1. Save local changes in the given PATHs as a new version of shelf 
NAME.\n"
+     "     A new log message can be given with -m, -F, etc.\n"
+     "\n"
+     "     The same as 'svn shelve --keep-local'.\n"
+     "\n"
+     "  2. Apply the VERSION (default: latest) of shelf NAME to the working 
copy.\n"
+     "\n"
+     "     The same as 'svn unshelve'.\n"
+     "\n"
+     "  3. List all versions of shelf NAME.\n"
+     "\n"
+     "The default PATH is the current working directory.\n"),
+    {'q', opt_dry_run,
+     opt_depth, opt_targets, opt_changelist,
+     SVN_CL__LOG_MSG_OPTIONS,
+     opt_list},
+    { {opt_list, N_("list all versions of a shelf")} }
+  },
+
   { "shelve", svn_cl__shelve, {0}, N_
-    ("Put a local change aside, as if putting it on a shelf.\n"
+    ("Put local changes aside, as if putting them on a shelf.\n"
      "usage: 1. shelve [--keep-local] NAME [PATH...]\n"
      "       2. shelve --delete NAME\n"
      "       3. shelve --list\n"
      "\n"
-     "  1. Save the local change in the given PATHs to a patch file, and\n"
-     "     revert that change from the WC unless '--keep-local' is given.\n"
-     "     If a log message is given with '-m' or '-F', include it at the\n"
-     "     beginning of the patch file.\n"
+     "  1. Save the local changes in the given PATHs to a shelf named NAME.\n"
+     "     Revert those changes from the WC unless '--keep-local' is given.\n"
+     "     If a log message is given with '-m' or '-F', replace the shelf's\n"
+     "     current log message (if any).\n"
+     "\n"
+     "     'svn shelve --keep-local' is like 'svn checkpoint save'.\n"
      "\n"
-     "  2. Delete the shelved change NAME.\n"
-     "     (A backup is kept, named with a '.bak' extension.)\n"
+     "  2. Delete the shelf named NAME.\n"
      "\n"
-     "  3. List shelved changes. Include the first line of any log message\n"
-     "     and some details about the contents of the change, unless '-q' is\n"
+     "  3. List shelves. Include the first line of any log message\n"
+     "     and some details about the contents of the shelf, unless '-q' is\n"
      "     given.\n"
      "\n"
      "  The kinds of change you can shelve are those supported by 'svn diff'\n"
@@ -1703,9 +1702,9 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "     mergeinfo changes, copies, moves, mkdir, rmdir,\n"
      "     'binary' content, uncommittable states\n"
      "\n"
-     "  To bring back a shelved change, use 'svn unshelve NAME'.\n"
+     "  To bring back shelved changes, use 'svn unshelve NAME'.\n"
      "\n"
-     "  A shelved change is stored as a patch file, .svn/shelves/NAME.patch\n"
+     "  Shelves are stored in <WC>/.svn/shelves/\n"
     ),
     {opt_delete, opt_list, 'q', opt_dry_run, opt_keep_local,
      opt_depth, opt_targets, opt_changelist,
@@ -1714,29 +1713,29 @@ const svn_opt_subcommand_desc2_t svn_cl_
     } },
 
   { "unshelve", svn_cl__unshelve, {0}, N_
-    ("Bring a shelved change back to a local change in the WC.\n"
-     "usage: 1. unshelve [--keep-shelved] [NAME]\n"
+    ("Bring shelved changes back into the WC.\n"
+     "usage: 1. unshelve [NAME]\n"
      "       2. unshelve --list\n"
      "\n"
-     "  1. Apply the shelved change NAME to the working copy.\n"
-     "     Delete the patch unless the '--keep-shelved' option is given.\n"
-     "     (A backup is kept, named with a '.bak' extension.)\n"
-     "     NAME defaults to the most recent shelved change.\n"
+     "  1. Apply the shelf named NAME to the working copy.\n"
+     "     NAME defaults to the most recent shelf.\n"
      "\n"
-     "  2. List shelved changes. Include the first line of any log message\n"
-     "     and some details about the contents of the change, unless '-q' is\n"
+     "     Like 'svn checkpoint restore'.\n"
+     "\n"
+     "  2. List shelves. Include the first line of any log message\n"
+     "     and some details about the contents of the shelf, unless '-q' is\n"
      "     given.\n"
      "\n"
      "  Any conflict between the change being unshelved and a change\n"
      "  already in the WC is handled the same way as by 'svn patch',\n"
      "  creating a 'reject' file.\n"
     ),
-    {opt_keep_shelved, opt_list, 'q', opt_dry_run} },
+    {opt_list, 'q', opt_dry_run} },
 
   { "shelves", svn_cl__shelves, {0}, N_
-    ("List shelved changes.\n"
+    ("List shelves.\n"
      "usage: shelves\n"),
-    },
+    {'q'} },
 
   { "status", svn_cl__status, {"stat", "st"}, N_
     ("Print the status of working copy files and directories.\n"
@@ -2486,7 +2485,6 @@ sub_main(int *exit_code, int argc, const
         opt_state.keep_changelists = TRUE;
         break;
       case opt_keep_local:
-      case opt_keep_shelved:
         opt_state.keep_local = TRUE;
         break;
       case opt_with_all_revprops:

Modified: 
subversion/branches/shelve-checkpoint/tools/client-side/bash_completion
URL: 
http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint/tools/client-side/bash_completion?rev=1815634&r1=1815633&r2=1815634&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint/tools/client-side/bash_completion 
(original)
+++ subversion/branches/shelve-checkpoint/tools/client-side/bash_completion Fri 
Nov 17 22:02:35 2017
@@ -248,7 +248,7 @@ _svn()
        cmds="$cmds patch propdel pdel propedit pedit propget pget proplist"
        cmds="$cmds plist propset pset relocate resolve resolved revert status"
        cmds="$cmds switch unlock update upgrade"
-       cmds="$cmds checkpoint checkpoints"
+       cmds="$cmds checkpoint savepoint sp"
        cmds="$cmds shelve shelves unshelve"
 
        # help options have a strange command status...
@@ -1023,16 +1023,13 @@ _svn()
                cmdOpts="$qOpts $pOpts"
                ;;
        checkpoint)
-               cmdOpts="$qOpts save revert rollback list --list"
-               ;;
-       checkpoints)
-               cmdOpts="$qOpts"
+               cmdOpts="$qOpts save restore list --list"
                ;;
        shelve)
                cmdOpts="$qOpts --keep-local --delete --list $qOpts --dry-run 
--depth --targets $cOpts"
                ;;
        unshelve)
-               cmdOpts="$qOpts --keep-shelved --list $qOpts --dry-run"
+               cmdOpts="$qOpts --list $qOpts --dry-run"
                ;;
        shelves)
                cmdOpts="$qOpts"


Reply via email to