Index: src/info.c
==================================================================
--- src/info.c
+++ src/info.c
@@ -674,10 +674,12 @@
@
@ %z(href("%R/tree?ci=%S",zUuid))files
@ | %z(href("%R/fileage?name=%S",zUuid))file ages
@ | %z(href("%R/tree?nofiles&type=tree&ci=%S",zUuid))folders
@ | %z(href("%R/artifact/%S",zUuid))manifest
+ @ | %z(href("%R/vdiff?from=pbranch:%S&to=%S",zUuid,zUuid))
+ @ branch diff
if( g.perm.Write ){
@ | %z(href("%R/ci_edit?r=%S",zUuid))edit
}
@ |
@
Index: src/name.c
==================================================================
--- src/name.c
+++ src/name.c
@@ -181,10 +181,19 @@
" WHERE mtime<=julianday('%qz') AND type GLOB '%q'"
" ORDER BY mtime DESC LIMIT 1",
&zTag[4], zType);
return rid;
}
+
+ /* "pbranch:", as for parent branch. It returns the checkin of
+ the last checkin of the parent branch that has been merged in. */
+ if( memcmp(zTag, "pbranch:", 8)==0 ){
+ rid = symbolic_name_to_rid(&zTag[8], zType);
+ if( rid==0 ) return 0; /* TODO: Negative rid allowed here? */
+ rid = get_parent_branch_rid(rid);
+ return rid;
+ }
/* "tag:" + symbolic-name */
if( memcmp(zTag, "tag:", 4)==0 ){
rid = db_int(0,
"SELECT event.objid, max(event.mtime)"
@@ -1058,5 +1067,108 @@
*/
void test_phatoms_cmd(void){
db_find_and_open_repository(0,0);
describe_artifacts_to_stdout("IN (SELECT rid FROM blob WHERE size<0)", 0);
}
+
+/*
+** Returns the rid for the last checkin where the parent branch was merged.
+*/
+int get_parent_branch_rid(
+ int branchRid /* The rid to find parent branch for. */
+){
+ Stmt s;
+ char *branchName = 0; /* Name of the branch at rid */
+ char *parentBranchName = 0; /* Name of the parent branch */
+ int rid;
+
+ /* Get the name of the current branch */
+ branchName = db_text(0,
+ "SELECT value FROM tagxref"
+ " WHERE tagid=%d"
+ " AND tagxref.tagtype>0"
+ " AND rid=%d",
+ TAG_BRANCH, branchRid
+ );
+
+ if( !branchName )
+ return 0;
+
+ /* Find the name of the branch this was forked from */
+ db_prepare(&s,
+ "SELECT pid, tagxref.value FROM plink JOIN tagxref"
+ " WHERE cid=:rid"
+ " AND isprim=1"
+ " AND tagxref.tagid=%d"
+ " AND tagxref.tagtype>0"
+ " AND tagxref.rid=pid",
+ TAG_BRANCH
+ );
+ rid = branchRid;
+ while( rid>0 ){
+ db_bind_int(&s, ":rid", rid);
+ if( db_step(&s)==SQLITE_ROW ){
+ const char *zValue; /* Branch name of the pid */
+ rid = db_column_int(&s, 0);
+ zValue = db_column_text(&s, 1);
+ if( !zValue ){
+ rid = 0;
+ break;
+ }
+ if( fossil_strcmp(zValue,branchName) ){
+ parentBranchName = fossil_strdup(zValue);
+ break;
+ }
+ }else{
+ rid = 0;
+ break;
+ }
+ db_reset(&s);
+ }
+ db_finalize(&s);
+
+ if( rid==0 ){
+ fossil_free(branchName);
+ fossil_free(parentBranchName);
+ return 0;
+ }
+
+ /* Find the last checkin coming from the parent branch */
+ db_prepare(&s,
+ "SELECT pid, tagxref.value FROM plink JOIN tagxref"
+ " WHERE cid=:rid"
+ " AND tagxref.tagid=%d"
+ " AND tagxref.tagtype>0"
+ " AND tagxref.rid=pid ORDER BY isprim ASC",
+ TAG_BRANCH
+ );
+ rid = branchRid;
+ while( rid>0 ){
+ db_bind_int(&s, ":rid", rid);
+ int found = 0;
+ while( db_step(&s)==SQLITE_ROW ){
+ const char *zValue; /* Branch name of the pid */
+ found++;
+ rid = db_column_int(&s, 0);
+ zValue = db_column_text(&s, 1);
+ if( !zValue ){
+ break;
+ }
+ if( fossil_strcmp(parentBranchName,zValue)==0 ){
+ /* Found the last merge from the parent branch */
+ db_finalize(&s);
+ fossil_free(branchName);
+ fossil_free(parentBranchName);
+ return rid;
+ }
+ }
+ if( found==0 ){
+ break;
+ }
+ db_reset(&s);
+ }
+ db_finalize(&s);
+
+ fossil_free(branchName);
+ fossil_free(parentBranchName);
+ return 0;
+}