| | @@ -42,10 +42,44 @@ |
| 42 | 42 | if( z[7]!='-') return 0; |
| 43 | 43 | if( !fossil_isdigit(z[8]) ) return 0; |
| 44 | 44 | if( !fossil_isdigit(z[9]) ) return 0; |
| 45 | 45 | return 1; |
| 46 | 46 | } |
| 47 | + |
| 48 | +/* |
| 49 | +** Return the RID that is the "root" of the branch that contains |
| 50 | +** check-in "rid" if inBranch==0 or the first check-in in the branch |
| 51 | +** if inBranch==1. |
| 52 | +*/ |
| 53 | +int start_of_branch(int rid, int inBranch){ |
| 54 | + Stmt q; |
| 55 | + int rc; |
| 56 | + char *zBr; |
| 57 | + zBr = db_text("trunk","SELECT value FROM tagxref" |
| 58 | + " WHERE rid=%d AND tagid=%d" |
| 59 | + " AND tagtype>0", |
| 60 | + rid, TAG_BRANCH); |
| 61 | + db_prepare(&q, |
| 62 | + "SELECT pid, EXISTS(SELECT 1 FROM tagxref" |
| 63 | + " WHERE tagid=%d AND tagtype>0" |
| 64 | + " AND value=%Q AND rid=plink.pid)" |
| 65 | + " FROM plink" |
| 66 | + " WHERE cid=:cid AND isprim", |
| 67 | + TAG_BRANCH, zBr |
| 68 | + ); |
| 69 | + fossil_free(zBr); |
| 70 | + do{ |
| 71 | + db_reset(&q); |
| 72 | + db_bind_int(&q, ":cid", rid); |
| 73 | + rc = db_step(&q); |
| 74 | + if( rc!=SQLITE_ROW ) break; |
| 75 | + if( inBranch && db_column_int(&q,1)==0 ) break; |
| 76 | + rid = db_column_int(&q, 0); |
| 77 | + }while( db_column_int(&q, 1)==1 && rid>0 ); |
| 78 | + db_finalize(&q); |
| 79 | + return rid; |
| 80 | +} |
| 47 | 81 | |
| 48 | 82 | /* |
| 49 | 83 | ** Convert a symbolic name into a RID. Acceptable forms: |
| 50 | 84 | ** |
| 51 | 85 | ** * SHA1 hash |
| | @@ -66,20 +100,28 @@ |
| 66 | 100 | ** Return the RID of the matching artifact. Or return 0 if the name does not |
| 67 | 101 | ** match any known object. Or return -1 if the name is ambiguous. |
| 68 | 102 | ** |
| 69 | 103 | ** The zType parameter specifies the type of artifact: ci, t, w, e, g. |
| 70 | 104 | ** If zType is NULL or "" or "*" then any type of artifact will serve. |
| 105 | +** If zType is "br" then find the first check-in of the named branch |
| 106 | +** rather than the last. |
| 71 | 107 | ** zType is "ci" in most use cases since we are usually searching for |
| 72 | 108 | ** a check-in. |
| 73 | 109 | */ |
| 74 | 110 | int symbolic_name_to_rid(const char *zTag, const char *zType){ |
| 75 | 111 | int vid; |
| 76 | 112 | int rid = 0; |
| 77 | 113 | int nTag; |
| 78 | 114 | int i; |
| 115 | + int startOfBranch = 0; |
| 79 | 116 | |
| 80 | | - if( zType==0 || zType[0]==0 ) zType = "*"; |
| 117 | + if( zType==0 || zType[0]==0 ){ |
| 118 | + zType = "*"; |
| 119 | + }else if( zType[0]=='b' ){ |
| 120 | + zType = "ci"; |
| 121 | + startOfBranch = 1; |
| 122 | + } |
| 81 | 123 | if( zTag==0 || zTag[0]==0 ) return 0; |
| 82 | 124 | |
| 83 | 125 | /* special keyword: "tip" */ |
| 84 | 126 | if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || zType[0]=='c') ){ |
| 85 | 127 | rid = db_int(0, |
| | @@ -151,41 +193,18 @@ |
| 151 | 193 | " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 " |
| 152 | 194 | " AND event.objid=tagxref.rid " |
| 153 | 195 | " AND event.type GLOB '%q'", |
| 154 | 196 | &zTag[4], zType |
| 155 | 197 | ); |
| 198 | + if( startOfBranch ) rid = start_of_branch(rid,1); |
| 156 | 199 | return rid; |
| 157 | 200 | } |
| 158 | 201 | |
| 159 | 202 | /* root:TAG -> The origin of the branch */ |
| 160 | 203 | if( memcmp(zTag, "root:", 5)==0 ){ |
| 161 | | - Stmt q; |
| 162 | | - int rc; |
| 163 | | - char *zBr; |
| 164 | 204 | rid = symbolic_name_to_rid(zTag+5, zType); |
| 165 | | - zBr = db_text("trunk","SELECT value FROM tagxref" |
| 166 | | - " WHERE rid=%d AND tagid=%d" |
| 167 | | - " AND tagtype>0", |
| 168 | | - rid, TAG_BRANCH); |
| 169 | | - db_prepare(&q, |
| 170 | | - "SELECT pid, EXISTS(SELECT 1 FROM tagxref" |
| 171 | | - " WHERE tagid=%d AND tagtype>0" |
| 172 | | - " AND value=%Q AND rid=plink.pid)" |
| 173 | | - " FROM plink" |
| 174 | | - " WHERE cid=:cid AND isprim", |
| 175 | | - TAG_BRANCH, zBr |
| 176 | | - ); |
| 177 | | - fossil_free(zBr); |
| 178 | | - do{ |
| 179 | | - db_reset(&q); |
| 180 | | - db_bind_int(&q, ":cid", rid); |
| 181 | | - rc = db_step(&q); |
| 182 | | - if( rc!=SQLITE_ROW ) break; |
| 183 | | - rid = db_column_int(&q, 0); |
| 184 | | - }while( db_column_int(&q, 1)==1 && rid>0 ); |
| 185 | | - db_finalize(&q); |
| 186 | | - return rid; |
| 205 | + return start_of_branch(rid, 0); |
| 187 | 206 | } |
| 188 | 207 | |
| 189 | 208 | /* symbolic-name ":" date-time */ |
| 190 | 209 | nTag = strlen(zTag); |
| 191 | 210 | for(i=0; i<nTag-10 && zTag[i]!=':'; i++){} |
| | @@ -245,11 +264,14 @@ |
| 245 | 264 | " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 " |
| 246 | 265 | " AND event.objid=tagxref.rid " |
| 247 | 266 | " AND event.type GLOB '%q'", |
| 248 | 267 | zTag, zType |
| 249 | 268 | ); |
| 250 | | - if( rid>0 ) return rid; |
| 269 | + if( rid>0 ){ |
| 270 | + if( startOfBranch ) rid = start_of_branch(rid,1); |
| 271 | + return rid; |
| 272 | + } |
| 251 | 273 | |
| 252 | 274 | /* Undocumented: numeric tags get translated directly into the RID */ |
| 253 | 275 | if( memcmp(zTag, "rid:", 4)==0 ){ |
| 254 | 276 | zTag += 4; |
| 255 | 277 | for(i=0; fossil_isdigit(zTag[i]); i++){} |
| | @@ -657,21 +679,23 @@ |
| 657 | 679 | void whatis_cmd(void){ |
| 658 | 680 | int rid; |
| 659 | 681 | const char *zName; |
| 660 | 682 | int verboseFlag; |
| 661 | 683 | int i; |
| 684 | + const char *zType = 0; |
| 662 | 685 | db_find_and_open_repository(0,0); |
| 663 | 686 | verboseFlag = find_option("verbose","v",0)!=0; |
| 687 | + zType = find_option("type",0,1); |
| 664 | 688 | |
| 665 | 689 | /* We should be done with options.. */ |
| 666 | 690 | verify_all_options(); |
| 667 | 691 | |
| 668 | 692 | if( g.argc<3 ) usage("whatis NAME ..."); |
| 669 | 693 | for(i=2; i<g.argc; i++){ |
| 670 | 694 | zName = g.argv[i]; |
| 671 | 695 | if( i>2 ) fossil_print("%.79c\n",'-'); |
| 672 | | - rid = symbolic_name_to_rid(zName, 0); |
| 696 | + rid = symbolic_name_to_rid(zName, zType); |
| 673 | 697 | if( rid<0 ){ |
| 674 | 698 | Stmt q; |
| 675 | 699 | int cnt = 0; |
| 676 | 700 | fossil_print("name: %s (ambiguous)\n", zName); |
| 677 | 701 | db_prepare(&q, |
| 678 | 702 | |