Full Code of tj/git-extras for AI

main 65dd36ae62ce cached
364 files
1.0 MB
333.8k tokens
112 symbols
1 requests
Download .txt
Showing preview only (1,106K chars total). Download the full file or copy to clipboard to get everything.
Repository: tj/git-extras
Branch: main
Commit: 65dd36ae62ce
Files: 364
Total size: 1.0 MB

Directory structure:
gitextract_to9razmh/

├── .editorconfig
├── .github/
│   ├── .ignore_words
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── ci.yml
│       └── stale.yaml
├── .gitignore
├── .gitmodules
├── .pytest.ini
├── AUTHORS
├── CONTRIBUTING.md
├── Commands.md
├── History.md
├── Installation.md
├── LICENSE
├── Makefile
├── Readme.md
├── bin/
│   ├── git-abort
│   ├── git-alias
│   ├── git-archive-file
│   ├── git-authors
│   ├── git-browse
│   ├── git-browse-ci
│   ├── git-brv
│   ├── git-bulk
│   ├── git-changelog
│   ├── git-clear
│   ├── git-clear-soft
│   ├── git-coauthor
│   ├── git-commits-since
│   ├── git-contrib
│   ├── git-count
│   ├── git-cp
│   ├── git-create-branch
│   ├── git-delete-branch
│   ├── git-delete-merged-branches
│   ├── git-delete-squashed-branches
│   ├── git-delete-submodule
│   ├── git-delete-tag
│   ├── git-delta
│   ├── git-effort
│   ├── git-extras
│   ├── git-feature
│   ├── git-force-clone
│   ├── git-fork
│   ├── git-fresh-branch
│   ├── git-get
│   ├── git-gh-pages
│   ├── git-graft
│   ├── git-guilt
│   ├── git-ignore
│   ├── git-ignore-io
│   ├── git-info
│   ├── git-local-commits
│   ├── git-lock
│   ├── git-locked
│   ├── git-magic
│   ├── git-merge-into
│   ├── git-merge-repo
│   ├── git-missing
│   ├── git-mr
│   ├── git-obliterate
│   ├── git-paste
│   ├── git-pr
│   ├── git-psykorebase
│   ├── git-pull-request
│   ├── git-reauthor
│   ├── git-rebase-patch
│   ├── git-release
│   ├── git-rename-branch
│   ├── git-rename-file
│   ├── git-rename-remote
│   ├── git-rename-tag
│   ├── git-repl
│   ├── git-reset-file
│   ├── git-root
│   ├── git-scp
│   ├── git-sed
│   ├── git-setup
│   ├── git-show-merged-branches
│   ├── git-show-tree
│   ├── git-show-unmerged-branches
│   ├── git-squash
│   ├── git-stamp
│   ├── git-standup
│   ├── git-summary
│   ├── git-sync
│   ├── git-touch
│   ├── git-undo
│   ├── git-unlock
│   ├── git-unwip
│   ├── git-utimes
│   └── git-wip
├── brew-release.patch
├── check_dependencies.sh
├── check_integrity.sh
├── etc/
│   ├── bash_completion.sh
│   ├── git-extras-completion.zsh
│   └── git-extras.fish
├── helper/
│   ├── git-extra-utility
│   ├── has-git-commit
│   ├── is-git-repo
│   └── reset-env
├── install.cmd
├── install.sh
├── man/
│   ├── Readme.md
│   ├── git-abort.1
│   ├── git-abort.html
│   ├── git-abort.md
│   ├── git-alias.1
│   ├── git-alias.html
│   ├── git-alias.md
│   ├── git-archive-file.1
│   ├── git-archive-file.html
│   ├── git-archive-file.md
│   ├── git-authors.1
│   ├── git-authors.html
│   ├── git-authors.md
│   ├── git-browse-ci.1
│   ├── git-browse-ci.html
│   ├── git-browse-ci.md
│   ├── git-browse.1
│   ├── git-browse.html
│   ├── git-browse.md
│   ├── git-brv.1
│   ├── git-brv.html
│   ├── git-brv.md
│   ├── git-bulk.1
│   ├── git-bulk.html
│   ├── git-bulk.md
│   ├── git-changelog.1
│   ├── git-changelog.html
│   ├── git-changelog.md
│   ├── git-clear-soft.1
│   ├── git-clear-soft.html
│   ├── git-clear-soft.md
│   ├── git-clear.1
│   ├── git-clear.html
│   ├── git-clear.md
│   ├── git-coauthor.1
│   ├── git-coauthor.html
│   ├── git-coauthor.md
│   ├── git-commits-since.1
│   ├── git-commits-since.html
│   ├── git-commits-since.md
│   ├── git-continue.1
│   ├── git-continue.html
│   ├── git-continue.md
│   ├── git-contrib.1
│   ├── git-contrib.html
│   ├── git-contrib.md
│   ├── git-count.1
│   ├── git-count.html
│   ├── git-count.md
│   ├── git-cp.1
│   ├── git-cp.html
│   ├── git-cp.md
│   ├── git-create-branch.1
│   ├── git-create-branch.html
│   ├── git-create-branch.md
│   ├── git-delete-branch.1
│   ├── git-delete-branch.html
│   ├── git-delete-branch.md
│   ├── git-delete-merged-branches.1
│   ├── git-delete-merged-branches.html
│   ├── git-delete-merged-branches.md
│   ├── git-delete-squashed-branches.1
│   ├── git-delete-squashed-branches.html
│   ├── git-delete-squashed-branches.md
│   ├── git-delete-submodule.1
│   ├── git-delete-submodule.html
│   ├── git-delete-submodule.md
│   ├── git-delete-tag.1
│   ├── git-delete-tag.html
│   ├── git-delete-tag.md
│   ├── git-delta.1
│   ├── git-delta.html
│   ├── git-delta.md
│   ├── git-effort.1
│   ├── git-effort.html
│   ├── git-effort.md
│   ├── git-extras.1
│   ├── git-extras.html
│   ├── git-extras.md
│   ├── git-feature.1
│   ├── git-feature.html
│   ├── git-feature.md
│   ├── git-force-clone.1
│   ├── git-force-clone.html
│   ├── git-force-clone.md
│   ├── git-fork.1
│   ├── git-fork.html
│   ├── git-fork.md
│   ├── git-fresh-branch.1
│   ├── git-fresh-branch.html
│   ├── git-fresh-branch.md
│   ├── git-get.1
│   ├── git-get.html
│   ├── git-get.md
│   ├── git-gh-pages.1
│   ├── git-gh-pages.html
│   ├── git-gh-pages.md
│   ├── git-graft.1
│   ├── git-graft.html
│   ├── git-graft.md
│   ├── git-guilt.1
│   ├── git-guilt.html
│   ├── git-guilt.md
│   ├── git-ignore-io.1
│   ├── git-ignore-io.html
│   ├── git-ignore-io.md
│   ├── git-ignore.1
│   ├── git-ignore.html
│   ├── git-ignore.md
│   ├── git-info.1
│   ├── git-info.html
│   ├── git-info.md
│   ├── git-local-commits.1
│   ├── git-local-commits.html
│   ├── git-local-commits.md
│   ├── git-lock.1
│   ├── git-lock.html
│   ├── git-lock.md
│   ├── git-locked.1
│   ├── git-locked.html
│   ├── git-locked.md
│   ├── git-magic.1
│   ├── git-magic.html
│   ├── git-magic.md
│   ├── git-merge-into.1
│   ├── git-merge-into.html
│   ├── git-merge-into.md
│   ├── git-merge-repo.1
│   ├── git-merge-repo.html
│   ├── git-merge-repo.md
│   ├── git-missing.1
│   ├── git-missing.html
│   ├── git-missing.md
│   ├── git-mr.1
│   ├── git-mr.html
│   ├── git-mr.md
│   ├── git-obliterate.1
│   ├── git-obliterate.html
│   ├── git-obliterate.md
│   ├── git-paste.1
│   ├── git-paste.html
│   ├── git-paste.md
│   ├── git-pr.1
│   ├── git-pr.html
│   ├── git-pr.md
│   ├── git-psykorebase.1
│   ├── git-psykorebase.html
│   ├── git-psykorebase.md
│   ├── git-pull-request.1
│   ├── git-pull-request.html
│   ├── git-pull-request.md
│   ├── git-reauthor.1
│   ├── git-reauthor.html
│   ├── git-reauthor.md
│   ├── git-rebase-patch.1
│   ├── git-rebase-patch.html
│   ├── git-rebase-patch.md
│   ├── git-release.1
│   ├── git-release.html
│   ├── git-release.md
│   ├── git-rename-branch.1
│   ├── git-rename-branch.html
│   ├── git-rename-branch.md
│   ├── git-rename-file.1
│   ├── git-rename-file.html
│   ├── git-rename-file.md
│   ├── git-rename-remote.1
│   ├── git-rename-remote.html
│   ├── git-rename-remote.md
│   ├── git-rename-tag.1
│   ├── git-rename-tag.html
│   ├── git-rename-tag.md
│   ├── git-repl.1
│   ├── git-repl.html
│   ├── git-repl.md
│   ├── git-reset-file.1
│   ├── git-reset-file.html
│   ├── git-reset-file.md
│   ├── git-root.1
│   ├── git-root.html
│   ├── git-root.md
│   ├── git-scp.1
│   ├── git-scp.html
│   ├── git-scp.md
│   ├── git-sed.1
│   ├── git-sed.html
│   ├── git-sed.md
│   ├── git-setup.1
│   ├── git-setup.html
│   ├── git-setup.md
│   ├── git-show-merged-branches.1
│   ├── git-show-merged-branches.html
│   ├── git-show-merged-branches.md
│   ├── git-show-tree.1
│   ├── git-show-tree.html
│   ├── git-show-tree.md
│   ├── git-show-unmerged-branches.1
│   ├── git-show-unmerged-branches.html
│   ├── git-show-unmerged-branches.md
│   ├── git-squash.1
│   ├── git-squash.html
│   ├── git-squash.md
│   ├── git-stamp.1
│   ├── git-stamp.html
│   ├── git-stamp.md
│   ├── git-standup.1
│   ├── git-standup.html
│   ├── git-standup.md
│   ├── git-summary.1
│   ├── git-summary.html
│   ├── git-summary.md
│   ├── git-sync.1
│   ├── git-sync.html
│   ├── git-sync.md
│   ├── git-touch.1
│   ├── git-touch.html
│   ├── git-touch.md
│   ├── git-undo.1
│   ├── git-undo.html
│   ├── git-undo.md
│   ├── git-unlock.1
│   ├── git-unlock.html
│   ├── git-unlock.md
│   ├── git-unwip.1
│   ├── git-unwip.html
│   ├── git-unwip.md
│   ├── git-utimes.1
│   ├── git-utimes.html
│   ├── git-utimes.md
│   ├── git-wip.1
│   ├── git-wip.html
│   ├── git-wip.md
│   ├── index.txt
│   └── man-template.md
├── need_git_commit
├── not_need_git_repo
├── scripts/
│   └── checkstyle.py
└── tests/
    ├── README.md
    ├── bin/
    │   ├── open
    │   ├── start
    │   └── xdg-open
    ├── conftest.py
    ├── git-abort.bats
    ├── git-alias.bats
    ├── git-archive-file.bats
    ├── git-authors.bats
    ├── git-browse-ci.bats
    ├── git-browse.bats
    ├── git-continue.bats
    ├── helper.py
    ├── pyproject.toml
    ├── test_git_abort.py
    ├── test_git_alias.py
    ├── test_git_archive_file.py
    ├── test_git_authors.py
    ├── test_git_browse.py
    ├── test_git_browse_ci.py
    ├── test_git_continue.py
    └── test_util.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
indent_style = space
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[Makefile]
indent_style = tab

[*.patch]
trim_trailing_whitespace = false

[*.md]
trim_trailing_whitespace = false

[*.html]
trim_trailing_whitespace = false

[*.py]
indent_size = 4

[*.bats]
indent_style = tab
indent_size = 4

[tests/*.sh]
indent_style = tab
indent_size = 4


================================================
FILE: .github/.ignore_words
================================================
gool
Cant


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--

Note

* Mark the PR as draft until it's ready to be reviewed.
* Please update the documentation to reflect the changes made in the PR.
* If the command is covered by tests under ./tests, please add/update tests for any changes unless you have a good reason. 
* Make a new commit to resolve conversations instead of `push -f`.
* To resolve merge conflicts, merge from the `main` branch instead of rebasing over `main`.
* Please wait for the reviewer to mark a conversation as resolved.

-->


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"


================================================
FILE: .github/workflows/ci.yml
================================================
name: ci
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Check out code.
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - name: 'Get Changed Files'
        id: 'files'
        run: |
          CHANGED_FILES=$(git diff --name-only "${BASE_SHA:-$BEFORE_SHA}...${HEAD_SHA:-$GITHUB_REF}")
          echo "::notice::Changed files: $CHANGED_FILES"
          {
            echo "added_modified<<EOF"
            echo "$CHANGED_FILES"
            echo "EOF"
          } >> "$GITHUB_OUTPUT"
        env:
          BASE_SHA: ${{ github.event.pull_request.base.sha }}
          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
          BEFORE_SHA: "${{ github.event.before }}"
      - uses: 'actions/setup-go@v6'
        with:
          go-version: '1.20'
      - name: 'Install EditorConfig Lint'
        run: go install 'github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@latest'
      - name: 'Check EditorConfig Lint'
        run: echo "$FILES" | xargs ~/go/bin/editorconfig-checker
        env:
          # NOTE: use env to pass the output in order to avoid possible injection attacks
          FILES: "${{ steps.files.outputs.added_modified }}"
      - name: checkstyle
        run: ./scripts/checkstyle.py
      - name: Shellcheck
        run: shellcheck --severity=error bin/* ./*.sh
      - name: Lint and format Python with Ruff
        uses: astral-sh/ruff-action@v3

  typo:
    runs-on: ubuntu-latest
    steps:
      - name: Check out code.
        uses: actions/checkout@v6
      - name: Install poetry
        run: pip install poetry
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          cache: 'poetry'
          cache-dependency-path: "tests/pyproject.toml"
          python-version-file: "tests/pyproject.toml"
      - name: Install dependencies
        run: |
          cd tests || exit
          poetry install --only dev
      - name: spell check
        run: |
          cd tests
          git grep --cached -l '' .. | \
            grep -v -e 'History\.md' -e 'AUTHORS' -e 'man/.*\.1' -e 'man/.*\.html' | \
            xargs poetry run codespell --ignore-words=../.github/.ignore_words

  test-pytest:
    name: 'Test with Pytest'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
           submodules: recursive
      - name: Install poetry
        run: pip install poetry
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: '3.12'
          cache: 'poetry'
          cache-dependency-path: "tests/pyproject.toml"
          python-version-file: "tests/pyproject.toml"
      - name: Install Python Dependencies
        run: |
          cd tests || exit
          poetry install --only test
      - name: Test with Pytest
        run: |
          cd tests
          poetry run pytest

  test-bats:
    name: 'Test with Bats'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
           submodules: recursive
      - name: Setup Bats
        id: setup-bats
        uses: bats-core/bats-action@4.0.0
        with:
          bats-version: 'v1.8.1'
      - name: Test with Bats
        env:
         BATS_LIB_PATH: ${{ steps.setup-bats.outputs.lib-path }}
         TERM: xterm
        run: bats ./tests

  build:
    strategy:
      fail-fast: false
      matrix:
        platform:
          - ubuntu-latest
          - macos-latest
    runs-on: ${{ matrix.platform }}
    steps:
      - name: Check out code.
        uses: actions/checkout@v6
      - name: Linux Install
        if: matrix.platform == 'ubuntu-latest'
        run: sudo apt-get install -y bsdmainutils
      - name: Script
        run: ./check_integrity.sh
      - name: Brew release
        if: matrix.platform == 'macos-latest'
        run: |
          mkdir ../release && git archive --format=tar.gz HEAD > ../release/git-extras-release.tar.gz
          cd ../release
          tar -xzf git-extras-release.tar.gz && make PREFIX=$(pwd) INSTALL_VIA=brew
          ./bin/git-extras update | grep "brew upgrade git-extras"


================================================
FILE: .github/workflows/stale.yaml
================================================
name: "Maintenance: Close Stale PRs"
on:
  schedule:
    - cron: "30 1 * * *"

permissions:
  pull-requests: "write"

jobs:
  stale:
    runs-on: "ubuntu-latest"
    if: github.repository_owner == 'tj'
    steps:
      - uses: "actions/stale@v10"
        with:
          close-pr-message: "This PR was closed because it has been stalled for 365 days with no activity. Feel free to make a new PR if you wish to continue"
          days-before-pr-stale: 350
          days-before-pr-close: 15


================================================
FILE: .gitignore
================================================
.venv/
__pycache__/
coverage/


================================================
FILE: .gitmodules
================================================
[submodule "vendor/bats-all"]
	path = vendor/bats-all
	url = https://github.com/hyperupcall/bats-all


================================================
FILE: .pytest.ini
================================================
[pytest]
minversion = 7.4
addopts = -ra -q
testpaths = tests
faulthandler_timeout = 5


================================================
FILE: AUTHORS
================================================
git-extras is written and maintained by various contributors:

Maintainers
```````````
- TJ Holowaychuk <tj@vision-media.ca>
- Hemanth.HM <hemanth.hm@gmail.com>
- Nimit Kalra <me@nimit.io>
- Nicolai Skogheim <nicolai.skogheim@gmail.com>
- spacewander <spacewanderlzx@gmail.com>
- Edwin Kofler <edwin@kofler.dev>
- Leroy <vanpipy@gmail.com>

Patches and Suggestions
```````````````````````
- Jonhnny Weslley
- Tobias Fendin
- LeeW
- timfeirg
- Niklas Schlimm
- nickl-
- CJ
- Paul Wise
- Damien Tardy-Panis
- Mark Eissler
- Yuriy VG
- Leila Muhtasib
- Richard Fearn
- Bill Wood
- Jesús Espino
- Rémy HUBSCHER
- go2null
- Andrew Janke
- David Baumgold
- Jan Schulz
- Kenneth Reitz
- Leroy
- Mark Pitman
- Peter Benjamin
- Günther Grill
- Luke Childs
- Sasha Khamkov
- equt
- oikarinen
- vyas
- Don Harper
- Pierre Ayoub
- Robin Winslow
- Ross Smith II
- Yi EungJun
- dependabot[bot]
- grindhold
- wyattscarpenter
- Aggelos Orfanakos
- Camille Reynders
- Carlos Prado
- Chris Hall
- Damian Krzeminski
- NANRI
- Alexander Krasnukhin
- Phally
- Rico Sta. Cruz
- Takuma Yamaguchi
- thomas menzel
- vr8ce
- Brian J Brennan
- Dominik Gedon
- Hogan Long
- Ivan Malopinsky
- Jonathan "Duke" Leto
- Julio Napurí
- Justin Dugger
- Nils Winkler
- Philipp Klose
- Raphael Boidol
- Richard Russon
- Sam Bostock
- Vladimir Jimenez
- gisphm
- jacobherrington
- overengineer
- phigoro
- wooorm
- Alexis GRIMALDI
- Allan Odgaard
- Andre Cerqueira
- Austin Ziegler
- Beth Skurrie
- Brice Dutheil
- Curtis McEnroe
- David Rogers
- Devin Withers
- Domenico Rotiroti
- Evan Grim
- Florian H
- Gert Van Gool
- Guillaume Seren
- Hozefa
- Igor Ostapenko
- Jean Jordaan
- Joshua Li
- Justin Guenther
- Kylie McClain
- Marc Harter
- Matiss
- Nate Jones
- Newell Zhu
- Patryk Małek
- Paul Schreiber
- Richard Littauer
- Tjaart van der Walt
- Tom Vincent
- Wil Moore III
- William Montgomery
- Ye Lin Aung
- luozexuan
- roxchgt
- soffolk
- 0xflotus
- Abdullah
- Adam Parkin
- Adriaan Zonnenberg
- Akim Demaille
- Alessandro Pagiaro
- Alex McHale
- Aloxaf
- Amir Tocker
- Ammar Najjar
- Amory Meltzer
- Andreas Duering
- Andrei Petcu
- Andrew Griffiths
- Andrew Marcinkevičius
- Andrew Starr-Bochicchio
- Andrew Sullivan Cant
- Andrey Elizarov
- Angel Aguilera
- Antoine Beaupré
- Aurélien Scoubeau
- Balazs Nadasdi
- Ben Parnell
- Beni Ben Zikry
- Brandon Zylstra
- Brian Goad
- Brian Murrell
- Bruno Sutic
- Caleb Maclennan
- Carl Casbolt
- Carlos Rodríguez
- Christophe Badoit
- Ciro Nunes
- CleanMachine1
- CodeByZach
- Craig MacGregor
- Dan Goodliffe
- Dan Jackson
- Dan Kilman
- Daniel Bruder
- Daniel Lublin
- Daniel Schildt
- Dave James Miller
- David Hartmann
- Dominic Barnes
- Dung Quang
- Edward Betts
- Eli Schwartz
- Emil Kjelsrud
- François M
- George Crabtree
- Gerrit-K
- Greg Allen
- Guilhem Saurel
- Guillermo Rauch
- Gunnlaugur Thor Briem
- Hasse Ramlev Hansen
- Heiko Becker
- Isaac Mungai
- J.C. Yamokoski
- Jack O. Wasey
- James Manning
- James Zhu
- Jan Krueger
- Jared Baur
- Jarod Stewart
- Jason Young
- Jens K. Mueller
- Jeremy Lin
- Jesse Sipprell
- Jianjin Fan
- Jobin Kurian
- Johannes Ewald
- John Evans
- John Hoffmann
- Jon Ander Peñalba
- Josh McKinney
- Joshua Appelman
- José María Gutiérrez @TheTechOddBug
- Katrin Leinweber
- Kevin Woo
- Konstantin Schukraft
- Kurban Mallachiev
- Leandro López
- Lone
- Luis Miguel Hernanz
- Maarten Winter
- Marco Glasbergen
- Matan Rosenberg
- Mathieu D. (MatToufoutu)
- Matt
- Matt Colyer
- Matt Headley
- Matthew Avant
- Mattias Andersson
- Michael Komitee
- Michael Matuzak
- Michele Bologna
- Montak Oleg
- Moritz Grauel
- Nate Eagleson
- Nate Fischer
- Nathan Rajlich
- Nick Campbell
- Nick Payne
- Nicolas Kosinski
- Niklas Fiekas
- Oliver Kopp
- Orestis
- Peter Bittner
- Piotr Górski
- Prayag Verma
- Przemek Kitszel
- R. Martinho Fernandes
- Raphael Fleischlin
- Rasmus Wriedt Larsen
- René
- Revisor
- Riceball LEE
- Rob Kennedy
- Robin von Bülow
- Ryan Bohn
- Sachin Gupta
- Sam Thursfield
- Sandro
- Sascha Andres
- SchleimKeim
- Sean Molenaar
- Sebastian Gniazdowski
- Sebastián Mancilla
- Simon Tate
- Stefan VanBuren
- Stephen Mathieson
- Steve Mao
- Stu Feldt
- SukkaW
- Tim Preston
- Timothy Hwang
- Tin Lai
- Todd Wolfson
- Tom Andrade
- Tom Ashworth
- Tony
- TweeKane
- Valérian Galliat
- Vitaly Chikunov
- Wei Lee
- Wei Wu
- Wen Sun
- Wiktor Żurawik
- Xavier Krantz
- Xiaopei Li
- Zeeshan Ahmed
- ax1036
- creynders
- dead-horse
- eszabpt
- fengkx
- jykntr
- kang
- meza
- neydroid
- nulltask
- sgleizes
- tfendin
- tiemonl
- zentarul
- zeroDivisible
- zhiyanfoo
- Áron Hoffmann
- Étienne BERSAC
- ☃ pitr
- 单元源


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

Thanks for contributing! Please read this document before you make a PR.

## Supported Platforms

Any changes must support the following platforms:

- macOS
- Linux
- OpenBSD (You may need to browse their man page)

Your change must also be compatible with the dependency constraints that we specify in [Installation](./Installation.md). If you aren't sure if a feature is compatible, check the manual or release notes. For example, the Bash changelog is [here](https://git.savannah.gnu.org/cgit/bash.git/tree/NEWS?h=devel).

If you aren't able to test your new command on a platform, make that clear in your PR; someone else may be able to test it on their system.

## Adding a New Command

Let's say you wish to add a new command. Assuming your new command is named `foo`:

1. Write a bash script under `./bin` called `git-foo`. The script should be started with `#!/usr/bin/env bash`.
2. Read `./man/Readme.md` and write documentation for `git-foo`.
3. Don't forget to introduce it in `Commands.md`.
4. Update `./etc/git-extras-completion.zsh`. Just follow existing code.
5. (Optional) Update `./etc/bash_completion.sh`.
6. (Optional) Update `./etc/git-extras.fish`.
7. (Optional) Add a test under `./tests`.
8. Run `./check_integrity.sh foo` to check if all done. (You may also run `./check_integrity.sh` to check all commands.)

You are welcome to open up an issue to discuss new commands or features before opening a pull request.

## Submitting a pull request

Please follow the suggestion in `./.github/PULL_REQUEST_TEMPLATE.md`.


================================================
FILE: Commands.md
================================================

 - [`git abort`](#git-abort)
 - [`git alias`](#git-alias)
 - [`git archive-file`](#git-archive-file)
 - [`git authors`](#git-authors)
 - [`git browse`](#git-browse)
 - [`git browse-ci`](#git-browse-ci)
 - [`git bulk`](#git-bulk)
 - [`git brv`](#git-brv)
 - [`git changelog`](#git-changelog)
 - [`git clear`](#git-clear)
 - [`git clear-soft`](#git-clear-soft)
 - [`git coauthor`](#git-coauthor)
 - [`git commits-since`](#git-commits-since)
 - [`git continue`](#git-continue)
 - [`git contrib`](#git-contrib)
 - [`git count`](#git-count)
 - [`git cp`](#git-cp)
 - [`git create-branch`](#git-create-branch)
 - [`git delete-branch`](#git-delete-branch)
 - [`git delete-merged-branches`](#git-delete-merged-branches)
 - [`git delete-squashed-branches`](#git-delete-squashed-branches)
 - [`git delete-submodule`](#git-delete-submodule)
 - [`git delete-tag`](#git-delete-tag)
 - [`git delta`](#git-delta)
 - [`git effort`](#git-effort)
 - [`git extras`](#git-extras)
 - [`git feature`](#git-feature)
 - [`git force-clone`](#git-force-clone)
 - [`git fork`](#git-fork)
 - [`git fresh-branch`](#git-fresh-branch)
 - [`git get`](#git-get)
 - [`git gh-pages`](#git-gh-pages)
 - [`git graft`](#git-graft)
 - [`git guilt`](#git-guilt)
 - [`git ignore`](#git-ignore)
 - [`git ignore-io`](#git-ignore-io)
 - [`git info`](#git-info)
 - [`git local-commits`](#git-local-commits)
 - [`git lock`](#git-lock)
 - [`git locked`](#git-locked)
 - [`git magic`](#git-magic)
 - [`git merge-into`](#git-merge-into)
 - [`git merge-repo`](#git-merge-repo)
 - [`git missing`](#git-missing)
 - [`git mr`](#git-mr)
 - [`git obliterate`](#git-obliterate)
 - [`git paste`](#git-paste)
 - [`git pr`](#git-pr)
 - [`git psykorebase`](#git-psykorebase)
 - [`git pull-request`](#git-pull-request)
 - [`git reauthor`](#git-reauthor)
 - [`git rebase-patch`](#git-rebase-patch)
 - [`git release`](#git-release)
 - [`git rename-branch`](#git-rename-branch)
 - [`git rename-file`](#git-rename-file)
 - [`git rename-tag`](#git-rename-tag)
 - [`git rename-remote`](#git-rename-remote)
 - [`git repl`](#git-repl)
 - [`git reset-file`](#git-reset-file)
 - [`git root`](#git-root)
 - [`git rscp`](#git-scp)
 - [`git scp`](#git-scp)
 - [`git sed`](#git-sed)
 - [`git setup`](#git-setup)
 - [`git show-merged-branches`](#git-show-merged-branches)
 - [`git show-tree`](#git-show-tree)
 - [`git show-unmerged-branches`](#git-show-unmerged-branches)
 - [`git stamp`](#git-stamp)
 - [`git squash`](#git-squash)
 - [`git standup`](#git-standup)
 - [`git summary`](#git-summary)
 - [`git sync`](#git-sync)
 - [`git touch`](#git-touch)
 - [`git undo`](#git-undo)
 - [`git unlock`](#git-unlock)
 - [`git utimes`](#git-utimes)
 - [`git unwip`](#git-unwip)
 - [`git wip`](#git-wip)

## git extras

The main `git-extras` command.

Output the current `--version`:

```bash
$ git extras --version
```

List available commands:

```bash
$ git extras --help
```

Update to the latest `git-extras`:

```bash
$ git extras update
```
## git gh-pages

Sets up the `gh-pages` branch.  (See [GitHub Pages](https://pages.github.com/) documentation.)

## git feature

Create/Merge the given feature branch `name`:

```bash
$ git feature dependencies
```

To Setup a remote tracking branch:

```bash
$ git feature dependencies -r upstream
```
_Note_: If no remote name is passed with the `-r` option, it will push to _origin_.

Afterwards, the same command will check it out:

```bash
$ git checkout master
$ git feature dependencies
```

When finished, we can `feature finish` to merge it into the current branch:

```bash
$ git checkout master
$ git feature finish dependencies
```

_Note_: If a remote is setup to track the branch, it will be deleted.

## git contrib

Output `author`'s contributions to a project:

```bash
$ git contrib visionmedia
visionmedia (18):
  Export STATUS_CODES
  Replaced several Array.prototype.slice.call() calls with Array.prototype.unshift.call()
  Moved help msg to node-repl
  Added multiple arg support for sys.puts(), print(), etc.
  Fix stack output on socket error
  ...
```

## git summary

Outputs a repo or path summary:

```bash
$ git summary

project     : git-extras
repo age    : 10 months ago
branch      : master
last active : 3 weeks ago
active on   : 93 days
commits     : 163
files       : 93
uncommitted : 3
authors     :
   97   Tj Holowaychuk          59.5%
   37   Jonhnny Weslley         22.7%
    8   Kenneth Reitz           4.9%
    5   Aggelos Orfanakos       3.1%
    3   Jonathan "Duke" Leto    1.8%
    2   Gert Van Gool           1.2%
    2   Domenico Rotiroti       1.2%
    2   Devin Withers           1.2%
    2   TJ Holowaychuk          1.2%
    1   Nick Campbell           0.6%
    1   Alex McHale             0.6%
    1   Jason Young             0.6%
    1   Jens K. Mueller         0.6%
    1   Guillermo Rauch         0.6%
```

This command can also take a *committish*, and will print a summary for commits in
the committish range:

```bash
$ git summary v42..
```

This command can also take an options `--line`, will print a summary by lines

```bash
$ git summary --line

project  : git-extras
 lines    : 8420
 authors  :
 2905 Tj Holowaychuk            34.5%
 1901 Jonhnny Weslley           22.6%
 1474 nickl-                    17.5%
  653 Leila Muhtasib            7.8%
  275 Tony                      3.3%
  267 Jesús Espino             3.2%
  199 Philipp Klose             2.4%
  180 Michael Komitee           2.1%
  178 Tom Vincent               2.1%
  119 TJ Holowaychuk            1.4%
  114 Damian Krzeminski         1.4%
   66 Kenneth Reitz             0.8%
   22 Not Committed Yet         0.3%
   17 David Baumgold            0.2%
   12 Brian J Brennan           0.1%
    6 Leandro López            0.1%
    6 Jan Krueger               0.1%
    6 Gunnlaugur Thor Briem     0.1%
    3 Hogan Long                0.0%
    3 Curtis McEnroe            0.0%
    3 Alex McHale               0.0%
    3 Aggelos Orfanakos         0.0%
    2 Phally                    0.0%
    2 NANRI                     0.0%
    2 Moritz Grauel             0.0%
    1 Jean Jordaan              0.0%
    1 Daniel Schildt            0.0%
```

The `--line` option can also take a path, which will print a filtered summary for that folder or file.

The option `--output-style` tries to put as much summary information of the repo into defined styled way as possible.
This is how the `tabular` output style and `oneline` output style look like

```bash
$ git summary --output-style tabular
# Repo     | Age       | Last active | Active on | Commits | Uncommitted | Branch
git-extras | 13 years  | 7 hours ago | 807 days  | 1703    | 3           | master

$ git summary --output-style oneline
git-extras / age: 13 years / last active: 7 hours ago / active on 807 days / commits: 1703 / uncommitted: 3 / branch: master
```

## git effort

  Displays "effort" statistics, currently just the number of commits per file, showing highlighting where the most activity is. The "active days" column is the total number of days which contributed modifications to this file.

```
node (master): git effort --above 15 {src,lib}/*
```

  If you wish to ignore files with commits `<=` a value you may use `--above`:

```
$ git effort --above 5
```

  If you wish to see only the commits in the last month you may use `--since` (it supports the same syntax like `git log --since`):

```
 $ git effort -- --since='last month'
```

  By default `git ls-files` is used, however you may pass one or more files to `git-effort(1)`, for example:

```
$ git effort bin/* lib/*
```

## git bulk

`git bulk` adds convenient support for operations that you want to execute on multiple git repositories.

  * simply register workspaces that contain multiple git repos in their directory structure
  * run any git command on the repositories of the registered workspaces in one command to `git bulk`
  * use the "guarded mode" to check on each execution

```bash
usage: git bulk [-g] ([-a]|[-w <ws-name>]) <git command>
       git bulk --addworkspace <ws-name> <ws-root-directory> (--from <URL or file>)
       git bulk --removeworkspace <ws-name>
       git bulk --addcurrent <ws-name>
       git bulk --purge
       git bulk --listall
```

  Register a workspace so that `git bulk` knows about it (it will be registered in your `.gitconfig`):

```bash
$ git bulk --addworkspace personal ~/workspaces/personal
```

  Notice that `<ws-root-directory>` must be an absolute path (or an environment variable pointing to an absolute path).
  In the case of a **single quoted environment variable**, it will be dereferenced at `git-bulk` runtime, suitable for dynamic workspaces (*e.g.*, defined in your `.bashrc`).
  As an illustration:

```bash
$ git bulk --addworkspace personal '$PERSONAL_WORKSPACE'
```

  With option `--from` the URL to a single repository or a file containing multiple URLs can be added and they will be cloned directly into the workspace. Suitable for the initial setup of a multi-repo project.

```bash
$ git bulk --addworkspace projectX ~/workspaces/projectx --from https://github.com/x/project-x.git

# OR with a file containing many repositories on each line:
$ git bulk --addworkspace projectX ~/workspaces/projectx --from ~/workspaces/repositories.txt
```
with `repositories.txt` be like:
```
https://github.com/x/project-x-1.git
https://github.com/x/project-x-2.git
https://github.com/x/project-x-3.git
```

  Register the current directory as a workspace to `git bulk`

```bash
$ git bulk --addcurrent personal
```

  List all registered workspaces:

```bash
$ git bulk --listall
bulkworkspaces.personal /Users/niklasschlimm/workspaces/personal

```

  Run a git command on the repositories of the current workspace:

```bash
$ git bulk fetch
```

![fetchdemo](https://cloud.githubusercontent.com/assets/876604/23709805/e8178406-041a-11e7-9a0c-01de5fbf8944.png)

  Run a git command on one specific workspace and its repositories:

```bash
$ git bulk -w personal fetch
```

  Run a git command on all workspaces and their repositories:

```bash
$ git bulk -a fetch
```

  Run a git command but ask user for confirmation on every execution (guarded mode):

```bash
$ git bulk -g fetch
```

  Remove a registered workspace:

```bash
$ git bulk --removeworkspace personal
```
  Remove all registered workspaces:

```bash
$ git bulk --purge
```

## git brv

Pretty listing of branches sorted by the date of their last commit.

```bash
$ git brv
2020-01-14 adds-git-brv fork/adds-git-brv 1ca0d76 Fixes #700: Adds git-brv
2020-01-08 master       origin/master     265b03e Merge pull request #816 from spacewander/git-sed-pathspec
```

When your repo has many branches, it can be more convenient to see this list in reverse. This can be set as the default by setting the git-extras.brv.reverse git option to true.

```bash
$ git brv --reverse
2020-01-08 master       origin/master     265b03e Merge pull request #816 from spacewander/git-sed-pathspec
2020-01-14 adds-git-brv fork/adds-git-brv 1ca0d76 Fixes #700: Adds git-brv
```

## git repl

Git read-eval-print-loop. Lets you run `git` commands without typing 'git'.

Commands can be prefixed with an exclamation mark (!) to be interpreted as
a regular command.

Type `exit`, `quit`, or `q` to end the repl session.

Any arguments to git repl will be taken as the first command to execute in
the repl.

### CONFIGURATION

Commands entered in a repl session will be saved to a history file and be available in
future sessions, similar to a shell or programming language repl. By default,
there is one global history file, ~/.git_repl_history. You can specify that your projects
each have their own independent history file. This file will be saved in .git_repl_history
at the top level of the repo, and will need to be added to the repo or global .gitignore.

```bash
# remove the --global flag to configure only an individual project to have its own history file
git config --global git-extras.repl.use-local-history "true"
```

You can specify a default command to run when hitting enter:

```bash
git config --global git-extras.repl.on-enter-command "git status -sb"
```

You can configure which character is used at the end of the prompt: (default `>`):

```bash
git config --global git-extras.repl.prompt-character "±"
```

You can specify the prefix for the prompt, or remove it (default `git`):

```bash
git config --global git-extras.repl.prefix ""
```

You can have the name of the current git repo shown in the prompt (default `false`):

```bash
git config --global git-extras.repl.show-project-name "true"
```

```bash
$ git repl
git version 2.34.1
git-extras version 7.3.0
Type 'ls' to ls files below current directory; '!command' to execute any command or just 'subcommand' to execute any git subcommand; 'quit', 'exit', 'q', ^D, or ^C to exit the git repl.

git (master)> ls-files
History.md
Makefile
Readme.md
bin/git-changelog
bin/git-count
bin/git-delete-branch
bin/git-delete-tag
bin/git-ignore
bin/git-release

git (master)> !echo Straight from the shell!
Straight from the shell!

git (master)> quit
```

## git coauthor

Add a co-author to the last commit

```bash
$ git coauthor user user@email.com

[master b62ceae] Add documentation files
 Date: Sat Aug 17 17:33:53 2019 -0500
 2 files changed, 145 insertions(+), 0 deletions(-)
 create mode 100644 README.md
 create mode 100644 CONTRIBUTING.md

 $ git log -1

commit b62ceae2685e6ece071f3c3754e9b77fd0a35c88 (HEAD -> master)
Author: user person <userperson@email.com>
Date:   Sat Aug 17 17:33:53 2019 -0500

    Add documentation files

    Co-authored-by: user <user@email.com>
```

## git commits-since

List commits since `date` (defaults to "last week"):

```bash
$ git commits-since
... changes since last week
TJ Holowaychuk - Fixed readme
TJ Holowaychuk - Added git-repl
TJ Holowaychuk - Added git-delete-tag
TJ Holowaychuk - Added git-delete-branch

$ git commits-since yesterday
... changes since yesterday
TJ Holowaychuk - Fixed readme
```

## git count

Output commit count:

```bash
$ git count

total 1844
```

Output detailed commit count:

```bash
$ git count --all

visionmedia (1285)
Tj Holowaychuk (430)
Aaron Heckmann (48)
csausdev (34)
ciaranj (26)
Guillermo Rauch (6)
Brian McKinney (2)
Nick Poulden (2)
Benny Wong (2)
Justin Lilly (1)
isaacs (1)
Adam Sanderson (1)
Viktor Kelemen (1)
Gregory Ritter (1)
Greg Ritter (1)
ewoudj (1)
James Herdman (1)
Matt Colyer (1)

total 1844
```

## git fork

Fork the given github &lt;repo&gt;. Like clone but forks first.

```Shell
$ git fork https://github.com/LearnBoost/expect.js
```

or just:

```Shell
$ git fork LearnBoost/expect.js
```

Does the following:
- forks the repo (prompts for github username and pass)
- clones the repo into the current directory
- adds the original repo as a remote so can track upstream changes
- all remotes refs use git over ssh if configured, otherwise https will be used


```Shell
$ cd expect.js && git remote -v
origin          git@github.com:<user>/expect.js (fetch)
origin          git@github.com:<user>/expect.js (push)
upstream        git@github.com:LearnBoost/expect.js (fetch)
upstream        git@github.com:LearnBoost/expect.js (push)
```

## git force-clone

If the clone target directory exists and is a git repository, reset its
contents to a clone of the remote.

``` bash
$ git force-clone [-b {branch_name}] {remote_url} {destination_path}
$ git force-clone -b master https://github.com/tj/git-extras ./target-directory
```

**CAUTION**: If the repository exists, this will destroy *all* local changes
to the repository - changed files will be reset and local branches will be
removed.

[More information](man/git-force-clone.md).

## git release

Release commit with the given &lt;tag&gt; and other options:

```bash
$ git release 0.1.0
```

If you are using [semver](https://semver.org) in your project, you could also use the command below:
(Run `git help release` for more information)

```bash
$ git release --semver major/minor/patch
```

Does the following:

  - Executes _.git/hooks/pre-release.sh_ (if present), passing it the given tag and remain arguments
  - Commits changes (to changelog etc) with message "Release &lt;tag&gt;"
  - Tags with the given &lt;tag&gt;
  - Push the branch / tags
  - Executes _.git/hooks/post-release.sh_ (if present), passing it the given tag and remain arguments


## git rename-branch

Rename a branch locally, and sync to remote via `git push`.

```
# renames any branch
$ git rename-branch old-name new-name

# renames current branch
$ git rename-branch new-name
```

## git rename-file

Rename a file or directory and ensure Git recognizes the change, regardless of filesystem case-sensitivity.
It combines the functionality of the `mv` command and `git mv`. This is particularly useful for renaming files or directories
to change only their case, which might not be detected by Git on case-insensitive filesystems.

```bash
# Rename a file
git rename-file old_filename new_filename

# Rename a directory
git rename-file old_directory new_directory
```

## git rename-tag

Rename a tag (locally and remotely).
```
$ git tag test
$ git push --tags
Total 0 (delta 0), reused 0 (delta 0)
To git@myserver.com:myuser/myrepository.git
    * [new tag]         test -> test
$ git tag
test
$ git rename-tag test test2
Deleted tag 'test' (was 1111111)
Total 0 (delta 0), reused 0 (delta 0)
To git@myserver.com:myuser/myrepository.git
    * [new tag]         test2 -> test2
remote: warning: Deleting a non-existent ref.
To git@myserver.com:myuser/myrepository.git
    - [deleted]         refs/tag/test
$ git tag
test2
```

## git rename-remote

Rename a git remote regardless of name conflict, and then list current git remotes.
```
$ git remote -v
origin	git@myserver.com:myuser/foo.git (fetch)
origin	git@myserver.com:myuser/foo.git (push)
upstream	git@myserver.com:myuser/bar.git (fetch)
upstream	git@myserver.com:myuser/bar.git (push)
$ git-rename-remote upstream origin
origin	git@myserver.com:myuser/bar.git (fetch)
origin	git@myserver.com:myuser/bar.git (push)
```

## git reauthor

Rewrite history to change author's identity.

Replace the personal email and name of Jack to his work ones
```bash
$ git reauthor --old-email jack@perso.me --correct-email jack@work.com --correct-name 'Jack Foobar'
```

Replace the email and name of Jack to the ones defined in the Git config
```bash
$ git reauthor --old-email jack@perso.me --use-config
```

Replace only the email of Jack (keep the name already used)
```bash
$ git reauthor --old-email jack@perso --correct-email jack@perso.me
```

Change only the committer email of Jack (keep the author email already used)
```bash
$ git reauthor --old-email jack@perso.me --correct-email jack@work.com --type committer
```

Set Jack's identity as the only one of the whole repository
```bash
$ git reauthor --all --correct-email jack@perso.me --correct-name Jack
```

Set Jack as the only committer of the whole repository (keeps authors)
```bash
$ git reauthor --all --correct-email jack@perso.me --correct-name Jack --type committer
```


## git alias

Define, search and show aliases.

Define a new alias:

```bash
$ git alias last "cat-file commit HEAD"
```

Search for aliases that match a pattern (one argument):

```bash
$ git alias ^la
last = cat-file commit HEAD
```

Show all aliases (no arguments):

```bash
$ git alias
s = status
amend = commit --amend
rank = shortlog -sn --no-merges
whatis = show -s --pretty='tformat:%h (%s, %ad)' --date=short
whois = !sh -c 'git log -i -1 --pretty="format:%an <%ae>
```

## git ignore

Too lazy to open up `.gitignore`?  Me too!

```bash
$ git ignore build "*.o" "*.log"
... added 'build'
... added '*.o'
... added '*.log'
```

Without any patterns, `git-ignore` displays currently ignored patterns in both your global and your local `.gitignore` files:

```bash
$ git ignore
Global gitignore: /Users/foo/.gitignore_global
*~
.metadata
---------------------------------
Local gitignore: .gitignore
build
*.o
*.log
```

To show just the global or just the local file's contents, you can use the following optional parameters:

* `-g` or `--global` to show just the global file
* `-l` or `--local` to show just the local file
* `-p` or `--private` to show just the repository's file

```bash
$ git ignore -g
Global gitignore: /Users/foo/.gitignore_global
*~
.metadata
```

```bash
$ git ignore -l
Local gitignore: .gitignore
build
*.o
*.log
```

## git ignore-io

Generate sample gitignore file from [gitignore.io](https://www.toptal.com/developers/gitignore)

Without option, `git ignore-io <type>` shows the sample gitignore of specified types on screen.

```bash
$ git ignore-io vim

    # Created by https://www.toptal.com/developers/gitignore/api/vim

    ### Vim ###
    [._]*.s[a-w][a-z]
    [._]s[a-w][a-z]
    *.un~
    Session.vim
    .netrwhist
    *~
```

To export it to `.gitignore` file you can use the following options:

* `-a` or `--append` to append the result to `.gitignore`
* `-r` or `--replace` to export `.gitignore` with the result

```bash
$ git ignore-io vim python
```

For efficiency, `git ignore-io` store all available types at `~/.gi_list`.
To list all the available types:

* `-l` or `-L` : These two options will show the list in different format. Just try it.

You can also search type from the list by:

* `-s <word>` or `--search <word>`

```bash
$ git ignore-io -s ja

    django
    jabref
    java
    ninja
```


## git info

Show information about the repo:

```bash
$ git info

    ## Remote URLs:

    origin              git@github.com:sampleAuthor/git-extras.git (fetch)
    origin              git@github.com:sampleAuthor/git-extras.git (push)

    ## Remote Branches:

    origin/HEAD -> origin/master
    origin/myBranch

    ## Local Branches:

    myBranch
    * master

    ## Submodule(s):

      a234567 path2submodule1/submodule1 (branch/tag)
    + b234567 path2submodule2/submodule2 (branch/tag)
    - c234567 path2submodule3/submodule3 (branch/tag)
      e234567 path2submodule4/submodule4 (branch/tag)

    ## Most Recent Commit:

    commit e3952df2c172c6f3eb533d8d0b1a6c77250769a7
    Author: Sample Author <sampleAuthor@gmail.com>

    Added git-info command.

    ## Configuration (.git/config):

    color.diff=auto
    color.status=auto
    color.branch=auto
    user.name=Sample Author
    user.email=sampleAuthor@gmail.com
    core.repositoryformatversion=0
    core.filemode=true
    core.bare=false
    core.logallrefupdates=true
    core.ignorecase=true
    remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
    remote.origin.url=git@github.com:mub/git-extras.git
    branch.master.remote=origin
    branch.master.merge=refs/heads/master

```

If you wish to omit the config section, you may use `--no-config`:

```bash
$ git info --no-config
```

## git cp

Copy a file to another one keeping its history and allowing for merge conflicts handling.

```bash
$ git cp README.md README.rst
```

## git create-branch

Create local branch `name`:

```bash
$ git create-branch development
```

Create local branch `name` and setup a remote tracking branch in `origin`:

```bash
$ git create-branch -r development
```

Create local branch `name` and setup a remote tracking branch in `upstream`:

```bash
$ git create-branch -r upstream development
```

## git delete-branch

Delete local and remote branch `name`:

```bash
$ git delete-branch integration
```

## git delete-submodule

Delete submodule `name`:

```bash
$ git delete-submodule lib/foo
```

## git delete-tag

Delete local and remote tag `name`:

```bash
$ git delete-tag 0.0.1
```

## git delete-merged-branches

Deletes branches that are listed in `git branch --merged`.

```bash
$ git delete-merged-branches
Deleted feature/themes (was c029ab3).
Deleted feature/live_preview (was a81b002).
Deleted feature/dashboard (was 923befa).
...
```

## git delete-squashed-branches

Deletes branches that have been "squashed-merged" into a specified branch; this branch will be checked out as a side-effect. If no branch is specified, then it will default to the current checked out branch.

```bash
$ (feature-branch) git delete-squashed-branches main
Deleted branch dependabot/bundler/kramdown-2.3.1 (was 1d3fb00).
Deleted branch dependabot/bundler/rexml-3.2.5 (was a7e4052).
$ (main) git ...
```

## git fresh-branch

Create empty local branch `docs`:

```bash
$ git fresh-branch docs
```

## git get

Clone repository into a subdirectory of the configured path, `"$HOME/some-dir"`:

```bash
$ git config --global --add git-extras.get.clone-path "$HOME/some-dir"
$ git get 'https://github.com/hyperupcall/bake'
```

## git guilt

Calculate the change in blame between two revisions

```bash
# Find blame delta over the last three weeks
$ git guilt `git log --until="3 weeks ago" --format="%H" -n 1` HEAD
Paul Schreiber                +++++++++++++++++++++++++++++++++++++++++++++(349)
spacewander                   +++++++++++++++++++++++++++++++++++++++++++++(113)
Mark Eissler                  ++++++++++++++++++++++++++
CJ                            +++++
nickl-                        -
Jesse Sipprell                -
Evan Grim                     -
Ben Parnell                   -
hemanth.hm                    --
```

## git merge-into

Merge `src` branch into `dest`, and keep yourself on current branch. If `src` branch not given, it will merge current one to `dest`:

```bash
$ git merge-into [src] dest
```

## git graft

Merge commits from `src-branch` into `dest-branch`.

```bash
$ git graft new_feature master
```

## git squash

Merge commits from `src-branch` into the current branch as a _single_ commit.
Also works if a commit reference from the current branch is provided.
When `[msg]` is given `git-commit(1)` will be invoked with that message. This is
useful when small individual commits within a topic branch are irrelevant and
you want to consider the topic as a single change.

```bash
$ git squash fixed-cursor-styling
$ git squash fixed-cursor-styling "Fixed cursor styling"
$ git squash 95b7c52
$ git squash HEAD~3
$ git squash HEAD~3 "Work on a feature"
```

## git authors

Populates the file matching `authors|contributors -i` with the authors of commits, according to the number of commits per author.

See the ["MAPPING AUTHORS" section](https://git-scm.com/docs/git-shortlog#_mapping_authors) of **git-shortlog**(1) to coalesce together commits by the same person.

Updating AUTHORS file:

```bash
$ git authors && cat AUTHORS

TJ Holowaychuk <tj@vision-media.ca>
hemanth.hm <hemanth.hm@gmail.com>
Jonhnny Weslley <jw@jonhnnyweslley.net>
nickl- <github@jigsoft.co.za>
Leila Muhtasib <muhtasib@gmail.com>
```

Listing authors:

```bash
$ git authors --list

TJ Holowaychuk <tj@vision-media.ca>
hemanth.hm <hemanth.hm@gmail.com>
Jonhnny Weslley <jw@jonhnnyweslley.net>
nickl- <github@jigsoft.co.za>
Leila Muhtasib <muhtasib@gmail.com>
```

Listing authors without email:

```bash
$ git authors --list --no-email

TJ Holowaychuk
hemanth.hm
Jonhnny Weslley
nickl-
Leila Muhtasib
```

## git changelog

Generates a changelog from git(1) tags (annotated or lightweight) and commit messages. Existing changelog files with filenames that begin with _Change_ or _History_ will be identified automatically with a case insensitive match pattern and existing content will be appended to the new output generated--this behavior can be disabled by specifying the prune option (-p|--prune-old). The generated file will be opened in **$EDITOR** when set.

If no tags exist, then all commits are output; if tags exist, then only the most-recent commits are output up to the last identified tag. This behavior can be changed by specifying one or both of the range options (-f|--final-tag and -s|--start-tag).

The following options are available:

```bash
  -a, --all                 Retrieve all commits (ignores --start-tag, --final-tag)
  -l, --list                Display commits as a list, with no titles
  -t, --tag                 Tag label to use for most-recent (untagged) commits
  -f, --final-tag           Newest tag to retrieve commits from in a range
  -s, --start-tag           Oldest tag to retrieve commits from in a range
  -n, --no-merges           Suppress commits from merged branches
  -p, --prune-old           Replace existing Changelog entirely with new content
  -x, --stdout              Write output to stdout instead of to a Changelog file
  -h, --help, ?             Usage help
```

Type `git changelog --help` for basic usage or `man git-changelog` for more information.

**NOTE:** By default, `git changelog` will concatenate the content of any detected changelog to its output. Use the `-p` option to prevent this behavior.

### Examples

Generate a new changelog consisting of all commits since the last tag, use the tag name _1.5.2_ for the title of this recent commits section (the date will be generated automatically as today's date):

```bash
$ git changelog --tag 1.5.2 && cat History.md

1.5.2 / 2015-03-15
==================

* Docs for git-ignore. Closes #3
* Merge branch 'ignore'
* Added git-ignore
* Fixed <tag> in docs
* Install docs
* Merge branch 'release'
* Added git-release
* Passing args to git shortlog
* Added --all support to git-count
```

List all commits since the last tag:

```bash
$ git changelog --list

* Docs for git-ignore. Closes #3
* Merge branch 'ignore'
* Added git-ignore
* Fixed <tag> in docs
* Install docs
* Merge branch 'release'
* Added git-release
* Passing args to git shortlog
* Added --all support to git-count
```

List all commits since the beginning:

```bash
$ git changelog --list --all

* Docs for git-ignore. Closes #3
* Merge branch 'ignore'
* Added git-ignore
* Fixed <tag> in docs
* Install docs
* Merge branch 'release'
* Added git-release
* Passing args to git shortlog
* Added --all support to git-count
...
<many many commits>
...
* Install docs.
* Merge branch 'release'.
* Added 'git-release'.
* Fixed readme.
* Passing args to git shortlog.
* Initial commit
```

## git undo

Remove the latest commit:

```bash
git undo
```

Remove the latest 3 commits:

```bash
git undo 3
```

## git sed

Run grep as directed but replace the given files with the pattern.

For example,
```bash
$ git sed 'this' 'that'
$ git sed 'this' 'that' g
$ git sed 'this' 'that' -- path/ path2/
```

## git setup

Set up a git repository (if one doesn't exist), add all files, and make an initial commit. `dir` defaults to the current working directory.

## git scp

A convenient way to copy files from the current working tree to the working directory of a remote repository. If a `<commits>...` is provided, only files that has changed within the commit range will be copied.

Internally this script uses `rsync` and not `scp` as the name suggests.

`git-rscp` - The reverse of `git-scp`. Copies specific files from the working directory of a remote repository to the current working directory.

### Examples

 Copy unstaged files to remote. Useful when you want to make quick test without making any commits

    $ git scp staging

 Copy staged and unstaged files to remote

    $ git scp staging HEAD

 Copy files that has been changed in the last commit, plus any staged or unstaged files to remote

    $ git scp staging HEAD~1

 Copy files that has been changed between now and a tag

    $ git scp staging v1.2.3

 Copy specific files

    $ git scp staging index.html .gitignore .htaccess

 Copy specific directory

    $ git scp staging js/vendor/

## git show-merged-branches

Show all branches merged in to current HEAD.

## git show-unmerged-branches

Show all branches **not** merged in to current HEAD.

## git show-tree

Show the decorated graph view of one liner summarized commits from all branches.
For example, running `git show-tree` will display:
```
*   4b57684 (HEAD, develop) Merge branch upstream master.
|\
| *   515e94a Merge pull request #128 from nickl-/git-extras-html-hyperlinks
| |\
| | * 815db8b (nickl/git-extras-html-hyperlinks, git-extras-html-hyperlinks) help ronn make hyperlinks.
| * | 7398d10 (nickl/develop) Fix #127 git-ignore won't add duplicates.
| |/
| | * ab72c1e (refs/stash) WIP on develop: 5e943f5 Fix #127 git-ignore won't add duplicates.
| |/
|/|
* | 730ca89 (bolshakov) Rebase bolshakov with master
|/
* 60f8371 (origin/master, origin/HEAD, master) Merge pull request #126 from agrimaldi/fix-changelog-last-tag
...
```

Be free to try it for yourself!


## git stamp

Stamp the last commit message

Commit message is

```bash
Fix timezone bug
```

Reference the issues numbers from your bug tracker

```bash
$ git stamp Issue FOO-123

commit 787590e42c9bacd249f3b79faee7aecdc9de28ec
Author: Jack <jack@work.com>
Commit: Jack <jack@work.com>

    Fix timezone bug

    Issue FOO-123

$ git stamp Issue FOO-456 \#close

commit f8d920511e052bea39ce2088d1d723b475aeff87
Author: Jack <jack@work.com>
Commit: Jack <jack@work.com>

    Fix timezone bug

    Issue FOO-123

    Issue FOO-456 #close
```

Link to its review page

```bash
$ git stamp Review https://reviews.foo.org/r/4567/

commit 6c6bcf43bd32a76e37b6fc9708d3ff0ae723c7da
Author: Jack <jack@work.com>
Commit: Jack <jack@work.com>

    Fix timezone bug

    Issue FOO-123

    Issue FOO-456 #close

    Review https://reviews.foo.org/r/4567/
```

Replace previous issues with a new one
(Note that the identifier is case insensitive)

```bash
$ git stamp --replace issue BAR-123

commit 2b93c56b2340578cc3478008e2cadb05a7bcccfa
Author: Jack <jack@work.com>
Commit: Jack <jack@work.com>

    Fix timezone bug

    Review https://reviews.foo.org/r/4567/

    issue BAR-123
```


## git standup

Recall what you did or find what someone else did in a given range of time.
For instance, recall John's commits since last week(7 days ago):
```
git standup -a John -d 7
```

## git touch

Call `touch` on the given file, and add it to the current index. One-step creation of new files.

## git obliterate

Completely remove a file from the repository, including past commits and tags.

```bash
git obliterate secrets.json
```

## git local-commits

List all commits on the local branch that have not yet been sent to origin. Any additional arguments will be passed directly to git log.

## git archive-file

Creates a zip archive of the current git repository. The name of the archive will depend on the current HEAD of your git repository.

## git missing

Print out which commits are on one branch or the other but not both. Optionally, you can specify a path to limit the comparison to a specific directory or file.

```bash
$ git missing master
< d14b8f0 only on current checked out branch
> 97ef387 only on master
```

```bash
$ git missing master -- src/
< ed52989 only on current branch, in src/ directory
> 7988c4b only on master, in src/ directory
```

## git lock

Lock a local file `filename`:

```bash
$ git lock config/database.yml
```

## git locked

List local locked files:

```bash
$ git locked
config/database.yml
```

## git unlock

Unlock a local file `filename`

```bash
$ git unlock config/database.yml
```

## git reset-file

Reset one file to `HEAD` or certain commit

Reset one file to HEAD

```bash
$ git reset-file .htaccess
```

or reset one file to certain commit

```bash
$ git reset-file .htaccess dc82b19
```

## git mr

Checks out a merge request from GitLab. Usage: `git mr <ID|URL> [REMOTE]`.
Default remote is `origin`.

``` bash
$ git mr 51
From gitlab.com:owner/repository
 * [new ref]         refs/merge-requests/51/head -> mr/51
Switched to branch 'mr/51'
```

With full URL, the head is fetched from a temporary remote pointing to the base URL.

``` bash
$ git mr https://gitlab.com/owner/repository/merge_requests/51
From gitlab.com:owner/repository
 * [new ref]         refs/merge-requests/51/head -> mr/51
Switched to branch 'mr/51'
```

Just like [git pr](#git-pr), `git mr` accepts a `clean` argument to trash all
`mr/` branches. Ensure current branch is not one.

## git paste

Sends commits to a pastebin site using pastebinit.

By default it sends the commits between your current branch
and the branch your current branch is based on (the upstream branch).

``` bash
$ git paste
https://paste.debian.net/1234567/
```

All options are passed to `git format-patch --stdout`
so you can also pass options understood by `git-rev-parse(1)`
in order to select a different set of commits.

``` bash
$ git paste @^
https://paste.debian.net/1234567/
```

See the [pastebinit documentation](https://manpages.debian.org/pastebinit)
for information about how to chose a different pastebin site to the default.

## git pr

Checks out a pull request from GitHub

```bash
$ git pr 226
From https://github.com/tj/git-extras
 * [new ref]       refs/pulls/226/head -> pr/226
Switched to branch 'pr/226'
```

To use a remote other than `origin`, e.g. `upstream` if you're working in a fork, specify it as the second parameter:

```bash
$ git pr 226 upstream
From https://github.com/tj/git-extras
 * [new ref]       refs/pulls/226/head -> pr/226
Switched to branch 'pr/226'
```

You can also checkout a pull request based on a GitHub url

```bash
$ git pr https://github.com/tj/git-extras/pull/453
From https://github.com/tj/git-extras
 * [new ref]         refs/pull/453/head -> pr/453
Switched to branch 'pr/453'
```

To remove all local pull request branches, provide the magic `clean` parameter:

```bash
$ git pr clean
Deleted branch 'pr/226' (was 1234567).
```

## git root

show the path to root directory of git repo

```bash
$ pwd
.../very-deep-from-root-directory
$ cd `git root`
$ git add . && git commit
```

## git delta

Lists files that differ from another branch.

```bash
$ touch README.md
$ git setup
$ git checkout -b hello
$ echo hello >> README.md
$ git delta
README.md
$ touch Makefile
$ git add Makefile
$ git delta
Makefile
README.md
```

## git clear

Does a hard reset and deletes all untracked files from the working directory, including those in .gitignore.

## git clear-soft

Does a hard reset and deletes all untracked files from the working directory, excluding those in .gitignore.

## git merge-repo

Merges two repository histories.

```bash
$ git merge-repo other-repo.git master new_dir
```

The above merges `other-repo.git`'s  `master` branch into the current repository's `new_dir` directory.

```bash
$ git merge-repo git@github.com:tj/git-extras.git master .
```

The above merges a remote repo's `master` branch into the current repository's directory, not preserving history.


## git psykorebase

Rebase a branch on top of another using a merge commit and only one conflict handling.

```bash
$ git psykorebase master
```

The above rebase the current branch on top of `master` branch .

```bash
$ git psykorebase --continue
```

The above continue the rebase after conflicts have been handled.

```bash
$ git psykorebase master feature
```

The above rebase `feature` branch on top of `master` branch

## git pull-request

Create pull request via commandline.

## git rebase-patch

Given you have a patch that doesn't apply to the current HEAD, but you know it applied to some commit in the past,
`git rebase-patch` will help you find that commit and do a rebase.

For example,
```
$ git rebase-patch test.patch
Trying to find a commit the patch applies to...
Patch applied to dbcf408dd26 as 7dc8b23ae1a
First, rewinding head to replay your work on top of it...
Applying: test.patch
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging README.txt
```

Then your last commit has the changes of the patch and is named `test.patch`.

## git sync

Sync local branch with its remote branch

```bash
$ git sync
```

Sync local branch with origin/master

```bash
$ git sync origin master
```

## git browse

Opens the current git repository website in your default web browser.

```bash
$ git browse

$ git browse upstream
```

## git browse-ci

Opens the current git repository CI website (e.g. GitHub Actions, GitLab CI,
Bitbucket Pipelines) in your default web browser.

```bash
$ git browse-ci

$ git browse-ci upstream
```

## git utimes

Change files modification time to their last commit date. Does not touch files that are in the working tree or index.

The `--newer` flag preserves the original modification time of files that were committed from the local repo, by only touching files that are newer than their last commit date.

```bash
git-extras$ ls -l bin | head
total 308
-rwxr-xr-x 1 vt vt   489 Jul 28  2015 git-alias
-rwxr-xr-x 1 vt vt  1043 Nov  8 13:56 git-archive-file
-rwxr-xr-x 1 vt vt   970 Nov  8 13:56 git-authors
-rwxr-xr-x 1 vt vt   267 Nov  8 13:56 git-back
-rwxr-xr-x 1 vt vt   899 Nov  8 13:56 git-browse
-rwxr-xr-x 1 vt vt  1932 Nov  8 13:56 git-brv
-rwxr-xr-x 1 vt vt  6282 Nov  8 13:56 git-bulk
-rwxr-xr-x 1 vt vt 18561 Nov  8 13:56 git-changelog
-rwxr-xr-x 1 vt vt   215 Nov  8 13:56 git-clear

git-extras$ git utimes --newer
+ touch -d 2020-05-22T10:40:29+08:00 bin/git-archive-file
+ touch -d 2017-05-05T16:02:09+08:00 bin/git-authors
+ touch -d 2020-02-23T11:41:54+08:00 bin/git-back
+ touch -d 2020-06-23T09:31:21+10:00 bin/git-browse
+ touch -d 2020-01-15T10:46:19+01:00 bin/git-brv
+ touch -d 2019-12-21T13:35:59+08:00 bin/git-bulk
+ touch -d 2019-09-05T12:41:38+08:00 bin/git-changelog
+ touch -d 2016-11-19T16:41:19+00:00 bin/git-clear
[...]

git-extras$ ls -l bin | head
total 308
-rwxr-xr-x 1 vt vt   489 Jul 28  2015 git-alias
-rwxr-xr-x 1 vt vt  1043 May 22 05:40 git-archive-file
-rwxr-xr-x 1 vt vt   970 May  5  2017 git-authors
-rwxr-xr-x 1 vt vt   267 Feb 23  2020 git-back
-rwxr-xr-x 1 vt vt   899 Jun 23 02:31 git-browse
-rwxr-xr-x 1 vt vt  1932 Jan 15  2020 git-brv
-rwxr-xr-x 1 vt vt  6282 Dec 21  2019 git-bulk
-rwxr-xr-x 1 vt vt 18561 Sep  5  2019 git-changelog
-rwxr-xr-x 1 vt vt   215 Nov 19  2016 git-clear
```

Note above, that because of the `--newer` flag, the file `git-alias` was not touched since its modified date is earlier than the commit date.

## git abort

Abort current revert, rebase, merge or cherry-pick, without the need to find exact command in history.

## git magic

Commits changes with a generated message.

## git continue

Continue current revert, rebase, merge or cherry-pick, without the need to find exact command in history.

## git wip

Create a Work In Progress(WIP) commit, which will include all changes in the
working directory. (i.e., changes to existing files, new files, removed files)

```bash
$ git wip
```

## git unwip

Undo a Work In Progress(WIP) commit and put all of those changes back into the
working directory.

```bash
$ git unwip
```


================================================
FILE: History.md
================================================

7.4.0 / 2025-06-19
==================

  * Format comparisons, functions, and redirections to be consistent (#1201)
  * add git-wip and git-unwip (#669)
  * chore(deps): bump bats-core/bats-action from 3.0.0 to 3.0.1
  * Mostly finish pytest to Bats conversion (#1200)
  * Implement half of tests in Bats (#1187)
  * Add stale bot for old PRs (#1186)
  * feat(git-bulk): add new option to not follow hidden directories (#1195)
  * Feat: allow git-summary showing full path of repository (#1193)
  * feat(git-bulk): add new option to no follow symlinks (#1194)
  * docs(git-bulk): Add zsh completion (#1190)
  * fix(git-bulk): fix workspace selection when cd fails (#1197)
  * fix(git-bulk): quiet find errors by default (#1196)
  * fix(git-bulk): fix a bad integer expression (#1198)
  * chore(deps): bump astral-sh/ruff-action from 2 to 3 (#1189)
  * Fix all ShellCheck errors and add to CI (#1179)
  * chore(deps): bump astral-sh/ruff-action from 1 to 2 (#1188)
  * fix(ci): use poetry (#1183)
  * Delete etc/test.fish (#1185)
  * feat: add git-continue (#1176)
  * feat: add ruff linter with ci check (#1182)
  * fix(ci): missing dollar sign (#1184)
  * fix(github-actions): changed files output for editorcondig-checker (#1180)
  * Revert "feat: add ruff linter with ci check (#1178)" (#1181)
  * feat: add ruff linter with ci check (#1178)
  * Support `GITHUB_TOKEN` var for `git-fork` and `git-pull-request` (#1177)
  * Bump version to 7.4.0-dev (#1175)

7.3.0 / 2024-10-20
==================

  * Fix stripping trailing forward slash for git-get (#1172)
  * Change git-cp to use cleaner branch approach (#1169)
  * Improve warning for `git clear` (#1168)
  * Enhance `git-repl` (#1160)
  * Update some documentation that was out of sync (#1164)
  * Use filetimes in check_integrity (#1162)
  * Update git-alias.md: add brs to prevent incorrect line behavior (#1161)
  * Update git-bulk.md: use correct stylization in synopsis (#1163)
  * Update git-repl.md: typo: "let's" for "lets" (#1158)
  * Update instructions for the OpenSUSE installation (#1157)
  * Add pathspec support in `git-missing` (#1156)
  * feat: add rename-file command (#1149)
  * Update Commands.md (#1148)
  * fix: git-summary commit count (#1147)
  * tests: update dependencies (#1142)
  * chore(deps): bump masesgroup/retrieve-changed-files from 2 to 3 (#1144)
  * chore(deps): bump actions/setup-go from 4 to 5 (#1143)
  * ci: add dependabot update for GitHub actions (#1141)
  * ci: update actions (#1140)
  * Bump version to 7.3.0-dev (#1139)

7.2.0 / 2024-04-21
==================

  * refactor: test utils and simplify the case code (#1136)
  * Add --proceed flag to git-delete-squashed-branches (#1134) (#1135)
  * test(browse-ci): add unit tests (#1130)
  * test(git-browse): add unit tests (#1127)
  * feat: add reverse option to git-brv (#1123)
  * fix(utimes): change /dev/stdin to -
  * fix(utimes): Support filenames with backspaces, etc. (#1122)
  * chore: add poetry to handle the tests of the git extras (#1121)
  * Fix typo in ci.yml (#1120)
  * Fix: harden utimes, use single quotes (#1109)
  * Fix: patch git-utimes (fixes #1118) (#1119)
  * add pull request manner (#1113)
  * maintenance: Add my name as maintainer in AUTHORS (#1117)
  * test(git-authors): add unit test (#1098)
  * Add more comprensive dependencies (#1111)
  * fix: git-standup find error (tj#1106) (#1110)
  * Improve defaults for testing suite (#1104)
  * feat: Speed up utimes (#1108)
  * Overhaul CONTRIBUTING document (#1103)
  * Bump version to 7.2.0-dev (#1099)

7.1.0 / 2023-10-28
==================

  * git-cp: don't stop execution when merge.ff is not set (#1096)
  * Allow `git cp` to create destination folder automatically (#1091)
  * fix: Use `-iname` and expressions instead of `-iregex` (#1094)
  * change installation source from master to main (#1092)
  * test(git-archive-file): add unit test (#1084)
  * ci: Use Go v1.20 for running `editorconfig-checker` (#1086)
  * test(git-alias): add its unit test (#1077)
  * makefile: Allow bypassing conflict check (#1080)
  * fix: Restore zsh completions to working completion (#1079)
  * fix: add missing quote in git-extras-completion.zsh (#1078)
  * feat: Implement completion for `git coauthor` (#1074)
  * fix: Move improvements via ShellCheck (#1075)
  * feat(auto-test): CI with pytest (#1066)
  * git-feature: add configurable branch separator (#1072)
  * git-psykorebase: determine branch names with bash pattern substitution (#1073)
  * git-cp: continue to merge when merge.ff is only (#1070)
  * git archive-file: change base ARCHIVE_NAME (#1071)
  * readme: Add secondary location of screencast (#1065)
  * fix: Improve Bash hygiene (#1056)
  * feat: Implement `git-get` command (#1045)
  * Corrected grammar in bin/git-cp (#1061)
  * Improve `git-ignore` command (#1047)
  * I have made two improvements to the git-bulk: (#1054)
  * Type properly `__gitex_command_successful` calls and capitalizate github to GitHub (#1049)
  * Add typo checker
  * Fix comment typo in git-authors (#1050)
  * tweak: Fix typos (#1046)
  * Makefile: init SYSCONFDIR before using it (#1044)
  * Makefile: tune MANPREFIX configuration for FreeBSD (#1043)
  * Makefile: set bash COMPL_DIR to FreeBSD expected defaults (#1042)
  * Bump version to 7.1.0-dev (#1041)

7.0.0 / 2023-04-20
==================

  * git-delete-tag: should not be quoted
  * Add the current branch git summary (#1034)
  * chore: Improve Bash variously (#1032)
  * Change the oneline option to a tebular version in the git summary (#1031)
  * chore: Remove `X`-style equality comparisons (#1028)
  * chore: Various Bash improvements (#1029)
  * fix: No longer pollute env with `GREP_OPTIONS`
  * tweak editor config (#1027)
  * revert the completion dir change on MacOS (#1026)
  * Update gitignore.io urls to Toptal urls (#1025)
  * Add EditorConfig file (#1022)
  * Make the bulk output slimmer (#1020)
  * chore: Fix more Bash inconsistencies (#1021)
  * Repo status overview (#1017)
  * Replace egrep with grep -E (#1019)
  * chore: More Bash improvements and removing deprecations (#1016)
  * chore: Improve quoting and builtin usage (#1015)
  * Add summary fields (#1013)
  * Fix quiet mode of the bulk command (#1014)
  * git-summary: remove stray \ in grep call (#1010)
  * Allow to run git-extras within git-bulk (#1008)
  * Make git-summary accept multiple paths for the --lines argument (#1005)
  * Makefile: ensure bash is used instead of /bin/sh (#1004)
  * fix base branch in the pull-request command (#1003)
  * Update docs for git abort change (#1000)
  * Bump version to 6.6.0-dev (#997)

6.5.0 / 2022-10-06
==================

  * git root: show '.' when using with -r in the root dir (#995)
  * git standup: work as expected when no configured (#996)
  * rephrase question depending on switch (#984)
  * Include revert conflicts in git abort (#992)
  * fix(git-effort):fork: retry: Resource temporarily unavailable #979 (#990)
  * git-sync --force will sync without interaction (#989)
  * fix(git-cp): keep the history of the files
  * git-bulk: previous refactor redirected $PWD to stderr by mistake
  * Fix lazy loading bash_completion from XDG_DATA_DIRS
  * Minor changes to man/git-standup.md
  * Replaced -g and -A with -F gpg|authordate
  * fix(bin/git-browse): fix commit hash
  * fix(bin/git-browse): fix bitbucket url
  * feat: open website at file & line number or range
  * #970 standup added -A flag for author date
  * update docs due to formatting error in git-utimes man page
  * update per shellcheck advice
  * update git-utimes.{1,html} to add --newer flag
  * Don't read git-extras.standup.implicit-week twice in git standup
  * quote mod_s and git_s integer vars
  * updates per request of spacewander
  * Update Commands.md
  * allow modification date updates for symbolic links
  * add --newer flag and ignore files in the working tree or index
  * Documented config git-extras.standup.implicit-week
  * Minor change to git standup -w documentation
  * Improved check if -w or -d was given to git standup
  * Renamed config git-extras.standup.implicit-week from git-extras.standup-implicit-week
  * Documented weekend behaviour of git standup -w
  * docs(instllation): replace `git.io`
  * Bump version to 6.5.0-dev
  * Added config git-extras.standup-implicit-week for git standup
  * Document git standup -w option

6.4.0 / 2022-04-22
==================

  * Merge pull request #964 from spacewander/bro
  * git-browse/browse-ci: use powershell.exe only when it is available
  * Merge pull request #944 from SimonTate/feature/sem-ver-prefix
  * Merge pull request #957 from jackwasey/quiet-or-stderr
  * git-release: Add prefix to semver
  * Merge pull request #959 from pbnj/feat/git-browse-ci
  * fix: fix stderr & stdout redirect
  * Merge pull request #962 from spacewander/gicc
  * git-ignore-io: make sure .gi_list is created before access
  * git-ignore: the directory of target file may not exist
  * fix(git-browse-ci): set pipefail
  * docs: fix docs
  * chore: update docs & completions
  * feat: implement git-browse-ci
  * quiet option, errors to stderr
  * Merge pull request #956 from tfendin/xargs-conflicting-args
  * Removed xargs from git-effort
  * Merge pull request #955 from katrinleinweber/summary-highlight-path-opt
  * Highlight path option more
  * Merge pull request #951 from tfendin/local-commits-all-remotes
  * Updated manual for git local-commits, must track a branch
  * Merge pull request #946 from tfendin/default_branch_logic
  * Made local-commits work with all remotes
  * Updated Readme.md after review
  * Merge pull request #949 from tfendin/git-ignore-ensure-newline
  * Added section about main branch to the Readme file
  * Merge pull request #947 from tfendin/git-unlock-synopsis-fix
  * Merge pull request #948 from tfendin/git-ignore-core-excludesFile
  * Clarified comment of when newline should be added
  * Updated git-extras manual after review.
  * git-ignore: ensure new patterns comes after a newline
  * Fixed bug in git-ignore which ignored config core.excludeFiles
  * Spell corr in git-unlock synopsis
  * Consider init.defaultBranch in git_extra_default_branch, changed default branch to main.
  * Merge pull request #885 from spacewander/add_pkg
  * doc: add packaging status
  * Merge pull request #940 from overengineer/feature/magic
  * Ignored error when git restore --staged fails when there is no commit
  * Merge branch 'master' into merge/magic
  * Added git-magic command
  * Bump version to 6.4.0-dev

6.3.0 / 2021-10-02
==================

  * Merge pull request #942 from spacewander/ffgd
  * git-delete-squashed-branches: fail fast if can't checkout
  * Merge pull request #939 from SimonTate/feature/force-clear
  * git-clear: add force option
  * Merge pull request #936 from tfendin/multiline_synopsis_fix
  * Merge pull request #937 from tfendin/dedup_email_case_insensitive
  * Merge pull request #934 from tfendin/no-merge-summary
  * Adopted git --dedup-by-email to the project coding style
  * summary --dedup-by-email now compares email adresses case insensitive.
  * Updated lines under Synopsis in the manuals so they are commonly formatted
  * Add incompability check for git summary --line --no-merges, split synopsis in its manual.
  * Merge pull request #935 from ax1036/git-un-lock
  * fix git (un)lock with spaced filenames
  * Updated completion for git summary
  * Updated documentation for git-summary --no-merges
  * Added option --no-merges to git summary
  * Merge pull request #932 from spacewander/git-su
  * git-summary: support filtering `--line` with path
  * Merge pull request #865 from pkitszel/pkitszel-git-abort
  * Add git-abort
  * Merge pull request #928 from duckunix/master
  * Update point to github docs for forks from API
  * update working
  * git-fork | Update man/md/html pages to talk about need of the github personal access token
  * Updated documentation (AUTHORS)
  * bin/git-fork | updating for feedback from PR #928
  * git-fork | update to match REST-API auth standards as of 2021-06
  * Merge pull request #926 from nicokosi/patch-1
  * Update install doc: Homebrew is not just for macOS
  * Merge pull request #924 from allejo/feature/delete-squashed-branches
  * delete-squashed-branches: Make side-effect clear in docs
  * delete-squashed-branches: Make branch checkout side effect clear
  * Add delete-squashed-branches command
  * Merge pull request #923 from CleanMachine1/patch-1
  * Picture is broken
  * Merge pull request #920 from matan129/patch-1
  * Ignore checked-out branches on different worktrees
  * Merge pull request #917 from heirecka/remove-git-line-summary-man-page
  * Bump version to 6.3.0-dev
  * doc: Remove man page for git-line-summary

6.2.0 / 2021-03-26
==================

  * Merge pull request #915 from spacewander/typo
  * Merge pull request #914 from spacewander/xch
  * Merge pull request #916 from spacewander/utimes
  * fix(git-utimes): make sure it work under OS X.
  * chore: fix typo
  * fix(git-ignore): use $XDG_CONFIG_HOME only when it is defined
  * Merge pull request #910 from 0xflotus/patch-1
  * fixed small error
  * Merge pull request #908 from nodeg/fix_installation
  * Fix grammer
  * Correct macOS spelling
  * Correct openSUSE spelling and update Version
  * Merge pull request #907 from bbenzikry/zinit-docs
  * Update zinit docs
  * Merge pull request #906 from prestontim/master
  * Remove bug|refactor|chore from documentation
  * Merge pull request #899 from spacewander/git-summary
  * git-summary: reject invalid option
  * ci: use checkout@v2
  * Merge pull request #897 from spacewander/ga
  * ci: move to GitHub Action
  * Merge pull request #882 from vt-alt/git-utimes
  * Merge pull request #896 from Aloxaf/fix_completion
  * fix: zsh completion of git-coauthor command
  * Merge pull request #895 from vanpipy/feature/optional-start-point-when-creeate-branch
  * doc: add the usage of the parameter `--from` for create-branch and feature
  * feat(feature): checkout from start point if exists
  * feat(create-branch): add optional --from to set the start point
  * Merge pull request #894 from alessandro308/merge-into-stashed
  * Merge-into: add stash before to checkout
  * Merge pull request #892 from equt/#891
  * Merge pull request #888 from equt/master
  * Merge pull request #889 from vanpipy/feature/delete-tag
  * [ fix #891 ] Cast branch output if HEAD not exists
  * [ feat ] Quote the default_path var
  * [ fix ] Quote env var
  * [ fix ] Quote the XDG_CACHE_HOME
  * [ feat ] Use default global ignore file
  * [ refactor ] Optimize var not existing check
  * [ fix ] Fix hardcode ignore list file path
  * [ feat ] Add XDG_CACHE_HOME check
  * Merge pull request #890 from zhujian0805/master
  * adding a format for git-contrib
  * git-utimes: Change files modification time to their last commit date
  * feat(delete-tag): get default remote from git config if exists
  * Merge pull request #884 from elonderin/fix-squash-help
  * squash help: re-ran make for extras and squash
  * squash help: ran make man/git-extras.{html,1}
  * squash help: ran make man/git-squash.{html,1}
  * squash help: corrects option name in PR
  * Merge remote-tracking branch 'u/master' into HEAD
  * Merge pull request #886 from TheTechOddBug/master
  * Fixing summary for --squash-msg option.
  * Updates git-squash.md: fixes help which was unclear and had remnants from copied template it appears
  * Bump version to 6.2.0-dev

6.1.0 / 2020-09-26
==================

  * Merge pull request #878 from spacewander/default_br
  * Merge pull request #880 from spacewander/fix_bsd_sed_regex
  * git-info: fix regex for bsd sed
  * Merge pull request #879 from spacewander/pass_arg
  * feat: pass origin argument down to git execution
  * change: migrate default branch
  * Merge pull request #872 from yuravg/pr_typo
  * doc: fix typo
  * Merge pull request #869 from spacewander/typo
  * git-back: removed
  * fix typo
  * Merge pull request #868 from spacewander/zsh_completion
  * sort completion in alphabetical order
  * remove incorrect completion
  * git-info: add zsh completion
  * Merge pull request #867 from yuravg/pr2source
  * doc: fix argument description
  * git-info: moved argument checking
  * git-info: fix namespace
  * doc: update derived git-info files
  * doc: add description for git-info
  * Add bash completion for git-info
  * git-info: colorized headers
  * git-info: extend configuration and commit information
  * git-info: remove notes about git-log, git-show
  * git-info: add info about submodules
  * git-info: fix indentation, remove comment
  * Merge pull request #864 from v-y-a-s/pr
  * Grammar correction
  * Remove $user
  * corrections
  * Update doc
  * fix config message name
  * Remove comments
  * PR test
  * Merge pull request #860 from soraxas/implement-fish-completions
  * implement fish completions file
  * Merge pull request #853 from bethesque/feat/git-browse-with-multiple-remotes
  * feat(browse): automatically select origin remote if one exists, fallback to first otherwise
  * Merge pull request #854 from bethesque/fix/git-browse-sed-on-mac
  * fix(browse): update sed pattern to work on mac
  * Bump version to 6.1.0-dev

6.0.0 / 2020-06-22
==================

  * doc: remove gitter
  * git-cp: remove trailing space
  * Merge pull request #849 from vr8hub/undodoc
  * Merge pull request #850 from vr8hub/newundo
  * Tighten numeric regex
  * Cleanup code
  * Modify to work when only a single commit, add parameter checks
  * Correct undo documentation to match code order of parameters
  * Merge pull request #847 from Amorymeltzer/patch-1
  * docs: Note flag for git extra --version
  * Merge pull request #846 from spacewander/note
  * doc: add a note about the package maintainer.
  * Merge pull request #844 from ihoro/installation-via-freebsd-pkg
  * Merge pull request #843 from spacewander/remove_git_feature
  * break change: remove docs and other stuff of git-feature's alias
  * Merge pull request #845 from alerque/remove-feature-aliases
  * Remove scripts that are mere alias wrappers for git-feature
  * docs: mention installation via FreeBSD pkg
  * Merge pull request #840 from spacewander/archive-invalid
  * Merge pull request #841 from sgleizes/bugfix/git-release-zsh-completion
  * Fix missing newline escapes in git-release zsh completion
  * git-archive-file: rename invalid chars in the output filename
  * Merge pull request #837 from jldugger/jldugger/pr-remote-default
  * Merge pull request #836 from jldugger/jldugger/feature-config
  * add a default for the remote to fetch a pr from
  * add a config setting for prefix
  * Merge pull request #829 from cpradog/master
  * update zsh completion for bug and refactor commands
  * updated zsh completion script
  * updated git-feature documentation
  * add squash option to git-feature
  * add squash option to git-feature
  * Merge pull request #826 from Natim/feature/825/add-git-cp
  * Simplify the code.
  * Signal if the destination already exists.
  * @spacewander review.
  * Merge pull request #827 from Natim/fix-man-page-for-git-psykorebase
  * Fix checks.
  * Update man page export for git-psykorebase with ronn-ng 0.9.0
  * @mschneiderwind review.
  * Add documentation.
  * Add first version of git-cp
  * Merge pull request #824 from mapitman/master
  * Fix documentation for git-browse
  * Merge pull request #823 from mapitman/master
  * Implement suggested changes from code review
  * Add git-browse command
  * Merge pull request #820 from spacewander/deprecate_git_back
  * change: deprecate git-back
  * Merge pull request #817 from bric3/adds-git-brv
  * Fixes #770: Adds git-brv
  * Merge pull request #816 from spacewander/git-sed-pathspec
  * git-sed: limit paths via pathspec
  * Bump version to 5.2.0-dev.

5.1.0 / 2019-12-21
==================

  * git-bulk: support cloning from a relative path
  * git-standuo: clarify the -a option
  * git-paste: check pastebinit before running it
  * git-coauthor: quote variable in the comparison
  * git-bulk: don't disappoint shellcheck
  * Merge pull request #812 from spacewander/git-sed-escape
  * git-sed: escape special characters for tr
  * Merge pull request #811 from eli-schwartz/portability
  * build: do not require the nonstandard and unpredictable 'which' utility
  * add repositories to workspace from source (#804)
  * Merge pull request #810 from roxchgt/read-not-need-repo
  * read COMMANDS_WIHOUT_REPO from not_need_git_repo file
  * Merge pull request #806 from spacewander/retire_make_with_msys
  * Merge pull request #808 from drasill/master
  * git-ignore: support non-default .git directory
  * retire the msysgit installation script
  * Merge pull request #802 from spacewander/fix-git-bulk-arg-count
  * git-bulk: line break is need in the SYNOPSIS doc section
  * fix bug in allowedargcount() to not execute command if wrong args count
  * Merge pull request #801 from spacewander/fix-delete-submodule
  * git-delete-submodule: don't remove the history of deleted submodule
  * Merge pull request #798 from wolviecb/signed_release
  * Add flags -s and -u for signed tags
  * Merge pull request #795 from spacewander/git-squash-commit-msg
  * Merge pull request #793 from spacewander/git-standup-group-by-branch
  * git-squash: miss completion script change
  * git-squash: clean up shellcheck warnings
  * git-squash: add --squash-messages to concat commit messages into one.
  * git-standup: add option to limit the number of commit
  * Merge pull request #789 from go2null/delete-empty-gitmodules
  * git-delete-submodule: comment the DUMMY prefix and ignore the output of grep -v.
  * git-standup: add separate newline between the output
  * add PR changes
  * add --force option to continue on error
  * improve readability
  * display git submodule status output before exiting
  * check git submodule status before declaring success
  * reorganize flow
  * delete empty .gitmodules
  * git-standup: add option '-B' to group the commits by branch
  * Merge pull request #792 from spacewander/git-summary-cleanup
  * git-summary: clean up other shellcheck warnings
  * git-summary: fix incorrect active days when commits range is given
  * git-summary: remove useless result function.
  * Merge pull request #790 from spacewander/git-summary-merge-email
  * git-summary: add --dedup-by-email to remove duplicate users
  * Merge pull request #788 from spacewander/doc_git_summary_line
  * git-summary: add missing example of --line option
  * Merge pull request #787 from rvbuelow/patch-1
  * Merge pull request #786 from mbologna/patch-1
  * Use GIT_DIR environment variable to to set .git directory
  * Docs: add OpenSUSE distribution information
  * Merge pull request #784 from spacewander/git-effort-col-len
  * git-effort: adjust column limit according to the paths
  * Merge pull request #708 from pabs3/git-paste
  * Regenerate docs
  * Add git-paste for sending patches to pastebin
  * Merge pull request #778 from pabs3/cleanups
  * Switch from using /tmp to using mktemp
  * Switch http URLs to https where possible
  * Fix typos
  * Fix an indefinite article in the documentation
  * Merge pull request #776 from spacewander/update_git_pr_doc
  * Merge pull request #777 from fengkx/zplugin-install-completion
  * docs(Installation): :memo: add src in zplugin ice modifier to source the completion file
  * git-pr: mention the limitation of -m option
  * Merge pull request #772 from jacobherrington/add-git-coauthor
  * Add conditional logic for linebreaks
  * Ensure arguments exist
  * Add git coauthor command
  * improve the quality of the integrity check.
  * Merge pull request #774 from jacobherrington/patch-2
  * Bump version to 5.1.0-dev.
  * Link to the contributing document

5.0.0 / 2019-08-16
==================

  * Merge pull request #769 from spacewander/no_line_summary
  * git-line-summary: should be the history
  * Merge pull request #768 from bric3/fix-more-character-encoding-issues
  * git-guilt: protect against encoding issues with LC_ALL=C
  * Merge pull request #767 from spacewander/rename_branch_order
  * git-rename-branch: change branch argument order
  * Merge pull request #765 from spacewander/column_dependency
  * Makefile: check dependencies before installation.
  * Installation.md: add dependencies section.
  * man/Readme.md: we don't need to update git-extras docs separately
  * Merge pull request #763 from spacewander/strict_check_integrity
  * check_integrity.sh: check more strickly.
  * Merge pull request #762 from spacewander/pr_merge
  * Merge pull request #761 from btmurrell/preference-for-create-branch
  * implements remote pref for create-branch
  * git-pr: add -m|--merge option to check out a merge commit
  * impl for checking remote pref
  * Merge pull request #754 from spacewander/prompt_passwd_before_2fa
  * git-fork: prompt for password before 2FA code.
  * check_integrity.sh: improve readability.
  * Merge pull request #753 from tiemonl/GH-752_update_reauthor_documentation
  * GH-752 updated documentation to show rename workaround
  * Merge pull request #751 from timfeirg/master
  * git-mv-remote: rename a remote regardless of any existing remotes
  * Installation instructions added for CRUX (#746)
  * Merge pull request #723 from bittner/feature/git-undo-soft-leave-changes-staged
  * Merge pull request #744 from spacewander/git-guilt-identation
  * git-guilt: avoid exceeding 80 columns.
  * Bump version to 4.8.0-dev.
  * Make `git undo -s` restore the staging area

4.7.0 / 2019-02-09
==================

  * git-pr: emphasized that the remote is required when pulling multiple PRs.
  * Merge pull request #743 from spacewander/allow_multiple_pr
  * git-pr: accepted multiple GitHub URL or ID with remote.
  * git-pr: added <[remote]:pr number> option.
  * Merge pull request #740 from spacewander/tweak_man_readme
  * doc: clarify the current working directory when building the docs.
  * Merge pull request #739 from sleagon/master
  * feat: Add -s(--soft) for git sync
  * Merge pull request #738 from StuartFeldt/add-symlinks-to-bulk-command
  * Adding support for symlink directories in bulk command
  * Merge pull request #737 from smancill/standup-ensure-colors
  * git-standup: ensure color usage
  * Merge pull request #736 from spacewander/git_force_clone_not_need_git_repo
  * misc: sort command list in alphabetical order
  * git-force-clone: should not need git repo
  * Merge pull request #734 from zentarul/master
  * Fix missing double quotes after %DEBUG%
  * install.cmd: tweak comments
  * Merge pull request #732 from sachin-gupta/sg-mods
  * Fix: Dev: `/E` option required with MORE for working on higher version of Windows 10 (**_Build 17134_**)
  * Merge pull request #729 from orestisf1993/patch-1
  * git-rename-branch: Don't fail if remote doesn't exist
  * Bump version to 4.7.0-dev.

4.6.0 / 2018-08-11
==================

  * Merge pull request #727 from spacewander/strip_caret
  * Makefile: change the installed manpage destination in FreeBSD (#725)
  * git-changelog: should remove ^0 suffix from the commit description.
  * Merge pull request #722 from spacewander/git_changelog_start_commit
  * git-changelog: add --start-commit option, like --start-tag but for commit
  * Merge pull request #721 from spacewander/git_changelog_list_newline
  * git-changelog: add missing newline to the plain output
  * Merge pull request #713 from pabs3/docs
  * Merge pull request #717 from flatcap/ignore-private
  * optimisation of mkdir
  * Ensure info dir exists
  * add: git-ignore -p (private to repo)
  * Merge pull request #716 from francoism90/patch-1
  * Added Arch Linux
  * Merge pull request #714 from spacewander/fix_detect_sed_i_support
  * Documentation rebuild: git-sed.* flags argument
  * Documentation rebuild: git-clear.html whitespace removal
  * Documentation rebuild: git-extras.* updates
  * Documentation rebuild: index.txt updates
  * Documentation rebuild: dates and headers
  * Remove one of the documentation building tools
  * Remove some trailing whitespace
  * Merge pull request #715 from tjaartvdwalt/master
  * Major/Minor release should reset minor/patch versions to 0
  * Fix greedy match of version number
  * git-sed: fix previous bsd sed workaround
  * Merge pull request #712 from spacewander/detect_sed_i_support
  * git-sed: detect sed -i support and work around for the BSD sed
  * Merge pull request #709 from pabs3/git-sed
  * git-sed: discover a separator when the / character is used in arguments
  * git-sed: pass the -r option to the xargs command
  * git-sed: Allow the flags to be passed as a third argument
  * Merge pull request #706 from MontakOleg/delete-branch
  * Fix deleting branches without upstream
  * Merge pull request #704 from ramlev/master
  * Remove double path delimiters in zsh description
  * Merge pull request #703 from psprint/master
  * Installation.md: Zsh-plugin method which doesn't require root access
  * Bump version to 4.6.0-dev.

4.5.0 / 2018-02-18
==================

  * git-release: show message if nothing given after --semver
  * doc: update git-extras index
  * Merge pull request #639 from spacewander/avoid_deleting_local_upstream
  * Merge pull request #693 from xakraz/fix-mktemp-pattern
  * git-release: add --no-empty-commit for empty commit hater
  * git-release: create an empty release commit if there is nothing to commit
  * git-summary: unescape tab for linux column utility
  * git-undo: add confirmation when `-h` is specified
  * Fixed mktemp template to support busybox (and Alpine linux)
  * Merge pull request #691 from koppor/patch-1
  * Remove trailing dot of German Windows
  * Merge pull request #690 from dominicbarnes/release-push-tags-first
  * feat(git-release): push tags first to help ci tools not miss them
  * Merge pull request #687 from spacewander/add_semver
  * git-release: handle extra non-numeric prefix in tag with --semver
  * Merge pull request #686 from spacewander/add_semver
  * git-release: add --semver option
  * Merge pull request #684 from spacewander/ignore_unknown_arg
  * git-release: function usage doesn't exist, ignore unknown argument instead
  * Merge pull request #681 from EdwardBetts/master
  * Fix so 'git rebase-patch' is described once.
  * Merge pull request #680 from lhernanz/master
  * Preserve the existing user_commands in the git completion system
  * Merge pull request #679 from spacewander/update_git_changelog_doc
  * Merge pull request #678 from timhwang21/devs/thwang/docs-update
  * Mention how to control changelog format in docs of git-changelog
  * Docs> Add -- in front of cmd for git log
  * Merge pull request #676 from gormac/master
  * Fix 'Invalid code page' error when resetting code page at end of script
  * Merge pull request #675 from quite/effort-cursor
  * git-effort: restore normal (visible) cursor properly
  * Merge pull request #674 from tj/pull-request-two-factor-auth
  * Add GitHub two-factor auth support to git-pull-request
  * Merge pull request #672 from mehandes/patch-1
  * Added Nix/NixOS method of installation
  * Merge pull request #671 from sambostock/improve-ignore-io
  * Use local variables & format strings
  * Fix omission when alphabetically printing ignores
  * Remove arbitrary column limit on ignore-io
  * Merge pull request #670 from zeeshanu/patch-1
  * Fix typo
  * Merge pull request #668 from isaacm/patch-1
  * Fix typos, remove trailing whitespace
  * install: submit brew patch to upstream
  * Bump version to 4.5.0-dev.
  * git-delete-branch: avoid deleting local upstream

4.4.0 / 2017-07-15
==================

  * install: display absolute path of zsh completion script
  * zsh: update completion of git bug|chore|feature|refactor|create-branch
  * git summary: use more common way to cd to top level directory
  * Merge pull request #664 from mapitman/master
  * Update man page for `create-branch`
  * Update man pages
  * Update docs for new behavior
  * Use "$@" instead of $@
  * Consolidate feature/bug/chore/refactor logic
  * Allow -r parameter to be in any order in command line
  * Add ability to specify a remote
  * Fix Issue #186
  * fix a wrong name in installation message
  * Merge pull request #662 from nschlimm/master
  * Added git-bulk to not_need_git_repo
  * fix various typos
  * Merge pull request #659 from bersace/mr
  * Add git-mr to checkout GitLab merge requests
  * Merge pull request #656 from dueringa/patch-1
  * Fix typo in git-extras
  * Merge pull request #654 from spacewander/replace-xargs-r
  * git-delete-merged-branches: replace xargs -r option
  * Bump version to 4.4.0-dev.

4.3.0 / 2017-05-05
==================

  * git-authors: remove trailing spaces
  * Merge pull request #649 from adriaanzon/patch-1
  * Merge pull request #651 from spacewander/pass-arguments-to-hooks
  * git-release: add pre-release failure message
  * git release: stop if pre-release hook fails
  * git-release: update docs
  * pass release arguments to pre/post-release scripts
  * git-fork: Let curl exit with error code on fail
  * Merge pull request #647 from SMillerDev/patch-1
  * Add BSD cat support
  * Merge pull request #646 from spacewander/upgrade-git-standup
  * git-standup: update zsh completion
  * git-standup: also update the docs
  * git-standup: add sanity check to -d option and overwrite -w option
  * git-standup: upgrade interface to catch up with kamranahmedse/git-standup
  * Merge pull request #642 from nschlimm/git-bulk-command
  * Typos again
  * Corrected repository location print out and docs ws-root-directory absolute path
  * Codereview Spacewander - whitespaces in workspace locations
  * Merge pull request #643 from jonyamo/git-pr_clean-git-config
  * Review from spacewander
  * Remove slashes from git-config command
  * Merge branch 'master' into git-bulk-command
  * Merge pull request #636 from spacewander/fix_rename_branch
  * Merge pull request #641 from tj/fix_pull_request_upstream
  * git-rename-branch: use detected upstream remote
  * git-pull-request: use detected upstream remote
  * Better behaviour in non workspace directories
  * Current workspace is default target of bulk operations
  * Even shorter
  * Code refactor
  * bug fix in single ws mode
  * code formatting
  * Fix in git-bulk head
  * New Command git-bulk initial commit
  * Merge pull request #635 from spacewander/fix_rename_branch
  * fix syntax & name variables better in rename-branch
  * Merge pull request #633 from nschlimm/columnsflex
  * taken out duplicate columns setting
  * Optimized file length calculation
  * Columns in git-effort adopt to file length
  * Merge pull request #630 from jjlin/rhel/centos
  * Add RHEL/CentOS installation
  * Merge pull request #629 from dankilman/fix-git-effort
  * Fix git-effort for paths starting with dash
  * Merge pull request #626 from jldugger/jldugger/email-fallback
  * fall back to EMAIL when user.email is not configured
  * Merge pull request #619 from spacewander/git-summary-separator
  * Merge pull request #624 from spacewander/has_git_commit
  * Check commit existed before running some commands
  * Merge pull request #615 from techjacker/master
  * Adds SSH prompt to git fork
  * use U+266A instead of comma as separator
  * Merge pull request #610 from nicolaiskogheim/fix-spelling
  * spelling: {a,an} archive. Fix #609
  * Merge pull request #606 from spacewander/fix-git-extras-update
  * fix git-extras update and tweak Windows detection
  * Merge pull request #585 from tardypad/stamp
  * Merge pull request #578 from tardypad/count_fix_extra_arguments
  * stamp: show real looking results in Commands.md doc
  * stamp: add warning in documentation about corner case
  * stamp: add zsh autocompletion
  * stamp: remove non used multiple lines error messages
  * stamp: the message consists in all terms after the identifier
  * stamp: identifier is case insensitive for the replacement
  * stamp: add to Commands doc
  * stamp: add manual
  * stamp: add bash autocompletion
  * stamp: add replace option
  * stamp: display new full message as result
  * stamp: add extra optional message parameter
  * stamp: add basic script
  * Merge pull request #601 from richardfearn/git-sed-spaces-in-filenames
  * Merge pull request #603 from richardfearn/git-clear-consistent-defaults
  * Merge pull request #602 from richardfearn/git-delete-merged-branches-fix
  * git-clear-soft: change default yes/no option to "no" (as with git-clear)
  * git-delete-merged-branches: use "xargs -r" to prevent error when there are no branches to delete
  * git-sed: use "git grep -z" and "xargs -0" to cope with spaces in filenames
  * Merge pull request #600 from richardfearn/git-fresh-branch-fix
  * Merge pull request #599 from richardfearn/improve-yes-no-prompts
  * git-fresh-branch: fix handling of 'yes' response when there are changes
  * git-{clear,clear-soft,sync}: improve yes/no prompts
  * Merge pull request #598 from richardfearn/fix-git-sed-typo
  * Merge pull request #597 from richardfearn/commands-md-improvements
  * git-sed: fix 'unkonwn' typo
  * Commands.md: add link to 'git summary' in 'git line-summary' documentation
  * Commands.md: add links to "git bug", etc. to index
  * Commands.md: add 'git rscp' link to 'git scp' documentation
  * Commands.md: put commands in alphabetical order
  * Merge pull request #596 from richardfearn/archive-file-typo-fix
  * Fix typo in archive-file documentation
  * Merge pull request #595 from aaguilera/master
  * fix: git-squash docs. Replaced 'actual' with 'current'
  * Merge pull request #592 from spacewander/fix_integrity
  * Add travis ci
  * Merge pull request #594 from spacewander/fix_release
  * show all commit messages if no tag found
  * strip out branches like trap-effort-signals
  * Add git-reauthor to completion script
  * Relax #! format check
  * Merge pull request #591 from nottrobin/force-clone
  * Be explicit about only resetting git directories
  * Fix branch option parsing
  * Fix usage
  * Use LC_ALL=C for locale consistency
  * Remove unnecessary check
  * git-force-clone
  * Merge pull request #590 from bbbco/changelog-tmp-file-fix
  * Need to remove the temp file regardless
  * Merge pull request #589 from yelinaung/yla/typo-fixes
  * Spelling fixes for the roon file and html files
  * Spelling fixes
  * Merge pull request #588 from spacewander/no-email
  * Add --no-email to git-author
  * Bump version to 4.3.0-dev.
  * count: remove usage of extra arguments for detailed display

4.2.0 / 2016-10-08
==================

  * remove contributors' email addresses to avoid #544
  * promote two maintainers
  * Merge pull request #584 from grindhold/fix-583
  * fixes #583
  * update docs to clarify rename-branch (#581)
  * Make git-pr set up branch for pulling (#570)
  * add link to ronn git repo (#575)
  * add rename-branch command (#576)
  * Merge pull request #569 from nicolaiskogheim/docs/repl-cleanup
  * git-repl: improve and clean up docs
  * Merge pull request #568 from wcmonty/master
  * Add 'exit' to git-repl command documentation
  * Add built in 'exit' command to git-repl
  * Merge pull request #567 from nicolaiskogheim/git-pull-request-fix#546
  * pull-request: should read local config if present
  * Merge pull request #566 from nfischer/fix-man-page-typo
  * git-release: fix typo in documentation
  * Merge pull request #565 from nicolaiskogheim/git-missing-argument-parsing
  * git-missing: do proper argument parsing. Fix #562
  * Merge pull request #563 from lukechilds/improve-fork
  * Update git-fork man page
  * Merge pull request #564 from sorbits/patch-3
  * Remove a non-contributor from AUTHORS
  * Update docs to reflect new git-fork behaviour
  * Set fork remotes using ssh if available
  * Add git reauthor (#548)
  * Merge pull request #555 from spacewander/contributing
  * modify CONTRIBUTING.md again
  * Merge pull request #557 from spacewander/check_integrity
  * Merge pull request #561 from lukechilds/improve-json-encoding
  * Clean up git-pull-request
  * Improve JSON encoding
  * Merge pull request #560 from lukechilds/patch-2
  * Merge pull request #559 from lukechilds/patch-1
  * Fix incorrect comment in git-fork
  * Fix typo in Installation.md
  * Merge pull request #558 from spacewander/fix_legacy_problem
  * add doc for git-pull-request and others
  * modify CONTRIBUTING.md
  * update check_integrity with nicolaiskogheim's patch
  * add git-release-patch to Commands.md
  * add git-back to Commands.md
  * regenerate git-obliterate doc
  * follow common shebang
  * add git-show-(un)merged-branches to Commands.md
  * Add check integrity script
  * Add contributing guideline
  * Merge pull request #554 from npcode/fork-origin
  * fork: Fetch `origin` after forking
  * fork: Quote refs by backtick rather than single quote
  * fork: Add git-fork.html removed by accident
  * Merge pull request #553 from npcode/fork-origin
  * fork: Describe the behavior if current dir is repo
  * fork: Rename 'origin' to 'upstream' after forking
  * Merge pull request #552 from npcode/fork-origin
  * fork: Fork 'origin' remote repo if repo is not given
  * Merge pull request #551 from spacewander/zsh-completion
  * submit zsh completion script to upstream
  * update the title of git-clear-soft
  * Merge pull request #550 from phuu/patch-1
  * Add note about overwriting git aliases
  * Merge pull request #547 from svanburen/patch-1
  * Fix typo
  * Merge pull request #545 from spacewander/via_ssh
  * fix git-fork by removing '.git'
  * Merge pull request #543 from spacewander/via_ssh
  * fix the support for forking via ssh
  * Merge pull request #412 from spacewander/git-obliterate
  * Merge pull request #536 from spacewander/delete_submodule
  * Merge pull request #537 from vigilancer/master
  * update documentation. fix "git ignore-io" flags
  * Update the way to delete submodule
  * Merge pull request #533 from Addvilz/add-git-clear-soft-modify-git-clear
  * Edit description of git clear-soft to indicate hard reset
  * Add git-clear-soft command 	Modify git-clear to indicate default behavior of removing git ignored files
  * Merge pull request #513 from lgastako/master
  * Merge pull request #525 from spacewander/git-standup
  * Merge pull request #526 from carrodher/patch-1
  * Add Ubuntu installation
  * add docs for git standup
  * add git-standup
  * Merge pull request #519 from ifdattic/patch-1
  * Fix typo: typess => types
  * Merge pull request #515 from ammarnajjar/fedora-install
  * Add Fedora package-manager installation instruction
  * Add -m flag to git-setup to set the initial commit message.
  * Merge pull request #512 from Lee-W/master
  * Merge pull request #1 from tj/master
  * Fix ignore-io searching bug
  * Merge pull request #508 from pra85/patch-1
  * Mention initial copyright year and add contributors to copyright
  * Merge pull request #509 from supercrabtree/master
  * Fix typo in git-clear documentation
  * Bump version to 4.2.0-dev.
  * add missing git-obliterate documentation
  * now we can specify a commit range for git-obliterate

4.1.0 / 2016-01-25
==================

  * Merge pull request #503 from spacewander/fix_502
  * Merge pull request #507 from rstacruz/git-pr-manual
  * Regerenate git-pr.html
  * Merge pull request #506 from rstacruz/git-pr-manual
  * Update git PR manual to mention URLs
  * handle GIT_EDITOR which contains space
  * use ps -f and awk to emulate pgrep
  * Merge pull request #500 from kumon/master
  * add upstream check & bugfix
  * add example of git-sync
  * upstream is used by default
  * Merge pull request #497 from JanSchulz/win_inst2
  * add git-sync
  * Merge pull request #499 from tj/add-bsd-installation
  * Add BSD installation instructions.
  * installation.md: Update information about column.exe
  * install.cmd: add a check for write rights to the install folder
  * install.cmd: properly escape the ! in the shebang line
  * Merge pull request #496 from JanSchulz/win_inst
  * Make the win installer more robust
  * Merge pull request #494 from apjanke/fix-git-repo-inclusion
  * Merge pull request #495 from JanSchulz/patch-1
  * Update Installation.md
  * Makefile: fix inverted list of commands that use is_git_repo
  * Add Gitter badge.
  * Bump version to 4.1.0-dev.

4.0.0 / 2015-12-28
==================

  * Add David Rogers to AUTHORS.
  * Merge pull request #481 from al-the-x/multi-file-touch
  * Better USAGE message
  * Touch multiple files supplied
  * Use `$@` instead of `$*` re #467
  * Update AUTHORS.
  * Merge pull request #490 from apjanke/etc-under-prefix
  * installation: put $SYSCONFDIR (/etc) under $PREFIX by default
  * Merge pull request #489 from apjanke/customize-etcdir
  * Makefile: allow customizing of SYSCONFDIR (/etc) location
  * Merge pull request #488 from apjanke/git-clear-shebang
  * Fix missing shebang in git-clear and missing +x on others
  * Update all man pages.
  * Merge pull request #479 from JanSchulz/global_gitignore
  * Merge pull request #448 from Lee-W/master
  * Add more info how to set global gitignore
  * Regenerate git-changelog man pages (.html and .1) for #471.
  * Merge pull request #471 from JanSchulz/merge-changelog
  * git-changelog: option to only use merges
  * Merge pull request #469 from JanSchulz/windows-install
  * Merge pull request #468 from spacewander/use-real-purplish
  * Use the default installation path in install.cmd
  * use real purplish
  * Merge pull request #466 from anarcat/master
  * Merge pull request #465 from spacewander/fix-color
  * add simple sed command
  * disable color if the output is not printed to tty
  * replace wildcard '?' to literal '?'
  * git-scp: use portable terminal escape sequences
  * Merge pull request #460 from apjanke/summary-defensive-locale
  * Merge pull request #458 from apjanke/makefile-refactor-libs
  * Merge pull request #459 from apjanke/effort-portable-colors
  * git-summary: protect against character encoding issues with LC_ALL=C
  * git-effort: use portable terminal escape sequences
  * Makefile: refactor is-git-repo inclusion logic
  * Merge pull request #454 from apjanke/makefile-escape-mktemp
  * Makefile: escape $ used inside eval as shell variable
  * Merge pull request #453 from jhnns/pr-url
  * Add possibility to also checkout pull requests based on GitHub urls
  * Merge pull request #452 from akimd/summary-locale
  * summary: beware of locale issues, and pass options to line-summary
  * Merge pull request #443 from Natim/patch-1
  * Merge pull request #444 from spacewander/install_without_alias
  * Merge pull request #446 from ssssam/fix-active-days
  * Merge pull request #447 from RichardLitt/patch-1
  * Update git-ignore-io mannual
  * Replace "export" option with "replace" in git-ignore-io
  * Remove exclamation mark
  * Remove warning when search without word.
  * Fix typo
  * Add warning when there is not argument after search, append and export
  * Fix ~/.gi_list not exist problem
  * Alphabetized list
  * effort, summary: Correctly estimate the number of active days
  * Merge pull request #445 from nicolaiskogheim/straighten-up-effort
  * effort: change order of arguments to function
  * effort: add usage message
  * effort: More robust argument parsing
  * add alias conflict prompt
  * Merge pull request #440 from spacewander/features/feature-alias
  * Add full name for list option
  * Fix usage error
  * Make sure git-authors doesn't return twice the same one.
  * update git-feature docs
  * add alias to git-feature
  * Modify print_last_modified_time to make it Linux compatible
  * Merge pull request #441 from spacewander/features/remove-checkout
  * Merge branch 'master' of https://github.com/Lee-W/git-extras
  * Fix doc error for git-ignore-io
  * Fix doc error for git-ignore-io
  * Remove redundant \n in tr
  * Not to update list each time git-ignore-io is executed
  * Refactor git-ignore-io and remove .gitignore
  * Update manual and description in Commands
  * remove duplicate checkout
  * Generate manual using ronn for git-ignore-io
  * Finish manual for git-ignore-io
  * Fix typo
  * Add description to Commands.md for git-ignore-io
  * Implement search function or git-ignore-io
  * Remove help from git-ignore-io
  * Init gitignore and ignore vim osx temp files
  * Merge gi_extension project into git extras as git-ignore-io
  * Merge pull request #436 from nwinkler/patch-1
  * Merge pull request #437 from nwinkler/patch-2
  * Fixed typo in install.sh
  * Updated documentation for git-ignore
  * Merge pull request #435 from nwinkler/patch-1
  * Added details to git-pr documentation
  * Merge pull request #433 from grindhold/git-clear
  * made more precise security-question.
  * more concise implementation of git-clear
  * Fix typo in variable name
  * added git-clear to Commands.md
  * added manpage for git-clear
  * implemented git-clear
  * Merge pull request #432 from stevemao/patch-1
  * fix link of `git feature|refactor|bug|chore`
  * Merge pull request #425 from nicolaiskogheim/makefile-fix
  * Mark default task as .PHONY
  * Merge pull request #430 from spacewander/git-extras
  * make it possible to update via `git extras`
  * Merge pull request #428 from spacewander/update-commands
  * Merge pull request #429 from nicolaiskogheim/merge-into-ff-only
  * merge-into: change --ff option to --ff-only. fix #421
  * update Commands.md
  * Merge pull request #411 from Natim/add-psykorebase-command
  * Improve man page presentation.
  * Add documentation.
  * Merge pull request #426 from spacewander/update-for-new-version
  * change 'search-term' to 'search-pattern'
  * abort git-alias when too many arguments given.
  * Merge pull request #423 from nicolaiskogheim/effort-paths
  * Merge pull request #424 from nicolaiskogheim/fork-docs
  * Merge pull request #422 from nicolaiskogheim/effort-bugfix
  * effort docs: add note about omitting unsorted results
  * effort docs: add example with directories
  * effort docs: filename -> path
  * effort docs: Adjust numbers in example
  * effort: rename 'file' to 'path' to be more accurate
  * Set default make task to be install
  * fork docs: change SSH to HTTPS in example
  * effort: fix active days always 1
  * Merge pull request #419 from nicolaiskogheim/git-guilt
  * Merge pull request #420 from nicolaiskogheim/git-summary
  * line-summary: 'function f{...' -> 'f() {...'
  * line-summary: add missing quotation marks
  * line-summary: tighten regex
  * summary docs: Remove --line example
  * summary docs: explain relation to git-line-summary
  * summary docs: use correct order of arguments
  * guilt: remove --help option
  * guilt: document call without arguments
  * guilt docs: Capitalize letters
  * guilt: Adds simplified example
  * Merge pull request #418 from nicolaiskogheim/fork-bugfix
  * fork: http-urls had colon instead of slash
  * Merge pull request #416 from nicolaiskogheim/fork-docs
  * Merge pull request #415 from nicolaiskogheim/contrib-docs
  * fork: original->upstream in docs
  * contrib: update docs
  * Merge pull request #414 from nicolaiskogheim/alias-docs
  * alias: docs
  * Add completion for git-psykorebase.
  * Create a bash version of git-psykorebase — Fixes #411
  * Merge pull request #409 from nicolaiskogheim/refactor-alias
  * alias: polish the docs
  * alias: bugfix
  * Merge pull request #408 from nicolaiskogheim/refactor-contrib
  * contrib: refactor, and conform to git
  * Merge pull request #405 from nicolaiskogheim/fix-filenames-with-spaces
  * Merge pull request #404 from nicolaiskogheim/freebsd-fix
  * Merge pull request #406 from nicolaiskogheim/portable-msysgit
  * git-alias: use sed insted of colrm
  * git-changelog: use cp instead of mv
  * git-extras: use git-help instead of man
  * add install script for PortableGit(msysgit)
  * Quote variables bc of filenames with spaces
  * Guard against 'seq 0'
  * Fix error on FreeBSD with process substitution
  * Pass --import-functions if required
  * Merge pull request #403 from andreicristianpetcu/master
  * effort: documentation for git effort --since #326
  * Merge pull request #401 from nicolaiskogheim/effort-above-error-on-NaN
  * effort: error on bad value to --above
  * Merge pull request #400 from nicolaiskogheim/fix-off-by-one
  * Merge pull request #391 from nicolaiskogheim/effort-limit-commits
  * Merge pull request #388 from chernjie/release
  * Merge pull request #398 from nicolaiskogheim/git-graft
  * Merge pull request #399 from nicolaiskogheim/git-archive-file
  * archive-file: cleaner way to get current branch
  * graft: Require destination branch. Fix #23
  * effort: don't count untouched files
  * Add info about new options to man pages
  * Add completion for more options to effort
  * Do proper argument parsing
  * effort: allow sending options to log. Fix #326
  * Merge pull request #396 from tocker/bug/changelog-catch-head
  * Catch "HEAD -> master" when creating the changelog
  * Merge pull request #394 from markeissler/changelog-signal-trap
  * Remove unused var.
  * Merge pull request #390 from nicolaiskogheim/effort-color-relative-to-above
  * Handle signals in git-changelog.
  * Meke coloring respect --above. Fix 74
  * Merge pull request #392 from nicolaiskogheim/WIP-effort-parallelize
  * Avoid spawning subshell
  * Remove unnecessary call to cat
  * perf: reduce calls to git log
  * Parallelize git-effort with xargs
  * Alter options to git log. Remove pipe
  * cd man && ./manning-up.sh && git diff --stat | grep ' 2 ' | awk '{print }' | xargs git checkout --
  * Merge pull request #386 from rstacruz/patch-2
  * Use https for git-fork
  * Merge pull request #385 from gisphm/master
  * added windows installation section in the Installation.md
  * format install.cmd
  * add install.cmd for installation on windows
  * Merge pull request #383 from Somasis/master
  * Makefile: Use a more portable mktemp invocation
  * Using shorter URL
  * Merge pull request #381 from spacewander/master
  * installation with curl and bash
  * Merge pull request #380 from spacewander/master
  * keep installation silent
  * Merge pull request #378 from spacewander/master
  * update installation in `git-extras update`
  * Merge pull request #377 from go2null/master
  * FIXes location of `--` for `grep`
  * FIXes 'mktemp' to work again on Linux
  * Merge pull request #373 from zlx/feature/document_line_summary
  * Document for git-line-summary
  * Merge pull request #372 from spacewander/patch-1
  * install the latest release version of git-extras
  * Merge pull request #370 from phigoro/master
  * git-effort: replace "wc | cut" with "wc | awk"
  * Merge pull request #369 from phigoro/master
  * align hashbang of git-guilt & git-merge-into
  * Merge pull request #368 from zlx/feature/strong_line_summary
  * Fix Fatal for git-line-summary
  * Merge pull request #365 from rkennedy/bug-ignore-regex2
  * Don't treat ignored patterns as regexps

3.0.0 / 2015-04-27
==================

  * Merge pull request #363 from chernjie/pre-release-docs
  * run pre-release ./manning-up.sh
  * Merge pull request #362 from chernjie/git-scp
  * Updated documentation for git-scp and slight feature change
  * Merge pull request #359 from chernjie/docs
  * Merge pull request #361 from markeissler/better-changelog-fixes
  * Fix git tag substring extraction for bash 3.2.
  * Merge pull request #360 from spacewander/master
  * Merge pull request #355 from markeissler/better-changelog-fixes
  * Merge branch 'better-changelog-fixes' of github.com:markeissler/git-extras into better-changelog-fixes
  * add support for git version below 2.2.0
  * Fix git-changelog for compatibility for bash<4. Fixes #337, #338
  * Merge pull request #1 from spacewander/better-changelog-fixes
  * correct the broken regex
  * Rearrange documentation links, see #358
  * Merge branch 'https://github.com/tj/git-extras.wiki/master' into docs, see #358
  * Merge pull request #357 from imsky/merge-repo
  * git-merge-repo
  * git merge-repo
  * add wiki for git-guilt
  * add support for git version below 2.2.0
  * Fix git-changelog for compatibility for bash<4. Fixes #337, #338
  * Merge pull request #349 from spacewander/git-guilt
  * fix indentation errors in git guilt
  * Merge pull request #345 from spacewander/git-guilt
  * Hope to fix #341
  * Merge pull request #344 from Somasis/master
  * use argument separator for usages of `grep` which can choke on weird input
  * helper/reset-env: helper to prevent GREP_OPTIONS from causing issues
  * Merge pull request #342 from spacewander/git-guilt
  * add docs for git guilt
  * add git-guilt
  * Merge pull request #340 from spacewander/git-effort
  * sort unless there is only one item
  * Merge pull request #333 from paulschreiber/merged-branches
  * add show-merged-branches and show-unmerged-branches
  * Merge pull request #334 from paulschreiber/dont-delete-svn-branch
  * when deleting merged branches, preserve "svn" branch for git-svn Fixed #328
  * Merge pull request #324 from chernjie/git-ignore
  * Merge pull request #331 from markeissler/better-changelog-fixes
  * Fix tag trapping when HEAD and tag point to same commit.
  * Fix gitflow commit history output.
  * Merge pull request #327 from markeissler/better-changelog-completion
  * Updated bash completions for better-changelog.
  * Update docs for revised git-changelog.
  * Merge pull request #325 from markeissler/better-changelog
  * Complete rewrite to support commit ranges for pretty and list output.
  * Support ~ in add_patterns for git-ignore
  * Support ~ in show git-ignore
  * add wiki for git-merge-into
  * Merge pull request #323 from spacewander/master
  * add docs for git-merge-into
  * add merge-into to merge two branches quickly
  * Merge pull request #322 from andrewsomething/master
  * git-fresh-branch: Check for changes and prompt for input before nuking. (Issue: #142)
  * Merge pull request #308 from spacewander/git-utility
  * Merge pull request #312 from RichardLitt/feature/concat-extra-feature-names
  * Merge pull request #320 from cironunes/gh-pages-fix
  * fix gh-pages to stash and don't delete files
  * Merge pull request #319 from pfctgeorge/allow-empty-when-setup
  * Allow empty initial commit when setup repo.
  * Merge pull request #317 from jykntr/master
  * git-summary correctly displays project name
  * git scp #300
  * Merge pull request #316 from code42day/changelog-config
  * changelog: add git-config support for format and log options
  * Merge pull request #315 from code42day/consistent-editor
  * use standard git editor in git-authors & git-changelog
  * Merge pull request #314 from snowyu/feature/custom-commit-message
  * + custom commit message options supports
  * Merge pull request #300 from chernjie/git-scp
  * Merge pull request #313 from wooorm/bug/fix-missing-closing-brace
  * Fix missing closing curly brance in `bash_completion.sh`
  * Added in option to concat extra feature names
  * link to git delta
  * git delta usage
  * Merge pull request #310 from imsky/git-delta
  * git-delta
  * Add git-authors
  * Merge pull request #309 from wooorm/feature/add-git-authors
  * Add git-authors
  * Updated Commands (markdown)
  * Updated Commands (markdown)
  * Updated Commands (markdown)
  * Updated Commands (markdown)
  * Updated Commands (markdown)
  * tj#300 Added bash completion
  * extra mktemp into git_extra_mktemp
  * Merge pull request #307 from ckhall/feature/add_git_chore_workflow
  * adding git-chore
  * Merge pull request #306 from spacewander/master
  * add enough X to fix #303. GNU mktemp requires at least three X in the last part of template.
  * Merge pull request #304 from wooorm/git-ignore-typo
  * Fix typo in in `git ignore` message
  * symlink git-rscp to git-scp
  * Avoid duplicating asterisk.
  * Updated License.
  * Fix link to git feature command
  * path argument can not be optional in `rscp`; add more docs
  * OMG a spelling mistake\!
  * Merge pull request #301 from raeffs/master
  * updated documentation because git-squash does no longer delete source-branch
  * Updated man page for git-scp
  * First RFC documentation
  * Merge pull request #299 from jonanp/git-delete-branch
  * When deleting a branch check if git has config.
  * Added a footer.
  * Merge pull request #298 from timfeirg/master
  * remove stuff from readme & form a list
  * add a few keywords
  * some remaining dashes
  * roughly finished
  * Updated Commands (markdown)
  * Updated Commands (markdown)
  * Updated Commands (markdown)
  * gonna use the clean sub command for each command explanation
  * adding links turn out to be a pain, go to sleep
  * add commands page link
  * add commands page, all copy & paste
  * add screencasts
  * copy from readme
  * Updated Install (markdown)
  * Created Install (markdown)
  * adapted a more generic, customizable and friendly script
  * Copy from git-goth https://github.com/chernjie/git-goth
  * Initial Home page
  * Merge pull request #296 from spacewander/add-completion
  * add more bash completion functions
  * Merge pull request #294 from GuillaumeSeren/feature/git-missing-add-ref-completion
  * Add ref completion to git-missing.
  * Merge pull request #293 from tj/revert-291-ignore-man-generated-files
  * Revert "Ignore *.html and *.1 auto-generated files in man/"
  * Merge pull request #292 from RasmusWL/make-handle-missing-man
  * make will not assume man pages already exists
  * Merge pull request #291 from jguenther/ignore-man-generated-files
  * Ignore man/git-*.html and man/git-*.1
  * Remove auto-generated files man/git-*.html and man/git-*.1
  * Merge pull request #226 from tsldh/master
  * added changelog to release as optional flag
  * Merge pull request #289 from mavant/feature/mktemp
  * Use mktemp for temporary file creation.
  * Merge pull request #288 from dead-horse/release-hook
  * make release hook more flexible
  * Merge pull request #287 from benjaminparnell/master
  * added --no-color to git-delete-merged-branches
  * More portable she-bangs.
  * Merge pull request #283 from e28eta/patch-1
  * Use process-specific tmp file and clean up on exit
  * Merge pull request #281 from emilkje/patch-1
  * Merge pull request #280 from valeriangalliat/feature/git-info-posix
  * Update Readme.md
  * git-info: POSIX compliance
  * Merge pull request #278 from tj/delete-submodule-fix
  * Fixes #277
  * Merge pull request #276 from spacewander/master
  * modify the behavior of git-ignore, now it will cd root to find .gitignore

2.2.0 / 2014-11-18
==================

* Update `mktemp` command to work on Mac OS X
* Merged pull request #273 from spacewander/master
* New command 'git root' to show the path to root of repo
* Merged pull request #271 from bohnman/git-rename-tag-fix
* Merged pull request #272 from spacewander/master
* Correct the format of git-rebase-patch.md.
* Replaced visionmedia/git-extras to tj/git-extras
* Merged pull request #270 from kevinawoo/hotfix/git-locked
* Added git-locked to check what files have been locked.
* Merged pull request #268 from GuillaumeSeren/bug/git-missing
* Fixed #267, git-missing did not catch branch name.

2.1.0 / 2014-10-13
==================

 * Fixes #266
 * Merge pull request #264 from jamesmanning/patch-1
 * fixed descriptions: match required/optional params
 * Merge pull request #263 from Yitsushi/bug/180-does-not-check-out-branch-if-it-already-exists
 * fix #180 and #232 feature|bug|refactor checkout
 * Merge pull request #262 from rstacruz/gh-259-git-pr
 * Implement git-pr
 * Merge pull request #261 from sanusart/master
 * FIX: representation of git-info
 * Merge pull request #260 from brandondrew/patch-1
 * import changes *from* a branch
 * Merge pull request #258 from spacewander/master
 * use mixin to add 'is git repo' check for some commands
 * Merge pull request #255 from sanusart/master
 * Bump version in `bin/git-extras`
 * Changelogs for version 2.0.0

2.0.0 / 2014-09-20
==================

 * Merge pull request #254 from spacewander/master
 * add welcome in git-repl
 * Merge pull request #253 from tailored-tunes/master
 * Added option to specify base
 * Merge pull request #252 from sorbits/patch-1
 * Update homebrew URL and remove ‘buggy’ label
 * Merge pull request #250 from sanusart/master
 * ADD: git-reset-file
 * Merge pull request #248 from rstacruz/patch-1
 * Readme: document git-delete-merged-branches
 * Merge pull request #247 from visionmedia/perm_fix
 * File perms fix.
 * Merge pull request #242 from sanusart/fix_feature_refactor_bug
 * Merge pull request #244 from toksea/patch-1
 * Merge pull request #243 from sanusart/issue234
 * Fix wrong git-info heading level in Readme.md
 * Revert 2 commits to `git-changelog`
 * Fix feature|refactor|bug testing argument for string length
 * Merge pull request #240 from egrim/bug/delete-merged-branches-clobbers-master
 * Update docs to match `git-delete-merged-branches` behavior
 * Exempt `master` from deleted branches
 * Merge pull request #239 from bruno-/refactor_git_squash
 * Refactor and improve `git squash`
 * Merge pull request #238 from techjacker/feature/git-fork
 * add git-fork
 * Merge pull request #236 from jbnicolai/align-authors-git-summary
 * Uses column -t to align summary output in a table.
 * Merge pull request #221 from zlx/feature/git-summary-doc
 * Merge pull request #224 from StewartJarod/patch-1
 * Merge pull request #189 from rhacker/patch-1
 * Merge pull request #235 from sanusart/patch-1
 * FIX: check if un-pushed commits
 * Merge pull request #202 from julionc/protecting-files
 * Update Readme.md with lock and unlock commands
 * git-unlock Unlock local files in git repository
 * git-lock Lock files in git repository
 * Merge pull request #100 from niklasf/rebase-patch
 * Add git-rebase-patch
 * Merge pull request #200 from emkay/patch-1
 * Merge pull request #195 from carlcasbolt/patch-1
 * Merge pull request #181 from zeroDivisible/feature/handle-misspellings
 * Merge pull request #193 from pzelnip/git-setup-no-overwrite
 * Merge pull request #183 from chernjie/master
 * Merge pull request #220 from sanusart/master
 * Merge pull request #63 from justone/git_missing
 * Merge pull request #173 from accerqueira/master
 * Merge pull request #194 from makeusabrew/patch-1
 * Merge pull request #216 from stephenmathieson/fix/changelog-large-versions
 * Merge pull request #188 from twolfson/dev/add.multi.delete.squashed
 * Merge pull request #219 from jhoffmann/patch-1
 * Merge pull request #222 from jsipprell/pull/filenames-containing-spaces
 * Merge pull request #223 from mwoc/master
 * Merge pull request #229 from yggdr/master
 * Merge pull request #231 from petersohn/master
 * Make git-obliterate work if there are whitespaces in filename
 * invoke bash via /usr/bin/env for portability
 * improved Makefile with BINPREFIX
 * fixed Makefile uninstall target for man files
 * Letter spacing in author list
 * Use two-space indents for log entry output, so it again is debian changelog compatible (as before commit 1235e4a5)
 * git effort: handle filenames containing whitespace cleanly
 * Add line-summary as an options --line  & doc
 * Add check for no changes in the tree (no sub-modules)
 * Update Readme.md
 * Fix changelog formatting for large version numbers
 * removing `git promote`
 * Update Readme.md
 * Fix git-squash typo
 * Address issue #190, git-setup should test for existing .git in target directory
 * Add comment for the code
 * Added multi-delete for git-delete-branch and git-delete-tag Correcting typos Compiled latest documentation Applying changes from delete-tag to delete-branch for consistency Removed unnecessary string quotes (thanks `git` ref design) and everything works Tags are not being found with string concatenation Updated delete-tag to accept multiple tags Corrections for delete-branch Updating docs for delete-tag Added 'Todd Wolfson' to AUTHORS Updated documentation for delete-branch Moved deletions to concatenate strings and delete in one fell swoop Reworking delete-branch to delete multiple branches in series
 * git-create-branch: bug fix for branch creation use HEAD instead of origin
 * changed the code for git bug|feature|refactor to only accept single argument when not finishing a bug|feature|refactor. This is an easy solution to avoid misspelings of the word 'finish'
 * allow options to be passed through to git log
 * adding git-missing command

1.9.1 / 2014-06-21
==================

 * add --no-merges option to changelog
 * fix git-changelog errors when multiple files match change|history
 * fix git-changelog errors on first usage
 * update git-changelog docs for --no-merges option

1.9.0 / 2013-06-18
==================

 * git-squash: add --me flag to flatten the current branch
 * Make repository_age() "history rewrite safe"
 * add git-line-summary

1.8.0 / 2013-05-15
==================

  * add `git-archive-file(1)`
  * add --tag support to git-changelog(1) to reduce manual editing
  * add !cmd support to git-repl
  * change: git-delete-merged-branches: use -D instead of delete-branch

1.7.0 / 2012-06-11
==================

  * Added repo age to `git-summary` [muhtasib]

1.6.0 / 2012-06-04
==================

  * Added `git-rename-tag`
  * Added current branch to `git-repl`
  * Fixed: use dirname for `git extras update` [wilmoore]

1.5.1 / 2012-03-15
==================

  * Reverted 1.5.0 changes, breaks git-changelog

1.4.0 / 2012-02-08
==================

  * Added: allow files to be passed to `git-effort(1)`. Closes #71
  * Added: hide/show cursor for `git-effort(1)`
  * Changed: color `git-effort(1)` commits / active days independently

1.3.0 / 2012-02-08
==================

  * Added active days to `git-effort(1)` output

1.2.0 / 2012-02-08
==================

  * Added a greater color range to `git-effort(1)`
  * Added `--above <n>` to `git-effort(1)`

1.1.0 / 2012-02-07
==================

  * Added `git-effort(1)` (not yet complete)

1.0.0 / 2012-02-04
==================

  * Added `git-squash BRANCH [MSG]` to merge as a single commit

0.9.0 / 2012-01-15
==================

  * Added bash completion support [jweslley]

0.8.1 / 2011-12-30
==================

  * Removed `git-promote`

0.8.0 / 2011-12-08
==================

  * Added `pre-release` and `post-release `hooks to git-release
  * Added `git-promote`
  * Fixed: "git extra update" errors when pwd includes whitespace

0.7.0 / 2011-08-24
==================

  * Added percentages to `git-summary`

0.6.0 / 2011-06-24
==================

  * Added `git-back` command for soft undos [Kenneth Reitz]

0.5.1 / 2011-05-20
==================

  * revert `git-ignore` but retain argc == 0 as showing .gitignore contents
  * revert broken `git-release`

0.5.0 / 2011-05-19
==================

  * Added `git-alias` [jweslley]
  * Added `git-create-branch` [jweslley]
  * Fixed one-liner due to `git extras update` change
  * Fixed; `git-setup` creates a directory if the provided one does not exist [jweslley]
  * Fixed; `git-setup` support for directories with spaces [jweslley]
  * Fixed; `git-ignore` with no args no longer fails if `.gitignore` does not exist [jweslley]

0.4.1 / 2011-04-05
==================

  * Changed; `git-graft` now defaults to current branch instead of master [Kenneth Reitz]

0.4.0 / 2011-04-05
==================

  * Added `git-refactor`
  * Added `git-bug`
  * Added `git-feature`

0.3.0 / 2011-03-29
==================

  * Added `git-pull-request`

0.2.0 / 2011-03-27
==================

  * Added `git-extras`
  * Added __LICENSE__
  * Removed `git-extras-version`, use `git extras --version`
  * Removed `git-extras-update`, use `git extras update`
  * Changed; make sure to get the last chronological tag, instead of relying on the bogus `git tag` sorting. [guillermo]

0.1.0 / 2011-02-10
==================

  * Added `gh-pages` command

0.0.7 / 2010-10-31
==================

  * Added man pages.
  * Added `make clean`.
  * Added `make docs`.
  * Added -d -> -D. Closes #15.
  * Added git-delete-submodule for delete submodules easily.
  * Added; `git-ignore` now shows the contents of _./.git-ignore_ if no args are present.

0.0.6 / 2010-10-22
==================

  * Added command `git-touch`.
  * Use a shallow clone in `git-update-extras`.
  * Create History.md if git-changelog can't find a target. Fixes #14.

0.0.5 / 2010-10-08
==================

  * Added `git-delete-submodule`.
  * Added; `git-ignore` without pattern shows .gitignore contents.
  * Added; `git-setup` argument is now optional, defaulting to the CWD.
  * Added REPL alias "ls" as ls-files.

0.0.4 / 2010-09-10
==================

  * Added: `git-delete-branch`: Also delete the remote branch.
  * Added `git-summary` commitish support.
  * Added `git-graft` dest branch default of _master_.
  * Added `git-setup`.
  * Added `git-graft`.
  * Added `git-undo` for removing recent commits.
  * Fixed `git-delete-branch`: Don't fail if the local branch doesn't exist.
  * Fixed __PREFIX__ to respect env vars.
  * Fixed shift in `git-count`.

0.0.3 / 2010-08-27
==================

  * Added `git-extras-version`.
  * Added `git-update-extras`.
  * Fixed `git-contrib` issue when the username is in a commit msg.
  * Fixed: delete remote tag only if local was deleted.
  * Fixed: delete remote branch only if local was deleted.
  * Fixed printing of authors for git-summary's on Ubuntu.
  * Fixed: read doesn't have the -e option in SH on my machine at least.

0.0.2 / 2010-08-24
==================

  * Added `git-summary`.
  * Added `git-commits-since`.
  * Added `git-repl`.
  * Added `git-delete-tag`.
  * Added `git-delete-branch`.
  * Added `git-contrib`.
  * Fixed handling off spaces in contributor's name for `git-contrib`.
  * Fixed spaces in `git-release` names/numbers.
  * Fixed readme.

0.0.1 / 2010-08-05
==================

  * Docs for `git-ignore`. Closes #3.
  * Merge branch 'ignore'.
  * Added `git-ignore`.
  * Readme typo.
  * Fixed <tag> in docs.
  * Install docs.
  * Merge branch 'release'.
  * Added `git-release`.
  * Fixed readme.
  * Readme.
  * Passing args to git shortlog.
  * Added --all support to git-count.
  * Initial commit.


================================================
FILE: Installation.md
================================================
# Installation

## Dependencies

Some commands require extra dependencies which are unavailable in some platforms.
You may need to install them manually. They are:

* bash 4.0+
* Git 2.17+
* `column`
* `awk`
* `find`
* `tput`
* cURL (only required for `git-fork`, `git-ignore-io`, `git-pull-request`)
* `ps` (only required for `git-changelog`)
* `rsync` (only required for `git-rscp`, `git-scp`)
* `xargs` (only required for `git-delete-merged-branches`, `git-force-clone`, `git-sed`, `git-scp`)

If `bash --version` shows a lower version, you need to update it.
For example, the default bash in Mac is usually too old and you may need to update it via `brew install bash`.

## Installing with a package manager

Note that only the Homebrew package is maintained by the git-extras developers directly.
Other packages are maintained by the distribution's packagers or third-party volunteers.

[![Packaging status](https://repology.org/badge/vertical-allrepos/git-extras.svg)](https://repology.org/project/git-extras/versions)

### Debian

```bash
$ sudo $apt_pref update
$ sudo $apt_pref install git-extras
```

### Fedora

```bash
$ sudo dnf install git-extras
```

### openSUSE

Substitute your openSUSE version in the command below (in this case we are considering openSUSE Leap 15.6):

```bash
$ sudo zypper ar https://download.opensuse.org/repositories/devel:/tools:/scm/15.6/devel:tools:scm.repo
```

and install it:

```bash
$ sudo zypper in -y git-extras
```

### RHEL/CentOS (requires [EPEL](https://fedoraproject.org/wiki/EPEL))

```bash
$ sudo yum install git-extras
```

### Ubuntu

```bash
$ sudo apt-get install git-extras
```

### Nix/NixOS

```bash
$ nix-env -i git-extras
```

### CRUX

[Abdullah](https://github.com/AWAN) has written a [Pkgfile](https://abdullah.today/ports/git-extras/Pkgfile) for his beloved [distro](https://crux.nu).

### Homebrew

```bash
$ brew install git-extras
```

Installing from Homebrew will not give you the option omit certain `git-extras` if they conflict with existing git aliases. To have this option, build from source.

### Arch Linux

* [git-extras](https://aur.archlinux.org/packages/git-extras/)
* [git-extras-git](https://aur.archlinux.org/packages/git-extras-git/)

### Windows

First, please install `Git for Windows 2.x` from 'https://github.com/git-for-windows/git/releases'.
Second, clone the `git-extras` repo into any folder you like.

```bash
git clone https://github.com/tj/git-extras.git
# checkout the latest tag (optional)
git checkout $(git describe --tags $(git rev-list --tags --max-count=1))
```

After that, execute the `install.cmd` in the command prompt. If you installed
git as admin, you need to run this prompt as admin, too. Per default, it finds
a `Git for Windows 2.x` if it's in the path (first path in `where git.exe` wins)
or installed in the default location `%ProgramFiles%\Git`. The fallback is
`C:\SCM\PortableGit`. If you didn't install git into one of these dirs, you have
to supply the path for the install location, e.g. if git is installed
in `c:\git`:

```batch
install.cmd "C:\git"
```

Last, to use `git summary` and `git ignore-io`, you need to copy
`column.exe` from a [msys2][1] installation from `folder-your-msys2-installed/usr/bin`
to `folder-your-git-installed/usr/bin` or wait for git 2.7.1, which will include column.exe.

### FreeBSD

```bash
$ pkg install git-extras
```

### BSD

Use the instructions to build from source below. Make sure you are using `gmake` (GNU `make`) instead of `make`.

## Building from source

Read [Dependencies](#dependencies) and ensure they are installed.

Obtain the git-extras source by cloning [its GitHub repo](https://github.com/tj/git-extras.git) or downloading a tarball of a [release](https://github.com/tj/git-extras/releases). Then install it by doing `make install` from the source tree.

```bash
$ git clone https://github.com/tj/git-extras.git
$ cd git-extras
# checkout the latest tag
$ git checkout $(git describe --tags $(git rev-list --tags --max-count=1))
$ [sudo] make install
```

By default, git-extras is installed under `/usr/local`. To install it at an
alternate location, specify a `PREFIX` when calling `make`.

```bash
# Non-root users can install under their home directory
make install PREFIX=$HOME/software

# For third-party software kept under /opt
make install PREFIX=/opt
```

If you want to relocate the bulk of the installation but still have configuration
files installed to the system `/etc` dir or other alternate location, you can
specify `SYSCONFDIR` in addition to `PREFIX`.

```sh
$ sudo make install PREFIX=/usr/local SYSCONFDIR=/etc
```

See the Makefile for details on advanced configuration options.

## Installing from network

One-liner:

```bash
curl -sSL https://raw.githubusercontent.com/tj/git-extras/main/install.sh | sudo bash /dev/stdin
```

## Installing as Zsh plugin

[ZInit](https://github.com/zdharma/zinit) can install git-extras by using:

```zsh
zinit ice as"program" pick"$ZPFX/bin/git-*" src"etc/git-extras-completion.zsh" make"PREFIX=$ZPFX"
zinit light tj/git-extras

# or with the for syntax + async load
zinit lucid wait'0a' for \
as"program" pick"$ZPFX/bin/git-*" src"etc/git-extras-completion.zsh" make"PREFIX=$ZPFX" tj/git-extras

```

`$ZPFX` is `~/.zinit/polaris` by default. Use `zinit update tj/git-extras` to update.
This method installs in `$HOME`, so you don't need to ask administrator to install package.

## Updating

If you installed git-extras with a package manager, use that package manager's tools to update it.

If you installed git-extras from source, you can run `git-extras update` to update it to the latest release. Be aware that this may lose any configuration options you specified during the original installation.

Enjoy `git-extras`!

[1]: https://sourceforge.net/projects/msys2/


================================================
FILE: LICENSE
================================================
(The MIT License)

Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca> and Contributors

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: Makefile
================================================
PREFIX ?= /usr/local
BINPREFIX ?= "$(PREFIX)/bin"
SYSCONFDIR ?= $(PREFIX)/etc
SHELL := bash

OS = $(shell uname)
ifeq ($(OS), FreeBSD)
	MANPREFIX ?= "$(PREFIX)/man/man1"
	ifeq ($(MANPREFIX), /usr/local)
		MANPREFIX = "/usr/local/man/man1"
	endif
else
	MANPREFIX ?= "$(PREFIX)/share/man/man1"
endif
ifeq ($(OS), Darwin)
	COMPL_DIR ?= "$(DESTDIR)$(SYSCONFDIR)/bash_completion.d"
else ifeq ($(OS), FreeBSD)
	COMPL_DIR ?= "$(DESTDIR)$(SYSCONFDIR)/bash_completion.d"
else
	COMPL_DIR ?= "$(DESTDIR)$(SYSCONFDIR)/bash-completion/completions"
endif

BINS = $(wildcard bin/git-*)
MANS = $(wildcard man/git-*.md)
MAN_BINS = $(filter-out man/git-extras.md, $(MANS))
MAN_HTML = $(MANS:.md=.html)
MAN_PAGES = $(MANS:.md=.1)
CODE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
INSTALL_VIA ?= source
# Libraries used by all commands
LIB = "helper/reset-env" "helper/git-extra-utility"

COMMANDS = $(subst bin/, , $(BINS))

default: install

docs: $(MAN_HTML) $(MAN_PAGES)

check:
	@echo "Check dependencies before installation"
	@./check_dependencies.sh
	@echo

install: check
	@if [ "$(INSTALL_VIA)" = brew ]; then \
		git apply brew-release.patch || { echo "Can't apply brew release patch"; exit 1; } \
	fi
	mkdir -p $(DESTDIR)$(MANPREFIX)
	mkdir -p $(DESTDIR)$(BINPREFIX)
	@echo '... installing bins to '$(DESTDIR)$(BINPREFIX)
	@echo '... installing man pages to '$(DESTDIR)$(MANPREFIX)
	$(eval TEMPFILE := $(shell mktemp -q $${TMPDIR:-/tmp}/git-extras.XXXXXX 2>/dev/null || mktemp -q))
	@# chmod from rw-------(default) to rwxrwxr-x, so that users can exec the scripts
	@chmod 775 $(TEMPFILE)
	$(eval EXISTED_ALIASES := $(shell \
		git config --get-regexp 'alias\..*' | awk '{print "git-" substr($$1, 7)}'))
	@$(foreach COMMAND, $(COMMANDS), \
		should_install='yes'; \
		if [ ! -z "$(filter $(COMMAND), $(EXISTED_ALIASES))" ] && [ "$$SKIP_CONFLICT_CHECK" != yes ]; then \
			read -p "$(COMMAND) conflicts with an alias, still install it? [y/n]: " answer; \
			if [ "$$answer" = 'n' ] || [ "$$answer" = 'N' ]; then \
				should_install="no"; \
			fi; \
		fi; \
		if [ "$$should_install" = 'yes' ]; then \
			echo "... installing $(COMMAND)"; \
			head -1 bin/$(COMMAND) > $(TEMPFILE); \
			cat $(LIB) >> $(TEMPFILE); \
			if ! grep "$(COMMAND)" not_need_git_repo >/dev/null; then \
				cat ./helper/is-git-repo >> $(TEMPFILE); \
			fi; \
			if grep "$(COMMAND)" need_git_commit >/dev/null; then \
				cat ./helper/has-git-commit >> $(TEMPFILE); \
			fi; \
			tail -n +2 bin/$(COMMAND) >> $(TEMPFILE); \
			cp -f $(TEMPFILE) $(DESTDIR)$(BINPREFIX)/$(COMMAND); \
		fi; \
	)
	@if [ -z "$(wildcard man/git-*.1)" ]; then \
		echo "WARNING: man pages not created, use 'make docs' (which requires 'ronn' ruby lib)"; \
	else \
		cp -f man/git-*.1 $(DESTDIR)$(MANPREFIX); \
		echo "cp -f man/git-*.1 $(DESTDIR)$(MANPREFIX)"; \
	fi
	@mkdir -p $(COMPL_DIR)
	cp -f etc/bash_completion.sh $(COMPL_DIR)/git-extras
	@echo ""
	@echo "If you are a zsh user, you may want to 'source $(CODE_DIR)etc/git-extras-completion.zsh'" \
		"and put this line into ~/.zshrc to enable zsh completion"
	@echo "If you are a fish user, you may want to copy or link '$(CODE_DIR)etc/git-extras.fish'" \
		"to '~/.config/fish/completions/'"

man/index.txt: $(MANS)
	echo '# manuals' > $@.tmp
	for file in $(sort $^) ; do \
		extra=$${file%.md} ; \
		extra=$${extra#man/} ; \
		echo "$$extra(1) $$extra" >> $@.tmp ; \
	done
	mv -f $@.tmp $@

man/git-extras.md: $(MAN_BINS)
	ln=$$(awk '/## COMMANDS/{print NR};' $@) ; \
	awk "NR <= $$ln+1" $@ > $@.tmp
	for file in $(sort $^) ; do \
		head -n1 $$file | \
		sed 's/^/   - **/;s/ -- /** /' >> $@.tmp ; \
	done
	ln=$$(awk '/## AUTHOR/{print NR};' $@) ; \
	awk "NR >= $$ln-1" $@ >> $@.tmp
	mv -f $@.tmp $@

man/%.html: man/%.md man/index.txt
	ronn \
		--manual "Git Extras" \
		--html \
		--pipe \
		$< > $@

man/%.1: man/%.md
	ronn -r \
		--manual "Git Extras" \
		--pipe \
		$< > $@

uninstall:
	@$(foreach BIN, $(BINS), \
		echo "... uninstalling $(DESTDIR)$(BINPREFIX)/$(notdir $(BIN))"; \
		rm -f $(DESTDIR)$(BINPREFIX)/$(notdir $(BIN)); \
	)
	@$(foreach MAN, $(MAN_PAGES), \
		echo "... uninstalling $(DESTDIR)$(MANPREFIX)/$(notdir $(MAN))"; \
		rm -f $(DESTDIR)$(MANPREFIX)/$(notdir $(MAN)); \
	)
	rm -f $(COMPL_DIR)/git-extras

clean: docclean

docclean:
	rm -f man/*.1
	rm -f man/*.html

test:
	pytest

.PHONY: default docs check install uninstall clean docclean test


================================================
FILE: Readme.md
================================================
# Git Extras

Little git extras.

## Screencasts

Just getting started? Check out these screencasts:

* [introduction](https://vimeo.com/45506445) ([archive.org link](https://web.archive.org/web/20230219181235id_/vod-progressive.akamaized.net/exp=1676834145~acl=%2Fvimeo-prod-skyfire-std-us%2F01%2F4101%2F1%2F45506445%2F107111328.mp4~hmac=065b68f23c4b6a222463097b36d1c346995a9559baa9b819972da95550018471/vimeo-prod-skyfire-std-us/01/4101/1/45506445/107111328.mp4)) -- covers `git-ignore`, `git-setup`, `git-changelog`, `git-release`, `git-effort` and more

## Installation

See the [Installation](Installation.md) page.

## Commands

Go to the [Commands](Commands.md) page for basic usage and examples.

__GIT utilities__ -- repo summary, repl, changelog population, author commit percentages and more

## Contributing

Interested in contributing? Awesome!

Please read [Contributing](CONTRIBUTING.md) before you make a PR, thanks!

## The change of the default branch

As of Git Extras 6.4 the assumed default branch name changed from `master` to `main`.
This affects the Git Extras commands `git archive-file`, `git delete-merged-branches`, `git delta`, `git pull-request`, `git show-merged-branches`, `git show-unmerged-branches`, and `git squash`.

To change the default branch name to `master`: change either the configuration `git-extras.default-branch` or `init.defaultBranch` to `master`; the former takes precedence.

For example, `git config git-extras.default-branch master`.


================================================
FILE: bin/git-abort
================================================
#!/usr/bin/env bash

set -euo pipefail

discover_op() {
  local gitdir
  # git rev-parse emits an error if not in a git repo so only need to bail out
  gitdir="$(git rev-parse --git-dir)" || exit
  local op
  for op in cherry_pick merge rebase revert ; do
      if [ -f "${gitdir}/${op^^}_HEAD" ]; then
          echo "${op/_/-}"
      fi
  done
}

validate_op() {
  local op="$1"
  if [ -z "$op" ]; then
    echo "No active operation found" >&2
    exit 1
  fi
  if [[ "$(echo "$op" | wc -l)" -gt 1 ]]; then
    echo "Multiple active operations found:" >&2
    gitdir="$(git rev-parse --git-dir)" || exit
    for o in $op; do
      echo "  - $o: HEAD: $(cat "${gitdir}/${o}_HEAD")" >&2
    done
    exit 1
  fi
}

discover_action() {
    local action=${1/git-/}
    if [ "$action" != "abort" ] && [ "$action" != "continue" ]; then
        echo "Invalid action: $1" >&2
        exit 1
    fi
    echo "$action"
}

action=$(discover_action "$(basename "$0")")
op=$(discover_op)
validate_op "$op"

git "$op" "--$action"


================================================
FILE: bin/git-alias
================================================
#!/usr/bin/env bash

options=""

usage() {
cat <<HERE
usage: git alias [options]                          # list all aliases
   or: git alias [options] <search-pattern>         # show aliases matching pattern
   or: git alias [options] <alias-name> <command>   # alias a command
options:

    --global  Show or create alias in the system config
    --local   Show or create alias in the repository config
HERE
}

if [[ "$1" == "--local" || "$1" == "--global" ]]; then
    options=$1
    shift
fi

case $# in
  0)
      if [[ -z "$options" ]]; then
        git config --get-regexp 'alias.*' | sed 's/^alias\.//' | sed 's/[ ]/ = /' | sort
      else
        git config "$options" --get-regexp 'alias.*' | sed 's/^alias\.//' | sed 's/[ ]/ = /' | sort
      fi
      ;;
  1)
      if [[ -z "$options" ]]; then
        git config --get-regexp 'alias.*' | sed 's/^alias\.//' | sed 's/[ ]/ = /' | sort | grep -e "$1"
      else
        git config "$options" --get-regexp 'alias.*' | sed 's/^alias\.//' | sed 's/[ ]/ = /' | sort | grep -e "$1"
      fi
      ;;
  2)
      if [[ -z "$options" ]]; then
        git config alias."$1" "$2"
      else
        git config "$options" alias."$1" "$2"
      fi
      ;;
  *) >&2 echo "error: too many arguments." && usage && exit 1 ;;
esac


================================================
FILE: bin/git-archive-file
================================================
#!/usr/bin/env bash

# extract current branch name
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)

# get name of the most top folder of current directory, used for the
# output filename
ARCHIVE_NAME=$(basename "$(git rev-parse --show-toplevel)")

if [[ $BRANCH = tags* ]]; then
    BRANCH=$(git describe)
    echo Building for tag "\"$BRANCH\""
    FILENAME=$ARCHIVE_NAME.$BRANCH.zip
else
    echo Building archive on branch "\"$BRANCH\""
    # get a version string, so archives will not be overwritten when creating
    # many of them
    VERSION=$(git describe --always --long)
    # if not on master append branch name into the filename
    if [ "$BRANCH" = "$(git_extra_default_branch)" ]; then
        FILENAME=$ARCHIVE_NAME.$VERSION.zip
    else
        FILENAME=$ARCHIVE_NAME.$VERSION.$BRANCH.zip
    fi
fi

# rename invalid chars for the file path
FILENAME=${FILENAME//\//-}
FILENAME=${FILENAME//\\/-}
# combine path and filename
OUTPUT=$PWD/$FILENAME

# building archive
git archive --format zip --output "$OUTPUT" "$BRANCH"

# also display size of the resulting file
echo Saved to \""$FILENAME"\" \("$(du -h "$OUTPUT" | cut -f1)"\)


================================================
FILE: bin/git-authors
================================================
#!/usr/bin/env bash

LIST=false
NO_EMAIL=false
FILE=""

while [[ $# -gt 0 ]]; do
  case $1 in
    -l|--list )
      LIST=true
      shift
      ;;
    --no-email )
      NO_EMAIL=true
      shift
      ;;
    * )
      break
  esac
done

if ! $LIST; then
  FILE=$1
  if [ -z "$FILE" ]; then
    FILE=$(find . -mindepth 1 -maxdepth 1 \( -iname '*authors*' -o -iname '*contributors*' \) | head -n1)
    if [ -z "$FILE" ]; then
      FILE='AUTHORS'
    fi
  fi
fi

#
# list authors sorted by number of commits (descending).
#

authors() {
  if $NO_EMAIL; then
    # email will be used to uniq authors.
    git shortlog HEAD -sne | awk '{$1=""; sub(" ", ""); print}' | awk -F'<' '!x[$1]++' | awk -F'<' '!x[$2]++' \
      | awk -F'<' '{gsub(/ +$/, "", $1); print $1}'
  else
    git shortlog HEAD -sne | awk '{$1=""; sub(" ", ""); print}' | awk -F'<' '!x[$1]++' | awk -F'<' '!x[$2]++'
  fi
}

#
# authors.
#

if $LIST; then
  authors
else
  authors >> "$FILE"
fi


================================================
FILE: bin/git-browse
================================================
#!/usr/bin/env bash

remote=${1:-""}
branch=""
filename=${2:-""}
line1=${3:-""}
line2=${4:-""}

# get remote name
if [[ $remote == "" ]]; then
    branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null)"
    remote=$(git config branch."${branch}".remote || echo "origin")
fi

if [[ $remote == "" ]]; then
    echo "Remote not found"
    exit 1
fi

remote_url=$(git remote get-url "$remote") || exit $?

if [[ $remote_url = git@* ]]; then
    url=$(echo "$remote_url" | sed -E -e 's/:/\//' -e 's/\.git$//' -e 's/.*@(.*)/http:\/\/\1/')
elif [[ $remote_url = http* ]]; then
    url=${remote_url%.git}
fi

# construct urls
commit_hash=$(git rev-parse HEAD 2>/dev/null)
commit_or_branch=${commit_hash:-${branch}}

if [[ $remote_url =~ gitlab ]]; then
    # construct gitlab urls
    # https://gitlab.com/<user_or_group>/<repo>/-/blob/<commit_or_branch>/<filename>#L<line1>-<line2>
    if [[ -n ${filename} ]]; then
        url="${url}/-/blob/${commit_or_branch}/${filename}"
        if [[ -n "${line1}" ]]; then
            url="${url}#L${line1}"
            if [[ -n "${line2}" ]]; then
                url="${url}-${line2}"
            fi
        fi
    fi
elif [[ $remote_url =~ github ]]; then
    # construct github urls
    # https://github.com/<user_or_org>/<repo>/blob/<commit_or_branch>/<filename>#L<line1>-L<line2>
    if [[ -n "${filename}" ]]; then
        url="${url}/blob/${commit_or_branch}/${filename}"
        if [[ -n "${line1}" ]]; then
            url="${url}#L${line1}"
            if [[ -n "${line2}" ]]; then
                url="${url}-L${line2}"
            fi
        fi
    fi
elif [[ $remote_url =~ bitbucket ]]; then
    # construct bitbucket urls
    # https://bitbucket.org/<user_or_org>/<repo>/src/<commit_or_branch>/<filename>#lines-<line1>:<line2>
    if [[ -n ${filename} ]]; then
        url=${url}/src/${commit_or_branch}/${filename}
        if [[ -n "${line1}" ]]; then
            url="${url}#lines-${line1}"
            if [[ -n "${line2}" ]]; then
                url="${url}:${line2}"
            fi
        fi
    fi
fi

# open url
case "$OSTYPE" in
darwin*)
    # MacOS
    open "$url"
    ;;
msys)
    # Git-Bash on Windows
    start "$url"
    ;;
linux*)
    # Handle WSL on Windows
    if uname -a | grep -i -q Microsoft && command -v powershell.exe; then
        powershell.exe -NoProfile start "$url"
    else
        xdg-open "$url"
    fi
    ;;
*)
    # fall back to xdg-open for BSDs, etc.
    xdg-open "$url"
    ;;
esac


================================================
FILE: bin/git-browse-ci
================================================
#!/usr/bin/env bash

set -e -o pipefail
if [[ $1 == "" ]]
then
    branch=$(git rev-parse --abbrev-ref HEAD &> /dev/null)
    remote=$(git config branch."${branch}".remote || echo "origin")
else
    remote=$1
fi

if [[ -z $remote ]]
then
    echo "Remote not found"
    exit 1
fi

remote_url=$(git remote get-url "${remote}") || exit $?

if [[ $remote_url = git@* ]]
then
    url=$(echo "${remote_url}" | sed -E -e 's/:/\//' -e 's/\.git$//' -e 's/.*@(.*)/http:\/\/\1/')
elif [[ $remote_url = http* ]]
then
    url=${remote_url%.git}
fi

if [[ $url =~ github ]]
then
    ci_url=${url}/actions
elif [[ $url =~ gitlab ]]
then
    ci_url=${url}/-/pipelines
elif [[ $url =~ bitbucket ]]
then
    ci_url=${url}/addon/pipelines/home
fi
case "$OSTYPE" in
    darwin*)
        # MacOS
        open "${ci_url}"
        ;;
    msys)
        # Git-Bash on Windows
        start "${ci_url}"
        ;;
    linux*)
        # Handle WSL on Windows
        if uname -a | grep -i -q Microsoft && command -v powershell.exe
        then
            powershell.exe -NoProfile start "${ci_url}"
        else
            xdg-open "${ci_url}"
        fi
        ;;
    *)
        # fall back to xdg-open for BSDs, etc.
        xdg-open "${ci_url}"
        ;;
esac


================================================
FILE: bin/git-brv
================================================
#!/usr/bin/env bash
# A sorted prettier branch -vv

if ! (( BASH_VERSINFO[0] > 4 ||
        BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] >= 2 )); then
    printf >&2 'This script requires bash 4.2 or newer\n'
    exit 1
fi

# allow the user to set a default reverse option in an environment variable
reverse=$(git config --get git-extras.brv.reverse || echo false)
while [[ $# -gt 0 ]]; do
    case $1 in
    -r | --reverse)
        reverse=true
        shift
        ;;
    *)
        break
        ;;
    esac
done

if [[ -t 1 ]]; then
    shopt -s checkwinsize
    COLUMNS=$(tput cols)
    color_branch_local=$(git config --get-color color.branch.local normal)
    color_branch_current=$(git config --get-color color.branch.current green)
    color_diff_commit=$(git config --get-color color.diff.commit yellow)
    color_branch_upstream=$(git config --get-color color.branch.upstream blue)
    reset=$(tput sgr0)
fi


declare -A upstream date hash message
eval "$(
    git for-each-ref --format='upstream[%(refname:short)]=%(upstream:short)' \
                     --shell 'refs/heads/**'
)"

for b in "${!upstream[@]}"; do
    blen=${#b} ulen=${#upstream[$b]}
    (( bwidth = blen > bwidth ? blen : bwidth ))
    (( uwidth = ulen > uwidth ? ulen : uwidth ))
    IFS=/ read -r 'date[$b]' 'hash[$b]' 'message[$b]' < <(
        git log --no-walk=unsorted --format=%ct/%h/%s "$b" --
    )
    hlen=${#hash[$b]}
    (( hwidth = hlen > hwidth ? hlen : hwidth ))
done

mapfile -t ordered < <(
    # the reverse option of git-brv causes the sort to be sorted normally rather than in reverse
    reverse_opt=""
    if [[ $reverse = false ]]; then
        reverse_opt="-r"
    fi
    for b in "${!date[@]}"; do
        printf '%d\t%s\n' "${date[$b]}" "$b"
    done | sort -n $reverse_opt | cut -f2-
)

current=$(git symbolic-ref -q --short HEAD)

for b in "${ordered[@]}"; do
    branch_color=$color_branch_local
    if [[ $b = "$current" ]]; then
        branch_color=$color_branch_current
    fi
    if [[ -t 1 ]]; then
        msg=${message[$b]:0:COLUMNS-bwidth-uwidth-hwidth-14}
    else
        msg=${message[$b]}
    fi
    printf '%(%Y-%m-%d)T %s%*s%s %s%*s%s %s%*s%s %s\n' \
           "${date[$b]}" \
           "$branch_color" "-$bwidth" "$b" "$reset" \
           "$color_branch_upstream" "-$uwidth" "${upstream[$b]}" "$reset" \
           "$color_diff_commit" "-$hwidth" "${hash[$b]}" "$reset" \
           "$msg"
done


================================================
FILE: bin/git-bulk
================================================
#!/usr/bin/env bash
inverse=$(tput rev)
reset=$(tput sgr0)
txtbld=$(tput bold)
bldred=${txtbld}$(tput setaf 1)

# default option settings
guardedmode=false
singlemode=false
allwsmode=false
quiet=false
no_follow_symlinks=false
no_follow_hidden=false

#
# print usage message
#
usage() {
  echo 1>&2 "usage: git bulk [--no-follow-symlinks] [--no-follow-hidden] [-q|--quiet] [-g] ([-a]|[-w <ws-name>]) <git command>"
  echo 1>&2 "       git bulk --addworkspace <ws-name> <ws-root-directory> (--from <URL or file>)"
  echo 1>&2 "       git bulk --removeworkspace <ws-name>"
  echo 1>&2 "       git bulk --addcurrent <ws-name>"
  echo 1>&2 "       git bulk --purge"
  echo 1>&2 "       git bulk --listall"
}

cdfail() {
  echo 1>&2 "failed to change directory: $1"
  exit 1
}

# add another workspace to global git config
addworkspace() {
  git config --global bulkworkspaces."$wsname" "$wsdir";
  if [ -n "$source" ]; then
        if [ ! -d "$wsdir" ]; then echo 1>&2 "Path of workspace doesn't exist, make it first."; exit 1; fi
        regex='http(s)?://|ssh://|(git@)?.*:.*/.*'
        if [[ "$source" =~ $regex ]]; then
            pushd "$wsdir" > /dev/null || cdfail "$wsdir"
            git clone "$source"
            popd > /dev/null || cdfail "$OLDPWD"
        else
            source=$(realpath "$source" 2>/dev/null)
            if [ -f "$source" ]; then
                pushd "$wsdir" > /dev/null || cdfail "$wsdir"
                while IFS= read -r line; do
                  if [ -n "$line" ]; then
                    # the git clone command to take the complete line in the repository.txt as separate argument. This facilitated the cloning of the repository with a custom folder name.
                    # shellcheck disable=SC2086
                    git clone $line;
                  fi
                done < "$source"
                popd > /dev/null || cdfail "$OLDPWD"
            else
                echo 1>&2 "format of URL or file unknown"
            fi
        fi
    fi
}

# add current directory
addcurrent() { git config --global bulkworkspaces."$wsname" "$PWD"; }

# remove workspace from global git config
removeworkspace() { checkWSName && git config --global --unset bulkworkspaces."$wsname"; }

# remove workspace from global git config
purge() { git config --global --remove-section bulkworkspaces; }

# list all current workspace locations defined
listall() { git config --global --get-regexp bulkworkspaces; }

# guarded execution of a git command in one specific repository
guardedExecution () {
  if [ "${quiet?}" != "true" ] || $guardedmode; then
    echo 1>&2 "${bldred}->${reset} executing ${inverse}git $gitcommand${reset} in repository ${leadingpath%/*}/${bldred}${curdir##*/}${reset}"
  fi

  if $guardedmode; then
    echo 1>&2 -n "   Execute command here (y/n)? "
    read -n 1 -r </dev/tty; echo 1>&2
    if [[ $REPLY =~ ^[Yy]$ ]]; then
      git "$@"
    fi
  else
    git "$@"
  fi
}

# check if the passed command is known as a core git command
checkGitCommand () {
  if git help -a | grep -o -q "\b${corecommand}\b"; then
    echo 1>&2 "Core command \"$corecommand\" accepted."
  else
    if git config --get-regexp alias | grep -o -q "\.${corecommand} "; then
      echo 1>&2 "Alias ${corecommand} accepted."
    else
      usage && echo 1>&2 "error: unknown GIT command: $corecommand" && exit 1
    fi
  fi
}

# check if workspace name is registered
checkWSName () {
  while read -r workspace; do
    parseWsName "$workspace"
    if [[ $rwsname == "$wsname" ]]; then return; fi
  done <<< "$(listall)"
  # when here the ws name was not found
  usage && echo 1>&2 "error: unknown workspace name: $wsname" && exit 1
}

# parse out wsname from workspacespec
parseWsName () {
  local wsspec="$1"
  # Get the workspace value from its specification in the `.gitconfig`.
  # May be an absolute path or a variable name of the form: `$VARNAME`
  rwsdir=${wsspec#* }
  if [[ ${rwsdir:0:1} == '$' ]]; then
    # Dereference the `rwsdir` value which is a variable name.
    rwsdir_varname=${rwsdir:1}
    rwsdir=${!rwsdir_varname}
    if [[ -z "${rwsdir}" ]]; then
      echo 1>&2 "error: bad environment variable: $rwsdir_varname" && exit 1
    fi
  fi
  rwsname=${wsspec#*.} && rwsname=${rwsname%% *}
}

# detects the wsname of the current directory
wsnameToCurrent () {
  while read -r workspace; do
    if [ -z "$workspace" ]; then continue; fi
    parseWsName "$workspace"
    if echo "$PWD" | grep -o -q "$rwsdir"; then wsname="$rwsname" && return; fi
  done <<< "$(listall)"
  # when here then not in workspace dir
  echo 1>&2 "error: you are not in a workspace directory. your registered workspaces are:" && \
    wslist="$(listall)" && echo 1>&2 "${wslist:-'<no workspaces defined yet>'}" && exit 1
}

# helper to check number of arguments.
allowedargcount () {
	if [ "$paramcount" -ne "${1:-0}"  ] && [ "$paramcount" -ne "${2:-0}" ]; then
		echo 1>&2 "error: wrong number of arguments" && usage;
		exit 1;
	fi
}

# execute the bulk operation
executBulkOp () {
  checkGitCommand
  if ! $allwsmode && ! $singlemode; then wsnameToCurrent; fi # by default git bulk works within the 'current' workspace
  listall | while read -r workspacespec; do
    parseWsName "$workspacespec"
    if [[ -n $wsname ]] && [[ $rwsname != "$wsname" ]]; then continue; fi
    cd "$rwsdir" || exit 1
    local actual=$PWD
    [ "${quiet?}" != "true" ] && echo 1>&2 "Executing bulk operation in workspace ${inverse}$actual${reset}"

    # build `find` flags depending on command-line options
    local find_flags=()
    if [[ "$no_follow_symlinks" == true ]]; then
      find_flags+=(-P)
    else
      find_flags+=(-L)
    fi
    # find all git repositories under the workspace on which we want to operate
    readarray allGitFolders < <(find "${find_flags[@]}" . -name ".git" 2>/dev/null)

    for line in "${allGitFolders[@]}"; do
      local gitrepodir=${line::${#line}-5} # cut the .git part of find results to have the root git directory of that repository
      cd "$gitrepodir" || exit 1 # into git repo location
      local curdir=$PWD
      local leadingpath=${curdir#"${actual}"}
      # do not execute if we do not want to consider a ".git" directory under a hidden directory
      if [ $no_follow_hidden = false ] || ! [[ "$leadingpath" =~ "/." ]]; then
        guardedExecution "$@"
      fi
      cd "$rwsdir" || exit 1 # back to origin location of last find command
    done
  done
}

paramcount="${#}"

# if no arguments show usage
if [[ $paramcount -le 0 ]]; then usage; fi

# parse command parameters
while [ "${#}" -ge 1 ] ; do
  case "$1" in
		--quiet|-q) quiet='true' ;;
    --listall|--purge)
      butilcommand="${1:2}" && break ;;
    --removeworkspace|--addcurrent|--addworkspace)
      butilcommand="${1:2}" && wsname="$2" && wsdir="$3" && if [ "$4" = "--from" ]; then source="$5"; fi && break ;;
    --no-follow-symlinks)
      no_follow_symlinks=true ;;
    --no-follow-hidden)
      no_follow_hidden=true ;;
    -a)
      allwsmode=true ;;
    -g)
      guardedmode=true ;;
    -w)
      singlemode=true && shift && wsname="$1" && checkWSName ;;
    --*)
      usage && echo 1>&2 "error: unknown argument $1" && exit 1 ;;
    -*)
      usage && echo 1>&2 "error: unknown argument $1" && exit 1 ;;
    *) # git core commands
      butilcommand="executBulkOp" && corecommand="$1" && gitcommand="$*" && break ;;
  esac && shift
done

# check option compatibility
if $allwsmode && $singlemode; then echo 1>&2 "error: options -w and -a are incompatible" && exit 1; fi

# if single mode check the supplied workspace name
if $singlemode; then echo 1>&2 "Selected single workspace mode in workspace: $wsname" && checkWSName; fi

# check right number of arguments
case $butilcommand in
  listall|purge) allowedargcount 1;;
  addcurrent|removeworkspace) allowedargcount 2;;
  addworkspace) allowedargcount 3 5;;
esac

# pass the origin arguments to the 'executBulkOp'
$butilcommand "$@" # run user command


================================================
FILE: bin/git-changelog
================================================
#!/usr/bin/env bash

DEF_TAG_RECENT="n.n.n"
GIT_LOG_OPTS="$(git config changelog.opts)"
GIT_LOG_FORMAT="$(git config changelog.format)"
[[ -z "$GIT_LOG_FORMAT" ]] && GIT_LOG_FORMAT='  * %s'
GIT_MERGELOG_FORMAT="$(git config changelog.mergeformat)"
[[ -z "$GIT_MERGELOG_FORMAT" ]] && GIT_MERGELOG_FORMAT='  * %s%n%w(64,4,4)%b'
GIT_EDITOR="$(git var GIT_EDITOR)"
PROGNAME="git-changelog"

git_editor() {
  if test -z "${GIT_EDITOR:+set}"
  then
    GIT_EDITOR="$(git var GIT_EDITOR)" || return $?
  fi

  eval "$GIT_EDITOR" '"$@"'
}

_usage() {
cat << EOF
usage: $PROGNAME options [file]
usage: $PROGNAME -h|help|?

Generate a Changelog from git(1) tags (annotated or lightweight) and commit
messages. Existing Changelog files with filenames that begin with 'Change' or
'History' will be identified automatically and their content will be appended
to the new output generated (unless the -p|--prune-old option is used). If no
tags exist, then all commits are output; if tags exist, then only the most-
recent commits are output up to the last identified tag.

OPTIONS:
  -a, --all                 Retrieve all commits (ignores --start-tag/commit, --final-tag)
  -l, --list                Display commits as a list, with no titles
  -t, --tag                 Tag label to use for most-recent (untagged) commits
  -f, --final-tag           Newest tag to retrieve commits from in a range
  -s, --start-tag           Oldest tag to retrieve commits from in a range
      --start-commit        Like --start-tag but use commit instead of tag
  -n, --no-merges           Suppress commits from merged branches
  -m, --merges-only         Only uses merge commits (uses both subject and body of commit)
  -p, --prune-old           Replace existing Changelog entirely with new content
  -x, --stdout              Write output to stdout instead of to a Changelog file
  -h, --help, ?             Show this message
EOF
}

_error() {
  [ $# -eq 0 ] && _usage && exit 0

  echo
  echo "ERROR: " "$@"
  echo
}

# _setValueForKeyFakeAssocArray()
# /*!
# @abstract Set value for key from a fake associative array
# @discussion
# Iterates over target_ary (an indexed array), searching for target_key, if the
#   key is found its value is set to new_value otherwise the target_key and
#   new_value are appended to the array.
#
#   The indexed array values must conform to this format:
#     "key:value"
#   Where key and value are separated by a single colon character.
#
#   Specify empty values as an empty, quoted string.
#
#   So-called "fake" associative arrays are useful for environments where the
#   installed version of bash(1) precedes 4.0.
# @param target_key Key to retrieve
# @param new_value New or updated value
# @param target_ary Indexed array to scan
# @return Returns new array with updated key (status 0) or an empty array
#   (status 1) on failure.
# */
_setValueForKeyFakeAssocArray() {
  # parameter list supports empty arguments!
  local target_key="$1"; shift
  local new_value="$1"; shift
  local target_ary=()
  local defaultIFS="$IFS"
  local IFS="$defaultIFS"
  local found=false

  IFS=$' ' target_ary=( $1 ) IFS="$defaultIFS"

  [[ -z "${target_key}" || "${#target_ary[@]}" -eq 0 ]] && echo "${value}" && return 1

  local _target_ary_length="${#target_ary[@]}"
  local i
  for (( i=0; i<"${_target_ary_length}"; i++ )); do
    local __val="${target_ary[$i]}"

    if [[ "${__val%%:*}" == "${target_key}" ]]; then
      target_ary[$i]="${__val%%:*}:${new_value}"
      found=true
      break
    fi

    unset __val
  done
  unset i _target_ary_length

  # key not found, append
  [[ "$found" == false ]] && target_ary+=( "${target_key}:${new_value}" )

  printf "%s" "${target_ary[*]}"
}

# _valueForKeyFakeAssocArray()
# /*!
# @abstract Fetch value for key from a fake associative array
# @discussion
# Iterates over target_ary (an indexed array), searching for target_key, if the
#   key is found its value is returned.
#
#   The indexed array values must conform to this format:
#     "key:value"
#   Where key and value are separated by a single colon character.
#
#   So-called "fake" associative arrays are useful for environments where the
#   installed version of bash(1) precedes 4.0.
# @param target_key Key to retrieve
# @param target_ary Indexed array to scan
# @return Returns string containing value (status 0) or an empty string
#   (status 1) on failure.
# */
_valueForKeyFakeAssocArray() {
  local target_key="$1"
  local target_ary=()
  local defaultIFS="$IFS"
  local IFS="$defaultIFS"
  local value=""

  IFS=$' ' target_ary=( $2 ) IFS="$defaultIFS"

  [[ -z "${target_key}" || "${#target_ary[@]}" -eq 0 ]] && echo "${value}" && return 1

  local t
  for t in "${target_ary[@]}"; do
    if [[ "${t%%:*}" == "${target_key}" ]]; then
      value="${t#*:}"
      break
    fi
  done
  unset t

  echo -e "${value}"; return 0
}

_fetchCommitRange() {
  local list_all="${1:-false}"
  local start_tag="$2"
  local final_tag="$3"

  # This shellcheck disable is applied to the whole if-body
  # shellcheck disable=SC2086
  if [[ "$list_all" == true ]]; then
    git log $GIT_LOG_OPTS --pretty=format:"${CUR_GIT_LOG_FORMAT}"
  elif [[ -n "$final_tag" && "$start_tag" == "null" ]]; then
    git log $GIT_LOG_OPTS --pretty=format:"${CUR_GIT_LOG_FORMAT}" "${final_tag}"
  elif [[ -n "$final_tag" ]]; then
    git log $GIT_LOG_OPTS --pretty=format:"${CUR_GIT_LOG_FORMAT}" "${start_tag}"'..'"${final_tag}"
  elif [[ -n "$start_tag" ]]; then
    git log $GIT_LOG_OPTS --pretty=format:"${CUR_GIT_LOG_FORMAT}" "${start_tag}"'..'
  fi | sed 's/^  \* \*/  */g'
}

_formatCommitPlain() {
  local start_tag="$1"
  local final_tag="$2"

  printf "%s\n" "$(_fetchCommitRange "false" "$start_tag" "$final_tag")"
}

_formatCommitPretty() {
  local title_tag="$1"
  local title_date="$2"
  local start_tag="$3"
  local final_tag="$4"
  local title="$title_tag / $title_date"
  local title_underline=""

  local i
  for i in $(seq ${#title}); do
    title_underline+="="
  done
  unset i

  printf '\n%s\n%s\n' "$title" "$title_underline"
  printf "\n%s\n" "$(_fetchCommitRange "false" "$start_tag" "$final_tag")"
}

commitList() {
  # parameter list supports empty arguments!
  local list_all="${1:-false}"; shift
  local title_tag="$1"; shift
  local start_tag="$1"; shift
  local final_tag="$1"; shift
  local list_style="${1:-false}"; shift # enable/disable list format
  local start_commit="$1"; shift
  local changelog="$FILE"
  local title_date="$(date +'%Y-%m-%d')"
  local tags_list=()
  local tags_list_keys=()
  local defaultIFS="$IFS"
  local IFS="$defaultIFS"

  if [[ -n "$start_commit" && "$final_tag" == "null" \
      && "$start_tag" == "null" ]]; then
    # if there is not tag after $start_commit,
    # output directly without fetch all tags
    if [[ "$list_style" == true ]]; then
      _formatCommitPlain "${start_commit}~"
    else
      _formatCommitPretty "$title_tag" "$title_date" "$start_commit~"
    fi

    return
  fi

  #
  # Tags look like this:
  #
  # >git log --tags --simplify-by-decoration --date="short" --pretty="format:%h$%x09%ad$%x09%d"
  #
  # ecf1f2b$        2015-03-15$     (HEAD, tag: v1.0.1, origin/master, origin/HEAD, master, hotfix/1.0.2)
  # a473e9c$        2015-03-04$     (tag: v1.0.0)
  # f2cb562$        2015-02-19$     (tag: v0.9.2)
  # 6197c2b$        2015-02-19$     (tag: v0.9.1)
  # 1e5f5e6$        2015-02-16$     (tag: v0.9.0)
  # 3de8ab5$        2015-02-11$     (origin/feature/restore-auto)
  # a15afd1$        2015-02-02$     (origin/feature/versionable)
  # 38a44e0$        2015-02-02$     (origin/feature/save-auto)
  # 3244b80$        2015-01-16$     (origin/feature/silent-history, upstream)
  # 85e45f8$        2014-08-25$
  #
  # The most-recent tag will be preceded by "HEAD, " if there have been zero
  # commits since the tag. Also notice that with gitflow, we see features.
  #

  # fetch our tags
  local _ref _date _tag _tab='%x09'
  local _tag_regex='tag: *'
  while IFS=$'\t' read -r _ref _date _tag; do
    [[ -z "${_tag}" ]] && continue
    # strip out tags form ()
    # git v2.2.0+ supports '%D', like '%d' without the " (", ")" wrapping. One day we should use it instead.
    _tag="${_tag# }"; _tag="${_tag//[()]/}"
    # trap tag if it points to last commit (HEAD)
    _tag="${_tag#HEAD*, }"
    # strip out branches
    [[ ! "${_tag}" =~ ${_tag_regex} ]] && continue
    # strip out any additional tags pointing to same commit, remove tag label
    _tag="${_tag%%,*}"; _tag="${_tag#tag: }"
    # add tag to assoc array; copy tag to tag_list_keys for ordered iteration
    tags_list+=( "${_tag}:${_ref}=>${_date}" )
    tags_list_keys+=( "${_tag}" )
  done <<< "$(git log --tags --simplify-by-decoration --date="short" --pretty="format:%h${_tab}%ad${_tab}%d")"
  IFS="$defaultIFS"
  unset _tag_regex
  unset _ref _date _tag _tab

  local _tags_list_keys_length="${#tags_list_keys[@]}"
  if [[ "${_tags_list_keys_length}" -eq 0 ]]
  then
    unset _tags_list_keys_length
    if [[ "$list_style" == true ]]; then
      printf "%s" "$(_fetchCommitRange "true")"
    else
      local title="$title_tag / $title_date"
      local title_underline=""

      local i
      for i in $(seq ${#title}); do
        title_underline+="="
      done
      unset i

      printf '\n%s\n%s\n' "$title" "$title_underline"
      printf "\n%s\n" "$(_fetchCommitRange "true")"
    fi
    return
  fi

  local _final_tag_found=false
  local _start_tag_found=false
  local i
  for (( i=0; i<"${_tags_list_keys_length}"; i++ )); do
    local __curr_tag="${tags_list_keys[$i]}"
    local __prev_tag="${tags_list_keys[$i+1]:-null}"
    local __curr_date
    __curr_date="$(_valueForKeyFakeAssocArray "${__curr_tag}" "${tags_list[*]}")"
    __curr_date="${__curr_date##*=>}"

    # output latest commits, up until the most-recent tag, these are all
    # new commits made since the last tagged commit.
    if [[ $i -eq 0 && ( -z "$final_tag" || "$final_tag" == "null" ) ]]; then
      if [[ "$list_style" == true ]]; then
        _formatCommitPlain "${__curr_tag}" >> "$tmpfile"
      else
        _formatCommitPretty "$title_tag" "$title_date" "${__curr_tag}"
      fi
    fi

    # both final_tag and start_tag are "null", user just wanted recent commits
    [[ "$final_tag" == "null" && "$start_tag" == "null" ]] && break;

    # find the specified final tag, continue until found
    if [[ -n "$final_tag" && "$final_tag" != "null" ]]; then
      [[ "$final_tag" == "${__curr_tag}" ]] && _final_tag_found=true
      [[ "$final_tag" != "${__curr_tag}" && "${_final_tag_found}" == false ]] && continue
    fi

    # find the specified start tag, break when found
    if [[ -n "$start_tag" ]]; then
      [[ "$start_tag" == "${__curr_tag}" ]] && _start_tag_found=true
      if [[ "${_start_tag_found}" == true ]]; then
        if [[ -n "$start_commit" ]]; then

          # output commits after start_commit to its closest tag
          if [[ "$list_style" == true ]]; then
            _formatCommitPlain "$start_commit~" "${__curr_tag}"
          else
            _formatCommitPretty "${__curr_tag}" "${__curr_date}" \
              "$start_commit~" "${__curr_tag}"
          fi

          break
        fi

        [[ "$start_tag" != "${__curr_tag}" ]] && break

      fi
    fi

    # output commits made between prev_tag and curr_tag, these are all of the
    # commits related to the tag of interest.
    if [[ "$list_style" == true ]]; then
      _formatCommitPlain "${__prev_tag}" "${__curr_tag}"
    else
      _formatCommitPretty "${__curr_tag}" "${__curr_date}" "${__prev_tag}" "${__curr_tag}"
    fi
    unset __curr_date
    unset __prev_tag
    unset __curr_tag
  done
  unset i
  unset _start_tag_found
  unset _final_tag_found
  unset _tags_list_keys_length

  return
}

commitListPlain() {
  local list_all="${1:-false}"
  local start_tag="$2"
  local final_tag="$3"
  local start_commit="$4"

  commitList "$list_all" "" "$start_tag" "$final_tag" "true" "$start_commit"
}

commitListPretty() {
  local list_all="${1:-false}"
  local title_tag="$2"
  local start_tag="$3"
  local final_tag="$4"
  local start_commit="$5"
  local title_date="$(date +'%Y-%m-%d')"

  commitList "$list_all" "$title_tag" "$start_tag" "$final_tag" "false" \
    "$start_commit"
}

_exit() {
  local pid_list=()
  local defaultIFS="$IFS"
  local IFS="$defaultIFS"

  stty sane; echo; echo "caught signal, shutting down"

  IFS=$'\n'
  # The format of `ps` is different between Windows and other platforms,
  # so we need to calculate the total column number(COL_NUM) of header first.
  # Why don't we just use the last column?
  # Because the body of CMD column may contain space and be treated as multiple fields.
  pid_list=( $(ps -f |
    awk -v ppid=$$ 'NR == 1 {
      COL_NUM = NF
    }
    $3 == ppid {
      # filter out temp processes created in this subshell
      if ($COL_NUM != "ps" && $COL_NUM != "awk" && $COL_NUM !~ "bash$")
        print $2
    }')
  )
  IFS="$defaultIFS"

  local _pid
  for _pid in "${pid_list[@]}"; do
    echo "killing: ${_pid}"
    kill -TERM "${_pid}"
  done

  wait; stty sane; exit 1
}

trap '_exit' SIGINT SIGQUIT SIGTERM

main() {
  local start_tag="null" # empty string and "null" mean two different things!
  local final_tag="null"

  local option=(
    "list_all:false"
    "list_style:false"
    "title_tag:$DEF_TAG_RECENT"
    "start_tag:"
    "start_commit:"
    "final_tag:"
    "output_file:"
    "use_stdout:false"
    "prune_old:false"
  )

  #
  # We work chronologically backwards from NOW towards start_tag where NOW also
  # includes the most-recent (un-tagged) commits. If no start_tag has been
  # specified, we work back to the very first commit; if a final_tag has been
  # specified, we begin at the final_tag and work backwards towards start_tag.
  #

  # An existing ChangeLog/History file will be appended to the output unless the
  # prune old (-p | --prune-old) option has been enabled.

  while [ "$1" != "" ]; do
    case $1 in
      -a | --all )
        option=( $(_setValueForKeyFakeAssocArray "list_all" true "${option[*]}") )
        ;;
      -l | --list )
        option=( $(_setValueForKeyFakeAssocArray "list_style" true "${option[*]}") )
        ;;
      -t | --tag )
        option=( $(_setValueForKeyFakeAssocArray "title_tag" "$2" "${option[*]}") )
        shift
        ;;
      -f | --final-tag )
        option=( $(_setValueForKeyFakeAssocArray "final_tag" "$2" "${option[*]}") )
        shift
        ;;
      -s | --start-tag )
        option=( $(_setValueForKeyFakeAssocArray "start_tag" "$2" "${option[*]}") )
        shift
        ;;
      --start-commit )
        option=( $(_setValueForKeyFakeAssocArray "start_commit" "$2" "${option[*]}") )
        shift
        ;;
      -n | --no-merges )
        GIT_LOG_OPTS='--no-merges'
        CUR_GIT_LOG_FORMAT="$GIT_LOG_FORMAT"
        ;;
      -m | --merges-only )
        GIT_LOG_OPTS='--merges'
        CUR_GIT_LOG_FORMAT="$GIT_MERGELOG_FORMAT"
        ;;
      -p | --prune-old )
        option=( $(_setValueForKeyFakeAssocArray "prune_old" true "${option[*]}") )
        ;;
      -x | --stdout )
        option=( $(_setValueForKeyFakeAssocArray "use_stdout" true "${option[*]}") )
        ;;
      -h | ? | help | --help )
        _usage
        exit 1
        ;;
      * )
        [[ "${1:0:1}" == '-' ]] && _error "Invalid option: $1" && _usage && exit 1
        option=( $(_setValueForKeyFakeAssocArray "output_file" "$1" "${option[*]}") )
        ;;
    esac
    shift
  done

  # The default log format unless already set
  [[ -z "$CUR_GIT_LOG_FORMAT" ]] && CUR_GIT_LOG_FORMAT="$GIT_LOG_FORMAT"

  local _tag="$(_valueForKeyFakeAssocArray "start_tag" "${option[*]}")"
  local start_commit="$(_valueForKeyFakeAssocArray "start_commit" "${option[*]}")"

  if [[ -n "$start_commit" ]]; then
    if [[ -n "${_tag}" ]]; then
      _error "--start-tag could not use with --start-commit!"
      return 1
    fi

    start_tag="$(git describe --tags --contains "$start_commit" 2>/dev/null || echo 'null')"
    if [[ -z "$start_tag" ]]; then
      _error "Could find the associative tag for the start-commit!"
      return 1
    fi

    # remove suffix from the $start_tag when no tag matched exactly
    start_tag="${start_tag%%~*}"
    # also remove "^0" added sometimes when tag matched exactly
    start_tag="${start_tag%%^0}"

  elif [[ -n "${_tag}" ]]; then
    start_tag="$(git describe --tags --abbrev=0 "${_tag}" 2>/dev/null)"
    if [[ -z "$start_tag" ]]; then
      _error "Specified start-tag does not exist!"
      return 1
    fi
  fi

  if [[ -n "${_tag}" ]]; then
    if [[ -n "$start_commit" ]]; then
      _error "--start-tag could not use with --start-commit!"
      return 1
    fi

  fi
  unset _tag

  local _tag="$(_valueForKeyFakeAssocArray "final_tag" "${option[*]}")"
  if [[ -n "${_tag}" ]]; then
    final_tag="$(git describe --tags --abbrev=0 "${_tag}" 2>/dev/null)"
    if [[ -z "$final_tag" ]]; then
      _error "Specified final-tag does not exist!"
      return 1
    fi
  fi
  unset _tag

  #
  # generate changelog
  #
  local tmpfile changelog title_tag
  tmpfile="$(git_extra_mktemp)"
  changelog="$(_valueForKeyFakeAssocArray "output_file" "${option[*]}")"
  title_tag="$(_valueForKeyFakeAssocArray "title_tag" "${option[*]}")"

  if [[ "$(_valueForKeyFakeAssocArray "list_style" "${option[*]}")" == true ]]; then
    if [[ "$(_valueForKeyFakeAssocArray "list_all" "${option[*]}")" == true ]]; then
      commitListPlain "true" >> "$tmpfile"
    else
      commitListPlain "false" "$start_tag" "$final_tag" \
        "$start_commit" >> "$tmpfile"
    fi
  else
    if [[ "$(_valueForKeyFakeAssocArray "list_all" "${option[*]}")" == true ]]; then
      commitListPretty "true" "$title_tag" >> "$tmpfile"
    else
      commitListPretty "false" "$title_tag" "$start_tag" "$final_tag" \
        "$start_commit" >> "$tmpfile"
    fi
  fi

  if [[ -z "$changelog" ]]; then
    changelog="$(find . -mindepth 1 -maxdepth 1 \( -iname '*change*' -o -iname '*history*' \) | head -n1)"
    if [[ -z "$changelog" ]]; then
      changelog="History.md";
    fi
  fi

  # append existing changelog?
  if [[ -f "$changelog" \
    && "$(_valueForKeyFakeAssocArray "prune_old" "${option[*]}")" == false ]]; then
    cat "$changelog" >> "$tmpfile"
  fi

  # output file to stdout or move into place
  if [[ "$(_valueForKeyFakeAssocArray "use_stdout" "${option[*]}")" == true ]]; then
    cat "$tmpfile"
    rm -f "$tmpfile"
  else
    cp -f "$tmpfile" "$changelog"
    rm -f "$tmpfile"

    if [[ -n "$GIT_EDITOR" ]]; then
      git_editor "$changelog" || _exit
    else
      less "$changelog" || _exit
    fi
  fi

  return
}

main "$@"

exit 0


================================================
FILE: bin/git-clear
================================================
#!/usr/bin/env bash
PROGNAME="git-clear"
FORCE=0

_usage() {
cat << EOF
usage: $PROGNAME options
usage: $PROGNAME -h|help|?

clear git repository

OPTIONS:
  -f, --force               Force clear without questioning user
  -h, --help, ?             Show this message
EOF
}

# Read arguments
while [ "$1" != "" ]; do
    case $1 in
        -f|--force)
            FORCE=1
        ;;
        -h|--help|?)
            _usage
            exit 1
        ;;
    esac

    shift
done

# Only wait for answer if not forced by user
if [[ $FORCE == 0 ]]; then
    echo -n "Sure? - THIS COMMAND MAY DELETE FILES THAT CANNOT BE RECOVERED, including those in .gitignore [y/N]: "
    read -r clean
else
    clean=y
fi

if [ "$clean" = "y" ]; then
    git clean -d -f -x && git reset --hard
fi


================================================
FILE: bin/git-clear-soft
================================================
#!/usr/bin/env bash

echo -n "Sure? - This command may delete files that cannot be recovered. Files and directories in .gitignore will be preserved [y/N]: "
read -r answer
if [ "$answer" = "y" ]
    then git clean -d -f && git reset --hard
fi


================================================
FILE: bin/git-coauthor
================================================
#!/usr/bin/env bash

set -e -o pipefail

coauthor=$1
email=$2

test -z "$coauthor" && echo "co-author required." 1>&2 && exit 1
test -z "$email" && echo "co-author email required." 1>&2 && exit 1

old_message="$(git log --format=%B -n1)"
if [[ "$old_message" == *"Co-authored-by:"* ]]; then
  git commit --amend -m "$old_message
Co-authored-by: $coauthor <$email>"
else
  git commit --amend -m "$old_message" -m "Co-authored-by: $coauthor <$email>"
fi


================================================
FILE: bin/git-commits-since
================================================
#!/usr/bin/env bash

REF=""
SINCE=""

while [[ $# -gt 0 ]]; do
    case "$1" in
        -r|--ref)
            if [[ -z "$2" ]]; then
                echo "error: option $1 requires an argument" >&2
                exit 1
            fi
            REF="$2"
            shift
            shift
            ;;
        *)
            # non-flag args accumulation, e.g. "last " + "week" -> "last week"
            SINCE="${SINCE:+$SINCE }$1"
            shift
            ;;
    esac
done

if [[ -n "$REF" && -n "$SINCE" ]]; then
    echo "error: '--ref <ref>' and '<date>' are mutually exclusive" >&2
    exit 1
fi

SINCE="${SINCE:-last week}"

if [[ -n "$REF" ]]; then
    git log --pretty='%h %an - %s' "$REF..HEAD"
else
    git log --pretty='%h %an - %s' --after="@{$SINCE}"
fi


================================================
FILE: bin/git-contrib
================================================
#!/usr/bin/env bash

user="$*"

test -z "$user" && echo "user name required." 1>&2 && exit 1

git shortlog --format=format:"%h %s" --author="$user"


================================================
FILE: bin/git-count
================================================
#!/usr/bin/env bash

if test "$1" = "--all"; then
  git shortlog -n -s | awk '{print substr($0,index($0,$2)) " (" $1 ")"}'
  echo
fi

echo total "$(git rev-list --count HEAD)"


================================================
FILE: bin/git-cp
================================================
#!/usr/bin/env bash
set -euo pipefail

PROGRAM=$0
CURRENT_FILENAME=""
DESTINATION_FILENAME=""

function usage()
{
    echo 1>&2 "USAGE: ${PROGRAM} CURRENT_FILENAME DESTINATION_FILENAME"
}

while [[ $# -gt 0 ]]
do
  key="$1"

  if [[ "$CURRENT_FILENAME" == "" ]]; then
      CURRENT_FILENAME=$key
  elif [[ "$DESTINATION_FILENAME" == "" ]]; then
      DESTINATION_FILENAME=$key
  else
      usage
      exit 30  # Error during arguments parsing
  fi
  shift  # past argument or value
done

if [[ "$DESTINATION_FILENAME" == "" ]]; then
    usage
    exit 20  # Missing arguments CURRENT_FILENAME
elif [[ "$CURRENT_FILENAME" == "" ]]; then
    usage
    exit 10  # Missing arguments CURRENT_FILENAME
else
    if [ -e "$DESTINATION_FILENAME"  ]; then
        echo 1>&2 "$DESTINATION_FILENAME already exists."
        echo 1>&2 "Make sure to remove the destination first."
        exit 40
    fi

    if [[ "$DESTINATION_FILENAME" == */ ]]; then
      echo 1>&2 "$DESTINATION_FILENAME is not a file path."
      exit 80
    fi
    if [[ "$DESTINATION_FILENAME" == */* ]]; then
      DESTINATION_DIR="${DESTINATION_FILENAME%/*}"
      if ! mkdir -p "$DESTINATION_DIR"; then
        echo 1>&2 "Failed to create destination directory: $DESTINATION_DIR"
        exit 160
      fi
    fi


    echo "Copying $CURRENT_FILENAME into $DESTINATION_FILENAME"

    # Pre-check that the source and destination will work
    git mv --dry-run "${CURRENT_FILENAME}" "${DESTINATION_FILENAME}"

    # Make a new branch and switch to it
    BRANCH_NAME="git-cp-$(date +%s)"
    git checkout -b "$BRANCH_NAME"

    # Move the original file to the new destination, in this branch
    git mv "${CURRENT_FILENAME}" "${DESTINATION_FILENAME}"
    git commit -nm "--Duplicate $CURRENT_FILENAME history into $DESTINATION_FILENAME"

    # Restore the original file to keep it in the history
    git checkout HEAD~ "${CURRENT_FILENAME}"
    git commit -nm "--Restore $CURRENT_FILENAME"

    # Switch to the original branch and merge this back in.
    git checkout -
    git merge --no-ff "$BRANCH_NAME" -m "Copy $CURRENT_FILENAME into $DESTINATION_FILENAME"

    # We're now done with the branch, so delete it.
    # We shouldn't need -D here, as we've already merged it back in.
    git branch -d "$BRANCH_NAME"
fi


================================================
FILE: bin/git-create-branch
================================================
#!/usr/bin/env bash

test $# -eq 0 && echo "branch argument required." 1>&2 && exit 1

# preference takes lowest priority; look for remote from prefs first
REMOTE_PREF=$(git config git-extras.create-branch.remote)
if [ -n "$REMOTE_PREF" ]; then
	REMOTE=$REMOTE_PREF
fi

while test $# != 0
do
	case $1 in
		-r|--remote)
			if [[ -n $2 ]]
			then
				REMOTE=$2
				shift
			else
				REMOTE=origin
			fi
			;;
		--from)
			if [[ -n $2 ]]; then
				START_POINT=$2
				shift
			fi
			;;
		*)
			BRANCH=$1
	esac
	shift
done

# handle ambiguous `-r` option argument by shift
if [[ -z $BRANCH ]] && [[ -n $REMOTE ]]
then
	BRANCH=$REMOTE
	REMOTE=origin
fi

test -z "$BRANCH" && echo "branch argument required." 1>&2 && exit 1

if [[ -n $REMOTE ]]
then
	stderr=$(git_extra_mktemp)
	git ls-remote --exit-code "$REMOTE" 1>/dev/null 2>"$stderr"
	REMOTE_EXIT=$?
	REMOTE_ERROR=$(<"$stderr")
	rm -f "$stderr"
	if [ $REMOTE_EXIT -eq 0 ]
	then
		if [[ -n $START_POINT ]]; then
			git fetch "$REMOTE"
			git checkout --track -b "$BRANCH" "$START_POINT"
			git push "$REMOTE" "HEAD:refs/heads/$BRANCH"
		else
			git push "$REMOTE" "HEAD:refs/heads/$BRANCH"
			git fetch "$REMOTE"
			git checkout --track -b "$BRANCH" "$REMOTE/$BRANCH"
		fi
		exit $?
	else
		echo
		echo "    Error connecting to remote '$REMOTE': $REMOTE_ERROR"
		echo
		exit $REMOTE_EXIT
	fi
fi

if [[ -n $START_POINT ]]
then
    git checkout -b "$BRANCH" "$START_POINT"
else
    git checkout -b "$BRANCH"
fi


================================================
FILE: bin/git-delete-branch
================================================
#!/usr/bin/env bash
set -e

# Assert there is at least one branch provided
test -z "$1" && echo "branch required." 1>&2 && exit 1

for branch in "$@"
do
  remote=$(git config "branch.$branch.remote" || echo "origin")
  ref=$(git config "branch.$branch.merge" || echo "refs/heads/$branch")

  git branch -D "$branch" || true
  # Avoid deleting local upstream
  [ "$remote" = "." ] && continue
  git branch -d -r "$remote/$branch" || continue
  git push "$remote" ":$ref"
done


================================================
FILE: bin/git-delete-merged-branches
================================================
#!/usr/bin/env bash

branches=$(git branch --no-color --merged | grep -vE "^(\*|\+)" | grep -v "$(git_extra_default_branch)" | grep -v svn)
if [ -n "$branches" ]
then
    echo "$branches" | xargs -n 1 git branch -d
fi


================================================
FILE: bin/git-delete-squashed-branches
================================================
#!/usr/bin/env bash

set -euo pipefail

proceed=false
if [[ $# -gt 0 && ("$1" == "--proceed" || "$1" == "-p") ]]; then
    proceed=true
    shift
fi

if [[ $# -eq 0 ]]; then
  targetBranch=$(git rev-parse --abbrev-ref HEAD)
else
  targetBranch=$1
  git checkout "$targetBranch"
fi

git for-each-ref refs/heads/ "--format=%(refname:short)" | while read -r branch; do
    mergeBase=$(git merge-base "$targetBranch" "$branch")

    if [[ $(git cherry "$targetBranch" "$(git commit-tree "$(git rev-parse "$branch^{tree}")" -p "$mergeBase" -m _)") == "-"* ]]; then
        if [[ $proceed == true ]]; then
            git branch -D "$branch" || true
        else
            git branch -D "$branch"
        fi
    fi
done


================================================
FILE: bin/git-delete-submodule
================================================
#!/usr/bin/env bash

abort() {
	error="$1" && shift
	echo "ERROR: $*" 1>&2
	test -z "$FORCE" && exit "$error"
}

# Don't abort on failures.  This allows to cleanup after a previous failure.
[ "$1" = '--force' ] && FORCE=1 && shift

test -z "$1"            && abort 1 'Submodule required'
cd "$(git root)"        || abort 5 'Cannot change to repository root'
test ! -f '.gitmodules' && abort 2 '.gitmodules file not found'

NAME="${1%/}"
test -z "$(git config --file='.gitmodules' "submodule.$NAME.url")" \
   && abort 3 'Submodule not found'

# 1. Handle the .git directory
# 1.a. Delete the relevant section from .git/config
git submodule deinit -f "$NAME" || abort 4 "Failed to deinitialize $NAME"
# 1.b. Delete empty submodule directory
git rm -f "$NAME"

# 2. Handle .gitmodules file
# 2.a. Delete the relevant line from .gitmodules
git config --file='.gitmodules' --remove-section "submodule.$NAME" 2>/dev/null || :
# 2.b and stage changes
git add '.gitmodules'
# 2.c. Delete empty .gitmodules
[  "$(wc -l '.gitmodules' | cut -d' ' -f1)" = '0' ] && git rm -f '.gitmodules'

# 3. Need to confirm and commit the changes for yourself
git_status_text="$(git submodule status 2>&1)"
git_status_exit=$?
if [ "$git_status_exit" -eq 0 ] \
    && printf '%s' "DUMMY$git_status_text" | grep -v "$NAME" > /dev/null; then
    #  grep fails when piping in an empty string, so we add a DUMMY prefix

	echo "Successfully deleted $NAME."
else
	abort 6 "Failed to delete $NAME with error:\n$git_status_text"
fi
printf '\n%s\n' '== git submodule status =='
printf '%s\n'   "$git_status_text"
printf '%s\n'   '=========================='
# shellcheck disable=SC2016
echo 'Confirm the output of `git submodule status` above (if any)' \
	'and then commit the changes.'


================================================
FILE: bin/git-delete-tag
================================================
#!/usr/bin/env bash

# Assert there is at least one tag provided
test -z "$1" && echo "tag required." 1>&2 && exit 1

# Detect the default remote exists or not
default_remote=$(git config git-extras.default-remote)

if [[ -n "$default_remote" ]]; then
    origin="$default_remote"
else
    origin=origin
fi

# Concatenate all the tag references
local_tags=""
origin_refs=""
for tagname in "$@"
do
  local_tags=$local_tags" $tagname"
  origin_refs=$origin_refs" :refs/tags/$tagname"
done

# Delete all the tags
# shellcheck disable=SC2086
git tag -d $local_tags
# shellcheck disable=SC2086
git push "$origin" $origin_refs


================================================
FILE: bin/git-delta
================================================
#!/usr/bin/env bash

branch=$(git_extra_default_branch)
filter=ACM

if test $# -eq 1; then
  branch=$1
else
  if test $# -eq 2; then
    branch=$1
    filter=$2
  fi
fi

git diff --name-only --diff-filter="$filter" "$branch"

================================================
FILE: bin/git-effort
================================================
#!/usr/bin/env bash

tmp=$(git_extra_mktemp)
above=0
# if the output won't be printed to tty, disable the color
test -t 1 && to_tty=true
color=

#
# print usage message
#
usage() {
  echo 1>&2 "usage: git effort [--above <value>] [<path>...] [-- [<log options>...]]"
}

#
# get dates for the given <commit>
#
dates() {
  eval "git log $args_to_git_log --pretty='format: %ad' --date=short -- \"$1\""
}

# tput, being quiet about unknown capabilities
tputq() {
  tput "$@" 2>/dev/null
  return 0
}

#
# hide cursor
#

hide_cursor() {
  tputq civis
}

#
# show cursor, and remove temporary file
#

show_cursor_and_cleanup() {
  tputq cnorm
  tputq sgr0
  rm "$tmp" > /dev/null 2>&1
  exit 0
}

#
# get active days for the given <commit>
#

active_days() {
  echo "$1" | sort -r | uniq | wc -l
}

#
# set 'color' based on the given <num>
#

color_for() {
  if [ "$to_tty" = true ]; then
    if   [ "$1" -gt 200 ]; then color="$(tputq setaf 1)$(tputq bold)"
    elif [ "$1" -gt 150 ]; then color="$(tputq setaf 1)"  # red
    elif [ "$1" -gt 125 ]; then color="$(tputq setaf 2)$(tputq bold)"
    elif [ "$1" -gt 100 ]; then color="$(tputq setaf 2)"  # green
    elif [ "$1" -gt 75 ]; then color="$(tputq setaf 5)$(tputq bold)"
    elif [ "$1" -gt 50 ]; then color="$(tputq setaf 5)"  # purplish
    elif [ "$1" -gt 25 ]; then color="$(tputq setaf 3)$(tputq bold)"
    elif [ "$1" -gt 10 ]; then color="$(tputq setaf 3)"  # yellow
    else color="$(tputq sgr0)" # default color
    fi
  else
    color=""
  fi
}

#
# compute the effort of the given <path ...>
#

effort() {
    path=$1
    local commit_dates
    local color reset_color commits len dot f_dot i msg active
    reset_color=""
    test "$to_tty" = true && reset_color="$(tputq sgr0)"
    if ! commit_dates=$(dates "$path"); then
      exit 255
    fi

    # Ensure it's not just an empty line
    if [ -z "$(head -c 1 <<<"$commit_dates")" ]
    then
      exit 0
    fi

    commits=$(wc -l <<<"$commit_dates")
    color='90'

    # ignore <= --above
    test "$commits" -le "$above" && exit 0

    # commits
    color_for $(( commits - above ))
    len=${#path}
    dot="."
    f_dot="$path"
    i=0 ; while test $i -lt $(( columns - len )) ; do
      f_dot=$f_dot$dot
      i=$((i+1))
    done

    msg=$(printf "  ${color}%s %-10d" "$f_dot" "$commits")

    # active days
    active=$(active_days "$commit_dates")
    color_for $(( active - above ))
    msg="$msg $(printf "${color} %d${reset_color}\n" "$active")"
    echo "$msg"
}

#
# print heading
#

heading() {
  echo
  printf "  %-${columns}s %-10s %s\n" 'path' 'commits' 'active days'
  echo
}

#
# output sorted results
#

sort_effort() {
  clear
  echo " "
  heading
  < "$tmp" sort -rn -k 2
}

#
# get processor count, default 8
#
procs() {
  if ! (nproc --all || getconf NPROCESSORS_ONLN || getconf _NPROCESSORS_ONLN || grep -c processor /proc/cpuinfo) 2>/dev/null; then
      echo 8
  fi
}

declare -a paths=()
while [ "${#}" -ge 1 ] ; do

  case "$1" in
    --above)
      shift
      above=$1
      ;;
    --)
      shift
      args_to_git_log=$(printf " %q" "${@:1}")
      break
      ;;
    --*)
      usage
      echo 1>&2 "error: unknown argument $1"
      echo 1>&2 "error: if that argument was meant for git-log,"
      echo 1>&2 "error: please put it after two dashes ( -- )."
      exit 1
      ;;
    *)
      paths+=( "$1" )
      ;;
  esac

  shift
done

# Exit if above-value is not an int
if [ -z "${above##*[!0-9]*}" ] ; then
  echo "error: argument to --above was not an integer" 1>&2
  exit 1
fi

# remove empty quotes that appear when there are no arguments
args_to_git_log="${args_to_git_log#\ \'\'}"
export args_to_git_log

# [path ...]

if test "${#paths}" -eq 0; then
  save_ifs=$IFS
  IFS=$(echo -en "\n\b")
  paths=($(git ls-files))
  IFS=$save_ifs
  unset save_ifs
fi

# set column width to match longest filename
max=0
for path in "${paths[@]}"; do
    cur=${#path}
    if [[ $max -lt $cur ]]; then
        max=$cur
    fi
done
columns=$(( max + 5 ))
export columns

# hide cursor

hide_cursor
trap show_cursor_and_cleanup INT

heading

# send paths to effort
nPaths=${#paths[@]}
nProcs=$(procs)
nJobs="\j"
for ((i=0; i<nPaths; ++i))
do
    while (( ${nJobs@P} >= nProcs )); do
        wait -n
    done
    effort "${paths[i]}" &
done|tee "$tmp"

# if more than one path, sort and print
test "$(wc -l "$tmp" | awk '{print $1}')" -gt 1 && sort_effort
echo

show_cursor_and_cleanup


================================================
FILE: bin/git-extras
================================================
#!/usr/bin/env bash

VERSION="7.5.0-dev"
INSTALL_SCRIPT="https://raw.githubusercontent.com/tj/git-extras/main/install.sh"

update() {
  local bin="$(command -v git-extras)"
  local prefix=${bin%/*/*}
  local orig=$PWD

  curl -s $INSTALL_SCRIPT | PREFIX="$prefix" bash /dev/stdin \
    && cd "$orig" \
    && echo "... updated git-extras $VERSION -> $(git extras --version)"
}

updateForWindows() {
  local bin="$(command -v git-extras)"
  local prefix=${bin%/*/*}
  local orig=$PWD

  # we need to clean up /tmp manually on windows
  cd /tmp \
    && rm -rf ./git-extras \
    && echo "Setting up 'git-extras'...." \
    && git clone https://github.com/tj/git-extras.git &> /dev/null \
    && cd git-extras \
	&& git checkout \
        $(git describe --tags $(git rev-list --tags --max-count=1)) \
        &> /dev/null \
	&& ./install.cmd "$prefix" \
	&& cd "$orig" \
	&& echo "... updated git-extras $VERSION -> $(git extras --version)"
  rm -rf /tmp/git-extras &> /dev/null
}

case "$1" in
  -v|--version)
    echo $VERSION && exit 0
    ;;
  update)
    platform=$(uname -s)
    if [ "${platform::9}" = "CYGWIN_NT" ] || \
      [ "${platform::5}" = "MINGW" ] || \
      [ "${platform::7}" = "MSYS_NT" ]
    then
      updateForWindows
    else
      update
    fi
    ;;
  *)
    git extras --help
    ;;
esac


================================================
FILE: bin/git-feature
================================================
#!/usr/bin/env ba
Download .txt
gitextract_to9razmh/

├── .editorconfig
├── .github/
│   ├── .ignore_words
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── ci.yml
│       └── stale.yaml
├── .gitignore
├── .gitmodules
├── .pytest.ini
├── AUTHORS
├── CONTRIBUTING.md
├── Commands.md
├── History.md
├── Installation.md
├── LICENSE
├── Makefile
├── Readme.md
├── bin/
│   ├── git-abort
│   ├── git-alias
│   ├── git-archive-file
│   ├── git-authors
│   ├── git-browse
│   ├── git-browse-ci
│   ├── git-brv
│   ├── git-bulk
│   ├── git-changelog
│   ├── git-clear
│   ├── git-clear-soft
│   ├── git-coauthor
│   ├── git-commits-since
│   ├── git-contrib
│   ├── git-count
│   ├── git-cp
│   ├── git-create-branch
│   ├── git-delete-branch
│   ├── git-delete-merged-branches
│   ├── git-delete-squashed-branches
│   ├── git-delete-submodule
│   ├── git-delete-tag
│   ├── git-delta
│   ├── git-effort
│   ├── git-extras
│   ├── git-feature
│   ├── git-force-clone
│   ├── git-fork
│   ├── git-fresh-branch
│   ├── git-get
│   ├── git-gh-pages
│   ├── git-graft
│   ├── git-guilt
│   ├── git-ignore
│   ├── git-ignore-io
│   ├── git-info
│   ├── git-local-commits
│   ├── git-lock
│   ├── git-locked
│   ├── git-magic
│   ├── git-merge-into
│   ├── git-merge-repo
│   ├── git-missing
│   ├── git-mr
│   ├── git-obliterate
│   ├── git-paste
│   ├── git-pr
│   ├── git-psykorebase
│   ├── git-pull-request
│   ├── git-reauthor
│   ├── git-rebase-patch
│   ├── git-release
│   ├── git-rename-branch
│   ├── git-rename-file
│   ├── git-rename-remote
│   ├── git-rename-tag
│   ├── git-repl
│   ├── git-reset-file
│   ├── git-root
│   ├── git-scp
│   ├── git-sed
│   ├── git-setup
│   ├── git-show-merged-branches
│   ├── git-show-tree
│   ├── git-show-unmerged-branches
│   ├── git-squash
│   ├── git-stamp
│   ├── git-standup
│   ├── git-summary
│   ├── git-sync
│   ├── git-touch
│   ├── git-undo
│   ├── git-unlock
│   ├── git-unwip
│   ├── git-utimes
│   └── git-wip
├── brew-release.patch
├── check_dependencies.sh
├── check_integrity.sh
├── etc/
│   ├── bash_completion.sh
│   ├── git-extras-completion.zsh
│   └── git-extras.fish
├── helper/
│   ├── git-extra-utility
│   ├── has-git-commit
│   ├── is-git-repo
│   └── reset-env
├── install.cmd
├── install.sh
├── man/
│   ├── Readme.md
│   ├── git-abort.1
│   ├── git-abort.html
│   ├── git-abort.md
│   ├── git-alias.1
│   ├── git-alias.html
│   ├── git-alias.md
│   ├── git-archive-file.1
│   ├── git-archive-file.html
│   ├── git-archive-file.md
│   ├── git-authors.1
│   ├── git-authors.html
│   ├── git-authors.md
│   ├── git-browse-ci.1
│   ├── git-browse-ci.html
│   ├── git-browse-ci.md
│   ├── git-browse.1
│   ├── git-browse.html
│   ├── git-browse.md
│   ├── git-brv.1
│   ├── git-brv.html
│   ├── git-brv.md
│   ├── git-bulk.1
│   ├── git-bulk.html
│   ├── git-bulk.md
│   ├── git-changelog.1
│   ├── git-changelog.html
│   ├── git-changelog.md
│   ├── git-clear-soft.1
│   ├── git-clear-soft.html
│   ├── git-clear-soft.md
│   ├── git-clear.1
│   ├── git-clear.html
│   ├── git-clear.md
│   ├── git-coauthor.1
│   ├── git-coauthor.html
│   ├── git-coauthor.md
│   ├── git-commits-since.1
│   ├── git-commits-since.html
│   ├── git-commits-since.md
│   ├── git-continue.1
│   ├── git-continue.html
│   ├── git-continue.md
│   ├── git-contrib.1
│   ├── git-contrib.html
│   ├── git-contrib.md
│   ├── git-count.1
│   ├── git-count.html
│   ├── git-count.md
│   ├── git-cp.1
│   ├── git-cp.html
│   ├── git-cp.md
│   ├── git-create-branch.1
│   ├── git-create-branch.html
│   ├── git-create-branch.md
│   ├── git-delete-branch.1
│   ├── git-delete-branch.html
│   ├── git-delete-branch.md
│   ├── git-delete-merged-branches.1
│   ├── git-delete-merged-branches.html
│   ├── git-delete-merged-branches.md
│   ├── git-delete-squashed-branches.1
│   ├── git-delete-squashed-branches.html
│   ├── git-delete-squashed-branches.md
│   ├── git-delete-submodule.1
│   ├── git-delete-submodule.html
│   ├── git-delete-submodule.md
│   ├── git-delete-tag.1
│   ├── git-delete-tag.html
│   ├── git-delete-tag.md
│   ├── git-delta.1
│   ├── git-delta.html
│   ├── git-delta.md
│   ├── git-effort.1
│   ├── git-effort.html
│   ├── git-effort.md
│   ├── git-extras.1
│   ├── git-extras.html
│   ├── git-extras.md
│   ├── git-feature.1
│   ├── git-feature.html
│   ├── git-feature.md
│   ├── git-force-clone.1
│   ├── git-force-clone.html
│   ├── git-force-clone.md
│   ├── git-fork.1
│   ├── git-fork.html
│   ├── git-fork.md
│   ├── git-fresh-branch.1
│   ├── git-fresh-branch.html
│   ├── git-fresh-branch.md
│   ├── git-get.1
│   ├── git-get.html
│   ├── git-get.md
│   ├── git-gh-pages.1
│   ├── git-gh-pages.html
│   ├── git-gh-pages.md
│   ├── git-graft.1
│   ├── git-graft.html
│   ├── git-graft.md
│   ├── git-guilt.1
│   ├── git-guilt.html
│   ├── git-guilt.md
│   ├── git-ignore-io.1
│   ├── git-ignore-io.html
│   ├── git-ignore-io.md
│   ├── git-ignore.1
│   ├── git-ignore.html
│   ├── git-ignore.md
│   ├── git-info.1
│   ├── git-info.html
│   ├── git-info.md
│   ├── git-local-commits.1
│   ├── git-local-commits.html
│   ├── git-local-commits.md
│   ├── git-lock.1
│   ├── git-lock.html
│   ├── git-lock.md
│   ├── git-locked.1
│   ├── git-locked.html
│   ├── git-locked.md
│   ├── git-magic.1
│   ├── git-magic.html
│   ├── git-magic.md
│   ├── git-merge-into.1
│   ├── git-merge-into.html
│   ├── git-merge-into.md
│   ├── git-merge-repo.1
│   ├── git-merge-repo.html
│   ├── git-merge-repo.md
│   ├── git-missing.1
│   ├── git-missing.html
│   ├── git-missing.md
│   ├── git-mr.1
│   ├── git-mr.html
│   ├── git-mr.md
│   ├── git-obliterate.1
│   ├── git-obliterate.html
│   ├── git-obliterate.md
│   ├── git-paste.1
│   ├── git-paste.html
│   ├── git-paste.md
│   ├── git-pr.1
│   ├── git-pr.html
│   ├── git-pr.md
│   ├── git-psykorebase.1
│   ├── git-psykorebase.html
│   ├── git-psykorebase.md
│   ├── git-pull-request.1
│   ├── git-pull-request.html
│   ├── git-pull-request.md
│   ├── git-reauthor.1
│   ├── git-reauthor.html
│   ├── git-reauthor.md
│   ├── git-rebase-patch.1
│   ├── git-rebase-patch.html
│   ├── git-rebase-patch.md
│   ├── git-release.1
│   ├── git-release.html
│   ├── git-release.md
│   ├── git-rename-branch.1
│   ├── git-rename-branch.html
│   ├── git-rename-branch.md
│   ├── git-rename-file.1
│   ├── git-rename-file.html
│   ├── git-rename-file.md
│   ├── git-rename-remote.1
│   ├── git-rename-remote.html
│   ├── git-rename-remote.md
│   ├── git-rename-tag.1
│   ├── git-rename-tag.html
│   ├── git-rename-tag.md
│   ├── git-repl.1
│   ├── git-repl.html
│   ├── git-repl.md
│   ├── git-reset-file.1
│   ├── git-reset-file.html
│   ├── git-reset-file.md
│   ├── git-root.1
│   ├── git-root.html
│   ├── git-root.md
│   ├── git-scp.1
│   ├── git-scp.html
│   ├── git-scp.md
│   ├── git-sed.1
│   ├── git-sed.html
│   ├── git-sed.md
│   ├── git-setup.1
│   ├── git-setup.html
│   ├── git-setup.md
│   ├── git-show-merged-branches.1
│   ├── git-show-merged-branches.html
│   ├── git-show-merged-branches.md
│   ├── git-show-tree.1
│   ├── git-show-tree.html
│   ├── git-show-tree.md
│   ├── git-show-unmerged-branches.1
│   ├── git-show-unmerged-branches.html
│   ├── git-show-unmerged-branches.md
│   ├── git-squash.1
│   ├── git-squash.html
│   ├── git-squash.md
│   ├── git-stamp.1
│   ├── git-stamp.html
│   ├── git-stamp.md
│   ├── git-standup.1
│   ├── git-standup.html
│   ├── git-standup.md
│   ├── git-summary.1
│   ├── git-summary.html
│   ├── git-summary.md
│   ├── git-sync.1
│   ├── git-sync.html
│   ├── git-sync.md
│   ├── git-touch.1
│   ├── git-touch.html
│   ├── git-touch.md
│   ├── git-undo.1
│   ├── git-undo.html
│   ├── git-undo.md
│   ├── git-unlock.1
│   ├── git-unlock.html
│   ├── git-unlock.md
│   ├── git-unwip.1
│   ├── git-unwip.html
│   ├── git-unwip.md
│   ├── git-utimes.1
│   ├── git-utimes.html
│   ├── git-utimes.md
│   ├── git-wip.1
│   ├── git-wip.html
│   ├── git-wip.md
│   ├── index.txt
│   └── man-template.md
├── need_git_commit
├── not_need_git_repo
├── scripts/
│   └── checkstyle.py
└── tests/
    ├── README.md
    ├── bin/
    │   ├── open
    │   ├── start
    │   └── xdg-open
    ├── conftest.py
    ├── git-abort.bats
    ├── git-alias.bats
    ├── git-archive-file.bats
    ├── git-authors.bats
    ├── git-browse-ci.bats
    ├── git-browse.bats
    ├── git-continue.bats
    ├── helper.py
    ├── pyproject.toml
    ├── test_git_abort.py
    ├── test_git_alias.py
    ├── test_git_archive_file.py
    ├── test_git_authors.py
    ├── test_git_browse.py
    ├── test_git_browse_ci.py
    ├── test_git_continue.py
    └── test_util.sh
Download .txt
SYMBOL INDEX (112 symbols across 10 files)

FILE: scripts/checkstyle.py
  class c (line 26) | class c:
  function utilGetStrs (line 38) | def utilGetStrs(line: Any, m: Any):
  function noDoubleBackslashFixer (line 47) | def noDoubleBackslashFixer(line: str, m: Any) -> str:
  function noPwdCaptureFixer (line 54) | def noPwdCaptureFixer(line: str, m: Any) -> str:
  function noTestDoubleEqualsFixer (line 61) | def noTestDoubleEqualsFixer(line: str, m: Any) -> str:
  function noFunctionKeywordFixer (line 71) | def noFunctionKeywordFixer(line: str, m: Any) -> str:
  function noVerboseRedirectionFixer (line 89) | def noVerboseRedirectionFixer(line: str, m: Any) -> str:
  function lintfile (line 94) | def lintfile(file: Path, rules: List[Rule], options: Dict[str, Any]):
  function main (line 136) | def main():

FILE: tests/conftest.py
  function create_repo (line 8) | def create_repo(dirname=None):
  function init_repo_git_status (line 16) | def init_repo_git_status(repo):
  function temp_repo (line 25) | def temp_repo():
  function named_temp_repo (line 32) | def named_temp_repo(request):
  function temp_repo_clean (line 41) | def temp_repo_clean():

FILE: tests/helper.py
  class TempRepository (line 16) | class TempRepository:
    method __init__ (line 17) | def __init__(self, repo_work_dir=None):
    method switch_cwd_under_repo (line 29) | def switch_cwd_under_repo(self):
    method get_cwd (line 33) | def get_cwd(self):
    method get_repo_dirname (line 36) | def get_repo_dirname(self):
    method get_repo_git (line 39) | def get_repo_git(self):
    method get_file (line 42) | def get_file(self, index):
    method get_filename (line 45) | def get_filename(self, index):
    method get_files (line 49) | def get_files(self):
    method create_tmp_dir (line 52) | def create_tmp_dir(self):
    method create_tmp_file (line 56) | def create_tmp_file(self, temp_dir=None):
    method remove_tmp_file (line 64) | def remove_tmp_file(self, file_path):
    method writefile (line 68) | def writefile(self, temp_file, data):
    method teardown (line 75) | def teardown(self):
    method invoke_extras_command (line 79) | def invoke_extras_command(self, name, *params):
    method invoke_installed_extras_command (line 86) | def invoke_installed_extras_command(self, name, *params):
    method change_origin (line 116) | def change_origin(self, origin_url):
    method change_origin_to_github (line 123) | def change_origin_to_github(self):
    method change_origin_to_gitlab (line 126) | def change_origin_to_gitlab(self):
    method change_origin_to_bitbucket (line 129) | def change_origin_to_bitbucket(self):

FILE: tests/test_git_abort.py
  class TestGitAbort (line 4) | class TestGitAbort:
    method test_init (line 5) | def test_init(self, temp_repo):
    method test_cherry_pick (line 20) | def test_cherry_pick(self, temp_repo):
    method test_merge (line 32) | def test_merge(self, temp_repo):
    method test_rebase (line 44) | def test_rebase(self, temp_repo):
    method test_revert (line 56) | def test_revert(self, temp_repo):

FILE: tests/test_git_alias.py
  class TestGitAlias (line 1) | class TestGitAlias:
    method test_init (line 2) | def test_init(self, temp_repo):
    method test_list_all (line 9) | def test_list_all(self, temp_repo):
    method test_list_all_globally (line 17) | def test_list_all_globally(self, temp_repo):
    method test_list_all_locally (line 22) | def test_list_all_locally(self, temp_repo):
    method test_search_globally (line 27) | def test_search_globally(self, temp_repo):
    method test_search_locally (line 35) | def test_search_locally(self, temp_repo):
    method test_get_alias_globally_and_defaultly (line 43) | def test_get_alias_globally_and_defaultly(self, temp_repo):
    method test_set_alias_globally_and_defaultly (line 48) | def test_set_alias_globally_and_defaultly(self, temp_repo):
    method test_get_alias_locally (line 54) | def test_get_alias_locally(self, temp_repo):
    method test_set_alias_locally (line 59) | def test_set_alias_locally(self, temp_repo):
    method test_teardown (line 65) | def test_teardown(self, temp_repo):

FILE: tests/test_git_archive_file.py
  class TestGitArchiveFile (line 5) | class TestGitArchiveFile:
    method test_init (line 6) | def test_init(self, temp_repo):
    method test_archive_file_on_tags_branch (line 14) | def test_archive_file_on_tags_branch(self, temp_repo):
    method test_archive_file_on_any_not_tags_branch_without_default_branch (line 21) | def test_archive_file_on_any_not_tags_branch_without_default_branch(
    method test_archive_file_on_any_not_tags_branch_with_default_branch (line 34) | def test_archive_file_on_any_not_tags_branch_with_default_branch(self,...
    method test_archive_file_on_branch_name_has_slash (line 44) | def test_archive_file_on_branch_name_has_slash(self, temp_repo):
    method test_archive_file_on_dirname_has_backslash (line 56) | def test_archive_file_on_dirname_has_backslash(self, named_temp_repo):
    method test_archive_file_on_tag_name_has_slash (line 64) | def test_archive_file_on_tag_name_has_slash(self, temp_repo):

FILE: tests/test_git_authors.py
  class TestGitAuthors (line 8) | class TestGitAuthors:
    method test_init (line 9) | def test_init(self, temp_repo):
    method test_output_authors_has_email_without_any_parameter (line 21) | def test_output_authors_has_email_without_any_parameter(self, temp_repo):
    method test_list_authors_has_email_defaultly (line 30) | def test_list_authors_has_email_defaultly(self, temp_repo):
    method test_list_authors_has_not_email (line 39) | def test_list_authors_has_not_email(self, temp_repo):

FILE: tests/test_git_browse.py
  function get_file_uri (line 6) | def get_file_uri(mode, filename, git):
  class TestGitBrowse (line 16) | class TestGitBrowse:
    method test_browse_github_file_on_mac (line 17) | def test_browse_github_file_on_mac(self, temp_repo):
    method test_browse_gitlab_file_on_mac (line 25) | def test_browse_gitlab_file_on_mac(self, temp_repo):
    method test_browse_bitbucket_file_on_mac (line 34) | def test_browse_bitbucket_file_on_mac(self, temp_repo):
    method test_browse_github_file_on_git_bash_on_window (line 43) | def test_browse_github_file_on_git_bash_on_window(self, temp_repo):
    method test_browse_gitlab_file_on_git_bash_on_window (line 52) | def test_browse_gitlab_file_on_git_bash_on_window(self, temp_repo):
    method test_browse_bitbucket_file_on_git_bash_on_window (line 61) | def test_browse_bitbucket_file_on_git_bash_on_window(self, temp_repo):
    method test_browse_github_file_on_WSL_with_microsoft_key (line 70) | def test_browse_github_file_on_WSL_with_microsoft_key(self, temp_repo):
    method test_browse_gitlab_file_on_WSL_with_microsoft_key (line 84) | def test_browse_gitlab_file_on_WSL_with_microsoft_key(self, temp_repo):
    method test_browse_bitbucket_file_on_WSL_with_microsoft_key (line 98) | def test_browse_bitbucket_file_on_WSL_with_microsoft_key(self, temp_re...
    method test_browse_github_file_on_WSL_without_microsoft_key (line 112) | def test_browse_github_file_on_WSL_without_microsoft_key(self, temp_re...
    method test_browse_gitlab_file_on_WSL_without_microsoft_key (line 126) | def test_browse_gitlab_file_on_WSL_without_microsoft_key(self, temp_re...
    method test_browse_bitbucket_file_on_WSL_without_microsoft_key (line 140) | def test_browse_bitbucket_file_on_WSL_without_microsoft_key(self, temp...
    method test_browse_github_file_not_mac_or_msys_or_linux (line 154) | def test_browse_github_file_not_mac_or_msys_or_linux(self, temp_repo):
    method test_browse_gitlab_file_not_mac_or_msys_or_linux (line 166) | def test_browse_gitlab_file_not_mac_or_msys_or_linux(self, temp_repo):
    method test_browse_bitbucket_file_not_mac_or_msys_or_linux (line 178) | def test_browse_bitbucket_file_not_mac_or_msys_or_linux(self, temp_repo):
    method test_browse_github_file_with_line_number (line 190) | def test_browse_github_file_with_line_number(self, temp_repo):
    method test_browse_gitlab_file_with_line_number (line 202) | def test_browse_gitlab_file_with_line_number(self, temp_repo):
    method test_browse_bitbucket_file_with_line_number (line 214) | def test_browse_bitbucket_file_with_line_number(self, temp_repo):
    method test_browse_unknown_site_file (line 226) | def test_browse_unknown_site_file(self, temp_repo):
    method test_browse_unknown_site_file_with_line_number (line 236) | def test_browse_unknown_site_file_with_line_number(self, temp_repo):

FILE: tests/test_git_browse_ci.py
  function get_ci_uri_by_domain (line 6) | def get_ci_uri_by_domain(mode):
  class TestGitBrowse (line 15) | class TestGitBrowse:
    method test_browse_github_ci_on_mac (line 16) | def test_browse_github_ci_on_mac(self, temp_repo):
    method test_browse_gitlab_ci_on_mac (line 22) | def test_browse_gitlab_ci_on_mac(self, temp_repo):
    method test_browse_bitbucket_ci_on_mac (line 29) | def test_browse_bitbucket_ci_on_mac(self, temp_repo):
    method test_browse_github_ci_on_git_bash_on_window (line 36) | def test_browse_github_ci_on_git_bash_on_window(self, temp_repo):
    method test_browse_gitlab_ci_on_git_bash_on_window (line 43) | def test_browse_gitlab_ci_on_git_bash_on_window(self, temp_repo):
    method test_browse_bitbucket_ci_on_git_bash_on_window (line 50) | def test_browse_bitbucket_ci_on_git_bash_on_window(self, temp_repo):
    method test_browse_github_ci_on_WSL_with_microsoft_key (line 57) | def test_browse_github_ci_on_WSL_with_microsoft_key(self, temp_repo):
    method test_browse_gitlab_ci_on_WSL_with_microsoft_key (line 69) | def test_browse_gitlab_ci_on_WSL_with_microsoft_key(self, temp_repo):
    method test_browse_bitbucket_ci_on_WSL_with_microsoft_key (line 81) | def test_browse_bitbucket_ci_on_WSL_with_microsoft_key(self, temp_repo):
    method test_browse_github_ci_on_WSL_without_microsoft_key (line 93) | def test_browse_github_ci_on_WSL_without_microsoft_key(self, temp_repo):
    method test_browse_gitlab_ci_on_WSL_without_microsoft_key (line 105) | def test_browse_gitlab_ci_on_WSL_without_microsoft_key(self, temp_repo):
    method test_browse_bitbucket_ci_on_WSL_without_microsoft_key (line 117) | def test_browse_bitbucket_ci_on_WSL_without_microsoft_key(self, temp_r...
    method test_browse_github_ci_not_mac_or_msys_or_linux (line 129) | def test_browse_github_ci_not_mac_or_msys_or_linux(self, temp_repo):
    method test_browse_gitlab_ci_not_mac_or_msys_or_linux (line 139) | def test_browse_gitlab_ci_not_mac_or_msys_or_linux(self, temp_repo):
    method test_browse_bitbucket_ci_not_mac_or_msys_or_linux (line 149) | def test_browse_bitbucket_ci_not_mac_or_msys_or_linux(self, temp_repo):
    method test_browse_unknown_site_file (line 159) | def test_browse_unknown_site_file(self, temp_repo):

FILE: tests/test_git_continue.py
  class TestGitContinue (line 4) | class TestGitContinue:
    method _init_repo (line 7) | def _init_repo(cls, repo):
    method test_init (line 22) | def test_init(self, temp_repo_clean):
    method test_cherry_pick (line 27) | def test_cherry_pick(self, temp_repo_clean):
    method test_merge (line 41) | def test_merge(self, temp_repo_clean):
    method test_rebase (line 56) | def test_rebase(self, temp_repo_clean):
    method test_revert (line 71) | def test_revert(self, temp_repo_clean):
Condensed preview — 364 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,124K chars).
[
  {
    "path": ".editorconfig",
    "chars": 391,
    "preview": "root = true\n\n[*]\nindent_style = space\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[Make"
  },
  {
    "path": ".github/.ignore_words",
    "chars": 10,
    "preview": "gool\nCant\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 496,
    "preview": "<!--\n\nNote\n\n* Mark the PR as draft until it's ready to be reviewed.\n* Please update the documentation to reflect the cha"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 118,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 4211,
    "preview": "name: ci\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\njobs:\n  lint:\n    runs-on: ubuntu-latest\n"
  },
  {
    "path": ".github/workflows/stale.yaml",
    "chars": 491,
    "preview": "name: \"Maintenance: Close Stale PRs\"\non:\n  schedule:\n    - cron: \"30 1 * * *\"\n\npermissions:\n  pull-requests: \"write\"\n\njo"
  },
  {
    "path": ".gitignore",
    "chars": 30,
    "preview": ".venv/\n__pycache__/\ncoverage/\n"
  },
  {
    "path": ".gitmodules",
    "chars": 101,
    "preview": "[submodule \"vendor/bats-all\"]\n\tpath = vendor/bats-all\n\turl = https://github.com/hyperupcall/bats-all\n"
  },
  {
    "path": ".pytest.ini",
    "chars": 86,
    "preview": "[pytest]\nminversion = 7.4\naddopts = -ra -q\ntestpaths = tests\nfaulthandler_timeout = 5\n"
  },
  {
    "path": "AUTHORS",
    "chars": 4575,
    "preview": "git-extras is written and maintained by various contributors:\n\nMaintainers\n```````````\n- TJ Holowaychuk <tj@vision-media"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1554,
    "preview": "# Contributing\n\nThanks for contributing! Please read this document before you make a PR.\n\n## Supported Platforms\n\nAny ch"
  },
  {
    "path": "Commands.md",
    "chars": 42536,
    "preview": "\n - [`git abort`](#git-abort)\n - [`git alias`](#git-alias)\n - [`git archive-file`](#git-archive-file)\n - [`git authors`]"
  },
  {
    "path": "History.md",
    "chars": 74074,
    "preview": "\n7.4.0 / 2025-06-19\n==================\n\n  * Format comparisons, functions, and redirections to be consistent (#1201)\n  *"
  },
  {
    "path": "Installation.md",
    "chars": 5817,
    "preview": "# Installation\n\n## Dependencies\n\nSome commands require extra dependencies which are unavailable in some platforms.\nYou m"
  },
  {
    "path": "LICENSE",
    "chars": 1115,
    "preview": "(The MIT License)\n\nCopyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca> and Contributors\n\nPermission is hereby granted"
  },
  {
    "path": "Makefile",
    "chars": 4381,
    "preview": "PREFIX ?= /usr/local\nBINPREFIX ?= \"$(PREFIX)/bin\"\nSYSCONFDIR ?= $(PREFIX)/etc\nSHELL := bash\n\nOS = $(shell uname)\nifeq ($"
  },
  {
    "path": "Readme.md",
    "chars": 1487,
    "preview": "# Git Extras\n\nLittle git extras.\n\n## Screencasts\n\nJust getting started? Check out these screencasts:\n\n* [introduction](h"
  },
  {
    "path": "bin/git-abort",
    "chars": 1018,
    "preview": "#!/usr/bin/env bash\n\nset -euo pipefail\n\ndiscover_op() {\n  local gitdir\n  # git rev-parse emits an error if not in a git "
  },
  {
    "path": "bin/git-alias",
    "chars": 1274,
    "preview": "#!/usr/bin/env bash\n\noptions=\"\"\n\nusage() {\ncat <<HERE\nusage: git alias [options]                          # list all ali"
  },
  {
    "path": "bin/git-archive-file",
    "chars": 1149,
    "preview": "#!/usr/bin/env bash\n\n# extract current branch name\nBRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)\n\n# get name of "
  },
  {
    "path": "bin/git-authors",
    "chars": 958,
    "preview": "#!/usr/bin/env bash\n\nLIST=false\nNO_EMAIL=false\nFILE=\"\"\n\nwhile [[ $# -gt 0 ]]; do\n  case $1 in\n    -l|--list )\n      LIST"
  },
  {
    "path": "bin/git-browse",
    "chars": 2469,
    "preview": "#!/usr/bin/env bash\n\nremote=${1:-\"\"}\nbranch=\"\"\nfilename=${2:-\"\"}\nline1=${3:-\"\"}\nline2=${4:-\"\"}\n\n# get remote name\nif [[ "
  },
  {
    "path": "bin/git-browse-ci",
    "chars": 1241,
    "preview": "#!/usr/bin/env bash\n\nset -e -o pipefail\nif [[ $1 == \"\" ]]\nthen\n    branch=$(git rev-parse --abbrev-ref HEAD &> /dev/null"
  },
  {
    "path": "bin/git-brv",
    "chars": 2423,
    "preview": "#!/usr/bin/env bash\n# A sorted prettier branch -vv\n\nif ! (( BASH_VERSINFO[0] > 4 ||\n        BASH_VERSINFO[0] == 4 && BAS"
  },
  {
    "path": "bin/git-bulk",
    "chars": 7955,
    "preview": "#!/usr/bin/env bash\ninverse=$(tput rev)\nreset=$(tput sgr0)\ntxtbld=$(tput bold)\nbldred=${txtbld}$(tput setaf 1)\n\n# defaul"
  },
  {
    "path": "bin/git-changelog",
    "chars": 18662,
    "preview": "#!/usr/bin/env bash\n\nDEF_TAG_RECENT=\"n.n.n\"\nGIT_LOG_OPTS=\"$(git config changelog.opts)\"\nGIT_LOG_FORMAT=\"$(git config cha"
  },
  {
    "path": "bin/git-clear",
    "chars": 779,
    "preview": "#!/usr/bin/env bash\nPROGNAME=\"git-clear\"\nFORCE=0\n\n_usage() {\ncat << EOF\nusage: $PROGNAME options\nusage: $PROGNAME -h|hel"
  },
  {
    "path": "bin/git-clear-soft",
    "chars": 243,
    "preview": "#!/usr/bin/env bash\n\necho -n \"Sure? - This command may delete files that cannot be recovered. Files and directories in ."
  },
  {
    "path": "bin/git-coauthor",
    "chars": 452,
    "preview": "#!/usr/bin/env bash\n\nset -e -o pipefail\n\ncoauthor=$1\nemail=$2\n\ntest -z \"$coauthor\" && echo \"co-author required.\" 1>&2 &&"
  },
  {
    "path": "bin/git-commits-since",
    "chars": 778,
    "preview": "#!/usr/bin/env bash\n\nREF=\"\"\nSINCE=\"\"\n\nwhile [[ $# -gt 0 ]]; do\n    case \"$1\" in\n        -r|--ref)\n            if [[ -z \""
  },
  {
    "path": "bin/git-contrib",
    "chars": 148,
    "preview": "#!/usr/bin/env bash\n\nuser=\"$*\"\n\ntest -z \"$user\" && echo \"user name required.\" 1>&2 && exit 1\n\ngit shortlog --format=form"
  },
  {
    "path": "bin/git-count",
    "chars": 176,
    "preview": "#!/usr/bin/env bash\n\nif test \"$1\" = \"--all\"; then\n  git shortlog -n -s | awk '{print substr($0,index($0,$2)) \" (\" $1 \")\""
  },
  {
    "path": "bin/git-cp",
    "chars": 2283,
    "preview": "#!/usr/bin/env bash\nset -euo pipefail\n\nPROGRAM=$0\nCURRENT_FILENAME=\"\"\nDESTINATION_FILENAME=\"\"\n\nfunction usage()\n{\n    ec"
  },
  {
    "path": "bin/git-create-branch",
    "chars": 1456,
    "preview": "#!/usr/bin/env bash\n\ntest $# -eq 0 && echo \"branch argument required.\" 1>&2 && exit 1\n\n# preference takes lowest priorit"
  },
  {
    "path": "bin/git-delete-branch",
    "chars": 475,
    "preview": "#!/usr/bin/env bash\nset -e\n\n# Assert there is at least one branch provided\ntest -z \"$1\" && echo \"branch required.\" 1>&2 "
  },
  {
    "path": "bin/git-delete-merged-branches",
    "chars": 218,
    "preview": "#!/usr/bin/env bash\n\nbranches=$(git branch --no-color --merged | grep -vE \"^(\\*|\\+)\" | grep -v \"$(git_extra_default_bran"
  },
  {
    "path": "bin/git-delete-squashed-branches",
    "chars": 716,
    "preview": "#!/usr/bin/env bash\n\nset -euo pipefail\n\nproceed=false\nif [[ $# -gt 0 && (\"$1\" == \"--proceed\" || \"$1\" == \"-p\") ]]; then\n "
  },
  {
    "path": "bin/git-delete-submodule",
    "chars": 1753,
    "preview": "#!/usr/bin/env bash\n\nabort() {\n\terror=\"$1\" && shift\n\techo \"ERROR: $*\" 1>&2\n\ttest -z \"$FORCE\" && exit \"$error\"\n}\n\n# Don't"
  },
  {
    "path": "bin/git-delete-tag",
    "chars": 621,
    "preview": "#!/usr/bin/env bash\n\n# Assert there is at least one tag provided\ntest -z \"$1\" && echo \"tag required.\" 1>&2 && exit 1\n\n# "
  },
  {
    "path": "bin/git-delta",
    "chars": 224,
    "preview": "#!/usr/bin/env bash\n\nbranch=$(git_extra_default_branch)\nfilter=ACM\n\nif test $# -eq 1; then\n  branch=$1\nelse\n  if test $#"
  },
  {
    "path": "bin/git-effort",
    "chars": 4432,
    "preview": "#!/usr/bin/env bash\n\ntmp=$(git_extra_mktemp)\nabove=0\n# if the output won't be printed to tty, disable the color\ntest -t "
  },
  {
    "path": "bin/git-extras",
    "chars": 1314,
    "preview": "#!/usr/bin/env bash\n\nVERSION=\"7.5.0-dev\"\nINSTALL_SCRIPT=\"https://raw.githubusercontent.com/tj/git-extras/main/install.sh"
  },
  {
    "path": "bin/git-feature",
    "chars": 1867,
    "preview": "#!/usr/bin/env bash\n\nbranch_prefix=$(git config --get git-extras.feature.prefix)\n\nif [ -z \"$branch_prefix\" ]; then\n   br"
  },
  {
    "path": "bin/git-force-clone",
    "chars": 2507,
    "preview": "#! /usr/bin/env bash\n\nset -euo pipefail\n\n_usage() {\n  echo \"\nUsage:\n  git-force-clone -b branch remote_url destination_p"
  },
  {
    "path": "bin/git-fork",
    "chars": 1982,
    "preview": "#!/usr/bin/env bash\n\nabort() {\n  echo \"$@\"\n  exit 1\n}\n\nurl=\"$1\"\ntest -z \"$url\" && url=$(git remote get-url origin 2> /de"
  },
  {
    "path": "bin/git-fresh-branch",
    "chars": 400,
    "preview": "#!/usr/bin/env bash\n\nbranch=$1\n\ntest -z \"$branch\" && echo \"branch required.\" 1>&2 && exit 1\n\nchanges=$(git status --porc"
  },
  {
    "path": "bin/git-get",
    "chars": 745,
    "preview": "#!/usr/bin/env bash\n\n_usage() {\n    printf '%s\\n' \"usage: ${0##*/} <url>\nusage: ${0##*/} --help\n\nClone a repository in a"
  },
  {
    "path": "bin/git-gh-pages",
    "chars": 554,
    "preview": "#!/usr/bin/env bash\n\necho 'setting up gh-pages'\necho '-------------------'\n \necho 'Tell me your github account username:"
  },
  {
    "path": "bin/git-graft",
    "chars": 250,
    "preview": "#!/usr/bin/env bash\n\nsrc=$1\ndst=$2\n\ntest -z \"$src\" && echo \"source branch required.\" 1>&2 && exit 1\ntest -z \"$dst\" && ec"
  },
  {
    "path": "bin/git-guilt",
    "chars": 3273,
    "preview": "#!/usr/bin/env bash\n\nfor param in \"$@\"\ndo\n    case $param in\n        -h)\n            echo 'Usage: git-guilt [<options>] "
  },
  {
    "path": "bin/git-ignore",
    "chars": 2781,
    "preview": "#!/usr/bin/env bash\n\nGIT_DIR=$(git rev-parse --git-dir 2>/dev/null)\n\nshow_contents() {\n  local file=\"${2/#~/$HOME}\"\n  if"
  },
  {
    "path": "bin/git-ignore-io",
    "chars": 4132,
    "preview": "#!/usr/bin/env bash\n\ngitignore_io_url=\"https://www.toptal.com/developers/gitignore/api/\"\ndefault_path=\"$HOME/.gi_list\"\ni"
  },
  {
    "path": "bin/git-info",
    "chars": 1571,
    "preview": "#!/usr/bin/env bash\n\nGREEN=\"$(tput setaf 2)\"\nNORMAL=\"$(tput sgr0)\"\nif [ \"$1\" = \"--color\" ] || [ \"$2\" = \"--color\" ] || \\\n"
  },
  {
    "path": "bin/git-local-commits",
    "chars": 51,
    "preview": "#!/usr/bin/env bash\n\ngit log \"@{upstream}..@\" \"$@\"\n"
  },
  {
    "path": "bin/git-lock",
    "chars": 144,
    "preview": "#!/usr/bin/env bash\n\nfilename=\"$1\"\ntest -z \"$filename\" && echo \"filename required.\" 1>&2 && exit 1\ngit update-index --sk"
  },
  {
    "path": "bin/git-locked",
    "chars": 65,
    "preview": "#!/usr/bin/env bash\n\ngit ls-files -v | grep ^S | sed -e 's|S ||'\n"
  },
  {
    "path": "bin/git-magic",
    "chars": 1536,
    "preview": "#!/usr/bin/env bash\n\n\n# Bash unofficial strict mode\nset -eo pipefail\nIFS=$'\\n\\t'\n\ncd \"$(git rev-parse --show-toplevel)\"\n"
  },
  {
    "path": "bin/git-merge-into",
    "chars": 944,
    "preview": "#!/usr/bin/env bash\n\ncurrent_branch() {\n    git rev-parse --abbrev-ref HEAD\n}\n\nusage() {\n    echo \"Usage: git merge-into"
  },
  {
    "path": "bin/git-merge-repo",
    "chars": 386,
    "preview": "#!/usr/bin/env bash\n\nrepo=$1\nbranch=$2\nprefix=$3\nflat=0\n\nif test \"$prefix\" = \".\"; then\n\tprefix=$(mktemp -u 'git-merge-re"
  },
  {
    "path": "bin/git-missing",
    "chars": 993,
    "preview": "#!/usr/bin/env bash\n\nusage() {\n    echo 1>&2 \"usage: git missing [<first branch>] <second branch> [<git log options>] [["
  },
  {
    "path": "bin/git-mr",
    "chars": 721,
    "preview": "#!/usr/bin/env bash\n\nset -eu\n\nif [  -z \"${1-}\" ] ; then\n    echo \"mr number or URL required. See --help for usage.\" 1>&2"
  },
  {
    "path": "bin/git-obliterate",
    "chars": 687,
    "preview": "#!/usr/bin/env bash\n\nfile=\"\"\nrange=\"\"\nfor i in \"$@\"\ndo\n    # use '--' to separate file list and rev-list arguments\n    t"
  },
  {
    "path": "bin/git-paste",
    "chars": 268,
    "preview": "#!/usr/bin/env bash\nset -e\nset -o pipefail\n\nif ! command -v pastebinit &>/dev/null; then\n    echo >&2 \"To run 'git paste"
  },
  {
    "path": "bin/git-pr",
    "chars": 1674,
    "preview": "#!/usr/bin/env bash\n# Based on https://gist.github.com/gnarf/5406589 and https://gist.github.com/jhnns/d654d9d6da6d3b749"
  },
  {
    "path": "bin/git-psykorebase",
    "chars": 2346,
    "preview": "#!/usr/bin/env bash\nPROGRAM=$0\nPRIMARY_BRANCH=\"\"\nSECONDARY_BRANCH=\"\"\nFF=\"--ff\"\nCONTINUE=\"no\"\n\ncurrent_branch() {\n    git"
  },
  {
    "path": "bin/git-pull-request",
    "chars": 1957,
    "preview": "#!/usr/bin/env bash\n\n#\n# Echo <msg> and exit\n#\n\nabort() {\n  echo >&2 \"$@\"\n  exit 1\n}\n\n#\n# Produce json with <title>, <bo"
  },
  {
    "path": "bin/git-reauthor",
    "chars": 4129,
    "preview": "#!/usr/bin/env bash\n\n\ninit_variables() {\n  COMMAND=${0#*-}\n\n  CONFIG=false\n  ALL=false\n  unset OLD_EMAIL\n  unset CORRECT"
  },
  {
    "path": "bin/git-rebase-patch",
    "chars": 1838,
    "preview": "#!/usr/bin/env bash\n\n# Warn on a dirty work tree.\ngit rev-parse --verify HEAD >/dev/null || exit 1\ngit update-index -q -"
  },
  {
    "path": "bin/git-release",
    "chars": 3114,
    "preview": "#!/usr/bin/env bash\nset -e\n\nhook() {\n  local hook=.git/hooks/$1.sh\n  # compat without extname\n  if test ! -f \"$hook\"; th"
  },
  {
    "path": "bin/git-rename-branch",
    "chars": 571,
    "preview": "#!/usr/bin/env bash\nset -e\n\n# Assert there is at least one branch provided\ntest -z \"$1\" && echo \"new branch name require"
  },
  {
    "path": "bin/git-rename-file",
    "chars": 2566,
    "preview": "#!/usr/bin/env bash\n\nset -euo pipefail\n\n# Usage function\nusage() {\n    cat <<EOF\nUsage: git rename-file [OPTIONS] <sourc"
  },
  {
    "path": "bin/git-rename-remote",
    "chars": 428,
    "preview": "#!/usr/bin/env bash\n\nset -euo pipefail\n\nold=$1\nnew=$2\n\ntest -z \"$old\" && echo \"old remote name required.\" 1>&2 && exit 1"
  },
  {
    "path": "bin/git-rename-tag",
    "chars": 260,
    "preview": "#!/usr/bin/env bash\n\nold=$1\nnew=$2\n\ntest -z \"$old\" && echo \"old tag name required.\" 1>&2 && exit 1\ntest -z \"$new\" && ech"
  },
  {
    "path": "bin/git-repl",
    "chars": 2884,
    "preview": "#!/usr/bin/env bash\nshopt -s extglob\n\ngit version\necho \"git-extras version \"\"$(git-extras -v)\"\necho \"Type 'ls' to ls fil"
  },
  {
    "path": "bin/git-reset-file",
    "chars": 309,
    "preview": "#!/usr/bin/env bash\n\nfile=\"$1\"\ncommit=\"$2\"\n\nif [[ -f $file ]]; then\n\tgit rm --cached -q -f -- \"$file\"\n\tif [[ -z $commit "
  },
  {
    "path": "bin/git-root",
    "chars": 532,
    "preview": "#!/usr/bin/env bash\n\ngit_root() {\n  git rev-parse --show-toplevel\n}\n\n# get the relative path of current path according t"
  },
  {
    "path": "bin/git-scp",
    "chars": 4046,
    "preview": "#!/usr/bin/env bash\n\nCOLOR_RED()   { test -t 1 && echo -n \"$(tput setaf 1)\"; }\nCOLOR_GREEN() { test -t 1 && echo -n \"$(t"
  },
  {
    "path": "bin/git-sed",
    "chars": 2776,
    "preview": "#!/usr/bin/env bash\n\nusage() {\n    cat <<EOF\nusage: git sed [ -c ] [ -f <flags> ] <search> <replacement> [ <flags> ]\n\nRu"
  },
  {
    "path": "bin/git-setup",
    "chars": 429,
    "preview": "#!/usr/bin/env bash\n\nCOMMIT_MESSAGE='Initial commit'\n\nif [ \"$1\" = \"-m\" ]; then\n    COMMIT_MESSAGE=$2\n    shift; shift\nfi"
  },
  {
    "path": "bin/git-show-merged-branches",
    "chars": 119,
    "preview": "#!/usr/bin/env bash\n\ngit branch --no-color --merged | grep -v \"\\*\" | grep -v \"$(git_extra_default_branch)\" | tr -d ' '\n"
  },
  {
    "path": "bin/git-show-tree",
    "chars": 89,
    "preview": "#!/usr/bin/env bash\n\ngit log --all --graph --decorate --oneline --simplify-by-decoration\n"
  },
  {
    "path": "bin/git-show-unmerged-branches",
    "chars": 122,
    "preview": "#!/usr/bin/env bash\n\ngit branch --no-color --no-merged | grep -v \"\\*\" | grep -v \"$(git_extra_default_branch)\" | tr -d ' "
  },
  {
    "path": "bin/git-squash",
    "chars": 1779,
    "preview": "#!/usr/bin/env bash\n\nSQUASH_MSG=\nfor arg in \"$@\"; do\n    case \"$arg\" in\n        --squash-msg)\n            SQUASH_MSG=1\n "
  },
  {
    "path": "bin/git-stamp",
    "chars": 1376,
    "preview": "#!/usr/bin/env bash\n\n\ninit_variables() {\n  COMMAND=${0#*-}\n\n  REPLACE=false\n  unset ID\n  unset MSG\n}\n\n\nusage() {\n  cat <"
  },
  {
    "path": "bin/git-standup",
    "chars": 8795,
    "preview": "#!/usr/bin/env bash\n\n# Code modified from https://github.com/kamranahmedse/git-standup,\n# under the MIT LICENSE.\nusage()"
  },
  {
    "path": "bin/git-summary",
    "chars": 6458,
    "preview": "#!/usr/bin/env bash\n\n\ncd \"$(git root)\" || { echo \"Can't cd to top level directory\";exit 1; }\n\nPROJECT_FULL_PATH=\nSUMMARY"
  },
  {
    "path": "bin/git-sync",
    "chars": 2393,
    "preview": "#!/usr/bin/env bash\n\nfunction _usage()\n{\n  local command=\"git sync\"\n  cat << EOS\nUsage:\n  ${command} [<remote> <branch>]"
  },
  {
    "path": "bin/git-touch",
    "chars": 200,
    "preview": "#!/usr/bin/env bash\n\nUSAGE(){\n  echo \"git touch <filename> [ <filename> . . .]\" 1>&2\n  exit 1\n}\n\ntest $# -lt 1 && USAGE\n"
  },
  {
    "path": "bin/git-undo",
    "chars": 1313,
    "preview": "#!/usr/bin/env bash\n\ncstr=\"commits\"\nccnt=$(git rev-list --count HEAD)\nif [ \"$ccnt\" -eq 1 ]; then cstr=\"commit\"; fi\nparm3"
  },
  {
    "path": "bin/git-unlock",
    "chars": 147,
    "preview": "#!/usr/bin/env bash\n\nfilename=\"$1\"\ntest -z \"$filename\" && echo \"filename required.\" 1>&2 && exit 1\ngit update-index --no"
  },
  {
    "path": "bin/git-unwip",
    "chars": 357,
    "preview": "#!/usr/bin/env bash\n\n# Based on scripts from git-utils:\n# * https://github.com/ddollar/git-utils/blob/master/git-unwip\n\n"
  },
  {
    "path": "bin/git-utimes",
    "chars": 2871,
    "preview": "#!/usr/bin/env bash\n#\n# Change files modification time to their last commit date\n#\n\n# Bash unofficial strict mode\nset -e"
  },
  {
    "path": "bin/git-wip",
    "chars": 232,
    "preview": "#!/usr/bin/env bash\n\n# Based on scripts from git-utils:\n# * https://github.com/ddollar/git-utils/blob/master/git-wip\n# *"
  },
  {
    "path": "brew-release.patch",
    "chars": 712,
    "preview": "diff --git a/bin/git-extras b/bin/git-extras\nindex e49cd24..4ae28b5 100755\n--- a/bin/git-extras\n+++ b/bin/git-extras\n@@ "
  },
  {
    "path": "check_dependencies.sh",
    "chars": 206,
    "preview": "#!/usr/bin/env bash\n\nerr() {\n    echo >&2 \"$1\"\n    exit 1\n}\n\nif ! command -v column >/dev/null 2>&1; then\n    err \"Need "
  },
  {
    "path": "check_integrity.sh",
    "chars": 2516,
    "preview": "#!/usr/bin/env bash\n\nerr() {\n    echo >&2 \"$1\"\n    exit 1\n}\n\nmake_doc() {\n    echo \"touch man/git-$1.md && make man/git-"
  },
  {
    "path": "etc/bash_completion.sh",
    "chars": 4002,
    "preview": "# shellcheck shell=bash\n# bash completion support for git-extras.\n\n__gitex_heads_unique() {\n  local branch specified=(\"$"
  },
  {
    "path": "etc/git-extras-completion.zsh",
    "chars": 16120,
    "preview": "# ------------------------------------------------------------------------------\n# Description\n# -----------\n#\n#  Comple"
  },
  {
    "path": "etc/git-extras.fish",
    "chars": 15512,
    "preview": "\nset __fish_git_extras_commands \\\n    \"alias:Define, search and show aliases\" \\\n    \"archive-file:Export the current HEA"
  },
  {
    "path": "helper/git-extra-utility",
    "chars": 541,
    "preview": "# put all utility functions here\n\n# make a temporary file\ngit_extra_mktemp() {\n    mktemp -t \"$(basename \"$0\")\".XXXXXXX\n"
  },
  {
    "path": "helper/has-git-commit",
    "chars": 246,
    "preview": "#\n# check whether current directory contains any git commit\n#\n\nhas_git_commit() {\n  git rev-parse --short HEAD > /dev/nu"
  },
  {
    "path": "helper/is-git-repo",
    "chars": 240,
    "preview": "#\n# check whether current directory is inside a git repository\n#\n\nis_git_repo() {\n  git rev-parse --show-toplevel > /dev"
  },
  {
    "path": "helper/reset-env",
    "chars": 91,
    "preview": "# reset environment variables that could interfere with normal usage\nunset -v GREP_OPTIONS\n"
  },
  {
    "path": "install.cmd",
    "chars": 4891,
    "preview": "@ECHO OFF\n:: don't leak env variables into the calling interpreter...\nsetlocal\n:: better defaults for dealing with quote"
  },
  {
    "path": "install.sh",
    "chars": 520,
    "preview": "#!/usr/bin/env bash\n\nmake_install() {\n    if [ -n \"$PREFIX\" ]\n    then\n        PREFIX=\"$PREFIX\" make install\n    else\n  "
  },
  {
    "path": "man/Readme.md",
    "chars": 753,
    "preview": "How to generate documentation:\n================================\n\n## DESCRIPTION\n\nTo generate documentation:\n\n1) Start by"
  },
  {
    "path": "man/git-abort.1",
    "chars": 622,
    "preview": ".\\\" generated with Ronn-NG/v0.8.0\n.\\\" http://github.com/apjanke/ronn-ng/tree/0.8.0\n.TH \"GIT\\-ABORT\" \"1\" \"August 2020\" \"\""
  },
  {
    "path": "man/git-abort.html",
    "chars": 4017,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' content='text/html;charset=utf8'>\n  <meta name='generato"
  },
  {
    "path": "man/git-abort.md",
    "chars": 480,
    "preview": "git-abort(1) -- Abort current git operation\n================================\n\n## SYNOPSIS\n\n`git-abort`\n\n## DESCRIPTION\n\n"
  },
  {
    "path": "man/git-alias.1",
    "chars": 1784,
    "preview": ".\\\" generated with Ronn-NG/v0.9.1\n.\\\" http://github.com/apjanke/ronn-ng/tree/0.9.1\n.TH \"GIT\\-ALIAS\" \"1\" \"September 2024\""
  },
  {
    "path": "man/git-alias.html",
    "chars": 5346,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' content='text/html;charset=utf8'>\n  <meta name='generato"
  },
  {
    "path": "man/git-alias.md",
    "chars": 1619,
    "preview": "git-alias(1) -- Define, search and show aliases\n===============================================\n\n## SYNOPSIS\n\n`git-alias"
  },
  {
    "path": "man/git-archive-file.1",
    "chars": 974,
    "preview": ".\\\" generated with Ronn-NG/v0.9.1\n.\\\" http://github.com/apjanke/ronn-ng/tree/0.9.1\n.TH \"GIT\\-ARCHIVE\\-FILE\" \"1\" \"May 202"
  },
  {
    "path": "man/git-archive-file.html",
    "chars": 4426,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' content='text/html;charset=utf8'>\n  <meta name='generato"
  },
  {
    "path": "man/git-archive-file.md",
    "chars": 804,
    "preview": "git-archive-file(1) -- Export the current HEAD of the git repository to an archive\n====================================="
  },
  {
    "path": "man/git-authors.1",
    "chars": 1329,
    "preview": ".\\\" generated with Ronn-NG/v0.9.1\n.\\\" http://github.com/apjanke/ronn-ng/tree/0.9.1\n.TH \"GIT\\-AUTHORS\" \"1\" \"November 2023"
  },
  {
    "path": "man/git-authors.html",
    "chars": 4829,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' content='text/html;charset=utf8'>\n  <meta name='generato"
  },
  {
    "path": "man/git-authors.md",
    "chars": 1141,
    "preview": "git-authors(1) -- Generate authors report\n=================================================\n\n## SYNOPSIS\n\n`git-authors` "
  },
  {
    "path": "man/git-browse-ci.1",
    "chars": 719,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-BROWSE\\-CI\" \"1\" \"March 2022\" \""
  },
  {
    "path": "man/git-browse-ci.html",
    "chars": 4184,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-browse-ci.md",
    "chars": 617,
    "preview": "git-browse-ci(1) -- <View the web page for the current repository>\n================================\n\n## SYNOPSIS\n\n`git-b"
  },
  {
    "path": "man/git-browse.1",
    "chars": 1102,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-BROWSE\" \"1\" \"June 2022\" \"\" \"Gi"
  },
  {
    "path": "man/git-browse.html",
    "chars": 4624,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-browse.md",
    "chars": 1003,
    "preview": "git-browse(1) -- <View the web page for the current repository>\n================================\n\n## SYNOPSIS\n\n`git-brow"
  },
  {
    "path": "man/git-brv.1",
    "chars": 1493,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-BRV\" \"1\" \"December 2023\" \"\" \"G"
  },
  {
    "path": "man/git-brv.html",
    "chars": 4861,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-brv.md",
    "chars": 1284,
    "preview": "git-brv(1) -- List branches sorted by their last commit date\n========================================================\n\n#"
  },
  {
    "path": "man/git-bulk.1",
    "chars": 4014,
    "preview": ".\\\" generated with Ronn-NG/v0.9.1\n.\\\" http://github.com/apjanke/ronn-ng/tree/0.9.1\n.TH \"GIT\\-BULK\" \"1\" \"February 2025\" \""
  },
  {
    "path": "man/git-bulk.html",
    "chars": 7710,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' content='text/html;charset=utf8'>\n  <meta name='generato"
  },
  {
    "path": "man/git-bulk.md",
    "chars": 4012,
    "preview": "git-bulk(1) -- Run git commands on multiple repositories\n========================================================\n\n## SY"
  },
  {
    "path": "man/git-changelog.1",
    "chars": 4630,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-CHANGELOG\" \"1\" \"June 2018\" \"\" "
  },
  {
    "path": "man/git-changelog.html",
    "chars": 8500,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-changelog.md",
    "chars": 4213,
    "preview": "git-changelog(1) -- Generate a changelog report\n===============================================\n\n## SYNOPSIS\n\n`git-chang"
  },
  {
    "path": "man/git-clear-soft.1",
    "chars": 986,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-CLEAR\\-SOFT\" \"1\" \"October 2017"
  },
  {
    "path": "man/git-clear-soft.html",
    "chars": 4789,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-clear-soft.md",
    "chars": 824,
    "preview": "git-clear-soft(1) -- Soft clean up a repository\n================================================\n\n## SYNOPSIS\n\n`git-clea"
  },
  {
    "path": "man/git-clear.1",
    "chars": 1043,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-CLEAR\" \"1\" \"September 2021\" \"\""
  },
  {
    "path": "man/git-clear.html",
    "chars": 4631,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-clear.md",
    "chars": 867,
    "preview": "git-clear(1) -- Rigorously clean up a repository\n================================================\n\n## SYNOPSIS\n\n`git-cle"
  },
  {
    "path": "man/git-coauthor.1",
    "chars": 779,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-COAUTHOR\" \"1\" \"August 2019\" \"\""
  },
  {
    "path": "man/git-coauthor.html",
    "chars": 4581,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-coauthor.md",
    "chars": 633,
    "preview": "git-coauthor(1) -- Add a co-author to the last commit\n================================\n\n## SYNOPSIS\n\n`git-coauthor` &lt;"
  },
  {
    "path": "man/git-commits-since.1",
    "chars": 2009,
    "preview": ".\\\" generated with Ronn-NG/v0.9.1\n.\\\" http://github.com/apjanke/ronn-ng/tree/0.9.1\n.TH \"GIT\\-COMMITS\\-SINCE\" \"1\" \"Januar"
  },
  {
    "path": "man/git-commits-since.html",
    "chars": 5491,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' content='text/html;charset=utf8'>\n  <meta name='generato"
  },
  {
    "path": "man/git-commits-since.md",
    "chars": 1879,
    "preview": "git-commits-since(1) -- Show commit logs since some date\n========================================================\n\n## SY"
  },
  {
    "path": "man/git-continue.1",
    "chars": 602,
    "preview": ".\\\" generated with Ronn-NG/v0.8.0\n.\\\" http://github.com/apjanke/ronn-ng/tree/0.8.0\n.TH \"GIT\\-CONTINUE\" \"1\" \"November 202"
  },
  {
    "path": "man/git-continue.html",
    "chars": 3955,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' content='text/html;charset=utf8'>\n  <meta name='generato"
  },
  {
    "path": "man/git-continue.md",
    "chars": 463,
    "preview": "git-continue(1) -- Continue current git operation\n================================\n\n## SYNOPSIS\n\n`git-continue`\n\n## DESC"
  },
  {
    "path": "man/git-contrib.1",
    "chars": 1194,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-CONTRIB\" \"1\" \"October 2017\" \"\""
  },
  {
    "path": "man/git-contrib.html",
    "chars": 4802,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-contrib.md",
    "chars": 1118,
    "preview": "git-contrib(1) -- Show user's contributions\n===========================================\n\n## SYNOPSIS\n\n`git-contrib` [&lt"
  },
  {
    "path": "man/git-count.1",
    "chars": 1076,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-COUNT\" \"1\" \"October 2017\" \"\" \""
  },
  {
    "path": "man/git-count.html",
    "chars": 4637,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-count.md",
    "chars": 891,
    "preview": "git-count(1) -- Show commit count\n=================================\n\n## SYNOPSIS\n\n`git-count` [--all]\n\n## DESCRIPTION\n\n "
  },
  {
    "path": "man/git-cp.1",
    "chars": 781,
    "preview": ".\\\" generated with Ronn-NG/v0.9.0\n.\\\" http://github.com/apjanke/ronn-ng/tree/0.9.0\n.TH \"GIT\\-CP\" \"1\" \"March 2020\" \"\" \"Gi"
  },
  {
    "path": "man/git-cp.html",
    "chars": 4244,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' content='text/html;charset=utf8'>\n  <meta name='generato"
  },
  {
    "path": "man/git-cp.md",
    "chars": 639,
    "preview": "git-cp(1) -- Copy a file keeping its history\n============================================\n\n## SYNOPSIS\n\n`git-cp` &lt;cur"
  },
  {
    "path": "man/git-create-branch.1",
    "chars": 2908,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-CREATE\\-BRANCH\" \"1\" \"November "
  },
  {
    "path": "man/git-create-branch.html",
    "chars": 7333,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-create-branch.md",
    "chars": 2543,
    "preview": "git-create-branch(1) -- Create branches\n=======================================\n\n## SYNOPSIS\n\n`git-create-branch` [-r|--"
  },
  {
    "path": "man/git-delete-branch.1",
    "chars": 834,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-DELETE\\-BRANCH\" \"1\" \"October 2"
  },
  {
    "path": "man/git-delete-branch.html",
    "chars": 4456,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-delete-branch.md",
    "chars": 701,
    "preview": "git-delete-branch(1) -- Delete branches\n=======================================\n\n## SYNOPSIS\n\n`git-delete-branch` &lt;br"
  },
  {
    "path": "man/git-delete-merged-branches.1",
    "chars": 704,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-DELETE\\-MERGED\\-BRANCHES\" \"1\" "
  },
  {
    "path": "man/git-delete-merged-branches.html",
    "chars": 4284,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-delete-merged-branches.md",
    "chars": 547,
    "preview": "git-delete-merged-branches(1) -- Delete merged branches\n=====================================================\n\n## SYNOPS"
  },
  {
    "path": "man/git-delete-squashed-branches.1",
    "chars": 1439,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-DELETE\\-SQUASHED\\-BRANCHES\" \"1"
  },
  {
    "path": "man/git-delete-squashed-branches.html",
    "chars": 5313,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-delete-squashed-branches.md",
    "chars": 1224,
    "preview": "git-delete-squashed-branches(1) -- Delete branches that were squashed\n=================================================="
  },
  {
    "path": "man/git-delete-submodule.1",
    "chars": 612,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-DELETE\\-SUBMODULE\" \"1\" \"April "
  },
  {
    "path": "man/git-delete-submodule.html",
    "chars": 4266,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-delete-submodule.md",
    "chars": 471,
    "preview": "git-delete-submodule(1) -- Delete submodules\n============================================\n\n## SYNOPSIS\n\n`git-delete-subm"
  },
  {
    "path": "man/git-delete-tag.1",
    "chars": 725,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-DELETE\\-TAG\" \"1\" \"October 2017"
  },
  {
    "path": "man/git-delete-tag.html",
    "chars": 4328,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-delete-tag.md",
    "chars": 581,
    "preview": "git-delete-tag(1) -- Delete tags\n================================\n\n## SYNOPSIS\n\n`git-delete-tag` &lt;tagname&gt;\n\n## DES"
  },
  {
    "path": "man/git-delta.1",
    "chars": 847,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-DELTA\" \"1\" \"October 2017\" \"\" \""
  },
  {
    "path": "man/git-delta.html",
    "chars": 4340,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-delta.md",
    "chars": 648,
    "preview": "git-delta(1) -- Lists changed files\n===================================\n\n## SYNOPSIS\n\n`git-delta` [&lt;branch&gt;] [&lt;"
  },
  {
    "path": "man/git-effort.1",
    "chars": 3714,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-EFFORT\" \"1\" \"October 2017\" \"\" "
  },
  {
    "path": "man/git-effort.html",
    "chars": 7229,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-effort.md",
    "chars": 3356,
    "preview": "git-effort(1) -- Show effort statistics on file(s)\n=================================\n\n## SYNOPSIS\n\n`git-effort` [--above"
  },
  {
    "path": "man/git-extras.1",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "man/git-extras.html",
    "chars": 15833,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' content='text/html;charset=utf-8'>\n  <meta name='generat"
  },
  {
    "path": "man/git-extras.md",
    "chars": 5186,
    "preview": "git-extras(1) -- Awesome GIT utilities\n=================================\n\n## SYNOPSIS\n\n`git-extras` [-v,--version] [-h,-"
  },
  {
    "path": "man/git-feature.1",
    "chars": 4500,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-FEATURE\" \"1\" \"December 2023\" \""
  },
  {
    "path": "man/git-feature.html",
    "chars": 9784,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-feature.md",
    "chars": 3894,
    "preview": "git-feature(1) -- Create/Merge feature branch\n========================================================\n\n## SYNOPSIS\n\n`gi"
  },
  {
    "path": "man/git-force-clone.1",
    "chars": 1982,
    "preview": ".\\\" generated with Ronn-NG/v0.9.1\n.\\\" http://github.com/apjanke/ronn-ng/tree/0.9.1\n.TH \"GIT\\-FORCE\\-CLONE\" \"1\" \"August 2"
  },
  {
    "path": "man/git-force-clone.html",
    "chars": 5519,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' content='text/html;charset=utf8'>\n  <meta name='generato"
  },
  {
    "path": "man/git-force-clone.md",
    "chars": 1641,
    "preview": "git-force-clone(1) -- overwrite local repositories with clone\n===\n\n## SYNOPSIS\n\n`force-clone --help`  \n`force-clone {rem"
  },
  {
    "path": "man/git-fork.1",
    "chars": 2496,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-FORK\" \"1\" \"October 2017\" \"\" \"G"
  },
  {
    "path": "man/git-fork.html",
    "chars": 6179,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-fork.md",
    "chars": 2109,
    "preview": "git-fork(1) -- Fork a repo on github\n====================================\n\n## SYNOPSIS\n\n`git-fork` [&lt;github-repo-url&"
  },
  {
    "path": "man/git-fresh-branch.1",
    "chars": 652,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-FRESH\\-BRANCH\" \"1\" \"October 20"
  },
  {
    "path": "man/git-fresh-branch.html",
    "chars": 4290,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' value='text/html;charset=utf8'>\n  <meta name='generator'"
  },
  {
    "path": "man/git-fresh-branch.md",
    "chars": 521,
    "preview": "git-fresh-branch(1) -- Create fresh branches\n============================================\n\n## SYNOPSIS\n\n`git-fresh-branc"
  },
  {
    "path": "man/git-get.1",
    "chars": 1078,
    "preview": ".\\\" generated with Ronn-NG/v0.9.1\n.\\\" http://github.com/apjanke/ronn-ng/tree/0.9.1\n.TH \"GIT\\-GET\" \"1\" \"May 2023\" \"\" \"Git"
  },
  {
    "path": "man/git-get.html",
    "chars": 4415,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv='content-type' content='text/html;charset=utf8'>\n  <meta name='generato"
  },
  {
    "path": "man/git-get.md",
    "chars": 985,
    "preview": "git-get(1) -- Clone a Git repository under a configured directory\n=================================================\n\n## "
  },
  {
    "path": "man/git-gh-pages.1",
    "chars": 1027,
    "preview": ".\\\" generated with Ronn/v0.7.3\n.\\\" http://github.com/rtomayko/ronn/tree/0.7.3\n.\n.TH \"GIT\\-GH\\-PAGES\" \"1\" \"October 2017\" "
  }
]

// ... and 164 more files (download for full content)

About this extraction

This page contains the full source code of the tj/git-extras GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 364 files (1.0 MB), approximately 333.8k tokens, and a symbol index with 112 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!