Fossil SCM

fossil-scm / src / stash.c
Source Blame History 796 lines
12a2a5e… drh 1 /*
c19f34c… drh 2 ** Copyright (c) 2010 D. Richard Hipp
12a2a5e… drh 3 **
12a2a5e… drh 4 ** This program is free software; you can redistribute it and/or
12a2a5e… drh 5 ** modify it under the terms of the Simplified BSD License (also
12a2a5e… drh 6 ** known as the "2-Clause License" or "FreeBSD License".)
12a2a5e… drh 7
12a2a5e… drh 8 ** This program is distributed in the hope that it will be useful,
12a2a5e… drh 9 ** but without any warranty; without even the implied warranty of
12a2a5e… drh 10 ** merchantability or fitness for a particular purpose.
12a2a5e… drh 11 **
12a2a5e… drh 12 ** Author contact information:
12a2a5e… drh 13 ** [email protected]
12a2a5e… drh 14 **
12a2a5e… drh 15 *******************************************************************************
12a2a5e… drh 16 **
12a2a5e… drh 17 ** This file contains code used to implement the "stash" command.
12a2a5e… drh 18 */
12a2a5e… drh 19 #include "config.h"
12a2a5e… drh 20 #include "stash.h"
12a2a5e… drh 21 #include <assert.h>
12a2a5e… drh 22
12a2a5e… drh 23
12a2a5e… drh 24 /*
12a2a5e… drh 25 ** SQL code to implement the tables needed by the stash.
ed06585… drh 26 **
ed06585… drh 27 ** Historical schema changes:
ed06585… drh 28 **
ed06585… drh 29 ** 2019-01-19: stash.hash and stashfile.hash columns added. The
ed06585… drh 30 ** corresponding stash.vid and stashfile.rid columns are
ed06585… drh 31 ** retained for compatibility with older versions of
ed06585… drh 32 ** fossil but are no longer used.
ed06585… drh 33 **
ed06585… drh 34 ** 2016-10-16: Change the PRIMARY KEY on stashfile from (origname,stashid)
ed06585… drh 35 ** to (newname,stashid).
ed06585… drh 36 **
ed06585… drh 37 ** 2011-09-01: stashfile.isLink column added
ed06585… drh 38 **
12a2a5e… drh 39 */
10e0d0b… jan.nijtmans 40 static const char zStashInit[] =
06aec61… drh 41 @ CREATE TABLE IF NOT EXISTS localdb.stash(
12a2a5e… drh 42 @ stashid INTEGER PRIMARY KEY, -- Unique stash identifier
ed06585… drh 43 @ vid INTEGER, -- Legacy baseline RID value. Do not use.
ed06585… drh 44 @ hash TEXT, -- The SHA hash for the baseline
12a2a5e… drh 45 @ comment TEXT, -- Comment for this stash. Or NULL
12a2a5e… drh 46 @ ctime TIMESTAMP -- When the stash was created
12a2a5e… drh 47 @ );
06aec61… drh 48 @ CREATE TABLE IF NOT EXISTS localdb.stashfile(
12a2a5e… drh 49 @ stashid INTEGER REFERENCES stash, -- Stash that contains this file
12a2a5e… drh 50 @ isAdded BOOLEAN, -- True if this is an added file
12a2a5e… drh 51 @ isRemoved BOOLEAN, -- True if this file is deleted
12a2a5e… drh 52 @ isExec BOOLEAN, -- True if file is executable
e4f1c1f… drh 53 @ isLink BOOLEAN, -- True if file is a symlink
ed06585… drh 54 @ rid INTEGER, -- Legacy baseline RID value. Do not use
ed06585… drh 55 @ hash TEXT, -- Hash for baseline or NULL
12a2a5e… drh 56 @ origname TEXT, -- Original filename
12a2a5e… drh 57 @ newname TEXT, -- New name for file at next check-in
ed06585… drh 58 @ delta BLOB, -- Delta from baseline or raw content
b2d51b1… andybradford 59 @ PRIMARY KEY(newname, stashid)
12a2a5e… drh 60 @ );
12a2a5e… drh 61 @ INSERT OR IGNORE INTO vvar(name, value) VALUES('stash-next', 1);
12a2a5e… drh 62 ;
ed06585… drh 63
ed06585… drh 64 /*
ed06585… drh 65 ** Make sure the stash and stashfile tables exist and have been
ed06585… drh 66 ** upgraded to their latest format. Create and upgrade the tables
ed06585… drh 67 ** as necessary.
ed06585… drh 68 */
ed06585… drh 69 static void stash_tables_exist_and_current(void){
ed06585… drh 70 if( db_table_has_column("localdb","stashfile","hash") ){
ed06585… drh 71 /* The schema is up-to-date. But it could be that an older version
ed06585… drh 72 ** of Fossil that does no know about the stash.hash and stashfile.hash
ed06585… drh 73 ** columns has run since the schema was updated, and added entries that
ed06585… drh 74 ** have NULL hash columns. Check for this case, and fill in any missing
ed06585… drh 75 ** hash values.
ed06585… drh 76 */
ed06585… drh 77 if( db_int(0, "SELECT hash IS NULL FROM stash"
ed06585… drh 78 " ORDER BY stashid DESC LIMIT 1")
ed06585… drh 79 ){
ed06585… drh 80 db_multi_exec(
ed06585… drh 81 "UPDATE stash"
ed06585… drh 82 " SET hash=(SELECT uuid FROM blob WHERE blob.rid=stash.vid)"
ed06585… drh 83 " WHERE hash IS NULL;"
ed06585… drh 84 "UPDATE stashfile"
ed06585… drh 85 " SET hash=(SELECT uuid FROM blob WHERE blob.rid=stashfile.rid)"
ed06585… drh 86 " WHERE hash IS NULL AND rid>0;"
ed06585… drh 87 );
ed06585… drh 88 }
ed06585… drh 89 return;
ed06585… drh 90 }
ed06585… drh 91
ed06585… drh 92 if( !db_table_exists("localdb","stashfile")
ed06585… drh 93 || !db_table_exists("localdb","stash")
ed06585… drh 94 ){
ed06585… drh 95 /* Tables do not exist. Create them from scratch. */
ed06585… drh 96 db_multi_exec("DROP TABLE IF EXISTS localdb.stash;");
ed06585… drh 97 db_multi_exec("DROP TABLE IF EXISTS localdb.stashfile;");
ed06585… drh 98 db_multi_exec(zStashInit /*works-like:""*/);
ed06585… drh 99 return;
ed06585… drh 100 }
ed06585… drh 101
ed06585… drh 102 /* The tables exists but are not necessarily current. Upgrade them
ed06585… drh 103 ** to the latest format.
ed06585… drh 104 **
ed06585… drh 105 ** We can assume the 2011-09-01 format that includes the stashfile.isLink
ed06585… drh 106 ** column. The only upgrades we need to worry about the PRIMARY KEY
ed06585… drh 107 ** change on 2016-10-16 and the addition of the "hash" columns on
ed06585… drh 108 ** 2019-01-19.
ed06585… drh 109 */
ed06585… drh 110 db_multi_exec(
ed06585… drh 111 "ALTER TABLE localdb.stash RENAME TO old_stash;"
ed06585… drh 112 "ALTER TABLE localdb.stashfile RENAME TO old_stashfile;"
ed06585… drh 113 );
ed06585… drh 114 db_multi_exec(zStashInit /*works-like:""*/);
ed06585… drh 115 db_multi_exec(
ed06585… drh 116 "INSERT INTO localdb.stash(stashid,vid,hash,comment,ctime)"
ed06585… drh 117 " SELECT stashid, vid,"
ed06585… drh 118 " (SELECT uuid FROM blob WHERE blob.rid=old_stash.vid),"
ed06585… drh 119 " comment, ctime FROM old_stash;"
ed06585… drh 120 "DROP TABLE old_stash;"
ed06585… drh 121 );
ed06585… drh 122 db_multi_exec(
ed06585… drh 123 "INSERT INTO localdb.stashfile(stashid,isAdded,isRemoved,isExec,"
ed06585… drh 124 "isLink,rid,hash,origname,newname,delta)"
ed06585… drh 125 " SELECT stashid, isAdded, isRemoved, isExec, isLink, rid,"
ed06585… drh 126 " (SELECT uuid FROM blob WHERE blob.rid=old_stashfile.rid),"
ed06585… drh 127 " origname, newname, delta FROM old_stashfile;"
ed06585… drh 128 "DROP TABLE old_stashfile;"
ed06585… drh 129 );
ed06585… drh 130 }
ed06585… drh 131
ed06585… drh 132 /*
ed06585… drh 133 ** Update the stash.vid and stashfile.rid values after a RID renumbering
ed06585… drh 134 ** event.
ed06585… drh 135 */
ed06585… drh 136 void stash_rid_renumbering_event(void){
ed06585… drh 137 if( !db_table_has_column("localdb","stash","hash") ){
ed06585… drh 138 /* If the stash schema was the older style that lacked hash value, then
ed06585… drh 139 ** recovery is not possible. Save off the old data, then reset the stash
ed06585… drh 140 ** to empty. */
ed06585… drh 141 if( db_table_exists("localdb","stash") ){
ed06585… drh 142 db_multi_exec("ALTER TABLE stash RENAME TO broken_stash;");
ed06585… drh 143 fossil_print("Unrecoverable stash content stored in \"broken_stash\"\n");
ed06585… drh 144 }
ed06585… drh 145 if( db_table_exists("localdb","stashfile") ){
ed06585… drh 146 db_multi_exec("ALTER TABLE stashfile RENAME TO broken_stashfile;");
ed06585… drh 147 fossil_print("Unrecoverable stashfile content stored"
ed06585… drh 148 " in \"broken_stashfile\"\n");
ed06585… drh 149 }
ed06585… drh 150 }else{
ed06585… drh 151 /* Reset stash.vid and stash.rid values based on hashes */
ed06585… drh 152 db_multi_exec(
ed06585… drh 153 "UPDATE stash"
ed06585… drh 154 " SET vid=(SELECT rid FROM blob WHERE blob.uuid=stash.hash);"
ed06585… drh 155 "UPDATE stashfile"
ed06585… drh 156 " SET rid=(SELECT rid FROM blob WHERE blob.uuid=stashfile.hash)"
ed06585… drh 157 " WHERE hash IS NOT NULL;"
ed06585… drh 158 );
ed06585… drh 159 }
ed06585… drh 160 }
12a2a5e… drh 161
12a2a5e… drh 162 /*
12a2a5e… drh 163 ** Add zFName to the stash given by stashid. zFName might be the name of a
12a2a5e… drh 164 ** file or a directory. If a directory, add all changed files contained
12a2a5e… drh 165 ** within that directory.
12a2a5e… drh 166 */
12a2a5e… drh 167 static void stash_add_file_or_dir(int stashid, int vid, const char *zFName){
12a2a5e… drh 168 char *zFile; /* Normalized filename */
12a2a5e… drh 169 char *zTreename; /* Name of the file in the tree */
12a2a5e… drh 170 Blob fname; /* Filename relative to root */
12a2a5e… drh 171 Blob sql; /* Query statement text */
12a2a5e… drh 172 Stmt q; /* Query against the vfile table */
12a2a5e… drh 173 Stmt ins; /* Insert statement */
12a2a5e… drh 174
12a2a5e… drh 175 zFile = mprintf("%/", zFName);
c56a387… mistachkin 176 file_tree_name(zFile, &fname, 0, 1);
12a2a5e… drh 177 zTreename = blob_str(&fname);
12a2a5e… drh 178 blob_zero(&sql);
49b0ff1… drh 179 blob_append_sql(&sql,
e4f1c1f… drh 180 "SELECT deleted, isexe, islink, mrid, pathname, coalesce(origname,pathname)"
12a2a5e… drh 181 " FROM vfile"
12a2a5e… drh 182 " WHERE vid=%d AND (chnged OR deleted OR origname NOT NULL OR mrid==0)",
12a2a5e… drh 183 vid
12a2a5e… drh 184 );
31c52c7… drh 185 if( fossil_strcmp(zTreename,".")!=0 ){
49b0ff1… drh 186 blob_append_sql(&sql,
12a2a5e… drh 187 " AND (pathname GLOB '%q/*' OR origname GLOB '%q/*'"
12a2a5e… drh 188 " OR pathname=%Q OR origname=%Q)",
12a2a5e… drh 189 zTreename, zTreename, zTreename, zTreename
12a2a5e… drh 190 );
12a2a5e… drh 191 }
49b0ff1… drh 192 db_prepare(&q, "%s", blob_sql_text(&sql));
12a2a5e… drh 193 blob_reset(&sql);
12a2a5e… drh 194 db_prepare(&ins,
ed06585… drh 195 "INSERT INTO stashfile(stashid, isAdded, isRemoved, isExec, isLink, rid, "
ed06585… drh 196 "hash, origname, newname, delta)"
ed06585… drh 197 "VALUES(%d,:isadd,:isrm,:isexe,:islink,:rid,"
ed06585… drh 198 "(SELECT uuid FROM blob WHERE rid=:rid),:orig,:new,:content)",
12a2a5e… drh 199 stashid
12a2a5e… drh 200 );
12a2a5e… drh 201 while( db_step(&q)==SQLITE_ROW ){
12a2a5e… drh 202 int deleted = db_column_int(&q, 0);
e4f1c1f… drh 203 int rid = db_column_int(&q, 3);
e4f1c1f… drh 204 const char *zName = db_column_text(&q, 4);
e4f1c1f… drh 205 const char *zOrig = db_column_text(&q, 5);
12a2a5e… drh 206 char *zPath = mprintf("%s%s", g.zLocalRoot, zName);
12a2a5e… drh 207 Blob content;
12a2a5e… drh 208
12a2a5e… drh 209 db_bind_int(&ins, ":rid", rid);
12a2a5e… drh 210 db_bind_int(&ins, ":isadd", rid==0);
12a2a5e… drh 211 db_bind_int(&ins, ":isrm", deleted);
abdedb2… drh 212 db_bind_int(&ins, ":isexe", db_column_int(&q, 1));
e4f1c1f… drh 213 db_bind_int(&ins, ":islink", db_column_int(&q, 2));
12a2a5e… drh 214 db_bind_text(&ins, ":orig", zOrig);
12a2a5e… drh 215 db_bind_text(&ins, ":new", zName);
e4f1c1f… drh 216
12a2a5e… drh 217 if( rid==0 ){
12a2a5e… drh 218 /* A new file */
1772357… drh 219 blob_read_from_file(&content, zPath, RepoFILE);
12a2a5e… drh 220 db_bind_blob(&ins, ":content", &content);
12a2a5e… drh 221 }else if( deleted ){
336e194… drh 222 blob_zero(&content);
12a2a5e… drh 223 db_bind_null(&ins, ":content");
12a2a5e… drh 224 }else{
12a2a5e… drh 225 /* A modified file */
12a2a5e… drh 226 Blob orig;
12a2a5e… drh 227 Blob disk;
10e0d0b… jan.nijtmans 228
1772357… drh 229 blob_read_from_file(&disk, zPath, RepoFILE);
12a2a5e… drh 230 content_get(rid, &orig);
12a2a5e… drh 231 blob_delta_create(&orig, &disk, &content);
12a2a5e… drh 232 blob_reset(&orig);
12a2a5e… drh 233 blob_reset(&disk);
12a2a5e… drh 234 db_bind_blob(&ins, ":content", &content);
12a2a5e… drh 235 }
1772357… drh 236 db_bind_int(&ins, ":islink", file_islink(zPath));
12a2a5e… drh 237 db_step(&ins);
12a2a5e… drh 238 db_reset(&ins);
12a2a5e… drh 239 fossil_free(zPath);
12a2a5e… drh 240 blob_reset(&content);
12a2a5e… drh 241 }
12a2a5e… drh 242 db_finalize(&ins);
12a2a5e… drh 243 db_finalize(&q);
12a2a5e… drh 244 fossil_free(zFile);
12a2a5e… drh 245 blob_reset(&fname);
12a2a5e… drh 246 }
12a2a5e… drh 247
12a2a5e… drh 248 /*
12a2a5e… drh 249 ** Create a new stash based on the uncommitted changes currently in
12a2a5e… drh 250 ** the working directory.
12a2a5e… drh 251 **
12a2a5e… drh 252 ** If the "-m" or "--comment" command-line option is present, gather
12a2a5e… drh 253 ** its argument as the stash comment.
12a2a5e… drh 254 **
12a2a5e… drh 255 ** If files are named on the command-line, then only stash the named
12a2a5e… drh 256 ** files.
12a2a5e… drh 257 */
12a2a5e… drh 258 static int stash_create(void){
12a2a5e… drh 259 const char *zComment; /* Comment to add to the stash */
12a2a5e… drh 260 int stashid; /* ID of the new stash */
bc36fdc… danield 261 int vid; /* Current check-out */
12a2a5e… drh 262
12a2a5e… drh 263 zComment = find_option("comment", "m", 1);
b9f569b… drh 264 (void)fossil_text_editor();
12a2a5e… drh 265 verify_all_options();
16371dc… drh 266 if( zComment==0 ){
16371dc… drh 267 Blob prompt; /* Prompt for stash comment */
16371dc… drh 268 Blob comment; /* User comment reply */
3e90ef6… jan.nijtmans 269 #if defined(_WIN32) || defined(__CYGWIN__)
9b800ee… mistachkin 270 int bomSize;
9b800ee… mistachkin 271 const unsigned char *bom = get_utf8_bom(&bomSize);
9b800ee… mistachkin 272 blob_init(&prompt, (const char *) bom, bomSize);
fb56561… jan.nijtmans 273 #else
16371dc… drh 274 blob_zero(&prompt);
fb56561… jan.nijtmans 275 #endif
16371dc… drh 276 blob_append(&prompt,
16371dc… drh 277 "\n"
16371dc… drh 278 "# Enter a description of what is being stashed. Lines beginning\n"
4c8a3fb… andybradford 279 "# with \"#\" are ignored. Stash comments are plain text except\n"
16371dc… drh 280 "# newlines are not preserved.\n",
16371dc… drh 281 -1);
16371dc… drh 282 prompt_for_user_comment(&comment, &prompt);
16371dc… drh 283 blob_reset(&prompt);
16371dc… drh 284 zComment = blob_str(&comment);
16371dc… drh 285 }
12a2a5e… drh 286 stashid = db_lget_int("stash-next", 1);
12a2a5e… drh 287 db_lset_int("stash-next", stashid+1);
12a2a5e… drh 288 vid = db_lget_int("checkout", 0);
ae092ec… drh 289 vfile_check_signature(vid, 0);
12a2a5e… drh 290 db_multi_exec(
ed06585… drh 291 "INSERT INTO stash(stashid,vid,hash,comment,ctime)"
ed06585… drh 292 "VALUES(%d,%d,(SELECT uuid FROM blob WHERE rid=%d),%Q,julianday('now'))",
ed06585… drh 293 stashid, vid, vid, zComment
12a2a5e… drh 294 );
12a2a5e… drh 295 if( g.argc>3 ){
12a2a5e… drh 296 int i;
12a2a5e… drh 297 for(i=3; i<g.argc; i++){
12a2a5e… drh 298 stash_add_file_or_dir(stashid, vid, g.argv[i]);
12a2a5e… drh 299 }
12a2a5e… drh 300 }else{
966ae9a… drh 301 stash_add_file_or_dir(stashid, vid, g.zLocalRoot);
12a2a5e… drh 302 }
12a2a5e… drh 303 return stashid;
12a2a5e… drh 304 }
12a2a5e… drh 305
12a2a5e… drh 306 /*
bc36fdc… danield 307 ** Apply a stash to the current check-out.
12a2a5e… drh 308 */
12a2a5e… drh 309 static void stash_apply(int stashid, int nConflict){
db052aa… drh 310 int vid;
12a2a5e… drh 311 Stmt q;
12a2a5e… drh 312 db_prepare(&q,
ed06585… drh 313 "SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta"
4531bcd… stephan 314 " FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash"
4531bcd… stephan 315 " UNION ALL SELECT 0, isRemoved, isExec, isLink, origname, newname, delta"
4531bcd… stephan 316 " FROM stashfile WHERE stashid=%d AND stashfile.hash IS NULL",
4531bcd… stephan 317 stashid, stashid
12a2a5e… drh 318 );
db052aa… drh 319 vid = db_lget_int("checkout",0);
e776494… andygoth 320 db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s)",
db052aa… drh 321 filename_collation());
12a2a5e… drh 322 while( db_step(&q)==SQLITE_ROW ){
12a2a5e… drh 323 int rid = db_column_int(&q, 0);
12a2a5e… drh 324 int isRemoved = db_column_int(&q, 1);
3ad119b… drh 325 int isExec = db_column_int(&q, 2);
e4f1c1f… drh 326 int isLink = db_column_int(&q, 3);
e4f1c1f… drh 327 const char *zOrig = db_column_text(&q, 4);
e4f1c1f… drh 328 const char *zNew = db_column_text(&q, 5);
12a2a5e… drh 329 char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
12a2a5e… drh 330 char *zNPath = mprintf("%s%s", g.zLocalRoot, zNew);
12a2a5e… drh 331 Blob delta;
12a2a5e… drh 332 undo_save(zNew);
12a2a5e… drh 333 blob_zero(&delta);
12a2a5e… drh 334 if( rid==0 ){
e776494… andygoth 335 db_multi_exec("INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", zNew);
e4f1c1f… drh 336 db_ephemeral_blob(&q, 6, &delta);
12a2a5e… drh 337 blob_write_to_file(&delta, zNPath);
1772357… drh 338 file_setexe(zNPath, isExec);
12a2a5e… drh 339 }else if( isRemoved ){
d8ec765… drh 340 fossil_print("DELETE %s\n", zOrig);
d8ec765… drh 341 file_delete(zOPath);
f741baa… drh 342 }else if( file_unsafe_in_tree_path(zNPath) ){
f741baa… drh 343 /* Ignore the unsafe path */
12a2a5e… drh 344 }else{
12a2a5e… drh 345 Blob a, b, out, disk;
1772357… drh 346 int isNewLink = file_islink(zOPath);
e4f1c1f… drh 347 db_ephemeral_blob(&q, 6, &delta);
1772357… drh 348 blob_read_from_file(&disk, zOPath, RepoFILE);
12a2a5e… drh 349 content_get(rid, &a);
12a2a5e… drh 350 blob_delta_apply(&a, &delta, &b);
75461b9… stephan 351 if( isLink == isNewLink && blob_compare(&disk, &a)==0 ){
e4f1c1f… drh 352 if( isLink || isNewLink ){
c97535c… dmitry 353 file_delete(zNPath);
e4f1c1f… drh 354 }
e4f1c1f… drh 355 if( isLink ){
c05f6af… dmitry 356 symlink_create(blob_str(&b), zNPath);
e4f1c1f… drh 357 }else{
10e0d0b… jan.nijtmans 358 blob_write_to_file(&b, zNPath);
e4f1c1f… drh 359 }
1772357… drh 360 file_setexe(zNPath, isExec);
d8ec765… drh 361 fossil_print("UPDATE %s\n", zNew);
d8ec765… drh 362 }else{
e4f1c1f… drh 363 int rc;
e4f1c1f… drh 364 if( isLink || isNewLink ){
e4f1c1f… drh 365 rc = -1;
e4f1c1f… drh 366 blob_zero(&b); /* because we reset it later */
c97535c… dmitry 367 fossil_print("***** Cannot merge symlink %s\n", zNew);
e4f1c1f… drh 368 }else{
d20ead1… drh 369 rc = merge_3way(&a, zOPath, &b, &out, MERGE_KEEP_FILES);
10e0d0b… jan.nijtmans 370 blob_write_to_file(&out, zNPath);
c97535c… dmitry 371 blob_reset(&out);
1772357… drh 372 file_setexe(zNPath, isExec);
e4f1c1f… drh 373 }
d8ec765… drh 374 if( rc ){
d8ec765… drh 375 fossil_print("CONFLICT %s\n", zNew);
12a2a5e… drh 376 nConflict++;
12a2a5e… drh 377 }else{
d8ec765… drh 378 fossil_print("MERGE %s\n", zNew);
12a2a5e… drh 379 }
12a2a5e… drh 380 }
12a2a5e… drh 381 blob_reset(&a);
12a2a5e… drh 382 blob_reset(&b);
12a2a5e… drh 383 blob_reset(&disk);
12a2a5e… drh 384 }
12a2a5e… drh 385 blob_reset(&delta);
31c52c7… drh 386 if( fossil_strcmp(zOrig,zNew)!=0 ){
12a2a5e… drh 387 undo_save(zOrig);
d8ec765… drh 388 file_delete(zOPath);
b2d51b1… andybradford 389 db_multi_exec(
b2d51b1… andybradford 390 "UPDATE vfile SET pathname='%q', origname='%q'"
b2d51b1… andybradford 391 " WHERE pathname='%q' %s AND vid=%d",
b2d51b1… andybradford 392 zNew, zOrig, zOrig, filename_collation(), vid
b2d51b1… andybradford 393 );
12a2a5e… drh 394 }
12a2a5e… drh 395 }
db052aa… drh 396 stash_add_files_in_sfile(vid);
12a2a5e… drh 397 db_finalize(&q);
12a2a5e… drh 398 if( nConflict ){
966ae9a… drh 399 fossil_print(
966ae9a… drh 400 "WARNING: %d merge conflicts - see messages above for details.\n",
966ae9a… drh 401 nConflict);
12a2a5e… drh 402 }
12a2a5e… drh 403 }
12a2a5e… drh 404
12a2a5e… drh 405 /*
12a2a5e… drh 406 ** Show the diffs associate with a single stash.
12a2a5e… drh 407 */
f8339c2… drh 408 static void stash_diff(
4e0e69f… drh 409 int stashid, /* The stash entry to diff */
4e0e69f… drh 410 int fBaseline, /* Diff against original baseline check-in if true */
1347a1d… drh 411 DiffConfig *pCfg /* Diff formatting options */
f8339c2… drh 412 ){
12a2a5e… drh 413 Stmt q;
12a2a5e… drh 414 Blob empty;
346de5d… drh 415 int bWebpage = (pCfg->diffFlags & (DIFF_WEBPAGE|DIFF_JSON|DIFF_TCL))!=0;
12a2a5e… drh 416 blob_zero(&empty);
1347a1d… drh 417 diff_begin(pCfg);
12a2a5e… drh 418 db_prepare(&q,
ed06585… drh 419 "SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta"
4531bcd… stephan 420 " FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash"
4531bcd… stephan 421 " UNION ALL SELECT 0, isRemoved, isExec, isLink, origname, newname, delta"
4531bcd… stephan 422 " FROM stashfile WHERE stashid=%d AND stashfile.hash IS NULL",
4531bcd… stephan 423 stashid, stashid
12a2a5e… drh 424 );
12a2a5e… drh 425 while( db_step(&q)==SQLITE_ROW ){
12a2a5e… drh 426 int rid = db_column_int(&q, 0);
12a2a5e… drh 427 int isRemoved = db_column_int(&q, 1);
e4f1c1f… drh 428 int isLink = db_column_int(&q, 3);
e4f1c1f… drh 429 const char *zOrig = db_column_text(&q, 4);
e4f1c1f… drh 430 const char *zNew = db_column_text(&q, 5);
12a2a5e… drh 431 char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
1c39f11… jan.nijtmans 432 Blob a, b;
caa6ad3… drh 433 pCfg->diffFlags &= (~DIFF_FILE_MASK);
2a47673… mgagnon 434 if( rid==0 ){
2a47673… mgagnon 435 db_ephemeral_blob(&q, 6, &a);
ea52b7d… drh 436 if( !bWebpage ) fossil_print("ADDED %s\n", zNew);
caa6ad3… drh 437 pCfg->diffFlags |= DIFF_FILE_ADDED;
1347a1d… drh 438 diff_print_index(zNew, pCfg, 0);
346de5d… drh 439 diff_file_mem(&empty, &a, zNew, pCfg);
2a47673… mgagnon 440 }else if( isRemoved ){
ea52b7d… drh 441 if( !bWebpage) fossil_print("DELETE %s\n", zOrig);
caa6ad3… drh 442 pCfg->diffFlags |= DIFF_FILE_DELETED;
1347a1d… drh 443 diff_print_index(zNew, pCfg, 0);
2a47673… mgagnon 444 if( fBaseline ){
2a47673… mgagnon 445 content_get(rid, &a);
346de5d… drh 446 diff_file_mem(&a, &empty, zOrig, pCfg);
2a47673… mgagnon 447 }
2a47673… mgagnon 448 }else{
2a47673… mgagnon 449 Blob delta;
1772357… drh 450 int isOrigLink = file_islink(zOPath);
2a47673… mgagnon 451 db_ephemeral_blob(&q, 6, &delta);
ea52b7d… drh 452 if( !bWebpage ) fossil_print("CHANGED %s\n", zNew);
2a47673… mgagnon 453 if( !isOrigLink != !isLink ){
1347a1d… drh 454 diff_print_index(zNew, pCfg, 0);
1347a1d… drh 455 diff_print_filenames(zOrig, zNew, pCfg, 0);
2a47673… mgagnon 456 printf(DIFF_CANNOT_COMPUTE_SYMLINK);
2a47673… mgagnon 457 }else{
2a47673… mgagnon 458 content_get(rid, &a);
2a47673… mgagnon 459 blob_delta_apply(&a, &delta, &b);
2a47673… mgagnon 460 if( fBaseline ){
346de5d… drh 461 diff_file_mem(&a, &b, zNew, pCfg);
2a47673… mgagnon 462 }else{
db034a5… drh 463 pCfg->diffFlags ^= DIFF_INVERT;
db034a5… drh 464 diff_file(&b, zOPath, zNew, pCfg, 0);
db034a5… drh 465 pCfg->diffFlags ^= DIFF_INVERT;
2a47673… mgagnon 466 }
e4f1c1f… drh 467 blob_reset(&a);
e4f1c1f… drh 468 blob_reset(&b);
e4f1c1f… drh 469 }
1c39f11… jan.nijtmans 470 blob_reset(&delta);
e4f1c1f… drh 471 }
72d07a5… drh 472 }
12a2a5e… drh 473 db_finalize(&q);
1347a1d… drh 474 diff_end(pCfg, 0);
12a2a5e… drh 475 }
12a2a5e… drh 476
12a2a5e… drh 477 /*
0b4f830… drh 478 ** Drop the indicated stash
12a2a5e… drh 479 */
12a2a5e… drh 480 static void stash_drop(int stashid){
12a2a5e… drh 481 db_multi_exec(
12a2a5e… drh 482 "DELETE FROM stash WHERE stashid=%d;"
12a2a5e… drh 483 "DELETE FROM stashfile WHERE stashid=%d;",
12a2a5e… drh 484 stashid, stashid
12a2a5e… drh 485 );
12a2a5e… drh 486 }
12a2a5e… drh 487
12a2a5e… drh 488 /*
12a2a5e… drh 489 ** If zStashId is non-NULL then interpret is as a stash number and
12a2a5e… drh 490 ** return that number. Or throw a fatal error if it is not a valid
12a2a5e… drh 491 ** stash number. If it is NULL, return the most recent stash or
12a2a5e… drh 492 ** throw an error if the stash is empty.
12a2a5e… drh 493 */
12a2a5e… drh 494 static int stash_get_id(const char *zStashId){
48ecfe6… andygoth 495 int stashid;
12a2a5e… drh 496 if( zStashId==0 ){
12a2a5e… drh 497 stashid = db_int(0, "SELECT max(stashid) FROM stash");
12a2a5e… drh 498 if( stashid==0 ) fossil_fatal("empty stash");
12a2a5e… drh 499 }else{
12a2a5e… drh 500 stashid = atoi(zStashId);
12a2a5e… drh 501 if( !db_exists("SELECT 1 FROM stash WHERE stashid=%d", stashid) ){
48ecfe6… andygoth 502 fossil_fatal("no such stash: %s", zStashId);
12a2a5e… drh 503 }
12a2a5e… drh 504 }
12a2a5e… drh 505 return stashid;
12a2a5e… drh 506 }
12a2a5e… drh 507
12a2a5e… drh 508 /*
12a2a5e… drh 509 ** COMMAND: stash
12a2a5e… drh 510 **
12a2a5e… drh 511 ** Usage: %fossil stash SUBCOMMAND ARGS...
12a2a5e… drh 512 **
e58c76a… drh 513 ** > fossil stash
b9f569b… drh 514 ** > fossil stash save ?FILES...?
b9f569b… drh 515 ** > fossil stash snapshot ?FILES...?
e58c76a… drh 516 **
e58c76a… drh 517 ** Save the current changes in the working tree as a new stash.
e58c76a… drh 518 ** Then revert the changes back to the last check-in. If FILES
e58c76a… drh 519 ** are listed, then only stash and revert the named files. The
e58c76a… drh 520 ** "save" verb can be omitted if and only if there are no other
e58c76a… drh 521 ** arguments. The "snapshot" verb works the same as "save" but
bc36fdc… danield 522 ** omits the revert, keeping the check-out unchanged.
b9f569b… drh 523 **
b9f569b… drh 524 ** Options:
b9f569b… drh 525 ** --editor NAME Use the NAME editor to enter comment
b9f569b… drh 526 ** -m|--comment COMMENT Comment text for the new stash
b9f569b… drh 527 **
e58c76a… drh 528 **
11384f1… drh 529 ** > fossil stash list|ls ?-v|--verbose? ?-W|--width NUM?
e58c76a… drh 530 **
e58c76a… drh 531 ** List all changes sets currently stashed. Show information about
e58c76a… drh 532 ** individual files in each changeset if -v or --verbose is used.
e58c76a… drh 533 **
e58c76a… drh 534 ** > fossil stash show|cat ?STASHID? ?DIFF-OPTIONS?
e58c76a… drh 535 ** > fossil stash gshow|gcat ?STASHID? ?DIFF-OPTIONS?
e58c76a… drh 536 **
e58c76a… drh 537 ** Show the contents of a stash as a diff against its baseline.
e58c76a… drh 538 ** With gshow and gcat, gdiff-command is used instead of internal
e58c76a… drh 539 ** diff logic.
e58c76a… drh 540 **
e58c76a… drh 541 ** > fossil stash pop
e58c76a… drh 542 ** > fossil stash apply ?STASHID?
e58c76a… drh 543 **
e58c76a… drh 544 ** Apply STASHID or the most recently created stash to the current
bc36fdc… danield 545 ** working check-out. The "pop" command deletes that changeset from
e58c76a… drh 546 ** the stash after applying it but the "apply" command retains the
e58c76a… drh 547 ** changeset.
e58c76a… drh 548 **
e58c76a… drh 549 ** > fossil stash goto ?STASHID?
e58c76a… drh 550 **
bc36fdc… danield 551 ** Update to the baseline check-out for STASHID then apply the
e58c76a… drh 552 ** changes of STASHID. Keep STASHID so that it can be reused
e58c76a… drh 553 ** This command is undoable.
e58c76a… drh 554 **
e2783d0… stephan 555 ** > fossil stash drop|rm ?STASHIDs...? ?-a|--all?
e58c76a… drh 556 **
e2783d0… stephan 557 ** Forget everything about the given STASHIDs. Forget the whole
e2783d0… stephan 558 ** stash if the -a|--all flag is used. Individual drops are
e2783d0… stephan 559 ** undoable but -a|--all is not.
e58c76a… drh 560 **
e58c76a… drh 561 ** > fossil stash diff ?STASHID? ?DIFF-OPTIONS?
e58c76a… drh 562 ** > fossil stash gdiff ?STASHID? ?DIFF-OPTIONS?
e58c76a… drh 563 **
e58c76a… drh 564 ** Show diffs of the current working directory and what that
e58c76a… drh 565 ** directory would be if STASHID were applied. With gdiff,
e58c76a… drh 566 ** gdiff-command is used instead of internal diff logic.
1aaa6fc… stephan 567 **
1aaa6fc… stephan 568 ** > fossil stash rename STASHID NEW-NAME
1aaa6fc… stephan 569 **
1aaa6fc… stephan 570 ** Change the description of the given STASHID entry to NEW-NAME.
12a2a5e… drh 571 */
12a2a5e… drh 572 void stash_cmd(void){
12a2a5e… drh 573 const char *zCmd;
12a2a5e… drh 574 int nCmd;
10e0d0b… jan.nijtmans 575 int stashid = 0;
12a2a5e… drh 576 undo_capture_command_line();
12a2a5e… drh 577 db_must_be_within_tree();
b06cd63… mistachkin 578 db_open_config(0, 0);
e1962ef… drh 579 db_begin_transaction();
ed06585… drh 580 stash_tables_exist_and_current();
12a2a5e… drh 581 if( g.argc<=2 ){
12a2a5e… drh 582 zCmd = "save";
12a2a5e… drh 583 }else{
12a2a5e… drh 584 zCmd = g.argv[2];
12a2a5e… drh 585 }
12a2a5e… drh 586 nCmd = strlen(zCmd);
2a85517… wyoung 587 if( strncmp(zCmd, "save", nCmd)==0 ){
d959c48… andybradford 588 if( unsaved_changes(0)==0 ){
d959c48… andybradford 589 fossil_fatal("nothing to stash");
d959c48… andybradford 590 }
fc6aea5… drh 591 stashid = stash_create();
fc6aea5… drh 592 undo_disable();
18575b1… drh 593 if( g.argc>=2 ){
fc6aea5… drh 594 int nFile = db_int(0, "SELECT count(*) FROM stashfile WHERE stashid=%d",
fc6aea5… drh 595 stashid);
85a7d82… stephan 596 char **newArgv;
fc6aea5… drh 597 int i = 2;
fc6aea5… drh 598 Stmt q;
85a7d82… stephan 599 if( nFile==0 ){
85a7d82… stephan 600 fossil_fatal("No modified files match the provided pattern.");
85a7d82… stephan 601 }
85a7d82… stephan 602 newArgv = fossil_malloc( sizeof(char*)*(nFile+2) );
fc6aea5… drh 603 db_prepare(&q,"SELECT origname FROM stashfile WHERE stashid=%d", stashid);
fc6aea5… drh 604 while( db_step(&q)==SQLITE_ROW ){
fc6aea5… drh 605 newArgv[i++] = mprintf("%s%s", g.zLocalRoot, db_column_text(&q, 0));
fc6aea5… drh 606 }
fc6aea5… drh 607 db_finalize(&q);
fc6aea5… drh 608 newArgv[0] = g.argv[0];
a50be7b… mistachkin 609 newArgv[1] = 0;
fc6aea5… drh 610 g.argv = newArgv;
fc6aea5… drh 611 g.argc = nFile+2;
fc6aea5… drh 612 }
60af514… drh 613 /* Make sure the stash has committed before running the revert, so that
60af514… drh 614 ** we have a copy of the changes before deleting them. */
60af514… drh 615 db_commit_transaction();
fc6aea5… drh 616 g.argv[1] = "revert";
fc6aea5… drh 617 revert_cmd();
07d739b… andybradford 618 fossil_print("stash %d saved\n", stashid);
7b2350a… andybradford 619 return;
fc6aea5… drh 620 }else
2a85517… wyoung 621 if( strncmp(zCmd, "snapshot", nCmd)==0 ){
fc6aea5… drh 622 stash_create();
fc6aea5… drh 623 }else
2a85517… wyoung 624 if( strncmp(zCmd, "list", nCmd)==0 || strncmp(zCmd, "ls", nCmd)==0 ){
966ae9a… drh 625 Stmt q, q2;
fa6ece7… jan.nijtmans 626 int n = 0, width;
5214a2a… jan.nijtmans 627 int verboseFlag = find_option("verbose","v",0)!=0;
fa6ece7… jan.nijtmans 628 const char *zWidth = find_option("width","W",1);
fa6ece7… jan.nijtmans 629
fa6ece7… jan.nijtmans 630 if( zWidth ){
fa6ece7… jan.nijtmans 631 width = atoi(zWidth);
fa6ece7… jan.nijtmans 632 if( (width!=0) && (width<=46) ){
fa6ece7… jan.nijtmans 633 fossil_fatal("-W|--width value must be >46 or 0");
fa6ece7… jan.nijtmans 634 }
fa6ece7… jan.nijtmans 635 }else{
0ff6a9e… mistachkin 636 width = -1;
fa6ece7… jan.nijtmans 637 }
5214a2a… jan.nijtmans 638 if( !verboseFlag ){
5214a2a… jan.nijtmans 639 verboseFlag = find_option("detail","l",0)!=0; /* deprecated */
5214a2a… jan.nijtmans 640 }
fc6aea5… drh 641 verify_all_options();
fc6aea5… drh 642 db_prepare(&q,
ed06585… drh 643 "SELECT stashid, hash, comment, datetime(ctime) FROM stash"
cf9eac3… drh 644 " ORDER BY ctime"
fc6aea5… drh 645 );
5214a2a… jan.nijtmans 646 if( verboseFlag ){
966ae9a… drh 647 db_prepare(&q2, "SELECT isAdded, isRemoved, origname, newname"
966ae9a… drh 648 " FROM stashfile WHERE stashid=$id");
966ae9a… drh 649 }
fc6aea5… drh 650 while( db_step(&q)==SQLITE_ROW ){
966ae9a… drh 651 int stashid = db_column_int(&q, 0);
fc6aea5… drh 652 const char *zCom;
fc6aea5… drh 653 n++;
d8ec765… drh 654 fossil_print("%5d: [%.14s] on %s\n",
966ae9a… drh 655 stashid,
12a2a5e… drh 656 db_column_text(&q, 1),
12a2a5e… drh 657 db_column_text(&q, 3)
12a2a5e… drh 658 );
12a2a5e… drh 659 zCom = db_column_text(&q, 2);
12a2a5e… drh 660 if( zCom && zCom[0] ){
d8ec765… drh 661 fossil_print(" ");
2476b81… drh 662 comment_print(zCom, 0, 7, width, get_comment_format());
966ae9a… drh 663 }
5214a2a… jan.nijtmans 664 if( verboseFlag ){
966ae9a… drh 665 db_bind_int(&q2, "$id", stashid);
966ae9a… drh 666 while( db_step(&q2)==SQLITE_ROW ){
966ae9a… drh 667 int isAdded = db_column_int(&q2, 0);
966ae9a… drh 668 int isRemoved = db_column_int(&q2, 1);
966ae9a… drh 669 const char *zOrig = db_column_text(&q2, 2);
966ae9a… drh 670 const char *zNew = db_column_text(&q2, 3);
966ae9a… drh 671 if( isAdded ){
966ae9a… drh 672 fossil_print(" ADD %s\n", zNew);
966ae9a… drh 673 }else if( isRemoved ){
966ae9a… drh 674 fossil_print(" REMOVE %s\n", zOrig);
966ae9a… drh 675 }else if( fossil_strcmp(zOrig,zNew)!=0 ){
966ae9a… drh 676 fossil_print(" RENAME %s -> %s\n", zOrig, zNew);
966ae9a… drh 677 }else{
966ae9a… drh 678 fossil_print(" EDIT %s\n", zOrig);
966ae9a… drh 679 }
966ae9a… drh 680 }
966ae9a… drh 681 db_reset(&q2);
966ae9a… drh 682 }
966ae9a… drh 683 }
966ae9a… drh 684 db_finalize(&q);
5214a2a… jan.nijtmans 685 if( verboseFlag ) db_finalize(&q2);
f41308d… drh 686 if( n==0 ) fossil_print("empty stash\n");
f41308d… drh 687 }else
2a85517… wyoung 688 if( strncmp(zCmd, "drop", nCmd)==0 || strncmp(zCmd, "rm", nCmd)==0 ){
8b17c23… jan.nijtmans 689 int allFlag = find_option("all", "a", 0)!=0;
f41308d… drh 690 if( allFlag ){
f41308d… drh 691 Blob ans;
7c52716… jan.nijtmans 692 char cReply;
f41308d… drh 693 prompt_user("This action is not undoable. Continue (y/N)? ", &ans);
7c52716… jan.nijtmans 694 cReply = blob_str(&ans)[0];
7c52716… jan.nijtmans 695 if( cReply=='y' || cReply=='Y' ){
f41308d… drh 696 db_multi_exec("DELETE FROM stash; DELETE FROM stashfile;");
f41308d… drh 697 }
f41308d… drh 698 }else if( g.argc>=4 ){
f41308d… drh 699 int i;
f41308d… drh 700 undo_begin();
f41308d… drh 701 for(i=3; i<g.argc; i++){
f41308d… drh 702 stashid = stash_get_id(g.argv[i]);
f41308d… drh 703 undo_save_stash(stashid);
f41308d… drh 704 stash_drop(stashid);
f41308d… drh 705 }
f41308d… drh 706 undo_finish();
f41308d… drh 707 }else{
f41308d… drh 708 undo_begin();
f41308d… drh 709 undo_save_stash(0);
f41308d… drh 710 stash_drop(stashid);
f41308d… drh 711 undo_finish();
f41308d… drh 712 }
f41308d… drh 713 }else
2a85517… wyoung 714 if( strncmp(zCmd, "pop", nCmd)==0 || strncmp(zCmd, "apply", nCmd)==0 ){
1392710… mark 715 char *zCom = 0, *zDate = 0, *zHash = 0;
1392710… mark 716 int popped = *zCmd=='p';
1392710… mark 717 if( popped ){
1392710… mark 718 if( g.argc>3 ) usage("pop");
1392710… mark 719 stashid = stash_get_id(0);
1392710… mark 720 }else{
1392710… mark 721 if( g.argc>4 ) usage("apply STASHID");
1392710… mark 722 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
1392710… mark 723 }
1392710… mark 724 zCom = db_text(0, "SELECT comment FROM stash WHERE stashid=%d", stashid);
1392710… mark 725 zDate = db_text(0, "SELECT datetime(ctime) FROM stash WHERE stashid=%d",
1392710… mark 726 stashid);
1392710… mark 727 zHash = db_text(0, "SELECT hash FROM stash WHERE stashid=%d", stashid);
1392710… mark 728 undo_begin();
1392710… mark 729 stash_apply(stashid, 0);
1392710… mark 730 if( popped ) undo_save_stash(stashid);
1392710… mark 731 fossil_print("%s stash:\n%5d: [%.14s] from %s\n",
1392710… mark 732 popped ? "Popped" : "Applied", stashid, zHash, zDate);
1392710… mark 733 if( zCom && *zCom ){
1392710… mark 734 fossil_print(" ");
1392710… mark 735 comment_print(zCom, 0, 7, -1, get_comment_format());
1392710… mark 736 }
1392710… mark 737 fossil_free(zCom);
1392710… mark 738 fossil_free(zDate);
1392710… mark 739 fossil_free(zHash);
1392710… mark 740 undo_finish();
1392710… mark 741 if( popped ) stash_drop(stashid);
1392710… mark 742 }else
2a85517… wyoung 743 if( strncmp(zCmd, "goto", nCmd)==0 ){
cd5a7e1… stephan 744 int nConflict;
cd5a7e1… stephan 745 int vid;
cd5a7e1… stephan 746 if( g.argc>4 ) usage("apply STASHID");
cd5a7e1… stephan 747 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
cd5a7e1… stephan 748 undo_begin();
ed06585… drh 749 vid = db_int(0, "SELECT blob.rid FROM stash,blob"
ed06585… drh 750 " WHERE stashid=%d AND blob.uuid=stash.hash", stashid);
12a2a5e… drh 751 nConflict = update_to(vid);
12a2a5e… drh 752 stash_apply(stashid, nConflict);
12a2a5e… drh 753 db_multi_exec("UPDATE vfile SET mtime=0 WHERE pathname IN "
12a2a5e… drh 754 "(SELECT origname FROM stashfile WHERE stashid=%d)",
12a2a5e… drh 755 stashid);
12a2a5e… drh 756 undo_finish();
12a2a5e… drh 757 }else
2a85517… wyoung 758 if( strncmp(zCmd, "diff", nCmd)==0
2a85517… wyoung 759 || strncmp(zCmd, "gdiff", nCmd)==0
2a85517… wyoung 760 || strncmp(zCmd, "show", nCmd)==0
2a85517… wyoung 761 || strncmp(zCmd, "gshow", nCmd)==0
2a85517… wyoung 762 || strncmp(zCmd, "cat", nCmd)==0
2a85517… wyoung 763 || strncmp(zCmd, "gcat", nCmd)==0
48ecfe6… andygoth 764 ){
9a6256c… jan.nijtmans 765 int fBaseline = 0;
1347a1d… drh 766 DiffConfig DCfg;
48ecfe6… andygoth 767
2a47673… mgagnon 768 if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){
2a47673… mgagnon 769 fBaseline = 1;
2a47673… mgagnon 770 }
5bec7a6… drh 771 if( find_option("tk",0,0)!=0 || gdiff_using_tk(zCmd[0]=='g') ){
48ecfe6… andygoth 772 db_close(0);
48ecfe6… andygoth 773 diff_tk(fBaseline ? "stash show" : "stash diff", 3);
2ed8cdc… drh 774 return;
2ed8cdc… drh 775 }
346de5d… drh 776 diff_options(&DCfg, zCmd[0]=='g', 0);
4e0e69f… drh 777 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
346de5d… drh 778 stash_diff(stashid, fBaseline, &DCfg);
4e0e69f… drh 779 }else
1aaa6fc… stephan 780 if( strncmp(zCmd, "rename", nCmd)==0 ){
1aaa6fc… stephan 781 if( g.argc!=5 ) usage("rename STASHID NAME");
1aaa6fc… stephan 782 stashid = stash_get_id(g.argv[3]);
1aaa6fc… stephan 783 db_multi_exec("UPDATE STASH SET COMMENT=%Q WHERE stashid=%d",
1aaa6fc… stephan 784 g.argv[4], stashid);
1aaa6fc… stephan 785 }
1aaa6fc… stephan 786 else if( strncmp(zCmd, "help", nCmd)==0 ){
966ae9a… drh 787 g.argv[1] = "help";
966ae9a… drh 788 g.argv[2] = "stash";
966ae9a… drh 789 g.argc = 3;
966ae9a… drh 790 help_cmd();
12a2a5e… drh 791 }else
12a2a5e… drh 792 {
12a2a5e… drh 793 usage("SUBCOMMAND ARGS...");
12a2a5e… drh 794 }
12a2a5e… drh 795 db_end_transaction(0);
12a2a5e… drh 796 }

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button