58 Commits

Author SHA1 Message Date
rkiel
c8253b8ed3 setup: more bash variable fixes 2021-04-17 09:34:49 -04:00
rkiel
3456564b20 setup: fixed ruby vs bash variable substitution 2021-04-17 09:25:21 -04:00
rkiel
ef8877b6e9 refactor: upgrade lodash 2020-11-26 09:37:25 -05:00
rkiel
dc31933d78 refactor: deprecate release 2020-11-26 09:08:35 -05:00
rkiel
995d4c779e refactor: update stand branches and support dot file 2020-11-26 08:57:01 -05:00
rkiel
780cd2eaff refactor: fixed zshrc 2020-11-22 23:59:34 -05:00
rkiel
ebefe2acfc refactor: zsh 2020-11-22 16:08:04 -05:00
rkiel
248bcfeda6 refactor: updates 2020-11-21 11:26:50 -05:00
rkiel
4cfb8975ad refactor: support zsh 2020-11-21 11:11:55 -05:00
rkiel
55f2118170 refactor: add FEATURE_USER 2020-11-21 10:32:42 -05:00
rkiel
7e9338128d refactor: added support for zsh 2020-11-21 10:20:23 -05:00
rkiel
5b9d2b0711 refactor: new direction 2019-07-20 09:21:10 -04:00
rkiel
438416bd41 finish end 2019-07-20 08:11:08 -04:00
rkiel
2443a88ad7 refactor 2019-07-18 16:09:29 -04:00
rkiel
308d62fc86 refactor 2019-07-18 15:40:37 -04:00
rkiel
48d64da20b started end 2019-07-14 22:04:51 -04:00
rkiel
604d3d84c4 refactor 2019-07-14 22:04:17 -04:00
rkiel
4c4a16af04 finish start 2019-07-14 17:41:38 -04:00
rkiel
38dd62aea1 more start 2019-07-14 16:56:47 -04:00
rkiel
6d41728543 finish start 2019-07-14 16:36:15 -04:00
rkiel
48f2d0ead0 finish start 2019-07-14 16:32:38 -04:00
rkiel
67b09c2cd0 finish start 2019-07-14 16:31:07 -04:00
rkiel
a688e646d3 node: working on start 2019-07-14 11:57:06 -04:00
rkiel
fe909bf44f node: started 2019-07-13 15:31:43 -04:00
rkiel
cfafb5d694 aliases: added show and log 2019-07-13 07:22:10 -04:00
rkiel
c3079f1e1e Revert "feature: handle merge conflicts on the feature branch not master"
This reverts commit d2498b699e.
2019-06-03 08:09:02 -04:00
rkiel
d2498b699e feature: handle merge conflicts on the feature branch not master 2019-05-28 22:43:08 -04:00
rkiel
01f3712085 xfind: remove puts 2019-04-14 20:21:30 -04:00
rkiel
1fed862a5f xfind: more includes and excludes 2019-03-18 19:17:27 -04:00
rkiel
0358d9a443 xfind: started 2019-03-16 23:42:16 -04:00
rkiel
0015d4d0ff updates: optimize rebase and merge 2019-01-30 21:51:39 -05:00
rkiel
bfaf1a457f updates: updated start 2019-01-30 21:37:53 -05:00
rkiel
d5ee0ecc4d updates: cleanup 2019-01-22 23:16:50 -05:00
rkiel
0bc0293d01 LICENSE.txt 2018-11-04 17:49:42 -05:00
Robert Kiel
ccd3e88b44 added require yaml 2018-09-03 10:16:25 -04:00
Robert Kiel
21532a0334 added republish push 2018-08-31 16:45:20 -04:00
Robert Kiel
6bbba03a59 added more support for package.json 2018-08-31 16:41:44 -04:00
Robert Kiel
31e18e7d62 added republish 2018-08-31 13:47:56 -04:00
Robert Kiel
ad83eac3ea created republish 2018-08-31 13:47:04 -04:00
Robert Kiel
b8702161e4 added git_fetch 2018-08-31 13:45:59 -04:00
Robert Kiel
ec5f41c940 added git_fetch 2018-08-31 13:45:08 -04:00
Robert Kiel
b606a6a9b6 added package_json_version 2018-08-31 13:43:54 -04:00
rkiel
35b68dadf2 installer: added release as a branch 2018-02-08 21:42:42 -05:00
Robert Kiel
0e31424185 Update RELEASE.md 2017-11-15 14:32:45 -05:00
Robert Kiel
8a4129a507 Update RELEASE.md 2017-11-15 14:30:46 -05:00
Robert Kiel
d94948aae1 Update start.rb 2017-11-15 14:15:53 -05:00
Robert Kiel
8e0354be69 Update runnable.rb 2017-11-15 14:11:38 -05:00
Robert Kiel
246142d6fd Update base.rb 2017-11-15 14:09:39 -05:00
rkiel
82973c3498 installer: added prompt 2017-11-09 10:20:29 -05:00
rkiel
af91a01f8f installer: refactor install 2017-11-09 09:43:34 -05:00
rkiel
8ab709a43e installer: refactor install 2017-11-09 09:43:22 -05:00
rkiel
6c83679f45 installer: install 2017-11-08 23:45:52 -05:00
rkiel
5fa3c5f719 installer: install 2017-11-08 23:42:07 -05:00
rkiel
96739bdc76 installer: install script 2017-11-08 22:59:55 -05:00
rkiel
b09accebd0 12-package.json: update when release candidate created 2017-10-10 20:23:06 -04:00
rkiel
f753b647d3 6-leave: added confirmation 2017-10-07 10:25:16 -04:00
rkiel
877f06944d 10-remotes: check for remote branch 2017-10-07 10:20:33 -04:00
rkiel
941aed3389 9-fetch: start using fetch 2017-10-07 09:56:56 -04:00
46 changed files with 3391 additions and 1163 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules

View File

@@ -4,76 +4,97 @@
### Usage
This utility is built around the standard branch `master` and branches for releases that follow the format of MAJOR.MINOR.PATCH.
This feature branch utility is built to work with a set of standard branches (`develop`,`main`,`master`,`release`).
These are the starting point branches from which you can create feature branches.
It is assumed that your starting point branch exists both locally and remotely.
Feature branches have specific format: USER-BASE-FEATURE.
You can override the default set of standard branches by incorporating a `.git-utilities-rc` file (JSON) into your project repository.
Branch names should be limited to a single word.
* USER is the username as specified by the USER environment variable
* BASE is the standard branch or release branch to base the feature branch on
* FEATURE is the name of the feature
```json
{
"branches": ["develop", "test", "production"]
}
```
Feature branch names have a specific format: USER-BRANCH-DESCRIPTION.
- USER is the owner of the feature branch and is specified by either the FEATURE_USER or USER environment variables. This should prevent any feature branch name conflicts and make it easier to know who to talk to about deleting old/unused feature branches.
- BRANCH is the standard branch from which the feature branch was started
- DESCRIPTION is a series of one or more words which describe the feature. The description will be prepended to all commit messages.
#### Start
To start a new feature, go to the standard branch or a release branch.
To start a new feature, checkout one of the standard branches.
Use the `start` subcommand followed by a short series of words to describe the feature.
For example, use a bug number and a short phrase as the description.
```
git checkout master
git checkout develop
feature start 4365 update help
```
Use the `start` subcommand with a feature name.
In this example, user `bob` will create a new branch called `bob-develop-4365-update-help`.
If you start with a branch other than one of the standard branches you will get an error.
For example,
```
feature start my new feature
```
git checkout hotfixes
feature start 4365 update help
For example, a new branch will be created called `rkiel-master-my-new-feature`
ERROR: invalid base branch. must be one of: develop, main, master, release
```
#### Commit
Use the `commit` subcommand to make it easier to write commit messages.
No need to specify the `-m` parameter or wrapping the message in quotes.
If you forget and pass in `-m` anyway, it will ignore it.
Of course, if you forget and pass in `-m` anyway, it will be ignore it.
The feature branch description will be prepended to your commit message.
For example,
```
feature commit this is a sample commit message
feature commit -m this is a sample commit message
feature commit corrected spelling mistakes
```
generates the command `git commit -m "this is a sample commit message"`.
The commit message will be prepended with the feature name. For example,
will generate the following commit message:
```
my-feature-name: this is a sample commit message
4365-update-help: corrected spelling mistakes
```
If you need to by-pass any git pre-commit hooks, you can use the `-f` option to force the commit.
This will invoke the commit with the `--no-verify` option.
It will also add `(no-verify)` to the end of your commit message. For example,
```
feature commit -f this is a sample commit message
feature commit -m this is a sample commit message -f
feature commit -f corrected spelling mistakes
```
generates the command `git commit -m "this is a sample commit message (no-verify)" --no-verify`.
will generate the following commit message:
```
4365-update-help: corrected spelling mistakes (no-verify)
```
#### Rebase
Use the `rebase` subcommand to pull down any changes from the standard branch and then rebase with your feature branch changes.
In addition, a backup copy of your feature changes will be pushed out to `origin`.
This backup should not be used to collaborate with others. It is just a personal backup and will be deleted and recreated with each `rebase`.
This remote backup branch should NEVER be used to collaborate with others.
It is just a personal backup and will be deleted and recreated with each `rebase`.
```
feature rebase
```
For example, `rkiel-master-my-new-feature` will be pushed out to `origin`.
For example, the `bob-develop-4365-update-help` branch will be pushed out to `origin`.
#### Merge
Use the `merge` subcommand to merge your feature branch changes to the standard branch.
A `rebase` will be performed automatically before the merge.
```
feature merge
@@ -94,11 +115,14 @@ feature end
Use the `trash` subcommand to forcibly close out the feature.
The standard branch will be checkout and the local feature branch will be forcibly deleted.
Make sure that your changes have been merged because they will be lost.
If there is a backup copy on `origin`, it will also be removed.
You must supply the name of the local feature branch on the command line as
a confirmation.
As a safety precaution, you must supply the name of the local feature branch on the command line as
a confirmation. This will hopefully protect you from accidentally running `feature trash` when you meant `feature end`.
WARNING: Make sure that your changes have been merged because they will be lost.
For example,
```
feature trash local-branch-confirmation
feature trash bob-develop-4365-update-help
```

21
LICENSE.txt Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Robert Kiel
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.

View File

@@ -4,66 +4,38 @@ This is a collection of simple command-line scripts, bash aliases, and bash util
The command-line scripts include:
* [feature](FEATURE.md) - make working with feature branches easier
* [release](RELEASE.md)- make working with release branches and tags easier
* [xgrep](XGREP.md)- make using `git-grep` easier
- [feature](FEATURE.md) - make working with feature branches easier
- [release](RELEASE.md)- make working with release branches and tags easier (DEPRECATED)
- [xgrep](XGREP.md)- make using `git-grep` easier
- [xfind](XFIND.md)- make using `find` easier
The command-line scripts are written in Ruby 2.x using just the standard libraries and do not require any gems to be installed.
For OS X users, these should just work out-of-box.
The `bash` utilities come directly from the [git source contrib](https://github.com/git/git/tree/master/contrib) and include:
* support for [tab completion](https://github.com/git/git/tree/master/contrib/completion/git-completion.bash)
* support for repository status in your [shell prompt](https://github.com/git/git/tree/master/contrib/completion/git-prompt.sh)
- support for [tab completion](https://github.com/git/git/tree/master/contrib/completion/git-completion.bash)
- support for repository status in your [shell prompt](https://github.com/git/git/tree/master/contrib/completion/git-prompt.sh)
## Installation
Clone the repository
```
mkdir -p ~/GitHub/rkiel
cd ~/GitHub/rkiel
mkdir -p ~/GitHub/rkiel && cd $_
git clone https://github.com/rkiel/git-utilities.git
```
To add the scripts to your path, add the following to `.bash_profile`
To update your `.bash_profile` and `.bashrc`.
```
export GIT_UTILITIES_BIN="~/GitHub/rkiel/git-utilities/bin"
export PATH=${GIT_UTILITIES_BIN}:$PATH
cd ~/GitHub/rkiel/git-utilities
./install/bin/setup $USER
```
To enable `bash` tab completion for `git` commands, add the following to `.bash_profile` (OS X) or `.bashrc` (Linux)
```
source ~/GitHub/rkiel/git-utilities/dotfiles/git-completion.bash
```
To enable your `bash` prompt to display repository status, add the following to `.bash_profile` (OS X) or `.bashrc` (Linux).
```
source ~/GitHub/rkiel/git-utilities/dotfiles/git-prompt.sh
```
Here's a sample prompt that includes the current branch (i.e. `$(__git_ps1 " %s")`)
```
export PS1='[\[\e[0;35m\]\u@\h\[\e[0m\] \[\e[1;34m\]\W\[\e[0;32m\]$(__git_ps1 " %s")\[\e[0m\]]\$ '
```
To include the `bash` aliases and enable tab completion for the `feature` script, add the following to `.bashrc`.
```
source ~/GitHub/rkiel/git-utilities/dotfiles/bashrc
```
If your user id (i.e. `env|grep USER`) is generic, such as `ec2-user` or `centos` or `ubuntu`, set a `FEATURE_USER` environment variable in your `.bash_profile`. Either your `USER` or `FEATURE_USER` should be unique relative to all the users who will be creating feature branches in your git repository.
```
export FEATURE_USER=rkiel
```
## Documention
* [See feature](FEATURE.md)
* [See release](RELEASE.md)
* [See xgrep](XGREP.md)
- [See feature](FEATURE.md)
- [See release](RELEASE.md) (DEPRECATED)
- [See xgrep](XGREP.md)
- [See xfind](XFIND.md)

View File

@@ -2,11 +2,13 @@
## Release
`release` is a command line utility to make working with releases easier. Releases are built and managed using branches and tags.
NOTE: This command is DEPRECATED.
Official release versions are tagged using a simplified [Semantic Versioning](http://semver.org/) format. The tags start with the letter `v` followed by MAJOR.MINOR.PATCH.
`release` is a command line utility to make working with releases easier. Releases are built and managed using branches and tags.
Before a release is tagged with a version, a release candidate branch can be created and used for development. The intent of the release candidate branch is to be short-term support for multiple developers and deployment to test environments. They are prefixed by `rc`.
Official release versions are tagged using a simplified [Semantic Versioning](http://semver.org/) format. The tags start with the letter `v` followed by MAJOR.MINOR.PATCH.
Before a release is tagged with a version, a release candidate branch can be created and used for development. The intent of the release candidate branch is to be short-term support for multiple developers and deployment to test environments. They are prefixed by `rc`.
### Usage
@@ -17,7 +19,7 @@ release help
release join version
release leave
release list
release start (major|minor|patch) [from] version
release start (major|minor|patch) from version [using master]
release tab [pattern]
release trash local-branch-confirmation
```
@@ -30,7 +32,7 @@ Create an official release tag.
release create version
```
You must be on the `master` branch. The latest code will be pulled from `master` and a tag created for the last commit. For example, the following command will create a `v1.0.0` tag.
You must be on the `master` branch. The latest code will be pulled from `master` and a tag created for the last commit. For example, the following command will create a `v1.0.0` tag.
```bash
git checkout master
@@ -42,16 +44,23 @@ release create 1.0.0
Create a shared, release candidate branch.
```bash
release start (major|minor|patch) [from] version
release start (major|minor|patch) from version [using master]
```
The `version` specified must be an existing official release version. The `major`, `minor`, and `patch` options will increment the new version number accordingly. For example, to create a patch update, the following command will create a `rc1.0.1` release candidate branch.
The `version` specified must be an existing official release version. The `major`, `minor`, and `patch` options will increment the new version number accordingly. For example, to create a patch update, the following command will create a `rc1.0.1` release candidate branch. If the optional `using master` is not specified, the release candiate branch will be created from the version tag (e.g. `v1.0.0`). Otherwise, the release candiate branch will be created from `master`. Also, if the repository contains a `package.json` file, the `version` property will automatically be set and committed.
```bash
git checkout master
release start patch from 1.0.0
```
or
```bash
git checkout master
release start patch from 1.0.0 from master
```
Once the shared release candidate branch has been created, use `feature` to create and manage personal feature branches.
#### Join
@@ -62,7 +71,7 @@ Join in on using a shared, release candidate branch that someone else has previo
release join version
```
The `version` specified must be an existing release candidate branch version. A local tracking branch will be created. For example, the following command will create `rc1.0.1` as a local tracking branch.
The `version` specified must be an existing release candidate branch version. A local tracking branch will be created. For example, the following command will create `rc1.0.1` as a local tracking branch.
```bash
git checkout master
@@ -79,7 +88,7 @@ Stop using a shared, release candidate branch but leave it intact for others to
release leave
```
Your local tracking branch will be forcibly removed. If there are any local changes on the branch, they will be lost. For example, the following command will remove `rc1.0.1` as a local tracking branch.
Your local tracking branch will be forcibly removed. If there are any local changes on the branch, they will be lost. For example, the following command will remove `rc1.0.1` as a local tracking branch.
```bash
git checkout rc1.0.1
@@ -94,7 +103,7 @@ Finish the release candidate and create an official release.
release finish
```
The latest code from the release candidate branch will be pulled and a tag created. The shared release candidate branch will then be removed. For example, the following command will create `v1.0.1` version tag and removed `rc1.0.1` branch.
The latest code from the release candidate branch will be pulled and a tag created. The shared release candidate branch will then be removed. For example, the following command will create `v1.0.1` version tag and removed `rc1.0.1` branch.
```bash
git checkout rc1.0.1
@@ -117,7 +126,7 @@ Throw away the release candidate.
release trash local-branch-confirmation
```
The shared release candidate branch will be forcibly removed and no version tag will be created. The release candidate branch must be checked out and entered as the `local-branch-confirmation`. For example, the following command will remove the `rc1.0.1` release candidate branch.
The shared release candidate branch will be forcibly removed and no version tag will be created. The release candidate branch must be checked out and entered as the `local-branch-confirmation`. For example, the following command will remove the `rc1.0.1` release candidate branch.
```branch
git checkout rc1.0.1

15
XFIND.md Normal file
View File

@@ -0,0 +1,15 @@
[<<back](README.md)
## Xfind utility
This utility makes it easier to use find.
```bash
Usage: xfind options term(s)
-d, --[no-]debug
-n NAME include NAME
-N NAME exclude NAME
-p PATH include PATH
-P PATH exclude PATH
-h, --help
```

View File

@@ -3,3 +3,15 @@
## Xgrep utility
This utility makes it easier to use git-grep.
```bash
Usage: xgrep options term(s)
-d, --[no-]debug
-f, --file
-i, --invert
-p, --include-path PATHS
-P, --exclude-path PATHS
-t, --include-type TYPES
-T, --exclude-type TYPES
-h, --help
```

9
bin/creature Executable file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/env node
const commander = require("commander");
const program = new commander.Command();
program
.command("start feature-words", "start a new feature")
.command("end", "end a feature")
.parse(process.argv);

33
bin/creature-end Executable file
View File

@@ -0,0 +1,33 @@
#!/usr/bin/env node
const _ = require("lodash");
const path = x => require("../" + x);
const git = path("js/git");
const shell = path("js/shell");
const commander = path("js/commander");
const validate = path("js/validate");
function endFeatureBranch(dp) {
const cmds = [
`git checkout ${dp.branch.standard}`,
`git branch -d ${dp.branch.current}`
];
const remoteBranch = _.get(dp, "branch.remote", false);
if (remoteBranch) {
cmds.push(`git push origin :${remoteBranch}`);
}
return shell.pipeline(cmds);
}
commander
.start()
.then(git.gather)
.then(commander.echo)
// .then(git.setCurrentBranch)
// .then(git.parseCurrentBranch)
// .then(validate.mustBeFeatureBranch)
// .then(git.setStandardBranch)
// .then(git.isBranchRemote)
// .then(endFeatureBranch)
.catch(err => console.error(err));

28
bin/creature-start Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env node
const _ = require("lodash");
const path = x => require("../" + x);
const git = path("js/git");
const shell = path("js/shell");
const commander = path("js/commander");
const validate = path("js/validate");
function createFeatureBranch(dp) {
return shell.pipeline([
"git fetch --prune --prune-tags --tags origin",
`git merge origin/${dp.branch.current}`,
"git push",
`git checkout -b ${dp.branch.feature}`,
`git push -u origin ${dp.branch.feature}`
]);
}
commander
.start()
.then(git.setCurrentBranch)
.then(validate.currentIsStandardBranch)
.then(git.setFeatureBranch)
.then(validate.featureIsNotStandardBranch)
.then(createFeatureBranch)
.catch(err => console.error(err));

17
bin/xfind Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env ruby
require_relative '../lib/xfind/commander'
if File.exist? './.xfind'
project_argv = File.read('./.xfind').split(/\s/).reject { |x| x.strip == "" }
argv = project_argv + ARGV
else
argv = ARGV
end
commander = Xfind::Commander.new(argv)
if commander.valid?
commander.execute
else
commander.help
end

14
dotfiles/bash_profile Normal file
View File

@@ -0,0 +1,14 @@
export EDITOR=vim
# generated by ./bin/generate-bash-prompt
# export PS1='[\[\e[0;35m\]\u@\h\[\e[0m\] \[\e[1;34m\]\W\[\e[0m\]]\$ '
export PS1='[\[\e[0;35m\]\u@\h\[\e[0m\] \[\e[1;34m\]\W\[\e[0;32m\]$(__git_ps1 " %s")\[\e[0m\]]\$ '
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
LOCALS=~/.bashrc_local
if [ -f $LOCALS ]; then
source $LOCALS
fi

View File

@@ -1,30 +1,30 @@
# alias add="git add"
alias branch="git branch"
alias checkout="git checkout"
# alias commit="feature commit"
alias pop="git stash pop --index"
alias pull="git pull"
alias push="git push"
alias master="git checkout master"
# alias develop="git checkout develop"
# alias diff="clear; git diff -w"
# alias linuxdiff="/usr/bin/diff"
# alias sysdiff="/usr/bin/diff"
# alias log="git log --graph --decorate --abbrev-commit --pretty=oneline"
# alias log="git log --graph --date=short --pretty=format:'%C(yellow)%h %C(white)%ad %C(black)[%C(green)%an%C(black)] %C(blue)%s%C(yellow)%d'"
alias stash="git stash save"
# alias status="git status; echo; echo STASH:; git stash list; echo"
alias h='history'
alias lsa='ls -la'
alias lsl='ls -l'
alias more='less -RX'
alias sl='ls'
alias a='git add'
alias b="git branch"
alias branch="git branch"
alias c='feature commit'
alias checkout="git checkout"
alias co='git checkout'
alias d='clear; git diff -w'
alias l="git log --graph --date=short --pretty=format:'%C(yellow)%h %C(white)%ad %C(black)[%C(green)%an%C(black)] %C(blue)%s%C(yellow)%d'"
alias log='git log -w -u'
alias m='feature merge'
alias master="git checkout master"
alias pop="git stash pop --index"
alias pull="git pull"
alias push="git push"
alias r='feature rebase'
alias s='git status; echo; echo STASH:; git stash list; echo'
alias show='git show -w'
alias stash="git stash save"
alias x='xgrep'
alias sfind='find . -not \( -type d -name .git -prune \) -not \( -type d -name node_modes -prune \) -and \( -type f \)|sort -f'
alias sgrep='find . -not \( -type d -name .git -prune \) -not \( -type d -name node_modes -prune \) -and \( -type f \)|sort -f|xargs grep --color=always'
alias cgrep='grep --color=always'
@@ -39,14 +39,9 @@ function get_feature_commands()
fi
}
function get_release_commands()
{
if [ -z $2 ] ; then
COMPREPLY=(`release tab`)
else
COMPREPLY=(`release tab $2`)
fi
}
complete -F get_feature_commands feature
complete -F get_release_commands release
LOCALS=~/.bashrc_locals
if [ -f $LOCALS ]; then
source $LOCALS
fi

File diff suppressed because it is too large Load Diff

293
dotfiles/git-completion.zsh Normal file
View File

@@ -0,0 +1,293 @@
#compdef git gitk
# zsh completion wrapper for git
#
# Copyright (c) 2012-2020 Felipe Contreras <felipe.contreras@gmail.com>
#
# The recommended way to install this script is to make a copy of it as a
# file named '_git' inside any directory in your fpath.
#
# For example, create a directory '~/.zsh/', copy this file to '~/.zsh/_git',
# and then add the following to your ~/.zshrc file:
#
# fpath=(~/.zsh $fpath)
#
# You need git's bash completion script installed. By default bash-completion's
# location will be used (e.g. pkg-config --variable=completionsdir bash-completion).
#
# If your bash completion script is somewhere else, you can specify the
# location in your ~/.zshrc:
#
# zstyle ':completion:*:*:git:*' script ~/.git-completion.bash
#
zstyle -T ':completion:*:*:git:*' tag-order && \
zstyle ':completion:*:*:git:*' tag-order 'common-commands'
zstyle -s ":completion:*:*:git:*" script script
if [ -z "$script" ]; then
local -a locations
local e bash_completion
bash_completion=$(pkg-config --variable=completionsdir bash-completion 2>/dev/null) ||
bash_completion='/usr/share/bash-completion/completions/'
locations=(
"$(dirname ${funcsourcetrace[1]%:*})"/git-completion.bash
"$HOME/.local/share/bash-completion/completions/git"
"$bash_completion/git"
'/etc/bash_completion.d/git' # old debian
)
for e in $locations; do
test -f $e && script="$e" && break
done
fi
local old_complete="$functions[complete]"
functions[complete]=:
GIT_SOURCING_ZSH_COMPLETION=y . "$script"
functions[complete]="$old_complete"
__gitcomp ()
{
emulate -L zsh
local cur_="${3-$cur}"
case "$cur_" in
--*=)
;;
--no-*)
local c IFS=$' \t\n'
local -a array
for c in ${=1}; do
if [[ $c == "--" ]]; then
continue
fi
c="$c${4-}"
case $c in
--*=|*.) ;;
*) c="$c " ;;
esac
array+=("$c")
done
compset -P '*[=:]'
compadd -Q -S '' -p "${2-}" -a -- array && _ret=0
;;
*)
local c IFS=$' \t\n'
local -a array
for c in ${=1}; do
if [[ $c == "--" ]]; then
c="--no-...${4-}"
array+=("$c ")
break
fi
c="$c${4-}"
case $c in
--*=|*.) ;;
*) c="$c " ;;
esac
array+=("$c")
done
compset -P '*[=:]'
compadd -Q -S '' -p "${2-}" -a -- array && _ret=0
;;
esac
}
__gitcomp_direct ()
{
emulate -L zsh
compset -P '*[=:]'
compadd -Q -S '' -- ${(f)1} && _ret=0
}
__gitcomp_nl ()
{
emulate -L zsh
compset -P '*[=:]'
compadd -Q -S "${4- }" -p "${2-}" -- ${(f)1} && _ret=0
}
__gitcomp_file ()
{
emulate -L zsh
compadd -f -p "${2-}" -- ${(f)1} && _ret=0
}
__gitcomp_direct_append ()
{
__gitcomp_direct "$@"
}
__gitcomp_nl_append ()
{
__gitcomp_nl "$@"
}
__gitcomp_file_direct ()
{
__gitcomp_file "$1" ""
}
_git_zsh ()
{
__gitcomp "v1.1"
}
__git_complete_command ()
{
emulate -L zsh
local command="$1"
local completion_func="_git_${command//-/_}"
if (( $+functions[$completion_func] )); then
emulate ksh -c $completion_func
return 0
else
return 1
fi
}
__git_zsh_bash_func ()
{
emulate -L ksh
local command=$1
__git_complete_command "$command" && return
local expansion=$(__git_aliased_command "$command")
if [ -n "$expansion" ]; then
words[1]=$expansion
__git_complete_command "$expansion"
fi
}
__git_zsh_cmd_common ()
{
local -a list
list=(
add:'add file contents to the index'
bisect:'find by binary search the change that introduced a bug'
branch:'list, create, or delete branches'
checkout:'checkout a branch or paths to the working tree'
clone:'clone a repository into a new directory'
commit:'record changes to the repository'
diff:'show changes between commits, commit and working tree, etc'
fetch:'download objects and refs from another repository'
grep:'print lines matching a pattern'
init:'create an empty Git repository or reinitialize an existing one'
log:'show commit logs'
merge:'join two or more development histories together'
mv:'move or rename a file, a directory, or a symlink'
pull:'fetch from and merge with another repository or a local branch'
push:'update remote refs along with associated objects'
rebase:'forward-port local commits to the updated upstream head'
reset:'reset current HEAD to the specified state'
restore:'restore working tree files'
rm:'remove files from the working tree and from the index'
show:'show various types of objects'
status:'show the working tree status'
switch:'switch branches'
tag:'create, list, delete or verify a tag object signed with GPG')
_describe -t common-commands 'common commands' list && _ret=0
}
__git_zsh_cmd_alias ()
{
local -a list
list=(${${(0)"$(git config -z --get-regexp '^alias\.*')"}#alias.})
list=(${(f)"$(printf "%s:alias for '%s'\n" ${(f@)list})"})
_describe -t alias-commands 'aliases' list && _ret=0
}
__git_zsh_cmd_all ()
{
local -a list
emulate ksh -c __git_compute_all_commands
list=( ${=__git_all_commands} )
_describe -t all-commands 'all commands' list && _ret=0
}
__git_zsh_main ()
{
local curcontext="$curcontext" state state_descr line
typeset -A opt_args
local -a orig_words
orig_words=( ${words[@]} )
_arguments -C \
'(-p --paginate --no-pager)'{-p,--paginate}'[pipe all output into ''less'']' \
'(-p --paginate)--no-pager[do not pipe git output into a pager]' \
'--git-dir=-[set the path to the repository]: :_directories' \
'--bare[treat the repository as a bare repository]' \
'(- :)--version[prints the git suite version]' \
'--exec-path=-[path to where your core git programs are installed]:: :_directories' \
'--html-path[print the path where git''s HTML documentation is installed]' \
'--info-path[print the path where the Info files are installed]' \
'--man-path[print the manpath (see `man(1)`) for the man pages]' \
'--work-tree=-[set the path to the working tree]: :_directories' \
'--namespace=-[set the git namespace]' \
'--no-replace-objects[do not use replacement refs to replace git objects]' \
'(- :)--help[prints the synopsis and a list of the most commonly used commands]: :->arg' \
'(-): :->command' \
'(-)*:: :->arg' && return
case $state in
(command)
_tags common-commands alias-commands all-commands
while _tags; do
_requested common-commands && __git_zsh_cmd_common
_requested alias-commands && __git_zsh_cmd_alias
_requested all-commands && __git_zsh_cmd_all
let _ret || break
done
;;
(arg)
local command="${words[1]}" __git_dir
if (( $+opt_args[--bare] )); then
__git_dir='.'
else
__git_dir=${opt_args[--git-dir]}
fi
(( $+opt_args[--help] )) && command='help'
words=( ${orig_words[@]} )
__git_zsh_bash_func $command
;;
esac
}
_git ()
{
local _ret=1
local cur cword prev
cur=${words[CURRENT]}
prev=${words[CURRENT-1]}
let cword=CURRENT-1
if (( $+functions[__${service}_zsh_main] )); then
__${service}_zsh_main
elif (( $+functions[__${service}_main] )); then
emulate ksh -c __${service}_main
elif (( $+functions[_${service}] )); then
emulate ksh -c _${service}
elif (( $+functions[_${service//-/_}] )); then
emulate ksh -c _${service//-/_}
fi
let _ret && _default && _ret=0
return _ret
}
_git

View File

@@ -66,6 +66,19 @@
# git always compare HEAD to @{upstream}
# svn always compare HEAD to your SVN upstream
#
# You can change the separator between the branch name and the above
# state symbols by setting GIT_PS1_STATESEPARATOR. The default separator
# is SP.
#
# When there is an in-progress operation such as a merge, rebase,
# revert, cherry-pick, or bisect, the prompt will include information
# related to the operation, often in the form "|<OPERATION-NAME>".
#
# When the repository has a sparse-checkout, a notification of the form
# "|SPARSE" will be included in the prompt. This can be shortened to a
# single '?' character by setting GIT_PS1_COMPRESSSPARSESTATE, or omitted
# by setting GIT_PS1_OMITSPARSESTATE.
#
# By default, __git_ps1 will compare HEAD to your SVN upstream if it can
# find one, or @{upstream} otherwise. Once you have set
# GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
@@ -78,12 +91,14 @@
# contains relative to newer annotated tag (v1.6.3.2~35)
# branch relative to newer tag or branch (master~4)
# describe relative to older annotated tag (v1.6.3.1-13-gdd42c2f)
# tag relative to any older tag (v1.6.3.1-13-gdd42c2f)
# default exactly matching tag
#
# If you would like a colored hint about the current dirty state, set
# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
# the colored output of "git status -sb" and are available only when
# using __git_ps1 for PROMPT_COMMAND or precmd.
# using __git_ps1 for PROMPT_COMMAND or precmd in Bash,
# but always available in Zsh.
#
# If you would like __git_ps1 to do nothing in the case when the current
# directory is set up to be ignored by git, then set
@@ -123,6 +138,7 @@ __git_ps1_show_upstream ()
done <<< "$output"
# parse configuration values
local option
for option in ${GIT_PS1_SHOWUPSTREAM}; do
case "$option" in
git|svn) upstream="$option" ;;
@@ -273,11 +289,43 @@ __git_ps1_colorize_gitstring ()
r="$c_clear$r"
}
# Helper function to read the first line of a file into a variable.
# __git_eread requires 2 arguments, the file path and the name of the
# variable, in that order.
__git_eread ()
{
local f="$1"
shift
test -r "$f" && read "$@" <"$f"
test -r "$1" && IFS=$'\r\n' read "$2" <"$1"
}
# see if a cherry-pick or revert is in progress, if the user has committed a
# conflict resolution with 'git commit' in the middle of a sequence of picks or
# reverts then CHERRY_PICK_HEAD/REVERT_HEAD will not exist so we have to read
# the todo file.
__git_sequencer_status ()
{
local todo
if test -f "$g/CHERRY_PICK_HEAD"
then
r="|CHERRY-PICKING"
return 0;
elif test -f "$g/REVERT_HEAD"
then
r="|REVERTING"
return 0;
elif __git_eread "$g/sequencer/todo" todo
then
case "$todo" in
p[\ \ ]|pick[\ \ ]*)
r="|CHERRY-PICKING"
return 0
;;
revert[\ \ ]*)
r="|REVERTING"
return 0
;;
esac
fi
return 1
}
# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
@@ -351,8 +399,8 @@ __git_ps1 ()
# incorrect.)
#
local ps1_expanded=yes
[ -z "$ZSH_VERSION" ] || [[ -o PROMPT_SUBST ]] || ps1_expanded=no
[ -z "$BASH_VERSION" ] || shopt -q promptvars || ps1_expanded=no
[ -z "${ZSH_VERSION-}" ] || [[ -o PROMPT_SUBST ]] || ps1_expanded=no
[ -z "${BASH_VERSION-}" ] || shopt -q promptvars || ps1_expanded=no
local repo_info rev_parse_exit_code
repo_info="$(git rev-parse --git-dir --is-inside-git-dir \
@@ -364,7 +412,7 @@ __git_ps1 ()
return $exit
fi
local short_sha
local short_sha=""
if [ "$rev_parse_exit_code" = "0" ]; then
short_sha="${repo_info##*$'\n'}"
repo_info="${repo_info%$'\n'*}"
@@ -384,6 +432,13 @@ __git_ps1 ()
return $exit
fi
local sparse=""
if [ -z "${GIT_PS1_COMPRESSSPARSESTATE}" ] &&
[ -z "${GIT_PS1_OMITSPARSESTATE}" ] &&
[ "$(git config --bool core.sparseCheckout)" = "true" ]; then
sparse="|SPARSE"
fi
local r=""
local b=""
local step=""
@@ -392,11 +447,7 @@ __git_ps1 ()
__git_eread "$g/rebase-merge/head-name" b
__git_eread "$g/rebase-merge/msgnum" step
__git_eread "$g/rebase-merge/end" total
if [ -f "$g/rebase-merge/interactive" ]; then
r="|REBASE-i"
else
r="|REBASE-m"
fi
r="|REBASE"
else
if [ -d "$g/rebase-apply" ]; then
__git_eread "$g/rebase-apply/next" step
@@ -411,10 +462,8 @@ __git_ps1 ()
fi
elif [ -f "$g/MERGE_HEAD" ]; then
r="|MERGING"
elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
r="|CHERRY-PICKING"
elif [ -f "$g/REVERT_HEAD" ]; then
r="|REVERTING"
elif __git_sequencer_status; then
:
elif [ -f "$g/BISECT_LOG" ]; then
r="|BISECTING"
fi
@@ -439,6 +488,8 @@ __git_ps1 ()
git describe --contains HEAD ;;
(branch)
git describe --contains --all HEAD ;;
(tag)
git describe --tags HEAD ;;
(describe)
git describe HEAD ;;
(* | default)
@@ -459,6 +510,7 @@ __git_ps1 ()
local i=""
local s=""
local u=""
local h=""
local c=""
local p=""
@@ -472,10 +524,9 @@ __git_ps1 ()
if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ] &&
[ "$(git config --bool bash.showDirtyState)" != "false" ]
then
git diff --no-ext-diff --quiet --exit-code || w="*"
if [ -n "$short_sha" ]; then
git diff-index --cached --quiet HEAD -- || i="+"
else
git diff --no-ext-diff --quiet || w="*"
git diff --no-ext-diff --cached --quiet || i="+"
if [ -z "$short_sha" ] && [ -z "$i" ]; then
i="#"
fi
fi
@@ -487,11 +538,16 @@ __git_ps1 ()
if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] &&
[ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
git ls-files --others --exclude-standard --error-unmatch -- ':/*' >/dev/null 2>/dev/null
git ls-files --others --exclude-standard --directory --no-empty-directory --error-unmatch -- ':/*' >/dev/null 2>/dev/null
then
u="%${ZSH_VERSION+%}"
fi
if [ -n "${GIT_PS1_COMPRESSSPARSESTATE}" ] &&
[ "$(git config --bool core.sparseCheckout)" = "true" ]; then
h="?"
fi
if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
__git_ps1_show_upstream
fi
@@ -499,9 +555,11 @@ __git_ps1 ()
local z="${GIT_PS1_STATESEPARATOR-" "}"
# NO color option unless in PROMPT_COMMAND mode
if [ $pcmode = yes ] && [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
__git_ps1_colorize_gitstring
# NO color option unless in PROMPT_COMMAND mode or it's Zsh
if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
if [ $pcmode = yes ] || [ -n "${ZSH_VERSION-}" ]; then
__git_ps1_colorize_gitstring
fi
fi
b=${b##refs/heads/}
@@ -510,8 +568,8 @@ __git_ps1 ()
b="\${__git_ps1_branch_name}"
fi
local f="$w$i$s$u"
local gitstring="$c$b${f:+$z$f}$r$p"
local f="$h$w$i$s$u"
local gitstring="$c$b${f:+$z$f}${sparse}$r$p"
if [ $pcmode = yes ]; then
if [ "${__git_printf_supports_v-}" != yes ]; then

15
dotfiles/zprofile Normal file
View File

@@ -0,0 +1,15 @@
export EDITOR=vim
autoload -Uz vcs_info
precmd_vcs_info() { vcs_info }
precmd_functions+=( precmd_vcs_info )
setopt prompt_subst
zstyle ':vcs_info:git:*' formats '%b'
# generated by ./bin/generate-bash-prompt
export PS1='[%B%F{magenta}%n@%m%f%b %B%F{blue}%1d%f%b %B%F{green}'\$vcs_info_msg_0_'%f%b]$ '
LOCALS=~/.zprofile_locals
if [ -f $LOCALS ]; then
source $LOCALS
fi

61
dotfiles/zshrc Normal file
View File

@@ -0,0 +1,61 @@
GIT_UTILITIES_BIN=~/GitHub/rkiel/git-utilities/bin
export PATH=${GIT_UTILITIES_BIN}:$PATH
export EDITOR=vim
autoload -Uz vcs_info
precmd_vcs_info() { vcs_info }
precmd_functions+=( precmd_vcs_info )
setopt prompt_subst
zstyle ':vcs_info:git:*' formats '%b'
# generated by ./bin/generate-bash-prompt
export PS1='[%B%F{magenta}%n@%m%f%b %B%F{blue}%1d%f%b %B%F{green}'\$vcs_info_msg_0_'%f%b]$ '
alias h='history'
alias lsa='ls -la'
alias lsl='ls -l'
alias more='less -RX'
alias sl='ls'
alias a='git add'
alias b="git branch"
alias branch="git branch"
alias c='feature commit'
alias checkout="git checkout"
alias co='git checkout'
alias d='clear; git diff -w'
alias l="git log --graph --date=short --pretty=format:'%C(yellow)%h %C(white)%ad %C(black)[%C(green)%an%C(black)] %C(blue)%s%C(yellow)%d'"
alias log='git log -w -u'
alias m='feature merge'
alias master="git checkout master"
alias pop="git stash pop --index"
alias pull="git pull"
alias push="git push"
alias r='feature rebase'
alias s='git status; echo; echo STASH:; git stash list; echo'
alias show='git show -w'
alias stash="git stash save"
alias x='xgrep'
alias sfind='find . -not \( -type d -name .git -prune \) -not \( -type d -name node_modes -prune \) -and \( -type f \)|sort -f'
alias sgrep='find . -not \( -type d -name .git -prune \) -not \( -type d -name node_modes -prune \) -and \( -type f \)|sort -f|xargs grep --color=always'
alias cgrep='grep --color=always'
alias vgrep='grep -v'
function get_feature_commands()
{
if [ -z $2 ] ; then
COMPREPLY=(`feature tab`)
else
COMPREPLY=(`feature tab $2`)
fi
}
complete -F get_feature_commands feature
LOCALS=~/.zshrc_locals
if [ -f $LOCALS ]; then
source $LOCALS
fi

44
install/bin/setup Executable file
View File

@@ -0,0 +1,44 @@
REPO="~/GitHub/rkiel/git-utilities"
GIT="~/GitHub/git/git"
# mkdir ~/GitHub/git && cd $_
# git clone https://github.com/git/git.git
# cd git
# ls|grep -v contrib|xargs rm -rf
if [ "$2" == "zsh" ] ; then
# FILE=~/.zprofile
# echo >> $FILE
# if [ ! -z "$1" ] ; then
# echo "export FEATURE_USER=$1" >> $FILE
# fi
# echo "GIT_UTILITIES_BIN=${REPO}/bin" >> $FILE
# echo "export PATH=${GIT_UTILITIES_BIN}:$PATH" >> $FILE
# # echo "source ${REPO}/dotfiles/git-completion.zsh" >> $FILE
# # echo "source ${REPO}/dotfiles/git-prompt.sh" >> $FILE
# echo "source ${REPO}/dotfiles/zprofile" >> $FILE
FILE=~/.zshrc
echo >> $FILE
if [ ! -z "$1" ] ; then
echo "export FEATURE_USER=$1" >> $FILE
fi
echo "GIT_UTILITIES=${REPO}" >> $FILE
echo 'source ${GIT_UTILITIES}/dotfiles/zshrc' >> $FILE
else
FILE=~/.bash_profile
echo >> $FILE
if [ ! -z "$1" ] ; then
echo "export FEATURE_USER=$1" >> $FILE
fi
echo "GIT_UTILITIES=${REPO}" >> $FILE
echo 'export PATH=${GIT_UTILITIES}/bin:$PATH' >> $FILE
echo 'source ${GIT_UTILITIES}/dotfiles/git-completion.bash' >> $FILE
echo 'source ${GIT_UTILITIES}/dotfiles/git-prompt.sh' >> $FILE
echo 'source ${GIT_UTILITIES}/dotfiles/bash_profile' >> $FILE
FILE=~/.bashrc
echo >> $FILE
echo "GIT_UTILITIES=${REPO}" >> $FILE
echo 'source ${GIT_UTILITIES}/dotfiles/bashrc' >> $FILE
fi

View File

@@ -0,0 +1,89 @@
require 'ostruct'
require 'optparse'
require 'json'
require_relative './prompt'
module Setup
class Commander
attr_accessor :options
def initialize (argv)
@options = OpenStruct.new
@option_parser = OptionParser.new do |op|
op.banner = "Usage: setup options"
op.on('-u','--user USER') do |argument|
options.user = argument
end
op.on_tail('-h','--help') do |argument|
puts op
exit
end
end
@option_parser.parse!(argv)
options.terms = argv # must be after parse!
end
def valid?
options.user
end
def help
puts @option_parser
exit
end
def execute
action = options.action
File.open("#{ENV['HOME']}/.bash_profile", "a") do |f|
f.puts
f.puts "# added by ~/GitHub/rkiel/git-utilities/install/bin/setup"
f.puts 'export GIT_UTILITIES_BIN="~/GitHub/rkiel/git-utilities/bin"'
f.puts 'export PATH=${GIT_UTILITIES_BIN}:$PATH'
f.puts 'source ~/GitHub/rkiel/git-utilities/dotfiles/git-completion.bash'
f.puts 'source ~/GitHub/rkiel/git-utilities/dotfiles/git-prompt.sh'
f.puts "export FEATURE_USER=#{options.user}" if options.user
f.puts "export PS1='#{Setup::Prompt.new.generate(options)}'"
f.puts
end
File.open("#{ENV['HOME']}/.bashrc", "a") do |f|
f.puts
f.puts "# added by ~/GitHub/rkiel/git-utilities/install/bin/setup"
f.puts 'source ~/GitHub/rkiel/git-utilities/dotfiles/bashrc'
f.puts
end
end
private
def run_cmd ( cmd )
puts
puts cmd
success = system cmd
unless success
error "(see above)"
end
puts
end
def error ( msg )
puts
puts "ERROR: #{msg}"
puts
exit
end
end
end

114
install/lib/setup/prompt.rb Normal file
View File

@@ -0,0 +1,114 @@
module Setup
class Prompt
USERNAME = '\u'
ABSOLUTE = '\w'
RELATIVE = '\W'
PROMPT = '\$'
HOSTNAME = '\h'
GIT = '$(__git_ps1 " %s")'
# Reset
Color_Off='\e[0m' # Text Reset
# Regular Colors
Black='\e[0;30m' # Black
Red='\e[0;31m' # Red
Green='\e[0;32m' # Green
Yellow='\e[0;33m' # Yellow
Blue='\e[0;34m' # Blue
Purple='\e[0;35m' # Purple
Cyan='\e[0;36m' # Cyan
White='\e[0;37m' # White
# Bold
BBlack='\e[1;30m' # Black
BRed='\e[1;31m' # Red
BGreen='\e[1;32m' # Green
BYellow='\e[1;33m' # Yellow
BBlue='\e[1;34m' # Blue
BPurple='\e[1;35m' # Purple
BCyan='\e[1;36m' # Cyan
BWhite='\e[1;37m' # White
# Underline
UBlack='\e[4;30m' # Black
URed='\e[4;31m' # Red
UGreen='\e[4;32m' # Green
UYellow='\e[4;33m' # Yellow
UBlue='\e[4;34m' # Blue
UPurple='\e[4;35m' # Purple
UCyan='\e[4;36m' # Cyan
UWhite='\e[4;37m' # White
# Background
On_Black='\e[40m' # Black
On_Red='\e[41m' # Red
On_Green='\e[42m' # Green
On_Yellow='\e[43m' # Yellow
On_Blue='\e[44m' # Blue
On_Purple='\e[45m' # Purple
On_Cyan='\e[46m' # Cyan
On_White='\e[47m' # White
# High Intensity
IBlack='\e[0;90m' # Black
IRed='\e[0;91m' # Red
IGreen='\e[0;92m' # Green
IYellow='\e[0;93m' # Yellow
IBlue='\e[0;94m' # Blue
IPurple='\e[0;95m' # Purple
ICyan='\e[0;96m' # Cyan
IWhite='\e[0;97m' # White
# Bold High Intensity
BIBlack='\e[1;90m' # Black
BIRed='\e[1;91m' # Red
BIGreen='\e[1;92m' # Green
BIYellow='\e[1;93m' # Yellow
BIBlue='\e[1;94m' # Blue
BIPurple='\e[1;95m' # Purple
BICyan='\e[1;96m' # Cyan
BIWhite='\e[1;97m' # White
# High Intensity backgrounds
On_IBlack='\e[0;100m' # Black
On_IRed='\e[0;101m' # Red
On_IGreen='\e[0;102m' # Green
On_IYellow='\e[0;103m' # Yellow
On_IBlue='\e[0;104m' # Blue
On_IPurple='\e[0;105m' # Purple
On_ICyan='\e[0;106m' # Cyan
On_IWhite='\e[0;107m' # White
def generate (options)
values = []
values << '['
values << color(Purple)
values << USERNAME
values << '@'
values << HOSTNAME
values << color(Color_Off)
values << ' '
values << color(BBlue)
values << RELATIVE
values << color(Green)
values << GIT
values << color(Color_Off)
values << ']'
values << PROMPT
values << ' '
values.join('')
end
private
def color (value)
'\['+value+'\]'
end
end
end

18
js/branch.js Normal file
View File

@@ -0,0 +1,18 @@
let lib;
// TODO: read from .git-utilities
function standard() {
return ["master", "release", "main", "develop"];
}
function isStandard(b) {
return lib.standard().includes(b);
}
function isNonStandard(b) {
return !lib.isStandard(b);
}
lib = { standard, isStandard, isNonStandard };
module.exports = lib;

45
js/commander.js Normal file
View File

@@ -0,0 +1,45 @@
const commander = require("commander");
const program = new commander.Command();
const something = program.parse(process.argv);
let lib;
function args() {
return something.args;
}
function featureName() {
return args().join("-");
}
function parse() {
return { program: something };
}
function prefix() {
return process.env.FEATURE_USER || process.env.USER;
}
function toPromise(dp) {
return Promise.resolve(dp);
}
function echo(dp) {
console.log(JSON.stringify(dp, null, 2));
return dp;
}
function start() {
return toPromise(parse());
}
lib = {
args,
parse,
featureName,
prefix,
start,
echo
};
module.exports = lib;

17
js/file.js Normal file
View File

@@ -0,0 +1,17 @@
const fs = require("fs");
const util = require("util");
let lib;
function exists(path) {
const stat = util.promisify(fs.stat);
return stat(path);
}
function read(path) {
const readFile = util.promisify(fs.readFile);
return readFile(path).then(buffer => buffer.toString("utf-8"));
}
lib = { exists, read };
module.exports = lib;

130
js/git.js Normal file
View File

@@ -0,0 +1,130 @@
const _ = require("lodash");
const path = x => require("../" + x);
const commander = path("js/commander");
const immutable = path("js/immutable");
const shell = path("js/shell");
const file = path("js/file");
const branch = path("js/branch");
let lib;
function setBranch(dp, field, branch) {
return immutable.set(dp, `branch.${field}`, branch);
}
function setCurrentBranch(dp) {
return file
.read(".git/HEAD")
.then(contents => contents.split("/"))
.then(parts => _.last(parts))
.then(last => last.trim())
.then(branch => immutable.set(dp, "branch.current", branch));
}
function setStandardAndFeature(dp) {
const current = _.get(dp, "branch.current");
if (branch.isStandard(current)) {
return immutable.set(
immutable.set(dp, "branch.standard", current),
"branch.feature",
false
);
} else {
const parts = current.split("-");
if (
parts.length > 2 &&
commander.prefix() === parts[0] &&
branch.isStandard(parts[1])
) {
return immutable.set(
immutable.set(dp, "branch.standard", parts[1]),
"branch.feature",
current
);
} else {
return immutable.set(
immutable.set(dp, "branch.standard", false),
"branch.feature",
false
);
}
}
}
function setRemote(dp) {
const current = _.get(dp, "branch.current");
if (branch.isStandard(current)) {
return immutable.set(dp, "branch.remote", false);
} else {
return file
.exists(`.git/refs/remotes/origin/${current}`)
.then(() => immutable.set(dp, "branch.remote", current))
.catch(() => immutable.set(dp, "branch.remote", false));
}
}
function gather(dp) {
return file
.exists(".git")
.then(() => ({}))
.then(lib.setCurrentBranch)
.then(lib.setStandardAndFeature)
.then(lib.setRemote)
.catch(() => {
throw "not in GIT_ROOT";
});
}
// function setCurrentBranch(dp) {
// const cmd = "git rev-parse --abbrev-ref HEAD";
//
// return shell.capture(cmd).then(x => immutable.set(dp, "branch.current", x));
// }
function setFeatureBranch(dp) {
const fb = [
commander.prefix(),
dp.branch.current,
commander.featureName()
].join("-");
return immutable.set(dp, "branch.feature", fb);
}
function parseCurrentBranch(dp) {
const parts = dp.branch.current.split("-");
return immutable.set(dp, "branch.parts", parts);
}
function setStandardBranch(dp) {
const parts = _.get(dp, "branch.parts", []);
return immutable.set(dp, "branch.standard", parts[1]);
}
function isBranchRemote(dp) {
const branch = _.get(dp, "branch.current");
const cmd = `git branch -r|grep origin|grep -v 'HEAD'|grep ${branch}`;
return shell
.capture(cmd)
.then(x => x.trim())
.then(x =>
x === ""
? immutable.set(dp, "branch.remote", false)
: immutable.set(dp, "branch.remote", branch)
);
}
lib = {
//setCurrentBranch,
setFeatureBranch,
setStandardBranch,
parseCurrentBranch,
isBranchRemote,
gather,
setStandardAndFeature,
setCurrentBranch,
setRemote,
setBranch: _.curry(setBranch)
};
module.exports = lib;

13
js/immutable.js Normal file
View File

@@ -0,0 +1,13 @@
const _ = require("lodash");
let lib;
function set(dp, path, value) {
return _.set(_.assign({}, dp), path, value);
}
lib = {
set
};
module.exports = lib;

47
js/shell.js Normal file
View File

@@ -0,0 +1,47 @@
const _ = require("lodash");
const util = require("util");
const child_process = require("child_process");
const exec = util.promisify(child_process.exec);
let lib;
function run(cmd) {
return exec(cmd);
}
function capture(cmd) {
return lib.run(cmd).then(x => x.stdout.trim());
}
function _something(dp) {
return function() {
return dp;
};
}
function something(cmd, dp) {
return lib.run(cmd).then(lib._something(dp));
}
function pipeline(cmds) {
return _.reduce(
cmds,
(accum, elem) => {
return accum
.then(() => console.log())
.then(() => console.log(elem))
.then(() => exec(elem));
},
Promise.resolve({})
).then(() => console.log());
}
lib = {
_something,
run,
capture,
pipeline,
something: _.curry(something)
};
module.exports = lib;

50
js/validate.js Normal file
View File

@@ -0,0 +1,50 @@
const path = x => require("../" + x);
const branch = path("js/branch");
const commander = path("js/commander");
let lib;
function currentIsStandardBranch(dp) {
if (branch.isNonStandard(dp.branch.current)) {
const branches = branch
.standard()
.sort()
.join(", ");
throw `ERROR: starting branch must be one of: ${branches}`;
} else {
return dp;
}
}
function featureIsNotStandardBranch(dp) {
if (branch.isStandard(commander.featureName())) {
const branches = branch
.standard()
.sort()
.join(", ");
throw `ERROR: feature branch cannot be any of: ${branches}`;
} else {
return dp;
}
}
function mustBeFeatureBranch(dp) {
const parts = dp.branch.parts;
if (
parts.length > 2 &&
commander.prefix() === parts[0] &&
branch.isStandard(parts[1])
) {
return dp;
} else {
throw `ERROR: ${dp.branch.current} is not a feature branch`;
}
}
lib = {
currentIsStandardBranch,
mustBeFeatureBranch,
featureIsNotStandardBranch
};
module.exports = lib;

View File

@@ -10,6 +10,7 @@ module Feature
:help,
:end,
:rebase,
:republish,
:merge,
:start,
:tab,

View File

@@ -14,18 +14,27 @@ module Feature
def execute
parts = parse_branch(current_branch)
standard_branch = parts[:standard]
feature_branch = current_branch
remote_branch = remote_branch(feature_branch)
if argv.size == 2
merge_to_branch = argv[1]
elsif argv.size == 1
merge_to_branch = parts[:standard]
end
feature_branch = current_branch
error "invalid branch: #{merge_to_branch}" unless standard_branches.include? merge_to_branch or merge_to_branch =~ /\d+\.\d+\.\d+/
# should match rebase
git_fetch
git_rebase ['origin', standard_branch].join('/')
if remote_branch != ""
git_remote_branch_delete feature_branch
end
git_push feature_branch
git_checkout merge_to_branch
git_pull merge_to_branch
git_merge feature_branch
git_push merge_to_branch
git_push_tags

View File

@@ -21,16 +21,13 @@ module Feature
error "USAGE: feature rebase" unless standard_branch
error "invalid feature branch: #{feature_branch}" if standard_branches.include? feature_branch
git_checkout standard_branch
git_pull standard_branch
git_checkout feature_branch
git_rebase standard_branch
git_fetch
git_rebase ['origin', standard_branch].join('/')
if remote_branch != ""
git_remote_branch_delete feature_branch
end
git_push feature_branch
end
end

73
lib/feature/republish.rb Normal file
View File

@@ -0,0 +1,73 @@
require_relative './base'
module Feature
class Republish < Feature::Base
def valid?
argv.size == 1
end
def help
"feature republish"
end
def execute
parts = parse_branch(current_branch)
standard_branch = parts[:standard]
feature_branch = current_branch
remote_branch = remote_branch(feature_branch)
error "USAGE: feature republish" unless standard_branch
error "invalid feature branch: #{feature_branch}" if standard_branches.include? feature_branch
git_checkout standard_branch
git_fetch
git_pull standard_branch
git_checkout feature_branch
git_rebase standard_branch
if remote_branch != ""
git_remote_branch_delete feature_branch
end
git_push feature_branch
version = package_json_version('0.0.0-0')
tags = `git tag -l`.strip.split("\n").select {|x| x.start_with? version}
tags = tags.map {|x| x =~ /^\d+.\d+.\d+[-]\d+$/ ? x.split('-').last : '0'}
tags = tags.map {|x| x.to_i }
tags << 0
new_number = tags.uniq.max + 1
new_tag = "#{version}-#{new_number}"
git_local_tag new_tag
git_push_tags
data = republish_push
data['push_to'].each do |repo|
puts "updating #{repo}"
repo_dir = File.join(Dir.pwd, '..', repo)
json = package_json_file repo_dir
update_tag data['name'], json['dependencies'], new_tag
update_tag data['name'], json['devDependencies'], new_tag
save_package_json_file json, repo_dir
end
end
private
def update_tag name, dependencies, new_tag
dependencies.keys.each do |key|
if key == name
value = dependencies[key]
parts = value.split('#')
dependencies[key] = [parts.first,'#',new_tag].join
end
end
end
end
end

View File

@@ -17,14 +17,15 @@ module Feature
feature_name = feature_words.join('-')
feature_branch = "#{ENV['FEATURE_USER']||ENV['USER']}-#{current_branch}-#{feature_name}"
error "invalid base branch: #{current_branch}" unless standard_branches.include? current_branch or current_branch =~ /\d+\.\d+\.\d+/
error "invalid base branch. must be one of: #{standard_branches.sort.join(', ')}" unless standard_branches.include? current_branch or current_branch =~ /\d+\.\d+\.\d+/
error "invalid feature branch: #{feature_name}" if standard_branches.include? feature_name
git_pull current_branch
git_local_branch_create feature_branch
git_fetch
git_merge ['origin', current_branch].join('/')
git_branch feature_branch
git_checkout feature_branch
git_push feature_branch
end
end

View File

@@ -63,6 +63,9 @@ module Release
error "Version branch already exists: #{branch}" if remote_branch(branch) != ""
end
def validate_branch_is_master (branch)
error "Branch must be master: #{branch}" if branch != "master"
end
end

View File

@@ -17,11 +17,11 @@ module Release
validate_version_format version
validate_current_branch_master
git_pull current_branch
git_fetch_and_merge current_branch
validate_version_is_new version
update_package_json version
update_package_json version, version
git_local_tag release_tag_from_version(version)

View File

@@ -16,16 +16,15 @@ module Release
validate_current_branch_is_release
git_pull release_branch
update_package_json version_from_release_branch(release_branch)
git_fetch_and_merge release_branch
git_local_tag release_tag_from_version(version_from_release_branch(release_branch))
git_push release_branch
git_push_tags
git_checkout "master"
git_checkout :master
git_fetch_and_merge :master
git_local_branch_delete release_branch

View File

@@ -15,7 +15,7 @@ module Release
subcommand, version = *argv
validate_current_branch_master
git_pull current_branch
git_fetch_and_merge current_branch
git_checkout_track release_branch_from_version(version)
end

View File

@@ -4,19 +4,30 @@ module Release
class Leave < Release::Base
def valid?
argv.size == 1
argv.size == 2
end
def help
"release leave"
"release leave local-branch-confirmation"
end
def execute
if argv.size == 2
confirmation_branch = argv[1]
else
confirmation_branch = ''
end
release_branch = current_branch
error "Missing confirmation of branch: #{release_branch}" if confirmation_branch == ''
error "Confirmation branch does not match current branch: #{confirmation_branch} vs #{release_branch}" if release_branch != confirmation_branch
validate_current_branch_is_release
git_checkout "master"
git_local_branch_trash current_branch
git_checkout :master
git_fetch_and_merge :master
git_local_branch_trash release_branch
end
end

View File

@@ -13,8 +13,8 @@ module Release
def execute
validate_current_branch_master
git_pull current_branch
git_fetch_and_merge current_branch
puts
puts show_existing_tags
puts

View File

@@ -4,25 +4,27 @@ module Release
class Start < Release::Base
def valid?
argv.size == 3 or argv.size == 4
argv.size == 4 or argv.size == 6
end
def help
"release start (major|minor|patch) [from] version"
"release start (major|minor|patch) from version [using master]"
end
def execute
case argv.size
when 3
subcommand, level, version = *argv
when 4
subcommand, level, verb, version = *argv
starting_branch = nil
when 6
subcommand, level, verb, version, verb2, starting_branch = *argv
validate_branch_is_master(starting_branch)
end
validate_version_format version
validate_current_branch_master
git_pull current_branch
git_fetch_and_merge current_branch
validate_version_exists version
@@ -38,11 +40,16 @@ module Release
error "unknow release level: #{level}"
end
starting_branch = release_tag_from_version(version) unless starting_branch
validate_version_does_not_exist new_version
validate_release_branch_does_not_exist(release_branch_from_version(new_version))
git_local_branch_create release_branch_from_version(new_version), release_tag_from_version(version)
git_local_branch_create release_branch_from_version(new_version), starting_branch
git_push_upstream(release_branch_from_version(new_version))
update_package_json new_version, "#{new_version} started"
git_push(release_branch_from_version(new_version))
end
private

View File

@@ -24,7 +24,8 @@ module Release
error "Confirmation branch does not match current branch: #{confirmation_branch} vs #{release_branch}" if release_branch != confirmation_branch
validate_current_branch_is_release
git_checkout 'master'
git_checkout :master
git_fetch_and_merge :master
git_local_branch_trash release_branch

View File

@@ -10,7 +10,14 @@ module Shared
end
def standard_branches
['master']
defaults = ['master','release','main','develop']
dot_file = ".git-utilities-rc"
if File.exist? dot_file
json = JSON.parse(File.read(dot_file))
json['branches'] or defaults
else
defaults
end
end
def version_pattern

View File

@@ -1,4 +1,5 @@
require 'json'
require 'yaml'
module Shared
@@ -21,14 +22,50 @@ module Shared
exit
end
def update_package_json (version)
def update_package_json (version, message)
if File.exist? 'package.json'
package_json = File.read('package.json')
json = JSON.parse(package_json)
json['version'] = version
File.write('package.json', JSON.pretty_generate(json))
git_add 'package.json'
git_commit version
git_commit message, true
end
end
def package_json_version (default_value)
if File.exist? 'package.json'
package_json = File.read('package.json')
json = JSON.parse(package_json)
json['version']
else
default_value
end
end
def package_json_file (dir = '.')
name = File.join(dir, 'package.json')
if File.exist? name
package_json = File.read(name)
JSON.parse(package_json)
else
{}
end
end
def save_package_json_file (json, dir = '.')
name = File.join(dir, 'package.json')
if File.exist? name
File.write(name, JSON.pretty_generate(json))
end
end
def republish_push
name = '.republish_push.yml'
if File.exist? name
contents = YAML.load_file(name)
else
{ "push_to" => [] }
end
end
@@ -36,10 +73,6 @@ module Shared
run_cmd "git add #{path}"
end
def git_commit (msg)
run_cmd "git commit -m '#{msg}'"
end
def git_show_branches
run_cmd "git branch"
end
@@ -48,6 +81,25 @@ module Shared
run_cmd "git checkout #{branch}"
end
def git_fetch
run_cmd "git fetch origin -p && git fetch origin --tags"
end
def git_remote_merge ( branch )
run_cmd "git merge origin/#{branch} -m 'merged by release'"
end
def is_remote_branch (branch)
`git branch -r|grep origin|grep -v 'HEAD'|grep #{branch}`.strip != ""
end
def git_fetch_and_merge (branch)
git_fetch
if is_remote_branch(branch)
git_remote_merge branch
end
end
def git_remote_branch_delete ( branch )
run_cmd "git push origin :#{branch}"
end
@@ -84,6 +136,10 @@ module Shared
run_cmd "git merge #{branch}"
end
def git_branch (branch)
run_cmd "git branch #{branch}"
end
def git_push (branch)
run_cmd "git push origin #{branch}"
end

117
lib/xfind/commander.rb Normal file
View File

@@ -0,0 +1,117 @@
require 'ostruct'
require 'optparse'
module Xfind
class Commander
attr_accessor :options
def initialize (argv)
@options = OpenStruct.new
options.debug = false
options.names = []
options.paths = [
{exclude: true, pattern: '.git'},
{exclude: true, pattern: 'node_modules'}
]
@option_parser = OptionParser.new do |op|
op.banner = "Usage: xfind options term(s)"
op.on('-d','--[no-]debug') do |argument|
options.debug = argument
end
op.on('-n NAME', 'include NAME') do |argument|
options.names << {exclude: false, pattern: argument}
end
op.on('-N NAME','exclude NAME') do |argument|
options.names << {exclude: true, pattern: argument}
end
op.on('-p PATH','include PATH') do |argument|
options.paths << {exclude: false, pattern: argument}
end
op.on('-P PATH','exclude PATH') do |argument|
options.paths << {exclude: true, pattern: argument}
end
op.on_tail('-h','--help') do |argument|
puts op
exit
end
end
@option_parser.parse!(argv)
options.terms = argv # must be after parse!
end
def valid?
true #options.terms.size > 0
end
def help
puts @option_parser
exit
end
def execute
include_paths = options.paths.reject {|x| x[:exclude] }.map {|x| "-path '*/#{x[:pattern]}/*'"}
if include_paths.size > 1
include_paths = include_paths.join(' -o ')
include_paths = ['\(', include_paths, '\)']
end
include_paths = include_paths.join(' ')
exclude_paths = options.paths.select {|x| x[:exclude] }.map {|x| "! -path '*/#{x[:pattern]}/*'"}
if exclude_paths.size > 1
exclude_paths = exclude_paths.join(' -a ')
exclude_paths = ['\(', exclude_paths, '\)']
end
exclude_paths = exclude_paths.join(' ')
include_names = options.names.reject {|x| x[:exclude] }.map {|x| "-name '*.#{x[:pattern]}'"}
if include_names.size > 1
include_names = include_names.join(' -o ')
include_names = ['\(', include_names, '\)']
end
include_names = include_names.join(' ')
exclude_names = options.names.select {|x| x[:exclude] }.map {|x| "! -name '*.#{x[:pattern]}'"}
if exclude_names.size > 1
exclude_names = exclude_names.join(' -a ')
exclude_names = ['\(', exclude_names, '\)']
end
exclude_names = exclude_names.join(' ')
commands = [
["find", ".", "-type f", include_names, exclude_names, include_paths, exclude_paths].join(" "),
"sort",
]
if options.terms.size > 0
terms = options.terms.map {|x| "grep --color=auto #{x}"}.join(' | ')
commands << ["xargs", terms].join(' ')
end
command = commands.join('|')
if options.debug
puts command
else
system command
end
end
private
def default_environment
Xfind::SimpleEnv.new
end
end
end

18
package-lock.json generated Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "git-utilities",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"commander": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
}
}
}

27
package.json Normal file
View File

@@ -0,0 +1,27 @@
{
"name": "git-utilities",
"version": "1.0.0",
"description": "This is a collection of simple command-line scripts, bash aliases, and bash utilities that make using `git` even easier.",
"main": "index.js",
"directories": {
"lib": "lib"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/rkiel/git-utilities.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/rkiel/git-utilities/issues"
},
"homepage": "https://github.com/rkiel/git-utilities#readme",
"dependencies": {
"commander": "^2.20.0",
"lodash": "^4.17.20"
}
}