-*- org -*-

#+STARTUP: hidestars oddeven

HINT: org-mode global cycling: S-TAB

HINT: To show all content (including any drawers), regardless of org-mode
startup visibility:

:    C-u C-u C-u TAB

[The above assumes the default key binding of TAB to [[elisp:org-cycle][org-cycle]].]


This is the 'NEWS' file for the 'ads-github-tools' project. This file contains
information on changes since the last release of the package, as well as a
running list of high-level changes from previous versions.  If critical bugs
are found in any of the software, notice of such bugs and the versions in
which they were fixed will be noted here, as well.

-----------------------------------------------------------------------

* ads-github-tools 0.3.1 (2020-10-12)

** fixes

*** issue 33: 'ads-github-fetch-all-upstreams -vcu foo*' leads to 'jq: error (at <stdin>:3): Cannot index string with string "owner"'

    https://github.com/salewski/ads-github-tools/issues/33

    The ads-github-fetch-all-upstreams(1) tool was previously using the
    default behavior of curl(1) to invoke GitHub v3 API endpoints and emit the
    retrieved responses on stdout, feeding that output in Unix pipelines to
    other programs (mostly to jq(1)).

    While that approach was fast and convenient when originally implemented,
    it also had the downside of preventing the program from properly detecting
    all failures because it could not check the HTTP response codes.

    The program now follows the pattern (used elsehwere in the
    'ads-github-tools') of configuring 'curl' to write the response body to a
    temporary file named by a well-known global variable, and emit the HTTP
    response code on stdout. The calling code is thus able to check the 'curl'
    exit status, the emitted HTTP response code, and the size and content of
    the response body independently of one another. This makes the program
    more robust in general, and avoids complaints emitting from the downstream
    jq(1) process that should have been handled upstream of it.


*** issue 34: 'ads-github-fetch-all-upstreams -vcu foo results in "line 1067: test: 7: unary operator expected" when github host is inaccessible'

    https://github.com/salewski/ads-github-tools/issues/34

    This issue was partially fixed by the above changes for issue #33, but a
    check specific to this issue has been added to verify that the obtained
    page count value contains all digits. This keeps any emitted error
    messages as close as possible to the source of the problem.


*** issue 39: 'ads-github-fetch-all-upstreams: default to triangular workflow, but allow override'

    https://github.com/salewski/ads-github-tools/issues/39

    Consistent with the 'ads-github-tools-0.3.0' release, when initially
    cloning a repo the 'ads-github-fetch-all-upstreams' program continues to
    use a "triangular" workflow by default.

    The manpage entry explains:
    #+BEGIN_QUOTE
       --triangular
       --no-triangular
           In newly cloned repos, use (or avoid using) a Git remote
           configuration suitable for supporting a triangular workflow.

           Among other things, a triangular config will cause the default
           branch in the local working directory to be configured to track the
           branch of the same name from the upstream remote.

           For a non-triangular configuration, the default branch in the local
           working directory will be configured to track the branch of the
           same name from the origin remote.

           See git-hub(1) for details.

           If neither "--triangular" nor "--no-triangular" is specified, then
           the "hub.triangular" setting from git-config(1) (scopes "global"
           and "system" only) is consulted, and honored if present. Finally,
           if neither command line options nor configuration specifies a
           preference, then a triangular configuration is the default.

           Note: Whether a triangular or non-triangular configuration is used
           is purely a matter of preference for the user (if any) that will be
           working with the newly cloned repo; it has no bearing on the
           functionality of the "ads-github-fetch-all-upstreams" program.
    #+END_QUOTE


*** issue 44: ads-github-show-rate-limits: http response code not checked

    https://github.com/salewski/ads-github-tools/issues/44

    The 'ads-github-show-rate-limits' program is now careful to check not only
    the curl(1) exit status of the 'GET /rate_limit' request, but also the
    HTTP response status. Previously it was obtaining the JSON response on the
    curl(1) stdout, and had no way to determine what the HTTP response code
    was. The new behavior is to follow our pattern of saving the raw response
    output to a temporary file, and having curl write the HTTP response code
    to stdout; this allows us to deal with both aspects independently.

    When the 'GET /rate_limit' call results in a non-success status, the
    program now emits and error message and exits with a non-zero status, as
    one would expect. If a JSON response payload was returned, it will be
    printed beneath the error message to provide additional context for the
    failure.

    Ex. 1:
    :    ads-github-show-rate-limits (error): HTTP response code was: "401"; expected 200 ("OK"); bailing out
    :        HTTP response payload may contain additional info:
    :            {"message":"Bad credentials","documentation_url":"https://docs.github.com/rest"}

    Ex. 2:
    :    ads-github-show-rate-limits (error): HTTP response code was: "404"; expected 200 ("OK"); bailing out
    :        HTTP response payload may contain additional info:
    :            {"message":"Not Found","documentation_url":"https://docs.github.com/rest"}

    If no response payload was returned, that fact will be explicitly stated,
    as well:

    Ex. 3:
    :    ads-github-show-rate-limits (error): HTTP response code was: "500"; expected 200 ("OK"); bailing out
    :        (HTTP response payload was empty)


*** issue 46: "fork" vs. "origin", etc.

    "git config: honor 'hub.upstreamremote' and 'hub.forkremote', if set"
    https://github.com/salewski/ads-github-tools/issues/46

    When clone a repo initially the default behavior at some point seemed to
    change from creating a Git remote named "origin" for the user's GitHub
    repo to creating a Git remote named "fork". This was due to a behavior
    change in the underlying git-hub(1) tool, which switched its behavior when
    the tool went verion 1.0 some time ago. Users of 'ads-github-tools' could
    influence the behavior of that tool by setting the 'hub.forkremote' and
    'hub.upstreamremote' git-config(1) values, but in the absence of such a
    config the user still got default behavior that was different from what it
    had been.

    The 'ads-github-fetch-all-upstreams' program has been modified to look for
    and honor the config mentioned above, but when not present it now asserts
    a preference for the name "origin" rather than "fork" when cloning a
    repo. It also asserts a preference for the name "upstream", but that name
    is in alignment with the git-hub(1) default already.

    Note that the changes introduced here cure the immediate problem of having
    Git remotes with the name "fork", but the solution as implemented is not
    entirely general. In particular, the name "upstream" for the other Git
    remote is baked-in at a fairly deep level, and will need additional
    surgery to use an arbitrary name. Thus, if the 'hub.upstreamremote'
    setting is present and contains a value other than "upstream", then when
    you run:

    :    $ ads-github-fetch-all-upstreams -vcu

    you will actually end up with three remotes rather than two for newly
    cloned repos. The program will create a remote named "upstream" in
    addition to whatever other name is specified. While this is clearly
    suboptimal, there have not been any problems with using the hard-coded
    name "upstream"; as a practical matter, it is not an emergency to address
    that. For best results, stick with the name "upstream" for now.


*** issue 53: fix perms on *.in template files in src/main/bash/bin/

    https://github.com/salewski/ads-github-tools/issues/53

    This was a minor in-tree cleanup activity. It was noticed that the *.in
    template files had their executable bit set, which was misleading. Those
    files are not intended to be directly executed, but rather are filtered at
    build time to produce the programs that /are/ directly executable. This
    was probably "origin cruft"; each of the programs was probably first
    implemented as a shell script which was then parameterized and otherwise
    modified to create the *.in template.


** improvements

*** issue 42: adapt for github deprecating password authentication, OAuth authz & app APIs

    https://github.com/salewski/ads-github-tools/issues/42

    GitHub has officially deprecated password-based authentication, and it
    will be disabled entirely on [2020-11-13 Fri]:

        https://developer.github.com/changes/2020-02-14-deprecating-password-auth/

    The 'ads-github-tools' programs were reviewed to determine the impact, if
    any, that those deprecations might have. The are not any application
    behavioral changes related to deprecations because the ads-github-tools
    were not using any of the deprecated authn or authz APIs.

    However, anyone that is using their GitHub user password in their ~/.netrc
    file will need to change their config to use what GitHub calls a "personal
    access token", instead. There are no known users that are not using a
    personal access token already, but if you happen to be one you will want
    to check out the official GitHub docs on the subject:

        https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token

    The executive summary is that you use a "personal access token" in
    basically the same way that you would use a password: you put it in your
    ~/.netrc file as the value for the 'password' field. It is a better
    approach than using the password itself, though, because the token can be
    configured to have more constrained permissions than the password; you
    decide what it can do at the time you create the token. (You can also
    delete and replace a personal access token with less disruption then you
    can change the password on your account if that password were used by
    various tools.)

    You may wish to create a token that is not able to perform certain actions
    (e.g., deleting repositories). That will have a minor impact on the
    ads-github-tools, but they will simply tell you when they are not able to
    perform some action.


*** issue 48: new tool: ads-github-repo-create(1)

    https://github.com/salewski/ads-github-tools/issues/48

    This new tool allows the user to create new GitHub repositories while
    working at the command line. The tool's '--help' output and sample usage
    below give a feel for what it can do:

**** ads-github-repo-create --help

     :    $ ./src/main/bash/bin/ads-github-repo-create --help
     :    usage: ads-github-repo-create { -h | --help }
     :      or:  ads-github-repo-create { -V | --version }
     :      or:  ads-github-repo-create [OPTION...] [--] REPO_NAME
     :
     :    Create a new GitHub repository.
     :
     :    Mandatory arguments to long options are mandatory for short options too.
     :
     :      -h, --help                 Print this help message on stdout
     :      -V, --version              Print the version of the program on stdout
     :      -a, --auto-init            Auto-initialize the repo with a minimal README.md file
     :          --prop-secs=NUMBER     Seconds to wait for GitHub data propagation before verifying
     :                                   Default is 4 seconds.
     :                                   Only relevant when -a (--auto-init) is in-effect.
     :      -b, --default-branch=NAME  Specify the name to use for the default branch.
     :                                   Implies -a (--auto-init).
     :      -d, --description=BLURB    Specify a short description blurb for the repo
     :          --force-replace        If repo already exists, attempt to replace it
     :                                   (delete, then re-create; requires 'delete_repo' scope)
     :          --homepage=URL         Specify a URL with more information about the repo
     :      -I, --disable-issues       Disable GitHub issues for the new repo
     :      -P, --disable-projects     Disable GitHub projects for the new repo
     :      -O, --output-format=WORD   Emit output in the format specified by WORD [default: text]
     :                                   Valid values for WORD include: 'text' and 'json'
     :      -p, --private              Make the repository a GitHub private repo (default is public)
     :      -v, --verbose              Print program progress messages on stderr. Specify multiple
     :                                   times to increase verbosity: info, debug, and tracing (set -x)
     :      -W, --disable-wiki         Disable GitHub wiki feature for the new repo
     :          --                     Signals the end of options and disables further options processing.
     :                                   Any remaining argument(s) will be interpretted as a repo name
     :
     :    Report bugs to Alan D. Salewski <ads@salewski.email>.


**** sample usage: ads-github-repo-create

     :    $ ads-github-repo-create 'aljunk-testing-repo-006'
     :    Summary of newly created repository:
     :                   Name: aljunk-testing-repo-006
     :               Is fork?: no
     :                  Owner: salewski
     :           Is archived?: no
     :           Is disabled?: no
     :
     :             Created at: 2020-10-09 07:09:52+0000
     :             Updated at: 2020-10-09 07:09:56+0000
     :
     :            Is private?: no
     :             Visibility: -
     :
     :      Auto-initialized?: no
     :         Default branch: main
     :
     :            Has issues?: yes
     :          Has projects?: yes
     :              Has wiki?: yes
     :
     :                 GitHub: https://github.com/salewski/aljunk-testing-repo-006
     :               Homepage: -
     :            Description: -
     :
     :          Clone via ssh: git@github.com:salewski/aljunk-testing-repo-006.git
     :        Clone via https: https://github.com/salewski/aljunk-testing-repo-006.git


**** issue 55: repo-create: make repo auto-initialization optional

     https://github.com/salewski/ads-github-tools/issues/55

     This issue documents a change in direction we took while designing the
     'ads-github-repo-create' tool. Originally the tool always
     auto-initialized the new repo, but that behavior interfered with use
     cases in which the GitHub repo was being created as the target for some
     existing Git repository (e.g., when mirroring a Git repo from elsewhere
     into GitHub). Consequently, the auto-initialize behavior was made
     optional, with the tradeoff being that the user needs to be cognizant of
     whether auto-initialization will be helpful to or an annoyance for the
     task at hand.


*** issue 49: update contact email

    https://github.com/salewski/ads-github-tools/issues/49

    The old contact email address 'salewski@att.net' /should/ still work, but
    the preferred address to use going forward is 'ads@salewski.email'. Note
    that the author has experienced a fair amount of mail lossage this year
    (2020) due to overly-aggressive mail filtering by the AT&T mail system;
    lots of legit mail does not get through, and there is no indication of the
    blockage. For best results, use the new address.


*** issue 50: added SPDX headers to source files

    https://github.com/salewski/ads-github-tools/issues/50


*** issue 52: new tool: ads-github-whoami(1)

    https://github.com/salewski/ads-github-tools/issues/52

    The new 'ads-github-whoami' tool shows information about the authenticated
    GitHub user.

    By default, it simply emits the username (a.k.a. "owner" or "login"):

    :    $ ads-github-whoami
    :    salewski

    The tool has a '-l' (--long) option that can be specified more than once
    to request increasingly verbose amounts of information. An option is also
    provided to request that the raw JSON output be emitted.

    Currently five "long" levels are supported: none, "1x", "2x", and "3x",
    and "4x". Additional '-l' opts are accepted, but (currently) anything more
    than four will not affect the output produced.

    The behavior of this option allows us to optimize for the common case, yet
    still keep noisy-looking, less-often-valuable information within easy
    reach.

    Note that the availability of the data displayed depends on the "scopes"
    of access associated with the GitHub "personal access token" used to
    authenticate. There are publicly visible fields (the type of thing you see
    on a given user's GitHub page), and fields that are private. Reading the
    data values for the private fields requires the 'user:read' access
    scope. In the examples that follow, that access has NOT been
    provided. Users need to decide for themselves which access are appropriate
    for their individual use cases. As you can see in the examples that
    follow, the 'ads-github-whoami' tool will simply display placeholder
    values for those fields that are not accessible.

**** no '-l' opts (default output)

     Emits just the GitHub username (a.k.a. "owner" or "login").

     :    $ ads-github-whoami
     :    salewski


**** one '-l' opt: "1x" long output

     In addition to the GitHub username, also show basic contact information
     for user, if available.

     :    $ ads-github-whoami -l
     :    salewski  999999  "Alan D. Salewski" <ads@salewski.email>


**** two '-l' opts: "2x" long output

     In addition to basic contact information for the user, also show (if
     available) the user's basic GitHub stats.

     :    $ ads-github-whoami -ll
     :    salewski  999999  "Alan D. Salewski" <ads@salewski.email>
     :          mfa enabled: [DATA NOT AVAILABLE]
     :        ─────────────────────────────────────────────────────
     :         public repos: 1234
     :        private repos:    -  (owned: -)
     :         public gists:   20
     :        private gists:    -
     :            followers:   23
     :            following:  239
     :        collaborators:    -
     :           plan space:    -
     :           disk usage:    -


**** three '-l' opts: "3x" long output

     In addition to the user's basic contact information and basic GitHub
     stats, also show (if available) location, website, organization
     affiliation, and bio.

     :    $ ads-github-whoami -lll
     :    salewski  999999  "Alan D. Salewski" <ads@salewski.email>
     :          mfa enabled: [DATA NOT AVAILABLE]
     :        ─────────────────────────────────────────────────────
     :         public repos: 1234
     :        private repos:    -  (owned: -)
     :         public gists:   20
     :        private gists:    -
     :            followers:   23
     :            following:  239
     :        collaborators:    -
     :           plan space:    -
     :           disk usage:    -
     :        ─────────────────────────────────────────────────────
     :              company: -
     :             hireable: -
     :             location: -
     :               github: https://github.com/salewski
     :              website: https://salewski.github.io/
     :                  bio: -


**** four '-l' opts: "4x" long output

     In addition to the user's basic contact information, basic GitHub stats,
     and bio info, also show (if available) GitHub account metadata that is
     less frequently interesting.

     :    $ ads-github-whoami -llll
     :    salewski  997214  "Alan D. Salewski" <ads@salewski.email>
     :          mfa enabled: [DATA NOT AVAILABLE]
     :        ─────────────────────────────────────────────────────
     :         public repos: 1234
     :        private repos:    -  (owned: -)
     :         public gists:   20
     :        private gists:    -
     :            followers:   23
     :            following:  239
     :        collaborators:    -
     :           plan space:    -
     :           disk usage:    -
     :        ─────────────────────────────────────────────────────
     :              company: -
     :             hireable: -
     :             location: -
     :               github: https://github.com/salewski
     :              website: https://salewski.github.io/
     :                  bio: -
     :        ─────────────────────────────────────────────────────
     :           created at: 2011-08-22 20:17:54+0000
     :           updated at: 2011-08-22 20:17:54+0000
     :            plan name: -
     :              node id: MBCDabcdWXYZwxyz==
     :           site admin: no



*** issue 54: fluff-up: ads-github-fetch-all-upstreams '-v' handling (support $TRACING)

    https://github.com/salewski/ads-github-tools/issues/54

    This change only impacts developers working on the 'ads-github-tools'.


* ads-github-tools 0.3.0 (2020-04-09)

** fixes

*** issue 24: ads-github-merge-all-upstreams: bogon REPO command line options fail silently

    https://github.com/salewski/ads-github-tools/issues/24

    If a repository is explicitly named on the 'ads-github-merge-all-upstreams'
    command line and is not actually processed, the program now emits an error
    message and exits with a non-zero status.

    This helps avoid the false-warm-and-fuzzy from silent non-action when the user
    fat-fingers one or more repo names on the command line.


*** issue 38: ads-github-fetch-all-upstreams: chokes attempting to clone non-fork repos

    https://github.com/salewski/ads-github-tools/issues/38

    This issue was due to our use of the underlying git-hub(1) used when
    cloning non-fork GitHub repos.

    When cloning a repo, the default behavior of git-hub(1) is to create a
    triangular workflow configuration, which is usually what you want when
    there is and upstream repo from which your origin repo was
    forked. However, if the repo is not a GitHub fork of some other GitHub
    repo, then we need to tell git-hub(1) to not try to create a triangular
    workflow config; attempting to do so will result in the error:

    #+BEGIN_SRC sh
        Warning: Repository username/some-repo is not a fork, just cloning, upstream will not be set
        usage: git-hub [-h] [--version] [-v] [-s] {clone,issue,pull,setup} ...
        git-hub: error: Can't use triangular workflow without an upstream repo
        ads-github-fetch-all-upstreams (error): was error while attempting to clone repo "some-repo" from GitHub; bailing out
    #+END_SRC

    The 'ads-github-fetch-all-upstreams' program is now careful to provide the
    '--no-triangular' option to git-hub's 'clone' sub-command when cloning a
    non-fork repo.


** improvements

*** issue 6: ads-github-show-rate-limits: allow user to request utc date output

    https://github.com/salewski/ads-github-tools/issues/6

    The 'ads-github-show-rate-limits' program has a new '-u' (--utc) option
    that allows the user to request that time fields be output in
    human-readable (RFC 3339) formatted UTC (as opposed to the default seconds
    since the Unix epoch, or (with the '-h' (--human-readable) option)
    human-readable local time.

    See ads-github-show-rate-limits(1) for details.


*** issue 8: ads-github-show-rate-limits: allow user to request json output

    https://github.com/salewski/ads-github-tools/issues/8

    The 'ads-github-show-rate-limits' program has a new '-O' (--output-format=WORD)
    option that allows the user to request different output formats. Currently
    the only two output formats accepted are 'text' (the default) and
    'json'.

    The default output of the program has not changed. It is still
    whitespace-separated columns of text. Specifying the new
    '--output-format=text' option is just an explicit way of requesting the
    default behavior.

    See ads-github-show-rate-limits(1) for full details.

    Some examples:

    + Example 1a: Default output

      :    $ ads-github-show-rate-limits
      :       core  5000  5000  1489368062
      :    graphql   200   200  1489368062
      :     search    30    30  1489364522

    + Example 1b: Same thing, only explicitly using the new '--output-format=text' option:

      :    $ ads-github-show-rate-limits --output-format text
      :       core  5000  5000  1489368062
      :    graphql   200   200  1489368062
      :     search    30    30  1489364522

    + Example 2a: Requesting JSON ouput:

      :    $ ads-github-show-rate-limits --output-format json
      :    {"resources":{"core":{"limit":5000,"remaining":5000,"reset":1489368065},"search":{"limit":30,"remaining":30,"reset":1489364525},"graphql":{"limit":200,"remaining":200,"reset":1489368065}},"rate":{"limit":5000,"remaining":5000,"reset":1489368065}}

    + Example 2b: Requesting JSON ouput, and then using jq(1) to pretty-print it:

      :    $ ads-github-show-rate-limits --output-format json | jq '.'
      :    {
      :      "resources": {
      :        "core": {
      :          "limit": 5000,
      :          "remaining": 5000,
      :          "reset": 1489368082
      :        },
      :        "search": {
      :          "limit": 30,
      :          "remaining": 30,
      :          "reset": 1489364542
      :        },
      :        "graphql": {
      :          "limit": 200,
      :          "remaining": 200,
      :          "reset": 1489368082
      :        }
      :      },
      :      "rate": {
      :        "limit": 5000,
      :        "remaining": 5000,
      :        "reset": 1489368082
      :      }
      :    }


*** issue 25: ads-github-show-rate-limits(1) indicates data is parsed from HTTP headers, but it is really parsed from the JSON in the HTTP body response of the .../rate_limit endpoint

    https://github.com/salewski/ads-github-tools/issues/25

    The ads-github-show-rate-limits(1) man page previously mis-documented the
    underlying mechanism used by the tool to obtain the user's GitHub API rate
    limits information. It was documented to obtain that information from the
    HTTP response headers rather than the JSON response body from the
    '/rate_limit' service endpoint.

    While per-endpoint calls do allow for the possibility of extracting GitHub
    service limit information out of the HTTP response headers (e.g., see the
    [[https://developer.github.com/v3/#rate-limiting]["Rate Limiting"]] section of the GitHub API documentation), the
    'ads-github-tools-show-rate-limits' program is actually making a call to
    the GitHub [[https://developer.github.com/v3/rate_limit/][/rate_limit]] API endpoint and extracting the data that it
    displays out of the JSON returned in the HTTP response body.


*** issue 28: ads-github-fetch-all-upstreams: unset GREP_OPTIONS to make grep(1) behavior predictable

    https://github.com/salewski/ads-github-tools/issues/28

    The 'ads-github-fetch-all-upstreams' program now unconditionally unsets
    the GREP_OPTIONS environment variable.

    This only has an effect if the grep program in use is GNU grep; other grep
    implementations did not recognize or alter their behavior based on the
    'GREP_OPTIONS' variable. GNU grep prior to version 2.11 (~2014-11) would
    append values from this variable to the command line, which would make
    behavior of our invocations in the current program unpredictable. Versions
    of GNU grep 2.11 or newer no longer behave that way, but do emit a warning
    on stderr about the change in behavior.

    Unsetting GREP_OPTIONS here has the effect of making our grep invocations
    predictable (when older versions of GNU grep are in use) and also of
    suppressing the spurious warning:

        grep: warning: GREP_OPTIONS is deprecated; please use an alias or script

    when newer versions of GNU grep are in use.


*** issue 29: ads-github-merge-all-upstreams: unset GREP_OPTIONS to make grep(1) behavior predictable

    https://github.com/salewski/ads-github-tools/issues/29

    Application of the same improvement as described above for
    ads-github-merge-all-upstreams, only here for the
    ads-github-merge-all-upstreams tool.


*** issue 41: eyesore avoidance: say "sync" rather than "synch" everywhere

    https://github.com/salewski/ads-github-tools/issues/41

    This was a cosmetic issue with the documentation.


*** issue 45: migrate build to use automake-1.16

    https://github.com/salewski/ads-github-tools/issues/45

    The project is now developed using GNU Automake 1.16 (rather than version
    1.14).

    The currently used version of GNU Autoconf (2.69) has not changed, but a
    crufty reference to an older version in our 'bootstrap' script has been
    cleaned up.


* ads-github-tools 0.2.0 (2017-02-26)

** fixes

*** issue 20: ads-github-merge-all-upstream: typo in log message ("a al" ==> "a la")

    https://github.com/salewski/ads-github-tools/issues/20

    Fixed typo in log message.


*** issue 21: ads-github-merge-all-upstreams: no longer chokes when it encounters a "detached HEAD"

    https://github.com/salewski/ads-github-tools/issues/21

    Prior to this fix the program choked (when the repo directory was
    initially in a "detached HEAD" state) upon attempting to restore the
    working directory to the state it was in prior to the program switching to
    the default branch. This happened because the code only knew how to deal
    with a working directory "attached" to a named branch. Since the repo was
    originally in the detached HEAD state, the program did not have a named
    branch to which it could switch back.

    Rather than attempt to switch back to an explicitly named branch, the code
    now basically does this:

    :    git checkout @{-1}

    which you can read as: "where HEAD used to be one move ago (before we
    checked-out the default branch)".

    The impact of the original problem was that the
    'ads-github-merge-all-upstreams' program stopped dead in its tracks and
    left the repo directory with the default branch checked out.

    The workaround was to simply re-run the program leaving that repo with the
    default branch checked out. Because the program then found the repo with
    the default branch already checked out, it did not attempt to swicth the
    branch, so also did not need to attempt to restore it to its original
    state. Once the program completed, the user could then manually check out
    the tag (or whatever) to then put the repo back into the original detached
    HEAD state (if so desired).

    With this fix, such workarounds are no longer needed.


** improvements

*** issue 19: ads-github-merge-all-upstreams: avoid using 'git branch' porcelain command

    https://github.com/salewski/ads-github-tools/issues/19

    Replaced three invocations of the git porcelain command 'git branch' with
    (as appropriate) invocations of git plumbing commands:

    : git symbolic-ref --short --quiet HEAD

    or:

    : git for-each-ref --format='%(refname:short)' 'refs/heads/'

    or:

    : git for-each-ref --format='%(refname:short)' 'refs/remotes/upstream/'


*** issue 22: ads-github-fetch-all-upstreams: add feature to detect and pull down only "missing" repos

    A '-m' (--missing-only) command line option has been added to the
    'ads-github-fetch-all-upstreams' program. This new option provides a
    shorthand way of invoking:

    :    $ ads-github-fetch-all-upstreams -c <MISSING_REPO>...

    while at the same time limiting the program's behavior to /only/ missing
    repos. And it does so without the user having to explicitly name (or even
    know) the values for each missing repository name.

    In this context, a "missing repository" has the same meaning as it does
    for the '-c' (--clone-if-missing) option. That is: any repository from
    GitHub where the local git working directory is not present.

    The following is the equivalent invocation of the above:

    :    $ ads-github-fetch-all-upstreams -m

    The semantics of:

    :    $ ads-github-fetch-all-upstreams -m <REPO>...

    limits the operation of the program to only those explicitly named repos, and
    will clone them only if they are missing (that is, the program will not fetch
    changes from the corresponding upstream repo when the local repo is already
    present; see "Design Notes" section below for more on the rationale for this
    behavior). If any of the explicitly named repos are already present, then the
    program will print an error message and exit with a non-zero status at the end
    (after cloning all of the other explicitly named repos (if any)). This is
    intended to make the user aware of any repo names fat-fingered on the command
    line.

    Note that the '-m' (--missing-only) option implies '-c'
    (--clone-if-missing), so the '-c' in the following is redundant (but
    innocuous):

    :    $ ads-github-fetch-all-upstreams -m -c

    Said another way, the '--missing-only' option limits the behavior of the
    program to operate /only/ on repos that are missing, so the behavior of
    the program when '--missing-only' is specified is meaningless unless
    '--clone-if-missing' were also implied.

**** Design Notes

     The author considered making the semantics of the '--missing-only'
     option, when provided with explicitly named repo names on the command
     line, be "fetch (or clone) these particular repos plus any repos that are
     missing".

     That approach would be consistent with the behavior of:

     :    $ ads-github-fetch-all-upstreams -c <NONMISSING_REPO>...

     insofar as the repos would be cloned if they were missing, but fetched
     otherwise. That idea was ultimately rejected because it would fetch
     updates for the repo if its working directory happened to be
     present. That's not "missing only" behavior, so would make the behavior
     of '--missing-only' (or whatever the option would be named) more
     difficult to explain and comprehend. It's also not the common case itch
     being scratched.

     This decision does mean, though, that there is currently no way to express
     "fetch (or clone) these particular repos plus any repos that are missing" when
     one or more of the explicitly named repos is already present, yet still have
     the program exit with a zero exit status. This use case can, of course, be
     easily accommodated by using two separate invocations of the program:

     :    $ # first clone (as fast as possible) any missing repos...
     :    $ ads-github-fetch-all-upstreams -m
     :
     :    $ # ...and then fetch changes for explicitly named repos (note no need for '-c' here)
     :    $ ads-github-fetch-all-upstreams <REPO>...

     The second invocation in that example will be an elaborate NOOP when all of
     the explicitly named repos were freshly cloned by the first invocation.

     If this example represents your common use case and you find this behavior
     limiting or otherwise annoying, please contact the author as outlined in the
     [[https://github.com/salewski/ads-github-tools/blob/master/BUGS][BUGS]] file.


*** issue 23: ads-github-fetch-all-upstreams: only one unprocessed named repo noted in error message

    https://github.com/salewski/ads-github-tools/issues/23

    In the version of `'ads-github-fetch-all-upstreams'` shipped with
    `ads-github-tools-0.1.1`, when a user fat-fingered more than one repo name
    on the command line, the program printed an error message that named only
    the first unprocessed repo name that was detected.

    The current version of the program improves on that behavior to name /all/
    unprocessed repo names. This gives a better indication to the user about
    the size of the error, and also gives the user the opportunity to correct
    all such errors at once (rather than playing whack-a-mole fixing one at a
    time and having successive runs of the program fail on the remaining repos
    that were not named in the error message).


* ads-github-tools 0.1.1 (2016-09-26)

** fixes

*** issue 17: ads-github-merge-all-upstreams: stderr message on failed ff merge indicates "bailing out", which is not always true

    https://github.com/salewski/ads-github-tools/issues/17

    In the version of 'ads-github-merge-all-upstreams' distributed as part of
    ads-github-tools-0.1.0, the tool would emit an incorrect "bailing out"
    message when the tool's '-k' (--keep-going) option was speecified and a
    fast-forward merge is not possible for some reason:

    :    $ ads-github-merge-all-upstreams -vkpp
    :    ...
    :    ads-github-merge-all-upstreams (info): [repo: "foobar"] currently checked-out branch ("master") is the default branch (no need for checkout)
    :    fatal: Not possible to fast-forward, aborting.
    :    ads-github-merge-all-upstreams (error): [repo: "foobar"] was error while attempting to merge 'upstream/master'; bailing out
    :    ads-github-merge-all-upstreams (warning): '-k' (--keep-going) specified; continuing
    :    ads-github-merge-all-upstreams (info): [repo: "bazqux"] currently checked-out branch ("master") is the default branch (no need for checkout)
    :    Already up-to-date.
    :    ...

    That message is correct for the default behavior of the program (when the
    '-k' option is not specified, but when the '-k' option /is/ specified, the
    message should not have indicated that the program was "bailing out"; it
    was not correct, and gave the impression that the error detection is not
    working correctly.

    The program has been fixed to emit "context aware" messages in these
    scenarios. With the default invocation (no command line options specified)
    is the same as it was previously:

    :    $ ads-github-merge-all-upstreams
    :    ...
    :    fatal: Not possible to fast-forward, aborting.
    :    ads-github-merge-all-upstreams (error): [repo: "foobar"] was error while attempting to merge 'upstream/master'; bailing out
    :
    :    $ echo $?
    :    1

    When the '-k' (--keep-going) option is specified, the error message
    related to the failed fast-forward merge no longer indicates that the
    program is "bailing out":

    :    $ ads-github-merge-all-upstreams -k
    :    fatal: Not possible to fast-forward, aborting.
    :    ads-github-merge-all-upstreams (error): [repo: "serverless"] was error while attempting to merge 'upstream/master'
    :    ads-github-merge-all-upstreams (warning): '-k' (--keep-going) specified; continuing
    :    ...
    :    ads-github-merge-all-upstreams (error): one or more errors encountered with '-k' (--keep-going) specified (see error output above for details); bailing out
    :
    :    $ echo $?
    :    1

    Note that the error message from the 'git merge --ff-only ...' command
    invoked internally still indicates that it is "aborting". We hope that it
    is clear from context that that is not coming directly from the
    'ads-github-merge-all-upstreams' tool and that users are not confused by
    it.


*** issue 18: ads-github-merge-all-upstreams: suppress "no upstream changes to merge" messages unless verbose output requested

    https://github.com/salewski/ads-github-tools/issues/18

    The default output of the 'ads-github-merge-all-upstreams' program (that
    is, when the program is invoked with no command line options) was
    previously too chatty; it was emitting a bunch of "no upstream changes to
    merge" messages:

    :    ...
    :    ads-github-merge-all-upstreams (info): [repo: "foo"] no upstream changes to merge, and "aggressive push" (a al '-p -p') not specified; skipping (okay)
    :    ads-github-merge-all-upstreams (info): [repo: "bar"] no upstream changes to merge, and "aggressive push" (a al '-p -p') not specified; skipping (okay)
    :    ads-github-merge-all-upstreams (info): [repo: "baz"] no upstream changes to merge, and "aggressive push" (a al '-p -p') not specified; skipping (okay)
    :    ...

    The program now only emits those messages when the user requests verbose
    output via '-v' (--verbose) option.


** improvements

*** issue 16: ads-github-merge-all-upstreams: use 'git push origin heads/<BRANCH>' to avoid ambiguity with tags of the same name as <BRANCH>

    https://github.com/salewski/ads-github-tools/issues/16

    If a repository had a tag name that matched the default branch name
    (typically "master"), then the previous version of the program would not
    be able to push the merged changes to the origin repository because the
    git refspec used internally was ambiguous. The program has been enhanced
    to qualify the default branch name as "heads/<BRANCH>" rather than just
    "<BRANCH>" to remove this ambiguity.


* ads-github-tools 0.1.0 (2016-08-20)

** Initial version of project. The project currently provides five command line programs:

   + ads-github-normalize-url

     Produces a "normalized" view of a given URL, suitable for use in
     generating an ID. Currently is a quick 'n dirty implementation optimized
     for this sole purpose, so there's no guarantee that the normalized
     variation of the URL will actually work

   + ads-github-hash-url

     Similar in spirit to 'git-hash-object(1)', this tool takes a (presumably
     normalized) URL and emits a checksum for it. Currently uses the SHA-3
     256-bit algorithm variant.
  
   + ads-github-show-rate-limits

     Shows the user's GitHub API rate limits ("core" and "search").

   + ads-github-fetch-all-upstreams

     Operates on the working directories of a collection of GitHub-hosted git
     repositories. The user can specify one or more repositories explicitly to
     restrict operations to just those repos. Each that is found with an
     'upstream' remote defined will have 'git fetch upstream' invoked in it.
  
     - With the '--clone-if-missing' option, any of the user's GitHub repos
       for which there is not a git working directory beneath the current
       location will be cloned (using the 'git-hub' tool's 'clone' operation,
       which sets up the 'upstream' remote if the repo is a fork).

     - There's also an '--upstream-remote-if-missing' option that will add the
       'upstream' remote on existing project working directories that do not
       have it (only if the project is a fork of another project, of course).
    
   + ads-github-merge-all-upstreams

     Operates on the working directories of a collection of GitHub-hosted git
     repositories. Each that is found with both 'origin' and 'upstream'
     remotes defined will have:

     :    git merge --ff-only upstream/<DEFAULT_BRANCH_NAME>

     invoked in it. The user can specify one or more repositories explicitly
     to restrict operations to just those repos. The program is careful to
     sanity check the local repository before attempting any operations on
     it. Also, it will skip any repository for which the git index has any
     changes recorded. Will (temporarily) check out the default branch before
     merging (if the working directory happens to have some other branch
     checked out); will restore the originally checked out branch when done if
     the temporary switch was necessary.

     - With the '--push' option, will invoke:

       :    git push origin <DEFAULT_BRANCH_NAME>

       for each repo.
