Fossil

Changes On Branch describe-cmd
Login

Changes On Branch describe-cmd

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch describe-cmd Excluding Merge-Ins

This is equivalent to a diff from b80ae0215e to e501d74440

2022-03-30
14:45
Add the new "fossil describe" command. ... (check-in: 36ca266479 user: drh tags: trunk)
14:36
Fix segfault and add message for ambiguous checkins. ... (Closed-Leaf check-in: e501d74440 user: danield tags: describe-cmd)
14:15
Merged in trunk. ... (check-in: 28fa015357 user: stephan tags: markdown-tagrefs)
14:01
Add comments, format code and remove magic size numbers. ... (check-in: 40de2cd9c3 user: danield tags: describe-cmd)
11:46
Add the "describe" command. This shows the commit hash along with (if applicable) its youngest ancestor with a non-propagating tag and the number of commits since that. ... (check-in: 3f06ed14fe user: danield tags: describe-cmd)
2022-03-28
13:39
Bug fix to the abs() function of pikchr. ... (check-in: b80ae0215e user: drh tags: trunk)
08:34
Updated a reference to macOS 11 from the backup doc: the condition it warns against is still true as of macOS 12.3. ... (check-in: 1bb4147fd2 user: wyoung tags: trunk)

Changes to src/info.c.

3676
3677
3678
3679
3680
3681
3682

































































































































































































      db_column_text(&q,0),
      db_column_text(&q,1),
      db_column_text(&q,2),
      db_column_text(&q,3));
  }
  db_finalize(&q);
}








































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
      db_column_text(&q,0),
      db_column_text(&q,1),
      db_column_text(&q,2),
      db_column_text(&q,3));
  }
  db_finalize(&q);
}

#if INTERFACE
/* 
** Description of a checkin relative to an earlier, tagged checkin.
*/
typedef struct CommitDescr {
  char *zRelTagname;        /* Tag name on the relative checkin */
  int nCommitsSince;        /* Number of commits since then */
  char *zCommitHash;        /* Hash of the described checkin */
  int isDirty;              /* Working directory has uncommitted changes */
} CommitDescr;
#endif

/*
** Describe the checkin given by 'zName', and possibly matching 'matchGlob',
** relative to an earlier, tagged checkin. Use 'descr' for the output.
**
** Finds the closest ancestor (ignoring merge-ins) that has a non-propagating
** label tag and the number of steps backwards that we had to search in
** order to find that tag.
**
** Return values:
**       0: ok
**      -1: zName does not resolve to a commit
**      -2: zName resolves to more than a commit
**      -3: no ancestor commit with a fitting non-propagating tag found
*/
int describe_commit(const char *zName, const char *matchGlob,
                    CommitDescr *descr){
  int rid;             /* rid for zName */
  const char *zUuid;   /* Hash of rid */
  int nRet = 0;        /* Value to be returned */
  Stmt q;              /* Query for tagged ancestors */

  rid = symbolic_name_to_rid(zName, "ci"); /* only commits */

  if( rid<=0 ){
    /* Commit does not exist or is ambiguous */
    descr->zRelTagname = mprintf("");
    descr->nCommitsSince = -1;
    descr->zCommitHash = mprintf("");
    descr->isDirty = -1;
    return (rid-1);
  }

  zUuid = rid_to_uuid(rid);
  descr->zCommitHash = mprintf("%s", zUuid);
  descr->isDirty = unsaved_changes(0);

  db_multi_exec(
    "DROP TABLE IF EXISTS singletonTaggedAncestors;"
    "CREATE TEMP TABLE singletonTaggedAncestors AS"
    "  WITH RECURSIVE "
    "  singletonTaggedCommits(rid,mtime,shorttag) AS ("
    "    SELECT DISTINCT b.rid,e.mtime,substr(t.tagname,5) AS shorttag"
    "          FROM blob b"
    "    INNER JOIN event e ON e.objid=b.rid"
    "    INNER JOIN tagxref tx ON tx.rid=b.rid"
    "    INNER JOIN tag t ON t.tagid=tx.tagid"
    "         WHERE e.type='ci'"
    "           AND tx.tagtype=1"
    "           AND t.tagname GLOB 'sym-%q'"
    "  ),"
    "  parent(pid,cid,isCP,isPrim) AS ("
    "    SELECT plink.pid, plink.cid, 0, isPrim FROM plink"
    "    UNION ALL"
    "    SELECT parentid, childid, 1, 0 FROM cherrypick WHERE NOT isExclude"
    "  ),"
    "  ancestor(rid, mtime, isCP, isPrim) AS ("
    "    SELECT objid, mtime, 0, 1 FROM event WHERE objid=%d"
    "    UNION"
    "    SELECT parent.pid, event.mtime, parent.isCP, parent.isPrim"
    "      FROM ancestor, parent, event"
    "     WHERE parent.cid=ancestor.rid"
    "       AND event.objid=parent.pid"
    "       AND NOT ancestor.isCP"
    "       AND (event.mtime >= "
    "              (SELECT max(mtime) FROM singletonTaggedCommits"
    "                 WHERE mtime<=(SELECT mtime FROM event WHERE objid=%d)))"
    "     ORDER BY mtime DESC"
    "     LIMIT 1000000"
    "  ) "
    "SELECT rid, mtime, isCP, isPrim, ROW_NUMBER() OVER (ORDER BY mtime DESC) rn"
    "  FROM ancestor",
    (matchGlob ? matchGlob : "*"), rid, rid
  );

  db_prepare(&q,
    "SELECT ta.rid, ta.mtime, ta.rn, b.uuid, substr(t.tagname, 5)"
    "        FROM singletonTaggedAncestors ta"
    "  INNER JOIN blob b ON b.rid=ta.rid"
    "  INNER JOIN tagxref tx ON tx.rid=ta.rid"
    "  INNER JOIN tag t ON tx.tagid=t.tagid"
    "       WHERE tx.tagtype=1 AND t.tagname GLOB 'sym-%q' "
    "         AND rn=(SELECT MAX(rn) FROM singletonTaggedAncestors)"
    "    ORDER BY tx.mtime DESC, t.tagname DESC LIMIT 1",
    (matchGlob ? matchGlob : "*")     
  );

  if( db_step(&q)==SQLITE_ROW ){
    const char *lastTag = db_column_text(&q, 4);
    descr->zRelTagname = mprintf("%s", lastTag);
    descr->nCommitsSince = db_column_int(&q, 2)-1;
    nRet = 0;
  }else{
    /* no ancestor commit with a fitting singleton tag found */
    descr->zRelTagname = mprintf("");
    descr->nCommitsSince = -1;
    nRet = -3;
  }

  db_finalize(&q);
  return nRet;
}

/*
** COMMAND: describe
**
** Usage: %fossil describe ?VERSION? ?OPTIONS?
**
** Provide a description of the given VERSION by showing a non-propagating
** tag of the youngest tagged ancestor, followed by the number of commits
** since that, and the short hash of VERSION.  If VERSION and the found 
** ancestor refer to the same commit, the last two components are omitted,
** unless --long is provided.
**
** If no VERSION is provided, describe the current checked-out version.  When
** no fitting tagged ancestor is found, show only the short hash of VERSION.
**
** Options:
**
**    --digits           Display so many hex digits of the hash (default 10)
**    -d|--dirty         Show whether there are changes to be committed
**    --long             Always show all three components
**    --match GLOB       Consider only non-propagating tags matching GLOB
*/
void describe_cmd(void){
  const char *zName;
  const char *zMatchGlob;
  const char *zDigits;
  int nDigits;
  int bDirtyFlag = 0;
  int bLongFlag = 0;
  CommitDescr descr;

  db_find_and_open_repository(0,0);
  bDirtyFlag = find_option("dirty","d",0)!=0;
  bLongFlag = find_option("long","",0)!=0;
  zMatchGlob = find_option("match", 0, 1);
  zDigits = find_option("digits", 0, 1);

  if ( !zDigits || ((nDigits=atoi(zDigits))==0) ){
    nDigits = 10;
  }

  /* We should be done with options.. */
  verify_all_options();
  if( g.argc<3 ){
    zName = "current";
  }else{
    zName = g.argv[2];
  }

  if( bDirtyFlag ){
    if ( g.argc>=3 ) fossil_fatal("cannot use --dirty with specific checkin");
  }

  switch( describe_commit(zName, zMatchGlob, &descr) ){
    case -1:
      fossil_fatal("commit %s does not exist", zName);
      break;
    case -2:
      fossil_fatal("commit %s is ambiguous", zName);
      break;
    case -3:
      fossil_print("%.*s%s\n", nDigits, descr.zCommitHash,
                  bDirtyFlag ? (descr.isDirty ? "-dirty" : "") : "");
      break;
    case 0:
      if( descr.nCommitsSince==0 && !bLongFlag ){
        fossil_print("%s%s\n", descr.zRelTagname,
                    bDirtyFlag ? (descr.isDirty ? "-dirty" : "") : "");
      }else{
        fossil_print("%s-%d-%.*s%s\n", descr.zRelTagname,
                    descr.nCommitsSince, nDigits, descr.zCommitHash,
                    bDirtyFlag ? (descr.isDirty ? "-dirty" : "") : "");
      }
      break;
    default:
      fossil_fatal("cannot describe commit");
      break;
  }
}