@kova1/pullr 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -26
- package/bin/pullr +9 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ everything current means `cd`-ing into each one.
|
|
|
12
12
|
|
|
13
13
|
```console
|
|
14
14
|
$ pullr ~/work
|
|
15
|
-
+ api (main, 3 new
|
|
15
|
+
+ api (main, 3 new commits)
|
|
16
16
|
= web (main)
|
|
17
17
|
- scratch (main has no upstream)
|
|
18
18
|
x infra (main)
|
|
@@ -32,6 +32,12 @@ brew install kova1max/tap/pullr
|
|
|
32
32
|
npm install -g @kova1/pullr
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
To try it without installing anything:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
npx @kova1/pullr --dry-run ~/work
|
|
39
|
+
```
|
|
40
|
+
|
|
35
41
|
Or copy [`bin/pullr`](bin/pullr) anywhere on your `PATH` - it is a single bash
|
|
36
42
|
script with no dependencies beyond `git`.
|
|
37
43
|
|
|
@@ -40,6 +46,24 @@ Every release is also mirrored to
|
|
|
40
46
|
`@kova1max/pullr` (GitHub requires the repo owner as scope). Installing from
|
|
41
47
|
there needs a GitHub token, so the npm registry above is the easier choice.
|
|
42
48
|
|
|
49
|
+
## What it will never do
|
|
50
|
+
|
|
51
|
+
pullr is built to be safe to run across a whole workspace without looking
|
|
52
|
+
first. It will never:
|
|
53
|
+
|
|
54
|
+
- **Create a merge commit.** Pulls are fast-forward only.
|
|
55
|
+
- **Touch a branch that has diverged** from its upstream. It is reported as
|
|
56
|
+
failed and left exactly as it was. Rebasing it is opt-in with `--rebase`,
|
|
57
|
+
and a rebase that hits a conflict is aborted, leaving the repository as it
|
|
58
|
+
was.
|
|
59
|
+
- **Stash or discard your changes.** There is no auto-stash; if git refuses
|
|
60
|
+
to update a dirty working tree, the repository is reported as failed.
|
|
61
|
+
- **Touch a repository on a detached `HEAD`**, or a branch with no upstream.
|
|
62
|
+
Both are skipped.
|
|
63
|
+
- **Enter a nested repository.** Repositories inside another repository,
|
|
64
|
+
including submodules, are left to their parent.
|
|
65
|
+
- **Follow symlinked directories.**
|
|
66
|
+
|
|
43
67
|
## Usage
|
|
44
68
|
|
|
45
69
|
```
|
|
@@ -53,25 +77,15 @@ pullr [options] [DIR]
|
|
|
53
77
|
| `--max-depth N` | `2` | How many directory levels below `DIR` to search. `0` = only `DIR` itself, `1` = `DIR` and its direct children, ... |
|
|
54
78
|
| `-n`, `--dry-run` | | Show what a run would do without pulling, see below |
|
|
55
79
|
| `-r`, `--rebase` | off | Rebase local commits onto the upstream instead of refusing a diverged branch (`git pull --rebase`). A rebase that hits a conflict is aborted and the repository is left as it was. |
|
|
80
|
+
| `--no-color` | | Disable colored output. Also disabled when the [`NO_COLOR`](https://no-color.org) environment variable is set, or when output is not a terminal. |
|
|
56
81
|
| `-V`, `--version` | | Print the version |
|
|
57
82
|
| `-h`, `--help` | | Show help |
|
|
58
83
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
- Runs `git pull --ff-only`, so it never creates merge commits. A branch that
|
|
62
|
-
has diverged from its upstream is reported as failed and left untouched.
|
|
63
|
-
With `--rebase`, that branch's local commits are rebased onto the upstream
|
|
64
|
-
instead, and the line reads `+ api (main, 3 new commits, 2 rebased)`. There
|
|
65
|
-
is no auto-stash: a dirty tree makes git refuse the rebase, which is
|
|
66
|
-
reported as failed.
|
|
67
|
-
- Does not descend into a repository once found - nested repositories and
|
|
68
|
-
submodules are left to their parent.
|
|
69
|
-
- Skips repositories on a detached `HEAD` and branches with no upstream.
|
|
70
|
-
- Does not follow symlinked directories.
|
|
71
|
-
- Exits `1` if any pull failed, `2` on invalid arguments, `0` otherwise.
|
|
84
|
+
### Output
|
|
72
85
|
|
|
73
86
|
Each repository gets one line: `+` updated, `=` already up to date, `-`
|
|
74
|
-
skipped, `x` failed (with git's output indented below it).
|
|
87
|
+
skipped, `x` failed (with git's output indented below it). Exits `1` if any
|
|
88
|
+
pull failed, `2` on invalid arguments, `0` otherwise.
|
|
75
89
|
|
|
76
90
|
### Dry run
|
|
77
91
|
|
|
@@ -97,17 +111,6 @@ remote as it is now, then prints the same lines a real run would (with
|
|
|
97
111
|
only updates remote-tracking refs: the working tree and current branch are
|
|
98
112
|
never modified. Exit codes match a real run.
|
|
99
113
|
|
|
100
|
-
## Development
|
|
101
|
-
|
|
102
|
-
```sh
|
|
103
|
-
npm install # installs bats
|
|
104
|
-
npm test # end-to-end tests against real temporary git repos
|
|
105
|
-
npm run lint # shellcheck
|
|
106
|
-
PULLR_BASH=/bin/bash npm test # run the suite under macOS's bash 3.2
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
Releases are cut by GitHub Actions - see [RELEASE.md](RELEASE.md).
|
|
110
|
-
|
|
111
114
|
## License
|
|
112
115
|
|
|
113
116
|
[MIT](LICENSE)
|
package/bin/pullr
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Recursively find git repos under a directory and fast-forward pull each one.
|
|
3
|
-
# Usage: pullr [--jobs N] [--max-depth N] [--dry-run] [--rebase] [DIR]
|
|
3
|
+
# Usage: pullr [--jobs N] [--max-depth N] [--dry-run] [--rebase] [--no-color] [DIR]
|
|
4
4
|
set -euo pipefail
|
|
5
5
|
|
|
6
|
-
VERSION="0.
|
|
6
|
+
VERSION="0.4.0" # set by the release workflow
|
|
7
7
|
|
|
8
8
|
usage() {
|
|
9
9
|
cat <<'EOF'
|
|
@@ -24,6 +24,8 @@ Options:
|
|
|
24
24
|
refusing a branch that has diverged (git pull --rebase).
|
|
25
25
|
A rebase that hits a conflict is aborted, leaving the
|
|
26
26
|
repository as it was.
|
|
27
|
+
--no-color Disable colored output. Also disabled when NO_COLOR is
|
|
28
|
+
set (https://no-color.org) or output is not a terminal.
|
|
27
29
|
-V, --version Print the version.
|
|
28
30
|
-h, --help Show this help.
|
|
29
31
|
EOF
|
|
@@ -32,6 +34,7 @@ EOF
|
|
|
32
34
|
mode=pull
|
|
33
35
|
jobs=4
|
|
34
36
|
rebase=0
|
|
37
|
+
color=1
|
|
35
38
|
max_depth=2
|
|
36
39
|
root=""
|
|
37
40
|
|
|
@@ -43,6 +46,7 @@ while (($#)); do
|
|
|
43
46
|
--max-depth=*) max_depth="${1#*=}"; shift ;;
|
|
44
47
|
-n|--dry-run) mode=dryrun; shift ;;
|
|
45
48
|
-r|--rebase) rebase=1; shift ;;
|
|
49
|
+
--no-color) color=0; shift ;;
|
|
46
50
|
-h|--help) usage; exit 0 ;;
|
|
47
51
|
-V|--version) echo "pullr $VERSION"; exit 0 ;;
|
|
48
52
|
-*) echo "Unknown option: $1" >&2; usage >&2; exit 2 ;;
|
|
@@ -58,7 +62,8 @@ root="${root:-.}"
|
|
|
58
62
|
[[ -d "$root" ]] || { echo "Not a directory: $root" >&2; exit 2; }
|
|
59
63
|
root="$(cd "$root" && pwd)"
|
|
60
64
|
|
|
61
|
-
|
|
65
|
+
# https://no-color.org: any non-empty NO_COLOR disables color
|
|
66
|
+
if [[ "$color" == 1 && -z "${NO_COLOR:-}" && -t 1 ]]; then
|
|
62
67
|
green=$'\e[32m' yellow=$'\e[33m' red=$'\e[31m' dim=$'\e[2m' reset=$'\e[0m'
|
|
63
68
|
else
|
|
64
69
|
green="" yellow="" red="" dim="" reset=""
|
|
@@ -121,7 +126,7 @@ pull_repo() {
|
|
|
121
126
|
"$(update_note "$n" "$local_n" rebased)" "$reset"
|
|
122
127
|
}
|
|
123
128
|
|
|
124
|
-
# "N new
|
|
129
|
+
# "N new commits[, M rebased|to rebase]", singular when N is 1
|
|
125
130
|
update_note() {
|
|
126
131
|
local n="$1" local_n="$2" verb="$3" note
|
|
127
132
|
note="$n new commit$([[ "$n" == 1 ]] || printf s)"
|