bk log(7.3ce)               BitKeeper User's Manual              bk log(7.3ce)

NAME
       bk log - print file revision history and/or metadata

SYNOPSIS
       bk log [-dDfS] [-c<d>] [-C<r>] [-L[<url>]] [-r<r>] [<file> ... | -]

DESCRIPTION
       The  bk log command is used to extract revision history and or metadata
       from a file or set of files.  The default behavior is to print  a  sum-
       mary  of  each  revision  to  each  of  the specified files.  There are
       options to restrict the set of revisions to print, a very commonly used
       one is -r+, which restricts the set to the most recent revision.

       With  no  options  bk  log output defaults to giving information on all
       revisions of all files in the present directory  that  are  under  Bit-
       Keeper  control.   Output is given as follows: the name of the file and
       range of revisions is followed by a detailed account of each  revision.
       Revision  number,  revision date and time, user who made that revision,
       what the relative path from root of repository is  to  that  file,  the
       comments that go with that revision, and documents if the file has been
       renamed.

OPTIONS
       -<n>             A numeric argument that limits the  number  of  deltas
                        printed per file.
       --begin=<script> The  dspec v2 language (see that section below and the
                        examples) is awk like and has optional begin/end  sec-
                        tions.   This option allows you to specify the body of
                        a begin section (if the file also has a begin  section
                        then  both  are run; order is undefined).  It is typi-
                        cally used with an on disk dspec in a dspec file  that
                        has  been  written in a way to do one thing by default
                        and another if a variable is set to non-zero.
       -c<date>         Cut-off dates.  See range specifications (below) or bk
                        help range for details.
       -C<rev>          Make  the  range be all revs that are the same cset as
                        <rev>.
       -d<spec>         Override the default output format (see below).
       --dspecf=<file>  Like -d but read the dspec from a file.
       -D               Do not skip files in the BitKeeper/deleted directory.
       -f               Print the changes in forward (oldest to newest) order.
                        The default is backward.
       -L[<url>]        Show  all deltas unique to this repository relative to
                        the (outgoing) parent or <url> if one  was  specified.
                        May not be combined with -c or -r.
       --lattice        Restrict  the  deltas  to those on the lattice between
                        the two range endpoints.  Unlike a  range,  the  lower
                        bound is included in the output.
       --longest        Restrict  the  deltas  to  those  on  the longest line
                        between the two range endpoints.  Unlike a range,  the
                        lower bound is included in the output.
       -n               Add a newline to each printed record.
       -r<rev>          Specify  a  revision,  or part of a range.  (Or key or
                        ment.")
       -S
       --standalone     Use  with  -L  in a nested component when you want the
                        component to act like a standalone repository.

   RANGE SPECIFICATIONS
       -r+             prints the most recent delta
       -r1.3..1.6      prints all deltas that are in 1.6's history but are not
                       in 1.3's history.
       -c2006/07..2006 prints all deltas from July 1 2006 to Dec 31 2006
       -c2006..2006    prints all deltas from Jan 1 2006 to Dec 31 2006
       -c-1d..         prints  all deltas made in the last 24 hours; similarly
                       for s, m, h, d, M, and Y  for  seconds,minutes,  hours,
                       days, months, and years.

DEFAULT OUTPUT FORMAT
       The  bk changes, and bk log commands have a default output format which
       may be modified on a per user or per  repository  basis.   The  default
       formats are named as follows:

       dspec-changes     Specifies  the  format  for  bk  changes  [-v] output
                         (without -vv).
       dspec-changes-vv  Specifies the format for bk changes -vv output  (ver-
                         bose with diffs).
       dspec-log         Specifies the format for bk log output.

       There   are  other  dspec-*  files,  if  you  want  some  fun  look  at
       dspec-*-json, if you understand those you understand that dspecs are  a
       little   programming   language.    The   shipped  files  live  in  `bk
       bin`/dspec-*

       These files can live in multiple places, this is the search  order  for
       "dspec-changes", the first one found is used:
              <repo>/BitKeeper/etc/dspec-changes
              <product>/BitKeeper/etc/dspec-changes (BitKeeper/Nested only)
              `bk dotbk`/dspec-changes
              /etc/BitKeeper/etc/dspec-changes
              `bk bin`/dspec-changes

MODIFYING THE OUTPUT FORMAT
       There  are many different pieces of information in a BitKeeper file and
       virtually all of them can be extracted using a non-default output  for-
       mat.

       To  extract specific information, a "dspec" (data specification) string
       is provided and where there are keywords surrounded by colons the  key-
       words  are  expanded much like printf(3).  This can lead to many useful
       one liners; want to see which file is the most busy in a repository?

           bk -U log -r+ -nd':DS: :GFILE' | sort -nr | head

       If you are familiar with awk(1) the processing  here  is  similar.   In
       awk,  each  line  is  a  record, here each delta is a record.  For each
       delta, you can provide a dspec which says what it is you want to  print
       from  that  delta.   Looking  at  the dspec-* files in the installation
       directory is recommended, there are  $begin/$end  sections  that  mimic
       awk.

       The  dspecs  can  contain the following set of escaped characters which
       will be replaced with the specified string:

       \b     Backspace
       \f     Form feed
       \n     Newline
       \r     Carriage return
       \t     Tab
       \123   3 digit octal value (pad with leading zeros)
       \<c>   c for any other character "c"

       In almost all cases, a trailing newline is not provided by any  of  the
       keywords  and  one  should  be  provided as needed.  The newline can be
       added in line or you can specify the -n option which will add a newline
       after each delta is processed.

       Multi-line keywords are normally printed as is, but you can format each
       line separately using a $each() loop (see ITERATIVE OUTPUT below).

   CONDITIONAL OUTPUT
       The dspec can produce output conditionally.  The following  prints  the
       revisions of foo.c that were made by joe:

           bk log -nd'$if(:USER:=joe){:REV:}' foo.c

   CONDITIONAL STATEMENTS
       $if(<expr>){<anything>}
           prints <anything> if <expr> is true.  If <expr> is a keyword, i.e.,
           :MERGE:, then the keyword is examined and returns true if it has  a
           value.  <anything> can contain keywords, i.e., :REV:.
       $unless(<expr>){<anything>}
           prints <anything> unless <expr> is true.
       $if(<expr>){<stuff if true>}$else{<stuff if false>}
           both  $if and $unless can have an optional $else clause that prints
           if the preceding clause was not printed.

   CONDITIONAL OPERATORS
       strings  <lhs>=<rhs> true if <lhs> is identical to <rhs>.
                <lhs>!=<rhs> true if <lhs> is different than <rhs>.
                <str>=~<glob> true if <str> matches <glob>.
                <str>=~</regexp/> true if <str> matches the regular expres-
                sion; /regexp/i does a case-insensitive match and /glob/g does
                a glob match.
                Note: spaces immediately before and after the operator are
                ignored.  To match against such a leading or trailing space,
                escape it.
       numbers  <lhs> -eq <rhs> equality;
                <lhs> -ge <rhs> equal or greater than;
                <lhs> -gt <rhs> greater than;
                <lhs> -le <rhs> equal or less than;
                <lhs> -lt <rhs> less than.
                Note: spaces are required on both sides of the operator.

   COMPOUND EXPRESSIONS
       As of BitKeeper release 4.1, dspecs support logical AND (A && B), logi-
       cal OR (A || B), and parenthesized subexpressions ((A && B) || (C &&
       D)).  Note: spaces immediately before and after the operator are
       ignored.  To match against such a leading or trailing space, escape it.

   ITERATIVE OUTPUT
       Some keywords, such as comments or tags, may be multi-line.  To print a
       prefix in front of each of these lines, the dspec is:

           bk log -d'$each(:C:){C  (:C:)\n}' foo.c

       This iteration works for all keywords, but normally is  only  used  for
       keywords  that can contain multiple lines like ALL_TAGS, C, TAGGED, and
       TAGS.

       The $first() builtin can be used to print only the first line of one of
       these  multi-line  keywords.   Some development efforts tend to use the
       first line of commit comments as a summary of the change; the rest  are
       more  details.  The dspec that ships with BitKeeper for bk changes uses
       this feature to implement bk changes --short.  To print the first  line
       of each comment in a changeset:

           bk changes -nd'$first(:C:)'

   VARIABLES
       When  the  bk log command is run over multiple revisions of one or more
       files, the data specification ("dspec")  is  evaluated  once  for  each
       revision, and it sometimes is useful to use dspec variables, denoted as
       '$0', '$1', up to '$9', to remember values across revisions  or  files.
       A variable is assigned a value with:

           ${0=<dspec>}

       where  <dspec>  is  a  recursively  evaluated data specification.  Once
       assigned, a variable retains its value for the remainder of the command
       (or  until reassigned).  Variables start out as empty strings (evaluate
       to zero in numeric context), and when re-assigned the old value is dis-
       carded.

   DSPEC VERSION 2
       This  little  printf  like language outgrew itself, having if/then/else
       and other control flow was too much on just one line.  We came up  with
       a  version  2  language that allows you to have dspecs that look like a
       programming language.  All of the output  from  BitKeeper  commands  is
       generated via the v2 language in external files (see dspec-* in the bin
       directory).  All of the commands that take dspecs also can take a  file
       containing the dspec; that's how the BitKeeper commands work, they just
       load those files.

       To switch into the new language a dspec has to begin like so:

           # dspec-v2

       The language is awk like, comments start with "#" and go to the end  of
       the  line.   Whitespace  is  ignored unless it is inside double quotes,
       then it is reproduced exactly.  Keywords are expanded inside of  double
       quotes as are the escaped characters mentioned above.  Control flow and
       begin/end blocks (all the $something) are unquoted.

       Like awk, there are optional begin/end blocks:

           $begin {
                   "[\n"
           }
           $end {
                   $if($0 -eq 1) {
                           "\n"
                   }
                   "]\n"
           }

       Those are from dspec-changes-json-v which is the dspec that is used for
       bk changes -v --json which (surprise!) produces json format output.  If
       you want to understand this language that is a good file to read.

       In many cases, all keywords will expand in begin/end blocks, those  are
       run  in  the  context  of the first/last delta selected.  If a range is
       selected that has no matching deltas (think bk changes -L for  example)
       then  none of the keywords will be expanded, the current system expands
       keywords if and only if there is a valid delta in play.

       A simple dspec-v2 example is the old bk prs output (SCCS compat):

           # dspec-v2
           ":DT: :REV: :D: :T::TZ: :USERHOST: :DS: :DP: :LI:/:LD:/:LU:\n"
           "P :DPN:\n"
           $each(:TAGGED:){"S (:TAGGED:)\n"}
           $each(:C:){"C (:C:)\n"}
           "------------------------------------------------\n"

   KEYWORDS
       Some keywords are per repository and are marked with R in the T  column
       below.   Some keywords are per file and are marked with F in the T col-
       umn below; other keywords are per delta and are marked  with  D.   Some
       keywords  only  make sense if they are changesets, they are marked with
       C.  Those keywords that can be either on a changeset or on a  file  are
       marked with D.

       Name          T   What is printed
       ==========================================================
       :AGE:         D   D's age, i.e., seven hours, two weeks, etc.
       :ALL_TAGS:    C   The tag[s] if this changeset has or ever had them
       :ATTACHED_ID: F   package id to be used for new deltas
       :BAM:         F   true if the file is managed as a BAM file
       :C:           D   D's comments
       :CHANGESET:   F   true if ChangeSet file, false for user files
       :COMMENTS:    D   comments portion of :PRS:
       :COMPRESSION: D   D's compression (gzip|none)
       :CSETKEY:     D   delta key if D is at a changeset boundary
       :CSETREV:     D   revision of first cset boundary after D
       :D:           D   D's date as YYYY/MM/DD
       :D_:          D   D's date as YYYY-MM-DD
       :DANGLING:    D   D's rev if & only if D is a dangling delta
       :DI:          D   D's includes/excludes as +I,I/-X,X (serials)
       :DIFFS:       D   D's changes in the form of traditional diffs
       :DIFFS_U:     D   D's changes in the form of unified diffs
       :DIFFS_UP:    D   D's changes in the form of unified/procedural diffs
       :DL:          D   lines inserted/deleted/unchanged in D
       :DM:          D   month part of D's date (Jan..Dec)
       :DOMAIN:      D   the domain part of the hostname of D
       :DP:          D   the serial number of the parent of D
       :DPN:         D   the pathname of g.file as of D
       :DS:          D   the serial number of D
       :DSUM:        D   D's 16 bit unsigned checksum (%05u)
       :DSUMMARY:    D   first line of :PRS:
       :DT:          D   D's type: (D|R|T) meaning (Data|Removed|Tag)
       :Dd:          D   day part of D's date as DD
       :Dm:          D   month part of D's date as MM
       :Dn:          D   serial numbers of D's includes, if any
       :Dt:          D   D's data as :DT::REV::D::T::USER::DS::DP:
       :Dx:          D   serial numbers of D's excludes, if any
       :Dy:          D   year part of D's date as YY or YYYY
       :ENC:         F   current encoding scheme (ascii|uuencode|BAM)
       :EVEN:        D   True on every other delta processed
       :F:           F   basename of the BitKeeper file
       :FLAGS:       D   file flags as of D in words (HASH, YEAR4...)
       :FSUM:        F   16 bit unsigned checksum of the s.file
       :FUDGE:       D   time stamp fudge used make time monotonic
       :FULLHOST:    D   same as :HOST: or :HOST:/:REALHOST:
       :FULLUSER:    D   same as :USER: or :USER:/:REALUSER:
       :G:           F   basename of the gfile
       :GB:          D   file as of version D
       :GCA:         D   find the graph GCA for D's parents
       :GCA2:        D   find the set GCA for D's parents
       :GFILE:       F   pathname of the gfile
       :GREV:        F   for a file with conflicts, the GCA of the unmerged tips
       :HASHCOUNT:   D   count of key/value pairs in D if & only if hash file
       :HOST:        D   hostname where D was made; could be BK_HOST
       :HTML_AGE:    D   age in a form suitable for web pages
       :HTML_C:      D   comments in a form suitable for web pages
       :ID:          D   the package id in effect when the delta was made
       :IMPORTER:    D   name of the importer of D, if D was an emailed patch
       :KEY:         D   BitKeeper key of D
       :KID:         D   D's direct kid in D's branch
       :KIDS:        D   all of D's direct kids in the graph
       :L:           D   the second field in D's rev (R.L.B.S)
       :LD:          D   lines deleted in D (%u)
       :LI:          D   lines inserted in D (%u)
       :LREV:        F   for a file with conflicts, the LOCAL unmerged tip
       :LU:          D   lines unchanged in D (%u)
       :Ld:          D   lines deleted in D (%05u)
       :Li:          D   lines inserted in D (%05u)
       :Lu:          D   lines unchanged in D (%05u)
       :MD5KEY:      D   crypto based BitKeeper key of D
       :MERGE:       D   D's rev if & only if D has a merge parent
       :MGP:         D   D's merge parent's serial number
       :MODE:        D   D's file modes as an octal (777)
       :MPARENT:     D   D's merge parent's revision
       :N:           D   Number of deltas, use instead of DS, DS may have gaps.
       :NEXT:        D   next entry after D in delta table
       :ODD:         D   True on every other delta processed
       :PACKAGE_ID:  R   per repository unique id (like bk id)
       :PARENT:      D   D's parent's revision
       :PREV:        D   previous entry before D in delta table
       :PRODUCT_ID:  R   per repository unique id (like bk -P id)
       :PRS:         D   old-style bk prs default output
       :R:           D   the first field in D's rev (R.L.B.S)
       :RANDOM:      F   random bits part of ROOTKEY
       :REALHOST:    D   real host where D was made, regardless of BK_HOST
       :REALUSER:    D   real programmer who made D, not assumed identity
       :RENAME:      D   D's path if different from parent's path
       :REPO_ID:     R   per repository unique id (like bk id -r)
       :REPOTYPE:    R   repotype: product|component|standalone
       :REV:         D   D's revision number
       :RI:          D   revision numbers of D's includes/excludes
       :ROOTKEY:     F   key of the 1.0 delta, file's internal name
       :RREV:        F   for a file with conflicts, the REMOTE unmerged tip
       :RWXMODE:     D   D's file modes as ascii (-rwxrwxrwx)
       :Rn:          D   revision numbers of D's includes
       :Rx:          D   revision numbers of D's excludes
       :S:           D   last field in D's rev (R.L.B.S)
       :SFILE:       F   pathname of s.file
       :SIBLINGS:    D   rev sibling's pointer in D
       :SPN:         D   pathname of s.file as of D
       :SYMLINK:     D   value of D's symlink target
       :T:           D   time of D as HH:MM:SS
       :TAGGED:      C   The tag[s] iff currently on this changeset
       :TAGS:        C   Tag[s] if on, or were on, this changeset (with notes)
       :TIME_T:      D   D's date as GMT time_t, TZ and Fudge adjusted
       :TIP:         D   D's rev if D is at the tip (TOT)
       :TZ:          D   offset from GMT as +/-HH:MM
       :Th:          D   hour part of D's date as HH
       :Tm:          D   minute part of D's date as MM
       :Ts:          D   seconds part of D's date as SS
       :USER:        D   programmer who made D; could be assumed identity
       :UTC:         D   D's time stamp as YYYYMMDDHHMMSS in GMT
       :UTC-FUDGE:   D   like UTC but without the date fudge
       :VERSION:     F   file format version

NOTES
       Keywords  marked with type C or D above can optionally be restricted to
       a given revision as follows:

           :KW|1.0:      # as of a literal revision
           :KW|PARENT:   # as of the current rev's parent
           :KW|MPARENT:  # as of the current rev's merge parent (if any)

       For example:

           bk log -hnd'$if(:DPN|PARENT: != :DPN:){rename :DPN|PARENT: => :DPN:}'

       Things that can go in the second part include a specific  revision  (eg
       1.0), PARENT, and MPARENT.

EXAMPLES
       To extract a key, which is a stable name for a changeset:

           bk changes -r1.234 -nd:MD5KEY:

       To count up all the deltas in all user files:

           bk -U log -nd:REV: | wc -l

       List users who have made changes in a subdirectory in the last month:

           bk -rSubDir log -c-1M.. -nd:USER: | sort -u

       To see the number of merge changesets:

           bk changes -nd'$if(:MERGE:){merge}' | wc -l

       To see the number of merges in user files:

           bk -U log -nd'$if(:MERGE:){merge}' | wc -l

       Count up lines inserted by a particular user in all non-merge deltas:

           bk -U log -nd'$if(:USER: = joe && !:MERGE:){:LI:}' |
           awk '{ lines += $1 } END { print lines }'

       The  default  dspec  for  the  bk changes command is below.  This is an
       example of a dspec-v2 style of writing dspecs, much more  pleasant  for
       complex reports.

           # dspec-v2

           # The default dspec used by 'bk changes' and 'bk changes -v'

           ":INDENT:"              # 2 spaces + 2 in component
           ":DPN:@:REV:"
           ${1=:USERHOST:}         # 1 == user || user@host
           $if (:CHANGESET: && !:COMPONENT_V:) {
               ", :Dy:-:Dm:-:Dd: :T::TZ:, $1"
               ${0=$1}                          # 0 == user of last cset
           } $else {
               $if($0 != $1){                   # print user if different
                         ", $1"
               }
           }
           $unless (:CHANGESET:) {
               " +:LI: -:LD:"                   # lines added/deleted
           }
           "\n"

           # bk changes --short is an alias for
           # bk changes --begin='${9=1}'
           # so $9 is the switch that decides between short/long form
           $if ($9 -eq 0) {                     # comments (long form)
               $each(:C:) {
                   ":INDENT:  (:C:)\n"
               }
           } $else {                            # comments (short form)
               ":INDENT:  "
               $first(:C:)
               "\n"
           }
           $each(:TAGS:) {
               "  TAG: (:TAGS:)\n"
           }
           $if ($9 -eq 0) {                     # skip merge info for --short
               $if (:MERGE:) {                  # merge shows both parents
                   ":INDENT:  MERGE: :MPARENT:\n"
               }
           }
           "\n"

SEE ALSO
       bk range

CATEGORY
       File

BitKeeper Inc                         1E1                        bk log(7.3ce)